sare_lib/encryption/
mod.rs

1use std::io::{Read, Seek, Write};
2
3use sare_core::{
4    encryption::{Decryptor as CoreDecryptor, EncryptionAlgorithm, Encryptor as CoreEncryptor},
5    format::{
6        encryption::{EncryptionMetadataFormat, KEMMetadataFormat, PKDFMetadataFormat},
7        header::{HeaderFormat, HeaderMetadataFormat},
8        signature::SignatureFormat,
9    },
10    hybrid_kem::{Encapsulation, HybridKEM},
11    kdf::{HKDF, HKDFAlgorithm, KDF, PKDF, PKDFAlgorithm},
12    sha3::{Digest, Sha3_256},
13};
14use secrecy::{ExposeSecret, SecretVec};
15
16use super::SARE_VERSION;
17use crate::{
18    SareError,
19    keys::{MasterKey, SharedPublicKey},
20    signing,
21};
22
23pub struct Encryptor(MasterKey);
24
25impl Encryptor {
26    /// Create a new encryptor with a master key
27    pub fn new(master_key: MasterKey) -> Self {
28        Self(master_key)
29    }
30
31    /// Compute SHA3-256 checksum of a data stream
32    pub fn checksum<R: Read>(mut data: R) -> Result<[u8; 32], SareError> {
33        let mut hasher = Sha3_256::new();
34        let mut buf = vec![0u8; 2_048 * 2_048];
35        loop {
36            let n = data.read(&mut buf)?;
37            if n == 0 {
38                break;
39            }
40            hasher.update(&buf[..n]);
41        }
42        let digest = hasher.finalize();
43        let mut out = [0u8; 32];
44        out.copy_from_slice(&digest);
45        Ok(out)
46    }
47
48    /// Generate a PKDF from a passphrase
49    pub fn get_pkdf(
50        passphrase: &SecretVec<u8>,
51        algorithm: PKDFAlgorithm,
52        _scaling_factor: u32,
53    ) -> PKDF {
54        let salt = PKDF::generate_salt();
55        PKDF::new(passphrase, salt, algorithm)
56    }
57
58    /// Encrypt data symmetrically using a passphrase
59    pub fn encrypt_with_passphrase<R: Read, W: Write>(
60        mut data: R,
61        mut output: W,
62        pkdf: PKDF,
63        algorithm: EncryptionAlgorithm,
64    ) -> Result<(), SareError> {
65        let encryption_key = pkdf.derive_key(32)?;
66        let encryptor = CoreEncryptor::new(encryption_key, algorithm);
67
68        let pkdf_metadata = PKDFMetadataFormat {
69            pkdf_salt: pkdf.salt,
70            pkdf_algorithm: pkdf.algorithm,
71        };
72
73        let encryption_metadata = EncryptionMetadataFormat {
74            encryption_algorithm: algorithm,
75            nonce: Some(encryptor.nonce.to_owned()),
76            kem_metadata: None,
77            pkdf_metadata: Some(pkdf_metadata),
78        };
79
80        let header_metadata = HeaderMetadataFormat {
81            signature_metadata: None,
82            encryption_metadata,
83            comment: None,
84        };
85
86        let header = HeaderFormat {
87            version: SARE_VERSION,
88            metadata: header_metadata,
89            signature: None,
90        };
91
92        output.write_all(&header.encode())?;
93
94        encryptor.encrypt(&mut data, &mut output)?;
95
96        Ok(())
97    }
98
99    /// Encrypt data asymmetrically for a recipient
100    pub fn encrypt_with_recipient<R: Read, W: Write>(
101        &self,
102        mut data: R,
103        mut output: W,
104        recipient: &SharedPublicKey,
105        algorithm: EncryptionAlgorithm,
106    ) -> Result<(), SareError> {
107        let (dh_keypair, kem_keypair) = self.0.get_encryption_keypair();
108        let encryption_pub = &recipient.fullchain_public_key.encryption_public_key;
109
110        let kem = Encapsulation::new(&encryption_pub.kem_public_key, encryption_pub.kem_algorithm);
111        let kem_ciphertext = kem.encapsulate()?.cipher_text;
112
113        let hybrid_kem = HybridKEM::new(dh_keypair, kem_keypair);
114        let shared_secret =
115            hybrid_kem.calculate_raw_shared_key(&kem_ciphertext, &encryption_pub.dh_public_key)?;
116        let concated_shared_secrets = SecretVec::new(
117            [
118                shared_secret.0.expose_secret().as_slice(),
119                &shared_secret.1.expose_secret().as_slice(),
120            ]
121            .concat(),
122        );
123
124        let kdf_salt = PKDF::generate_salt();
125        let encryption_key = HKDF::new(
126            &concated_shared_secrets,
127            kdf_salt.to_owned(),
128            HKDFAlgorithm::SHA256,
129        )
130        .expand(None)?;
131
132        let message_checksum = Self::checksum(&mut data)?;
133        let signature_header =
134            signing::Signing::new(self.0.clone()).sign_attached(&message_checksum);
135        let signature = signature_header.signature;
136
137        let kem_metadata = KEMMetadataFormat {
138            kem_algorithm: hybrid_kem.kem_keypair.algorithm,
139            dh_algorithm: hybrid_kem.dh_keypair.algorithm,
140            dh_sender_public_key: hybrid_kem.dh_keypair.public_key,
141            hkdf_algorithm: HKDFAlgorithm::SHA256,
142            kem_ciphertext,
143            kdf_salt,
144        };
145
146        let encryptor = CoreEncryptor::new(encryption_key, algorithm);
147        let encryption_metadata = EncryptionMetadataFormat {
148            encryption_algorithm: algorithm,
149            nonce: Some(encryptor.nonce.to_owned()),
150            kem_metadata: Some(kem_metadata),
151            pkdf_metadata: None,
152        };
153
154        let header_metadata = HeaderMetadataFormat {
155            encryption_metadata,
156            signature_metadata: signature.signature_metadata.clone(),
157            comment: None,
158        };
159
160        let header = HeaderFormat {
161            version: SARE_VERSION,
162            metadata: header_metadata,
163            signature: Some(signature),
164        };
165
166        output.write_all(&header.encode())?;
167
168        encryptor.encrypt(&mut data, &mut output)?;
169
170        Ok(())
171    }
172}
173
174pub struct Decryptor(MasterKey);
175
176impl Decryptor {
177    pub fn new(master_key: MasterKey) -> Self {
178        Self(master_key)
179    }
180
181    pub fn decode_file_header_and_rewind<R: Read + Seek>(
182        encrypted_data: &mut R,
183    ) -> Result<HeaderFormat, SareError> {
184        let header_bytes = HeaderFormat::peek_header_seek(encrypted_data)?;
185        Ok(HeaderFormat::decode(&header_bytes)?)
186    }
187
188    pub fn decode_file_header<R: Read>(encrypted_data: &mut R) -> Result<HeaderFormat, SareError> {
189        let header_bytes = HeaderFormat::separate_header(encrypted_data)?;
190        Ok(HeaderFormat::decode(&header_bytes)?)
191    }
192
193    pub fn decrypt_with_passphrase<R: Read, W: Write>(
194        passphrase_bytes: SecretVec<u8>,
195        mut encrypted_data: R,
196        mut output: W,
197    ) -> Result<(), SareError> {
198        let header = Self::decode_file_header(&mut encrypted_data)?;
199
200        if header.version > SARE_VERSION {
201            return Err(SareError::Unexpected(format!(
202                "sare version {} or higher is required, your version is {}",
203                header.version, SARE_VERSION
204            )));
205        }
206
207        let pkdf_metadata = header
208            .metadata
209            .encryption_metadata
210            .pkdf_metadata
211            .ok_or_else(|| SareError::Unexpected("Missing PKDF metadata".into()))?;
212
213        let pkdf = PKDF::new(
214            &passphrase_bytes,
215            pkdf_metadata.pkdf_salt,
216            pkdf_metadata.pkdf_algorithm,
217        );
218        let encryption_key = pkdf.derive_key(32)?;
219
220        let algorithm = header.metadata.encryption_metadata.encryption_algorithm;
221        let nonce = header
222            .metadata
223            .encryption_metadata
224            .nonce
225            .ok_or_else(|| SareError::Unexpected("Missing nonce".into()))?;
226
227        CoreDecryptor::new(encryption_key, nonce, algorithm)
228            .decrypt(&mut encrypted_data, &mut output)?;
229
230        Ok(())
231    }
232
233    pub fn decrypt_with_recipient<R: Read, W: Write>(
234        &self,
235        mut encrypted_data: R,
236        mut output: W,
237    ) -> Result<Option<SignatureFormat>, SareError> {
238        let header_bytes = HeaderFormat::separate_header(&mut encrypted_data)?;
239        let header = HeaderFormat::decode(&header_bytes)?;
240        let encryption_metadata = &header.metadata.encryption_metadata;
241
242        let kem_metadata = encryption_metadata
243            .kem_metadata
244            .as_ref()
245            .ok_or_else(|| SareError::Unexpected("Missing KEM metadata".into()))?;
246
247        let (dh_keypair, kem_keypair) = self.0.get_encryption_keypair();
248        let hybrid_kem = HybridKEM::new(dh_keypair, kem_keypair);
249
250        let shared_secret = hybrid_kem.calculate_raw_shared_key(
251            &kem_metadata.kem_ciphertext,
252            &kem_metadata.dh_sender_public_key,
253        )?;
254
255        let concated_shared_secrets = SecretVec::new(
256            [
257                shared_secret.0.expose_secret().as_slice(),
258                shared_secret.1.expose_secret().as_slice(),
259            ]
260            .concat(),
261        );
262
263        let encryption_key = HKDF::new(
264            &concated_shared_secrets,
265            kem_metadata.kdf_salt.to_owned(),
266            HKDFAlgorithm::SHA256,
267        )
268        .expand(None)?;
269
270        let nonce = encryption_metadata
271            .nonce
272            .as_ref()
273            .ok_or_else(|| SareError::Unexpected("Missing nonce".into()))?;
274
275        CoreDecryptor::new(
276            encryption_key,
277            nonce.to_owned(),
278            encryption_metadata.encryption_algorithm,
279        )
280        .decrypt(&mut encrypted_data, &mut output)?;
281
282        Ok(header.signature)
283    }
284}