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 pub fn new(master_key: MasterKey) -> Self {
28 Self(master_key)
29 }
30
31 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 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 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 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}