sare_lib/keys/
mod.rs

1use super::certificate::Certificate;
2pub use sare_core::encryption::{EncryptionAlgorithm, KeyWrap};
3pub use sare_core::format::encryption::*;
4pub use sare_core::format::keys::*;
5pub use sare_core::format::{EncodablePublic, EncodableSecret};
6pub use sare_core::hybrid_kem::{DHAlgorithm, DHKeyPair, KEMAlgorithm, KEMKeyPair};
7pub use sare_core::hybrid_sign::{ECAlgorithm, ECKeyPair, PQAlgorithm, PQKeyPair};
8use sare_core::kdf::{KDF, PKDF, PKDFAlgorithm};
9use sare_core::pem;
10pub use sare_core::seed::Seed;
11use secrecy::{ExposeSecret, SecretString, SecretVec};
12use std::io::{BufReader, Read, Write};
13
14use crate::SareError;
15
16pub const RECOMMENDED_PKDF_PARAMS: PKDFAlgorithm = PKDFAlgorithm::Scrypt(17, 8, 12);
17
18#[derive(Clone, Copy)]
19pub struct HybridSignAlgorithm {
20    ec_algorithm: ECAlgorithm,
21    pq_algorithm: PQAlgorithm,
22}
23
24impl Default for HybridSignAlgorithm {
25    fn default() -> Self {
26        HybridSignAlgorithm {
27            ec_algorithm: ECAlgorithm::Ed25519,
28            pq_algorithm: PQAlgorithm::Dilithium3,
29        }
30    }
31}
32
33impl HybridSignAlgorithm {
34    pub fn from_string(algo: String) -> Self {
35        match algo.to_ascii_uppercase().as_str() {
36            "ED25519_DILITHIUM3" => HybridSignAlgorithm {
37                ec_algorithm: ECAlgorithm::Ed25519,
38                pq_algorithm: PQAlgorithm::Dilithium3,
39            },
40            _ => HybridSignAlgorithm::default(),
41        }
42    }
43}
44
45#[derive(Clone, Copy)]
46pub struct HybridKEMAlgorithm {
47    pub dh_algorithm: DHAlgorithm,
48    pub kem_algorithm: KEMAlgorithm,
49}
50
51impl Default for HybridKEMAlgorithm {
52    fn default() -> Self {
53        HybridKEMAlgorithm {
54            dh_algorithm: DHAlgorithm::X25519,
55            kem_algorithm: KEMAlgorithm::Kyber768,
56        }
57    }
58}
59
60impl HybridKEMAlgorithm {
61    pub fn from_string(algo: String) -> Self {
62        match algo.to_ascii_uppercase().as_str() {
63            "X25519_KYBER768" => HybridKEMAlgorithm {
64                dh_algorithm: DHAlgorithm::X25519,
65                kem_algorithm: KEMAlgorithm::Kyber768,
66            },
67            _ => HybridKEMAlgorithm::default(),
68        }
69    }
70}
71
72pub struct MasterKey {
73    hybrid_kem_algorithm: HybridKEMAlgorithm,
74    hybrid_sign_algorithm: HybridSignAlgorithm,
75    master_seed: Seed,
76}
77
78impl MasterKey {
79    pub fn generate(
80        hybrid_kem_algorithm: HybridKEMAlgorithm,
81        hybrid_sign_algorithm: HybridSignAlgorithm,
82    ) -> Self {
83        let master_seed = Seed::generate();
84
85        MasterKey {
86            hybrid_kem_algorithm,
87            hybrid_sign_algorithm,
88            master_seed,
89        }
90    }
91
92    pub fn clone(&self) -> Self {
93        MasterKey {
94            hybrid_kem_algorithm: self.hybrid_kem_algorithm,
95            hybrid_sign_algorithm: self.hybrid_sign_algorithm,
96            master_seed: Seed::new(self.master_seed.clone_raw_seed()),
97        }
98    }
99
100    pub fn export<W: Write>(
101        &self,
102        passphrase_bytes: Option<SecretVec<u8>>,
103        mut output: W,
104    ) -> Result<(), SareError> {
105        match passphrase_bytes {
106            Some(passphrase) => {
107                let pkdf_salt = PKDF::generate_salt();
108
109                let pkdf = PKDF::new(&passphrase, pkdf_salt.to_owned(), RECOMMENDED_PKDF_PARAMS);
110
111                let pkdf_metadata = PKDFMetadataFormat {
112                    pkdf_salt,
113                    pkdf_algorithm: RECOMMENDED_PKDF_PARAMS,
114                };
115
116                // NOTE: Because length is exactly 32bytes and parsable into [u8; 32] KeyWrap won't return an error
117                let derived_key = pkdf.derive_key(32).unwrap();
118                let keywrap = KeyWrap::new(derived_key).unwrap();
119
120                let encrypted_seed = keywrap.wrap(self.master_seed.get_raw_seed()).unwrap();
121
122                let encryption_metadata = EncryptionMetadataFormat {
123                    kem_metadata: None,
124                    nonce: None,
125                    encryption_algorithm: EncryptionAlgorithm::AES256KW,
126                    pkdf_metadata: Some(pkdf_metadata),
127                };
128
129                // TODO: impl `From` in sare_core::format::keys
130                let secret_key_format = SecretKeyFormat {
131                    ec_algorithm: self.hybrid_sign_algorithm.ec_algorithm,
132                    pq_algorithm: self.hybrid_sign_algorithm.pq_algorithm,
133                    dh_algorithm: self.hybrid_kem_algorithm.dh_algorithm,
134                    kem_algorithm: self.hybrid_kem_algorithm.kem_algorithm,
135                    master_seed: SecretVec::from(encrypted_seed),
136                    encryption_metadata: Some(encryption_metadata),
137                };
138
139                output.write_all(secret_key_format.encode_pem().expose_secret().as_bytes())?;
140            }
141            None => {
142                // TODO: impl `From` in sare_core::format::keys
143                let secret_key_format = SecretKeyFormat {
144                    ec_algorithm: self.hybrid_sign_algorithm.ec_algorithm,
145                    pq_algorithm: self.hybrid_sign_algorithm.pq_algorithm,
146                    dh_algorithm: self.hybrid_kem_algorithm.dh_algorithm,
147                    kem_algorithm: self.hybrid_kem_algorithm.kem_algorithm,
148                    master_seed: self.master_seed.clone_raw_seed(),
149                    encryption_metadata: None,
150                };
151
152                output.write_all(secret_key_format.encode_pem().expose_secret().as_bytes())?;
153            }
154        }
155
156        Ok(())
157    }
158
159    pub fn is_encrypted(secret_key_format: &SecretKeyFormat) -> bool {
160        secret_key_format.encryption_metadata.is_some()
161    }
162
163    pub fn decode_pem<R: Read>(serialized_master_key: R) -> Result<SecretKeyFormat, SareError> {
164        let mut reader = BufReader::new(serialized_master_key);
165
166        let mut string_buf = String::new();
167        reader.read_to_string(&mut string_buf)?;
168        Ok(SecretKeyFormat::decode_pem(SecretString::from(string_buf))?)
169    }
170
171    pub fn import(
172        decoded_master_key_format: SecretKeyFormat,
173        passphrase_bytes: Option<SecretVec<u8>>,
174    ) -> Result<Self, SareError> {
175        let hybrid_sign_algorithm = HybridSignAlgorithm {
176            ec_algorithm: decoded_master_key_format.ec_algorithm,
177            pq_algorithm: decoded_master_key_format.pq_algorithm,
178        };
179
180        let hybrid_kem_algorithm = HybridKEMAlgorithm {
181            dh_algorithm: decoded_master_key_format.dh_algorithm,
182            kem_algorithm: decoded_master_key_format.kem_algorithm,
183        };
184
185        match passphrase_bytes {
186            Some(passphrase) => {
187                // NOTE: We'll check if it's encrypted first in CLI or other interfaces
188                // TODO: Mention this on code docs later
189                let encryption_metadata = decoded_master_key_format.encryption_metadata.unwrap();
190                // NOTE: It will not be None if it's encrypted
191                let pkdf_metadata = encryption_metadata.pkdf_metadata.unwrap();
192
193                let pkdf = PKDF::new(
194                    &passphrase,
195                    pkdf_metadata.pkdf_salt,
196                    pkdf_metadata.pkdf_algorithm,
197                );
198
199                let derived_key = pkdf.derive_key(32)?;
200
201                let keywrap = KeyWrap::new(derived_key)?;
202
203                let decrypted_master_seed =
204                    keywrap.dewrap(&decoded_master_key_format.master_seed)?;
205
206                Ok(MasterKey {
207                    hybrid_sign_algorithm,
208                    hybrid_kem_algorithm,
209                    master_seed: Seed::new(decrypted_master_seed),
210                })
211            }
212            None => Ok(MasterKey {
213                hybrid_sign_algorithm,
214                hybrid_kem_algorithm,
215                master_seed: Seed::new(decoded_master_key_format.master_seed),
216            }),
217        }
218    }
219
220    pub fn get_signing_keypair(&self) -> (ECKeyPair, PQKeyPair) {
221        let ec_algorithm = self.hybrid_sign_algorithm.ec_algorithm;
222        let pq_algorithm = self.hybrid_sign_algorithm.pq_algorithm;
223
224        let ec_keypair = ECKeyPair::from_seed(&self.master_seed, ec_algorithm);
225        let pq_keypair = PQKeyPair::from_seed(&self.master_seed, pq_algorithm);
226
227        (ec_keypair, pq_keypair)
228    }
229
230    pub fn get_encryption_keypair(&self) -> (DHKeyPair, KEMKeyPair) {
231        let dh_algorithm = self.hybrid_kem_algorithm.dh_algorithm;
232        let kem_algorithm = self.hybrid_kem_algorithm.kem_algorithm;
233
234        let dh_keypair = DHKeyPair::from_seed(&self.master_seed, dh_algorithm);
235        let kem_keypair = KEMKeyPair::from_seed(&self.master_seed, kem_algorithm);
236
237        (dh_keypair, kem_keypair)
238    }
239
240    pub fn get_signing_public_key(&self) -> SignaturePublicKeyFormat {
241        let (ec_keypair, pq_keypair) = self.get_signing_keypair();
242
243        SignaturePublicKeyFormat::from_keypairs(ec_keypair, pq_keypair)
244    }
245
246    pub fn get_encryption_public_key(&self) -> EncryptionPublicKeyFormat {
247        let (dh_keypair, kem_keypair) = self.get_encryption_keypair();
248
249        EncryptionPublicKeyFormat::from_keypairs(dh_keypair, kem_keypair)
250    }
251
252    pub fn export_signature_public<W: Write>(&self, mut output: W) -> Result<(), SareError> {
253        let signature_public_key = self.get_signing_public_key();
254
255        output.write_all(signature_public_key.encode_pem().as_bytes())?;
256        Ok(())
257    }
258
259    pub fn export_encryption_public<W: Write>(&self, mut output: W) -> Result<(), SareError> {
260        let encryption_public_key = self.get_signing_public_key();
261
262        output.write_all(encryption_public_key.encode_pem().as_bytes())?;
263        Ok(())
264    }
265
266    fn get_fullchain_public_key(&self) -> FullChainPublicKeyFormat {
267        let signature_public_key = self.get_signing_public_key();
268        let encryption_public_key = self.get_encryption_public_key();
269
270        FullChainPublicKeyFormat {
271            signature_public_key,
272            encryption_public_key,
273        }
274    }
275
276    pub fn export_public<W: Write>(&self, mut output: W) -> Result<[u8; 32], SareError> {
277        let fullchain_public_key = self.get_fullchain_public_key();
278
279        output.write_all(fullchain_public_key.encode_pem().as_bytes())?;
280        Ok(fullchain_public_key.calculate_fingerprint())
281    }
282
283    pub fn get_fullchain_public_fingerprint(&self) -> [u8; 32] {
284        self.get_fullchain_public_key().calculate_fingerprint()
285    }
286
287    pub fn get_fullchain_private_fingerprint(&self) -> Vec<u8> {
288        SecretKeyFormat::calculate_fingerprint(self.master_seed.clone_raw_seed())
289    }
290
291    pub fn to_mnemonic(&self) -> SecretString {
292        self.master_seed.to_mnemonic()
293    }
294}
295
296#[derive(Clone)]
297pub struct SharedPublicKey {
298    pub fullchain_public_key: FullChainPublicKeyFormat,
299    pub validation_certificate: Option<Certificate>,
300}
301
302impl SharedPublicKey {
303    pub fn new(fullchain: FullChainPublicKeyFormat, validation: Option<Certificate>) -> Self {
304        SharedPublicKey {
305            fullchain_public_key: fullchain,
306            validation_certificate: validation,
307        }
308    }
309
310    pub fn from_pem(pem_data: String) -> Result<Self, SareError> {
311        // Parse all PEM blocks at once
312        let all_pems =
313            pem::parse_many(&pem_data).map_err(|e| SareError::Unexpected(e.to_string()))?;
314
315        let mut fullchain_public_key: Option<FullChainPublicKeyFormat> = None;
316        let mut validation_certificate: Option<Certificate> = None;
317
318        for block in all_pems {
319            match block.tag() {
320                sare_core::format::keys::FULLCHAIN_PUBLIC_KEY_PEM_TAG => {
321                    fullchain_public_key =
322                        Some(FullChainPublicKeyFormat::decode_bson(block.contents())?);
323                }
324                sare_core::format::certificate::VALIDATION_PEM_TAG => {
325                    validation_certificate = Some(Certificate::decode_bson(block.contents())?)
326                }
327                _ => {}
328            }
329        }
330
331        let fullchain_public_key = fullchain_public_key.ok_or(SareError::Unexpected(
332            "Recipient's PublicKey is Missing".to_string(),
333        ))?;
334
335        Ok(SharedPublicKey {
336            fullchain_public_key,
337            validation_certificate,
338        })
339    }
340
341    pub fn export<W: Write>(&self, mut output: W) -> Result<[u8; 32], SareError> {
342        let fullchain_public_key = &self.fullchain_public_key;
343
344        output.write_all(fullchain_public_key.encode_pem().as_bytes())?;
345
346        if let Some(validation_certificate) = &self.validation_certificate {
347            validation_certificate.export(output)?;
348        }
349
350        Ok(fullchain_public_key.calculate_fingerprint())
351    }
352}