Skip to main content

relay_crypto/
alg.rs

1use rand_core::{CryptoRng, RngCore};
2use serde::{Serialize, de::DeserializeOwned};
3
4use crate::record::{Key, PubRecord};
5use relay_core::{
6    info::{EncryptionInfo, SignatureInfo},
7    prelude::{Payload, Signature},
8};
9
10#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
11pub enum AlgorithmError {
12    #[error("Algorithm mismatch: expected {0}, got {1}")]
13    AlgorithmMismatch(String, String),
14    #[error("Invalid secrets: {0}")]
15    InvalidSecrets(String),
16    #[error("Invalid meta: {0}")]
17    InvalidMeta(String),
18    #[error("Signature is missing")]
19    SignatureMissing,
20    #[error("Key derivation failed: {0}")]
21    KeyDerivation(String),
22    #[error("Invalid nonce")]
23    Nonce,
24    #[error("Invalid ephemeral")]
25    Ephemeral,
26    #[error("Encryption failed: {0}")]
27    Encrypt(String),
28    #[error("Decryption failed: {0}")]
29    Decrypt(String),
30    #[error("Failed: {0}")]
31    Error(String),
32}
33
34pub trait EncryptionContext {
35    fn decrypt<T>(&self, payload: &Payload<T>, aad: &[u8]) -> Result<Vec<u8>, AlgorithmError>;
36}
37
38pub trait EncryptionAlgorithm {
39    type Meta: Serialize + DeserializeOwned;
40    type Secrets: Serialize + DeserializeOwned;
41    type Context: EncryptionContext;
42
43    fn alg() -> &'static str;
44    fn info() -> Vec<u8> {
45        format!("relay-{}", Self::alg()).into_bytes()
46    }
47
48    fn generate(
49        &self,
50        rng: impl RngCore + CryptoRng,
51    ) -> Result<(Key, Self::Secrets), AlgorithmError>;
52
53    fn open_inner(
54        &self,
55        meta: &Self::Meta,
56        secrets: &Self::Secrets,
57    ) -> Result<Self::Context, AlgorithmError>;
58
59    fn encrypt_inner(
60        &self,
61        rng: impl RngCore + CryptoRng,
62        recipient: &PubRecord,
63        payload: &[u8],
64        aad: &[u8],
65    ) -> Result<(Self::Meta, Vec<u8>), AlgorithmError>;
66
67    fn open(&self, info: &EncryptionInfo, secrets: &[u8]) -> Result<Self::Context, AlgorithmError> {
68        if info.alg != Self::alg() {
69            return Err(AlgorithmError::AlgorithmMismatch(
70                info.alg.clone(),
71                Self::alg().to_string(),
72            ));
73        }
74
75        let meta: Self::Meta = serde_json::from_slice(&info.data)
76            .map_err(|e| AlgorithmError::InvalidMeta(format!("Failed to parse meta: {e}")))?;
77        let secrets: Self::Secrets = serde_json::from_slice(secrets)
78            .map_err(|e| AlgorithmError::InvalidSecrets(format!("Failed to parse secrets: {e}")))?;
79        self.open_inner(&meta, &secrets)
80    }
81
82    fn encrypt<T>(
83        &self,
84        rng: impl RngCore + CryptoRng,
85        recipient: &PubRecord,
86        payload: &[u8],
87        aad: &[u8],
88    ) -> Result<Payload<T>, AlgorithmError> {
89        self.encrypt_inner(rng, recipient, payload, aad)
90            .map(|(meta, ciphertext)| {
91                let meta_bytes = serde_json::to_vec(&meta).map_err(|e| {
92                    AlgorithmError::InvalidMeta(format!("Failed to serialize meta: {e}"))
93                })?;
94                Ok(Payload::new(
95                    EncryptionInfo {
96                        alg: Self::alg().to_string(),
97                        data: meta_bytes,
98                    },
99                    None,
100                    ciphertext,
101                ))
102            })?
103    }
104}
105
106pub trait SigningAlgorithm: Send + Sync {
107    type Meta: Serialize + DeserializeOwned;
108    type Secrets: Serialize + DeserializeOwned;
109
110    fn alg() -> &'static str;
111
112    fn sign_inner(
113        &self,
114        payload: &[u8],
115        secrets: &Self::Secrets,
116    ) -> Result<(Self::Meta, Vec<u8>), AlgorithmError>;
117
118    fn verify_inner(
119        &self,
120        meta: &Self::Meta,
121        signature: &[u8],
122        payload: &[u8],
123    ) -> Result<(), AlgorithmError>;
124
125    fn sign<T>(
126        &self,
127        payload: Payload<T>,
128        raw_secrets: &[u8],
129    ) -> Result<Payload<T>, AlgorithmError> {
130        let secrets: Self::Secrets = serde_json::from_slice(raw_secrets)
131            .map_err(|e| AlgorithmError::InvalidSecrets(format!("{e}")))?;
132
133        let (meta, sig_bytes) = self.sign_inner(&payload.signing_bytes(), &secrets)?;
134
135        let meta_bytes =
136            serde_json::to_vec(&meta).map_err(|e| AlgorithmError::InvalidMeta(format!("{e}")))?;
137
138        let mut signed_payload = payload;
139        signed_payload.signature = Some(Signature {
140            info: SignatureInfo {
141                alg: Self::alg().to_string(),
142                data: meta_bytes,
143            },
144            sig: sig_bytes,
145        });
146
147        Ok(signed_payload)
148    }
149
150    fn verify<T>(&self, payload: &Payload<T>) -> Result<(), AlgorithmError> {
151        let signature = payload
152            .signature
153            .as_ref()
154            .ok_or(AlgorithmError::SignatureMissing)?;
155
156        if signature.info.alg != Self::alg() {
157            return Err(AlgorithmError::AlgorithmMismatch(
158                signature.info.alg.clone(),
159                Self::alg().to_string(),
160            ));
161        }
162
163        let meta: Self::Meta = serde_json::from_slice(&signature.info.data)
164            .map_err(|e| AlgorithmError::InvalidMeta(format!("{e}")))?;
165
166        self.verify_inner(&meta, &signature.sig, &payload.signing_bytes())
167    }
168}