1use std::{
17 io::{self, prelude::*, SeekFrom},
18 mem, ops,
19};
20
21use aes::Aes256;
22use cfb::{CompoundFile, Stream};
23use cipher::{
24 block_padding::NoPadding, BlockDecryptMut, BlockEncryptMut, BlockSizeUser, KeyIvInit,
25 KeySizeUser,
26};
27use hmac::Mac;
28use rand::{CryptoRng, Rng};
29use sha2::{Digest, Sha512};
30use widestring::{utf16str, Utf16Str};
31
32#[cfg(test)] mod test;
33
34mod buffer;
35use buffer::EncryptingBufferingCursor;
36
37type HmacSha512 = hmac::Hmac<Sha512>;
38
39const SPIN_COUNT: u32 = 100_000;
41
42const ENCRYPTED_PACKAGE_HEADER_SIZE: u64 = size_of::<u64>() as u64;
45
46const BASE_ALIGN: usize = 4;
49
50const CHUNK_SIZE: usize = 4096;
53
54fn pad_to<const ALIGN: usize>(mut writer: impl Write, len: usize) {
55 if !len.is_multiple_of(ALIGN) {
56 writer
57 .write_all(&[0; ALIGN][..(len.next_multiple_of(ALIGN) - len)])
58 .unwrap();
59 }
60}
61
62struct LenBackpatchHole {
67 at: usize,
68}
69
70#[cfg(debug_assertions)]
71impl Drop for LenBackpatchHole {
72 fn drop(&mut self) {
73 panic!("Length never got patched into the buffer at the appropriate position.")
74 }
75}
76
77struct BufferAlignAssertScope<'a> {
80 #[cfg(debug_assertions)]
81 buffer: Option<&'a mut Vec<u8>>,
82 #[cfg(not(debug_assertions))]
83 buffer: &'a mut Vec<u8>,
84 #[cfg(debug_assertions)]
85 name: &'static str,
86 #[cfg(debug_assertions)]
87 initial_len: usize,
88 #[cfg(debug_assertions)]
89 grow_by: usize,
90}
91
92impl<'a> BufferAlignAssertScope<'a> {
93 #[cfg(debug_assertions)]
96 fn assert(buffer: &[u8], name: &str, at: &str) {
97 assert_eq!(
98 buffer.len() % BASE_ALIGN,
99 0,
100 "The buffer should be aligned to {BASE_ALIGN} bytes at the {at} of {name}"
101 );
102 }
103
104 #[cfg(debug_assertions)]
106 fn assert_end(&self) {
107 assert!(
108 self.len() >= self.initial_len,
109 "Expected the buffer to have grown from {} at the end of {}, but it now has a size of \
110 {}",
111 self.initial_len,
112 self.name,
113 self.len(),
114 );
115 let actual_growth = self.len() - self.initial_len;
116 assert_eq!(
117 actual_growth, self.grow_by,
118 "Expected the buffer to have grown by {} at the end of {}, but it grew by \
119 {actual_growth}",
120 self.grow_by, self.name,
121 );
122 Self::assert(self, self.name, "end");
123 }
124
125 #[cfg(debug_assertions)]
127 fn new_inner(name: &'static str, buffer: &'a mut Vec<u8>, grow_by: usize) -> Self {
128 Self::assert(buffer, name, "start");
129 let initial_len = buffer.len();
130 BufferAlignAssertScope {
131 buffer: Some(buffer),
132 name,
133 initial_len,
134 grow_by,
135 }
136 }
137
138 #[cfg(not(debug_assertions))]
141 fn new_inner(_: &'static str, buffer: &'a mut Vec<u8>, _: usize) -> Self {
142 BufferAlignAssertScope { buffer }
143 }
144
145 fn new(name: &'static str, buffer: &'a mut Vec<u8>, length: usize) -> Self {
148 buffer.reserve(length);
149 Self::new_inner(name, buffer, length)
150 }
151
152 fn clear(name: &'static str, buffer: &'a mut Vec<u8>, length: usize) -> Self {
155 buffer.clear();
156 Self::new(name, buffer, length)
157 }
158
159 fn pad(&mut self) {
161 let len = self.len();
162 pad_to::<BASE_ALIGN>(&mut **self, len);
163 }
164
165 fn length_field(&mut self) -> LenBackpatchHole {
167 let at = self.len();
168 self.extend(u32::to_le_bytes(0));
169 LenBackpatchHole { at }
170 }
171
172 fn back_patch(&mut self, hole: LenBackpatchHole) {
174 let len_as_le_bytes = u32::to_le_bytes(self[hole.at..].len().try_into().unwrap());
175 self[hole.at..(hole.at + size_of::<u32>())].copy_from_slice(&len_as_le_bytes);
176 mem::forget(hole);
177 }
178
179 #[cfg(debug_assertions)]
181 fn into_bytes(mut self) -> &'a [u8] {
182 self.assert_end();
183 let buffer = self.buffer.take().unwrap();
184 mem::forget(self);
185 buffer
186 }
187
188 #[cfg(not(debug_assertions))]
190 fn into_bytes(self) -> &'a [u8] {
191 self.buffer
192 }
193}
194
195impl ops::Deref for BufferAlignAssertScope<'_> {
196 type Target = Vec<u8>;
197
198 #[cfg(debug_assertions)]
199 fn deref(&self) -> &Vec<u8> {
200 self.buffer.as_ref().unwrap()
201 }
202
203 #[cfg(not(debug_assertions))]
204 fn deref(&self) -> &Vec<u8> {
205 self.buffer
206 }
207}
208
209impl ops::DerefMut for BufferAlignAssertScope<'_> {
210 #[cfg(debug_assertions)]
211 fn deref_mut(&mut self) -> &mut Vec<u8> {
212 self.buffer.as_mut().unwrap()
213 }
214
215 #[cfg(not(debug_assertions))]
216 fn deref_mut(&mut self) -> &mut Vec<u8> {
217 self.buffer
218 }
219}
220
221#[cfg(debug_assertions)]
222impl Drop for BufferAlignAssertScope<'_> {
223 fn drop(&mut self) {
224 self.assert_end();
225 }
226}
227
228const fn unicode_lp_p4_len(data: &Utf16Str) -> usize {
230 size_of::<u32>() + (data.len() * 2).next_multiple_of(BASE_ALIGN)
231}
232
233fn write_unicode_lp_p4(buffer: &mut Vec<u8>, data: &Utf16Str) {
235 let data_length_in_bytes = data.len() * 2;
236 let struct_len = unicode_lp_p4_len(data);
237 let mut buffer = BufferAlignAssertScope::new("UNICODE-LP-P4", buffer, struct_len);
238
239 buffer.extend(&u32::to_le_bytes(data_length_in_bytes.try_into().unwrap()));
241
242 for i in data.code_units() {
244 buffer.extend(&u16::to_le_bytes(i));
245 }
246
247 buffer.pad();
249}
250
251const VERSION_LEN: usize = size_of::<u16>() * 2;
253
254fn write_version(buffer: &mut Vec<u8>, major: u16, minor: u16) {
256 let mut buffer = BufferAlignAssertScope::new("Version", buffer, VERSION_LEN);
257 buffer.extend(&u16::to_le_bytes(major));
258 buffer.extend(&u16::to_le_bytes(minor));
259}
260
261fn data_space_version_info(buffer: &mut Vec<u8>) -> &[u8] {
265 let feature_identifier = utf16str!("Microsoft.Container.DataSpaces");
266 let struct_len = unicode_lp_p4_len(feature_identifier) + 3 * VERSION_LEN;
267 let mut buffer = BufferAlignAssertScope::clear("DataSpaceVersionInfo", buffer, struct_len);
268
269 write_unicode_lp_p4(&mut buffer, feature_identifier);
271 write_version(&mut buffer, 1, 0);
273 write_version(&mut buffer, 1, 0);
275 write_version(&mut buffer, 1, 0);
277
278 buffer.into_bytes()
279}
280
281fn data_space_map(buffer: &mut Vec<u8>) -> &[u8] {
284 let component = utf16str!("EncryptedPackage");
285 let name = utf16str!("StrongEncryptionDataSpace");
286 let struct_len = 5 * size_of::<u32>() + unicode_lp_p4_len(component) + unicode_lp_p4_len(name);
287 let mut buffer = BufferAlignAssertScope::clear("DataSpaceMap", buffer, struct_len);
288
289 buffer.extend(&u32::to_le_bytes(8));
291 buffer.extend(&u32::to_le_bytes(1));
293 let length_hole = buffer.length_field();
297 buffer.extend(&u32::to_le_bytes(1));
299 buffer.extend(&u32::to_le_bytes(0));
301 write_unicode_lp_p4(&mut buffer, component);
303 write_unicode_lp_p4(&mut buffer, name);
305
306 buffer.back_patch(length_hole);
307
308 buffer.into_bytes()
309}
310
311fn data_space_definition(buffer: &mut Vec<u8>) -> &[u8] {
315 let name = utf16str!("StrongEncryptionTransform");
316 let struct_len = 2 * size_of::<u32>() + unicode_lp_p4_len(name);
317 let mut buffer = BufferAlignAssertScope::clear("DataSpaceDefinition", buffer, struct_len);
318
319 buffer.extend(&u32::to_le_bytes(8));
321 buffer.extend(&u32::to_le_bytes(1));
323 write_unicode_lp_p4(&mut buffer, name);
325
326 buffer.into_bytes()
327}
328
329fn transform_info(buffer: &mut Vec<u8>) -> &[u8] {
333 let id = utf16str!("{FF9A3F03-56EF-4613-BDD5-5A41C1D07246}");
334 let name = utf16str!("Microsoft.Container.EncryptionTransform");
335 let struct_len = 2 * size_of::<u32>()
336 + unicode_lp_p4_len(id)
337 + unicode_lp_p4_len(name)
338 + 3 * VERSION_LEN
339 + 4 * size_of::<u32>();
340 let mut buffer = BufferAlignAssertScope::clear("TransformInfo", buffer, struct_len);
341
342 let transform_length_hole = buffer.length_field();
345 buffer.extend(&u32::to_le_bytes(1));
347 write_unicode_lp_p4(&mut buffer, id);
349 buffer.back_patch(transform_length_hole);
350
351 write_unicode_lp_p4(&mut buffer, name);
353 write_version(&mut buffer, 1, 0);
355 write_version(&mut buffer, 1, 0);
357 write_version(&mut buffer, 1, 0);
359
360 buffer.extend(&u32::to_le_bytes(0));
363 buffer.extend(&u32::to_le_bytes(0));
367 buffer.extend(&u32::to_le_bytes(0));
369 buffer.extend(&u32::to_le_bytes(4));
371
372 buffer.into_bytes()
373}
374
375#[allow(
377 single_use_lifetimes,
378 reason = "See the `anonymous_lifetime_in_impl_trait` feature"
379)]
380fn sha512<'a>(x: impl IntoIterator<Item = &'a [u8]>) -> [u8; 64] {
381 let mut sha = Sha512::new();
382 x.into_iter().for_each(|i| sha.update(i));
383 sha.finalize().into()
384}
385
386pub trait Password {
390 fn encode_utf16(&self) -> impl IntoIterator<Item = u16> + '_;
392}
393
394impl<T: Password + ?Sized> Password for &'_ T {
395 fn encode_utf16(&self) -> impl IntoIterator<Item = u16> {
396 T::encode_utf16(self)
397 }
398}
399
400impl Password for str {
401 fn encode_utf16(&self) -> impl IntoIterator<Item = u16> {
402 self.encode_utf16()
403 }
404}
405
406impl Password for String {
407 fn encode_utf16(&self) -> impl IntoIterator<Item = u16> {
408 (**self).encode_utf16()
409 }
410}
411
412impl Password for Utf16Str {
413 fn encode_utf16(&self) -> impl IntoIterator<Item = u16> {
414 self.code_units()
415 }
416}
417
418impl Password for widestring::Utf16String {
419 fn encode_utf16(&self) -> impl IntoIterator<Item = u16> {
420 self.code_units()
421 }
422}
423
424impl Password for widestring::U16Str {
425 fn encode_utf16(&self) -> impl IntoIterator<Item = u16> {
426 self.as_slice().iter().copied()
427 }
428}
429
430impl Password for widestring::U16String {
431 fn encode_utf16(&self) -> impl IntoIterator<Item = u16> {
432 self.as_slice().iter().copied()
433 }
434}
435
436fn encrypt(data: &mut [u8], key: [u8; 32], iv: [u8; 16]) -> &[u8] {
443 assert_eq!(data.len() % 16, 0);
444
445 cbc::Encryptor::<Aes256>::new(&key.into(), &iv.into())
446 .encrypt_padded_mut::<NoPadding>(data, data.len())
447 .unwrap();
448
449 data
450}
451
452fn decrypt(data: &mut [u8], key: [u8; 32], iv: [u8; 16]) -> &[u8] {
454 assert_eq!(data.len() % 16, 0);
455
456 cbc::Decryptor::<Aes256>::new(&key.into(), &iv.into())
457 .decrypt_padded_mut::<NoPadding>(data)
458 .unwrap();
459
460 data
461}
462
463fn block_key_to_iv(salt: [u8; 16], block_key: &[u8]) -> [u8; 16] {
465 let mut iv = [0; 16];
466 iv.copy_from_slice(&sha512([&salt as &[u8], block_key])[..16]);
467
468 iv
469}
470
471struct ChunkEncryptionContext {
473 key_salt: [u8; 16],
474 intermediate_key: [u8; 32],
475}
476
477pub struct Ecma376AgileWriter<F: Read + Write + Seek> {
487 cfb: Option<CompoundFile<F>>,
488 encrypted_package: EncryptingBufferingCursor<ENCRYPTED_PACKAGE_HEADER_SIZE, Stream<F>>,
491 verifier_salt: [u8; 16],
492 verifier_h_n: [u8; 64],
493 hmac_key: [u8; 64],
494 verifier_hash_input: [u8; 16],
495 dirty: bool,
496}
497
498impl<F: Read + Write + Seek> Ecma376AgileWriter<F> {
499 pub fn create(
507 rng: &mut (impl CryptoRng + Rng),
508 password: impl Password,
509 file: F,
510 ) -> io::Result<Self> {
511 #[allow(clippy::absolute_paths, reason = "this is more readable")]
512 let mut cfb = CompoundFile::create_with_version(cfb::Version::V3, file)?;
513 cfb.create_storage("\x06DataSpaces")?;
514
515 let mut buffer = Vec::new();
516
517 let write = |cfb: &mut CompoundFile<_>, name, data: &[u8]| -> io::Result<_> {
518 let mut stream = cfb.create_new_stream(name)?;
519 stream.write_all(data)?;
520 stream.flush()?;
521 Ok(stream)
522 };
523
524 write(
525 &mut cfb,
526 "/\x06DataSpaces/Version",
527 data_space_version_info(&mut buffer),
528 )?;
529
530 write(
531 &mut cfb,
532 "/\x06DataSpaces/DataSpaceMap",
533 data_space_map(&mut buffer),
534 )?;
535
536 cfb.create_storage("/\x06DataSpaces/DataSpaceInfo")?;
537 write(
538 &mut cfb,
539 "/\x06DataSpaces/DataSpaceInfo/StrongEncryptionDataSpace",
540 data_space_definition(&mut buffer),
541 )?;
542
543 cfb.create_storage("/\x06DataSpaces/TransformInfo")?;
544 cfb.create_storage("/\x06DataSpaces/TransformInfo/StrongEncryptionTransform")?;
545 write(
546 &mut cfb,
547 "/\x06DataSpaces/TransformInfo/StrongEncryptionTransform/\x06Primary",
548 transform_info(&mut buffer),
549 )?;
550
551 let mut key_salt = [0u8; 16];
552 rng.fill(&mut key_salt);
553 let mut intermediate_key = [0u8; 32];
554 rng.fill(&mut intermediate_key);
555
556 let mut verifier_salt = [0u8; 16];
557 rng.fill(&mut verifier_salt);
558
559 let mut verifier_h_0 = Sha512::new_with_prefix(verifier_salt);
560 for i in password.encode_utf16() {
561 verifier_h_0.update(u16::to_le_bytes(i));
562 }
563 let verifier_h_0 = <[u8; 64]>::from(verifier_h_0.finalize());
564
565 let mut verifier_h_n = verifier_h_0;
566 for i in 0..SPIN_COUNT {
567 verifier_h_n = sha512([&u32::to_le_bytes(i) as &[u8], &verifier_h_n]);
568 }
569
570 let mut hmac_key = [0u8; 64];
574 rng.fill(&mut hmac_key);
575
576 let mut verifier_hash_input = [0u8; 16];
577 rng.fill(&mut verifier_hash_input);
578
579 let encrypted_package = EncryptingBufferingCursor::new(
580 write(&mut cfb, "/EncryptedPackage", &u64::to_le_bytes(0))?,
581 ChunkEncryptionContext {
582 key_salt,
583 intermediate_key,
584 },
585 );
586
587 Ok(Ecma376AgileWriter {
588 cfb: Some(cfb),
589 encrypted_package,
590 verifier_salt,
591 verifier_h_n,
592 hmac_key,
593 verifier_hash_input,
594 dirty: true,
595 })
596 }
597
598 fn encryption_info(&self, stream: &mut Stream<F>, hmac: HmacSha512) -> io::Result<()> {
602 use base64::{
603 display::Base64Display,
604 engine::general_purpose::{GeneralPurpose, STANDARD},
605 };
606
607 fn base64(bytes: &[u8]) -> Base64Display<'_, 'static, GeneralPurpose> {
608 Base64Display::new(bytes, &STANDARD)
609 }
610
611 let verifier_key = |block_key: &[u8]| {
612 let hash = sha512([&self.verifier_h_n as &[u8], block_key]);
613 let mut out = [0; 32];
614 out.copy_from_slice(&hash[..32]);
615 out
616 };
617
618 write!(
624 stream,
625 include_str!("encryption_info.xml"),
626 key_salt_size = self.encrypted_package.encryption_context().key_salt.len(),
627 aes_block_size = Aes256::block_size(),
628 aes_key_bits = Aes256::key_size() * 8,
629 sha512_size = Sha512::output_size(),
630 key_salt_base64 = base64(&self.encrypted_package.encryption_context().key_salt),
631 encrypted_hmac_key = base64(encrypt(
632 &mut { self.hmac_key },
633 self.encrypted_package.encryption_context().intermediate_key,
634 block_key_to_iv(self.encrypted_package.encryption_context().key_salt, &[
635 0x5F, 0xB2, 0xAD, 0x01, 0x0C, 0xB9, 0xE1, 0xF6
636 ]),
637 )),
638 encrypted_hmac_value = base64(encrypt(
639 &mut { hmac.finalize().into_bytes() },
640 self.encrypted_package.encryption_context().intermediate_key,
641 block_key_to_iv(self.encrypted_package.encryption_context().key_salt, &[
642 0xA0, 0x67, 0x7F, 0x02, 0xB2, 0x2C, 0x84, 0x33
643 ]),
644 )),
645 spin_count = SPIN_COUNT,
646 verifier_salt_size = self.verifier_salt.len(),
647 verifier_salt_base64 = base64(&self.verifier_salt),
648 verifier_encrypted_hash_input = base64(encrypt(
649 &mut { self.verifier_hash_input },
650 verifier_key(&[0xFE, 0xA7, 0xD2, 0x76, 0x3B, 0x4B, 0x9E, 0x79]),
651 self.verifier_salt,
652 )),
653 verifier_encrypted_hash_value = base64(encrypt(
654 &mut Sha512::digest(self.verifier_hash_input),
655 verifier_key(&[0xD7, 0xAA, 0x0F, 0x6D, 0x30, 0x61, 0x34, 0x4E]),
656 self.verifier_salt,
657 )),
658 verifier_encrypted_key_value = base64(encrypt(
659 &mut { self.encrypted_package.encryption_context().intermediate_key },
660 verifier_key(&[0x14, 0x6E, 0x0B, 0xE7, 0xAB, 0xAC, 0xD0, 0xD6]),
661 self.verifier_salt,
662 )),
663 )
664 }
665
666 pub fn into_inner(mut self) -> io::Result<F> {
668 self.flush()?;
669 let out = self.cfb.take().unwrap();
670 mem::forget(self);
671 Ok(out.into_inner())
672 }
673
674 pub fn finalize(self) -> io::Result<()> {
677 self.into_inner().map(|_| ())
678 }
679
680 #[deprecated]
682 pub fn encrypt(self) -> io::Result<()> {
683 self.finalize()
684 }
685}
686
687impl<F: Read + Write + Seek> Read for Ecma376AgileWriter<F> {
688 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
689 self.encrypted_package.read(buf)
690 }
691}
692
693impl<F: Read + Write + Seek> Write for Ecma376AgileWriter<F> {
694 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
695 self.dirty = true;
696 self.encrypted_package.write(buf)
697 }
698
699 fn flush(&mut self) -> io::Result<()> {
702 let mut cfb = self.cfb.take().unwrap();
703
704 if !self.dirty {
705 cfb.flush()?;
709 return Ok(());
710 }
711
712 let len: u64 = self.encrypted_package.size();
713 pad_to::<16>(&mut self.encrypted_package, usize::try_from(len).unwrap());
714
715 let mut hmac = HmacSha512::new_from_slice(&self.hmac_key).unwrap();
716 self.encrypted_package.write_inner(|writer| {
718 writer.seek(SeekFrom::Start(0))?;
719
720 writer.write_all(&u64::to_le_bytes(len))?;
721 hmac.update(&u64::to_le_bytes(len));
722
723 let mut buffer = [0; 1024];
724 loop {
725 let length_read = writer.read(&mut buffer)?;
726 if length_read == 0 {
727 break;
728 }
729
730 hmac.update(&buffer[..length_read]);
731 }
732
733 writer.flush()?;
734
735 Ok(())
736 })?;
737
738 let mut encryption_info_stream = cfb.create_new_stream("/EncryptionInfo")?;
739 self.encryption_info(&mut encryption_info_stream, hmac)?;
740 encryption_info_stream.flush()?;
741
742 cfb.flush()?;
743
744 self.cfb = Some(cfb);
746
747 self.dirty = false;
748
749 Ok(())
750 }
751}
752
753impl<F: Read + Write + Seek> Seek for Ecma376AgileWriter<F> {
754 fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
755 self.encrypted_package.seek(pos)
756 }
757}
758
759impl<F: Read + Write + Seek> Drop for Ecma376AgileWriter<F> {
760 fn drop(&mut self) {
761 if self.cfb.is_some() {
762 self.flush().unwrap();
763 }
764 }
765}