1use std::{
2 fs::{self, File},
3 io::{Cursor, Read, Write},
4 sync::Arc,
5};
6
7use crate::{
8 errors::{Error::Other, Result},
9 kms,
10};
11use aws_sdk_kms::model::{DataKeySpec, EncryptionAlgorithmSpec};
12use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
13use compress_manager::{self, Decoder, Encoder};
14use log::info;
15use ring::aead::{Aad, LessSafeKey, Nonce, UnboundKey, AES_256_GCM, NONCE_LEN};
18use ring::rand::{SecureRandom, SystemRandom};
19
20const DEK_AES_256_LENGTH: usize = 32;
21
22#[derive(std::clone::Clone)]
24pub struct Envelope {
25 pub kms_manager: kms::Manager,
26 pub kms_key_id: String,
27
28 pub aad_tag: String,
31}
32
33impl Envelope {
34 pub async fn seal_aes_256(&self, d: &[u8]) -> Result<Vec<u8>> {
39 info!(
40 "AES_256 envelope-encrypting data (size before encryption {})",
41 human_readable::bytes(d.len() as f64)
42 );
43
44 let dek = self
45 .kms_manager
46 .generate_data_key(&self.kms_key_id, Some(DataKeySpec::Aes256))
47 .await?;
48 if dek.plaintext.len() != DEK_AES_256_LENGTH {
49 return Err(Other {
50 message: format!(
51 "DEK.plaintext for AES_256 must be {}-byte, got {}-byte",
52 DEK_AES_256_LENGTH,
53 dek.plaintext.len()
54 ),
55 is_retryable: false,
56 });
57 }
58
59 let random = SystemRandom::new();
60 let mut nonce_bytes = [0u8; NONCE_LEN];
61 match random.fill(&mut nonce_bytes) {
62 Ok(_) => {}
63 Err(e) => {
64 return Err(Other {
65 message: format!("failed to generate ring.random for nonce ({:?})", e),
66 is_retryable: false,
67 });
68 }
69 }
70 let unbound_key = match UnboundKey::new(&AES_256_GCM, &dek.plaintext) {
71 Ok(v) => v,
72 Err(e) => {
73 return Err(Other {
74 message: format!("failed to create UnboundKey ({:?})", e),
75 is_retryable: false,
76 });
77 }
78 };
79 let safe_key = LessSafeKey::new(unbound_key);
80
81 let mut cipher = d.to_vec();
83 match safe_key.seal_in_place_append_tag(
84 Nonce::assume_unique_for_key(nonce_bytes),
85 Aad::from(self.aad_tag.clone()),
86 &mut cipher,
87 ) {
88 Ok(_) => {}
89 Err(e) => {
90 return Err(Other {
91 message: format!("failed to seal ({:?})", e),
92 is_retryable: false,
93 });
94 }
95 }
96
97 let mut encrypted = Vec::new();
104
105 match encrypted.write_u16::<LittleEndian>(NONCE_LEN as u16) {
107 Ok(_) => {}
108 Err(e) => {
109 return Err(Other {
110 message: format!("failed to write ({:?})", e),
111 is_retryable: false,
112 });
113 }
114 }
115
116 match encrypted.write_u16::<LittleEndian>(dek.ciphertext.len() as u16) {
118 Ok(_) => {}
119 Err(e) => {
120 return Err(Other {
121 message: format!("failed to write ({:?})", e),
122 is_retryable: false,
123 });
124 }
125 }
126
127 match encrypted.write_all(&nonce_bytes) {
129 Ok(_) => {}
130 Err(e) => {
131 return Err(Other {
132 message: format!("failed to write ({:?})", e),
133 is_retryable: false,
134 });
135 }
136 }
137
138 match encrypted.write_all(&dek.ciphertext) {
140 Ok(_) => {}
141 Err(e) => {
142 return Err(Other {
143 message: format!("failed to write ({:?})", e),
144 is_retryable: false,
145 });
146 }
147 }
148
149 match encrypted.write_all(&cipher) {
151 Ok(_) => {}
152 Err(e) => {
153 return Err(Other {
154 message: format!("failed to write ({:?})", e),
155 is_retryable: false,
156 });
157 }
158 }
159
160 info!(
161 "AES_256 envelope-encrypted data (encrypted size {})",
162 human_readable::bytes(encrypted.len() as f64)
163 );
164 Ok(encrypted)
165 }
166
167 pub async fn unseal_aes_256(&self, d: &[u8]) -> Result<Vec<u8>> {
171 info!(
172 "AES_256 envelope-decrypting data (size before decryption {})",
173 human_readable::bytes(d.len() as f64)
174 );
175
176 let mut buf = Cursor::new(d);
183
184 let nonce_len = match buf.read_u16::<LittleEndian>() {
185 Ok(v) => v as usize,
186 Err(e) => {
187 return Err(Other {
188 message: format!("failed to read_u16 for nonce_len ({:?})", e),
189 is_retryable: false,
190 });
191 }
192 };
193 if nonce_len != NONCE_LEN {
194 return Err(Other {
195 message: format!("nonce_len {} != NONCE_LEN {}", nonce_len, NONCE_LEN),
196 is_retryable: false,
197 });
198 }
199
200 let dek_ciphertext_len = match buf.read_u16::<LittleEndian>() {
201 Ok(v) => v as usize,
202 Err(e) => {
203 return Err(Other {
204 message: format!("failed to read_u16 for dek_ciphertext_len ({:?})", e),
205 is_retryable: false,
206 });
207 }
208 };
209 if dek_ciphertext_len > d.len() {
210 return Err(Other {
211 message: format!(
212 "invalid DEK ciphertext len {} > cipher.len {}",
213 dek_ciphertext_len,
214 d.len()
215 ),
216 is_retryable: false,
217 });
218 }
219
220 let mut nonce_bytes = [0u8; NONCE_LEN];
221 match buf.read_exact(&mut nonce_bytes) {
222 Ok(_) => {}
223 Err(e) => {
224 return Err(Other {
225 message: format!("failed to read_exact for nonce_bytes ({:?})", e),
226 is_retryable: false,
227 });
228 }
229 };
230 let nonce = Nonce::assume_unique_for_key(nonce_bytes);
231
232 let mut dek_ciphertext = zero_vec(dek_ciphertext_len);
233 match buf.read_exact(&mut dek_ciphertext) {
234 Ok(_) => {}
235 Err(e) => {
236 return Err(Other {
237 message: format!("failed to read_exact for DEK.ciphertext ({:?})", e),
238 is_retryable: false,
239 });
240 }
241 };
242 let dek_plain = self
244 .kms_manager
245 .decrypt(
246 &self.kms_key_id,
247 Some(EncryptionAlgorithmSpec::SymmetricDefault),
248 dek_ciphertext,
249 )
250 .await?;
251 let unbound_key = match UnboundKey::new(&AES_256_GCM, &dek_plain) {
252 Ok(v) => v,
253 Err(e) => {
254 return Err(Other {
255 message: format!("failed to create UnboundKey ({:?})", e),
256 is_retryable: false,
257 });
258 }
259 };
260 let safe_key = LessSafeKey::new(unbound_key);
261
262 let mut cipher = Vec::new();
263 match buf.read_to_end(&mut cipher) {
264 Ok(_) => {}
265 Err(e) => {
266 return Err(Other {
267 message: format!("failed to read_to_end for ciphertext ({:?})", e),
268 is_retryable: false,
269 });
270 }
271 };
272
273 let decrypted =
274 match safe_key.open_in_place(nonce, Aad::from(self.aad_tag.clone()), &mut cipher) {
275 Ok(plaintext) => plaintext.to_vec(),
276 Err(e) => {
277 return Err(Other {
278 message: format!("failed to open_in_place ciphertext ({:?})", e),
279 is_retryable: false,
280 });
281 }
282 };
283
284 info!(
285 "AES_256 envelope-decrypted data (decrypted size {})",
286 human_readable::bytes(decrypted.len() as f64)
287 );
288 Ok(decrypted)
289 }
290
291 pub async fn seal_aes_256_file(
297 &self,
298 src_file: Arc<String>,
299 dst_file: Arc<String>,
300 ) -> Result<()> {
301 info!("envelope-encrypting file {} to {}", src_file, dst_file);
302 let d = match fs::read(src_file.to_string()) {
303 Ok(d) => d,
304 Err(e) => {
305 return Err(Other {
306 message: format!("failed read {:?}", e),
307 is_retryable: false,
308 });
309 }
310 };
311
312 let ciphertext = match self.seal_aes_256(&d).await {
313 Ok(d) => d,
314 Err(e) => {
315 return Err(e);
316 }
317 };
318
319 let mut f = match File::create(dst_file.to_string()) {
320 Ok(f) => f,
321 Err(e) => {
322 return Err(Other {
323 message: format!("failed File::create {:?}", e),
324 is_retryable: false,
325 });
326 }
327 };
328 match f.write_all(&ciphertext) {
329 Ok(_) => {}
330 Err(e) => {
331 return Err(Other {
332 message: format!("failed File::write_all {:?}", e),
333 is_retryable: false,
334 });
335 }
336 };
337
338 Ok(())
339 }
340
341 pub async fn unseal_aes_256_file(
343 &self,
344 src_file: Arc<String>,
345 dst_file: Arc<String>,
346 ) -> Result<()> {
347 info!("envelope-decrypting file {} to {}", src_file, dst_file);
348 let d = match fs::read(src_file.to_string()) {
349 Ok(d) => d,
350 Err(e) => {
351 return Err(Other {
352 message: format!("failed read {:?}", e),
353 is_retryable: false,
354 });
355 }
356 };
357
358 let plaintext = match self.unseal_aes_256(&d).await {
359 Ok(d) => d,
360 Err(e) => {
361 return Err(e);
362 }
363 };
364
365 let mut f = match File::create(dst_file.to_string()) {
366 Ok(f) => f,
367 Err(e) => {
368 return Err(Other {
369 message: format!("failed File::create {:?}", e),
370 is_retryable: false,
371 });
372 }
373 };
374 match f.write_all(&plaintext) {
375 Ok(_) => {}
376 Err(e) => {
377 return Err(Other {
378 message: format!("failed File::write_all {:?}", e),
379 is_retryable: false,
380 });
381 }
382 };
383
384 Ok(())
385 }
386
387 pub async fn compress_seal(&self, src_file: Arc<String>, dst_file: Arc<String>) -> Result<()> {
391 info!(
392 "compress-seal: compressing the file '{}'",
393 src_file.to_string()
394 );
395 let compressed_path = random_manager::tmp_path(10, None).unwrap();
396 compress_manager::pack_file(&src_file.to_string(), &compressed_path, Encoder::Zstd(3))
397 .map_err(|e| Other {
398 message: format!("failed compression {}", e),
399 is_retryable: false,
400 })?;
401
402 info!(
403 "compress-seal: sealing the compressed file '{}'",
404 compressed_path
405 );
406 self.seal_aes_256_file(Arc::new(compressed_path), dst_file.clone())
407 .await
408 }
409
410 pub async fn unseal_decompress(
414 &self,
415 src_file: Arc<String>,
416 dst_file: Arc<String>,
417 ) -> Result<()> {
418 info!(
419 "unseal-decompress: unsealing the encrypted file '{}'",
420 src_file.as_ref()
421 );
422 let unsealed_path = random_manager::tmp_path(10, None).unwrap();
423 self.unseal_aes_256_file(src_file.clone(), Arc::new(unsealed_path.clone()))
424 .await?;
425
426 info!(
427 "unseal-decompress: decompressing the file '{}'",
428 src_file.as_ref()
429 );
430 compress_manager::unpack_file(&unsealed_path, dst_file.as_ref(), Decoder::Zstd).map_err(
431 |e| Other {
432 message: format!("failed decompression {}", e),
433 is_retryable: false,
434 },
435 )
436 }
437}
438
439fn zero_vec(n: usize) -> Vec<u8> {
440 (0..n).map(|_| 0).collect()
441}
442
443pub async fn spawn_seal_aes_256_file<S>(envelope: Envelope, src_file: S, dst_file: S) -> Result<()>
444where
445 S: AsRef<str>,
446{
447 let envelope_arc = Arc::new(envelope);
448 let src_file_arc = Arc::new(src_file.as_ref().to_string());
449 let dst_file_arc = Arc::new(dst_file.as_ref().to_string());
450 tokio::spawn(async move {
451 envelope_arc
452 .seal_aes_256_file(src_file_arc, dst_file_arc)
453 .await
454 })
455 .await
456 .expect("failed spawn await")
457}
458
459pub async fn spawn_unseal_aes_256_file<S>(
460 envelope: Envelope,
461 src_file: S,
462 dst_file: S,
463) -> Result<()>
464where
465 S: AsRef<str>,
466{
467 let envelope_arc = Arc::new(envelope);
468 let src_file_arc = Arc::new(src_file.as_ref().to_string());
469 let dst_file_arc = Arc::new(dst_file.as_ref().to_string());
470 tokio::spawn(async move {
471 envelope_arc
472 .unseal_aes_256_file(src_file_arc, dst_file_arc)
473 .await
474 })
475 .await
476 .expect("failed spawn await")
477}
478
479pub async fn spawn_compress_seal<S>(envelope: Envelope, src_file: S, dst_file: S) -> Result<()>
480where
481 S: AsRef<str>,
482{
483 let envelope_arc = Arc::new(envelope);
484 let src_file_arc = Arc::new(src_file.as_ref().to_string());
485 let dst_file_arc = Arc::new(dst_file.as_ref().to_string());
486 tokio::spawn(async move { envelope_arc.compress_seal(src_file_arc, dst_file_arc).await })
487 .await
488 .expect("failed spawn await")
489}
490
491pub async fn spawn_unseal_decompress<S>(envelope: Envelope, src_file: S, dst_file: S) -> Result<()>
492where
493 S: AsRef<str>,
494{
495 let envelope_arc = Arc::new(envelope);
496 let src_file_arc = Arc::new(src_file.as_ref().to_string());
497 let dst_file_arc = Arc::new(dst_file.as_ref().to_string());
498 tokio::spawn(async move {
499 envelope_arc
500 .unseal_decompress(src_file_arc, dst_file_arc)
501 .await
502 })
503 .await
504 .expect("failed spawn await")
505}