ms_offcrypto_writer/
lib.rs

1//! This crate allows encrypting ECMA376/OOXML (so newer MS-Office files such as
2//! XLSX) using the agile encryption method as described in
3//! [MS-OFFCRYPTO](https://msopenspecs.azureedge.net/files/MS-OFFCRYPTO/[MS-OFFCRYPTO].pdf).
4//!
5//! See the [`Ecma376AgileWriter`] type for the actual API of this crate.
6//!
7//! # Implementation details
8//! All functions writing structures expect the buffer to be logically aligned
9//! to (= the length of the buffer is a multiple of) four bytes, and leave the
10//! buffer aligned to four bytes upon returning.
11//!
12//! A such, they may panic if and only if
13//! 1. They are passed an improperly aligned buffer, or
14//! 2. Reallocation of the buffer upon growing fails.
15
16use 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
39/// The number of iterations of hashing the password (see 2.3.4.13).
40const SPIN_COUNT: u32 = 100_000;
41
42/// The size of the header in the CFB stream of the actual encrypted data (see
43/// 2.3.4.4).
44const ENCRYPTED_PACKAGE_HEADER_SIZE: u64 = size_of::<u64>() as u64;
45
46/// The basic alignment for all data structures in the CFBs generated according
47/// to MS-OFFCRYPTO.
48const BASE_ALIGN: usize = 4;
49
50/// The size of the chunk that can be encrypted & decrypted independently of
51/// other chunks
52const 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
62/// A hole that the length of a substructure, including that length, should be
63/// back-patched into.
64///
65/// This type panics if dropped.
66struct 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
77/// A wrapper type around the buffer that includes extra assertions regarding
78/// structure size and buffer alignment.
79struct 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    /// Assert alignment of the `buffer` for the `"beginning"` or `"end"` (in
94    /// `at`) for a structure with some `name`.
95    #[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    /// Assert buffer alignment and structure size at the end of the structure.
105    #[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    /// Create a new `BufferAlignAssertScope` with all debugging information.
126    #[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    /// Create a new `BufferAlignAssertScope` *without* all debugging
139    /// information.
140    #[cfg(not(debug_assertions))]
141    fn new_inner(_: &'static str, buffer: &'a mut Vec<u8>, _: usize) -> Self {
142        BufferAlignAssertScope { buffer }
143    }
144
145    /// Create a new `BufferAlignAssertScope` for a structure with a given
146    /// length that should be appended to the buffer.
147    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    /// Create a new `BufferAlignAssertScope` for a structure with a given
153    /// length that should replace all data within the buffer.
154    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    /// Pad to the base alignment.
160    fn pad(&mut self) {
161        let len = self.len();
162        pad_to::<BASE_ALIGN>(&mut **self, len);
163    }
164
165    /// Add a 4 byte length field (`u32`) that should be back-patched later.
166    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    /// Back-patch a hole with the 4 byte length (`u32`), including that hole.
173    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    /// Produce the inner bytes as a reference
180    #[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    /// Produce the inner bytes as a reference
189    #[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
228/// Return the length in bytes of a `UNICODE-LP-P4`, as defined in 2.1.2.
229const fn unicode_lp_p4_len(data: &Utf16Str) -> usize {
230    size_of::<u32>() + (data.len() * 2).next_multiple_of(BASE_ALIGN)
231}
232
233/// Append a `UNICODE-LP-P4`, as defined in 2.1.2, to a buffer,
234fn 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    // Data length in bytes:
240    buffer.extend(&u32::to_le_bytes(data_length_in_bytes.try_into().unwrap()));
241
242    // Data:
243    for i in data.code_units() {
244        buffer.extend(&u16::to_le_bytes(i));
245    }
246
247    // Padding:
248    buffer.pad();
249}
250
251/// The length of a `Version`, as defined in 2.1.4.
252const VERSION_LEN: usize = size_of::<u16>() * 2;
253
254/// Append a `Version`, as defined in 2.1.4, to a buffer.
255fn 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
261/// Write a `DataSpaceVersionInfo`, as defined in 2.1.5, to a buffer, clearing
262/// any previous contents and returning a read-only slice to the resulting
263/// bytes.
264fn 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    // FeatureIdentifier:
270    write_unicode_lp_p4(&mut buffer, feature_identifier);
271    // ReaderVersion:
272    write_version(&mut buffer, 1, 0);
273    // UpdaterVersion:
274    write_version(&mut buffer, 1, 0);
275    // WriterVersion:
276    write_version(&mut buffer, 1, 0);
277
278    buffer.into_bytes()
279}
280
281/// Write a `DataSpaceMap`, as defined in 2.1.6, to a buffer, clearing any
282/// previous contents and returning a read-only slice to the resulting bytes.
283fn 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    // HeaderLength:
290    buffer.extend(&u32::to_le_bytes(8));
291    // EntryCount:
292    buffer.extend(&u32::to_le_bytes(1));
293    // MapEntries:
294    // a single entry of type: DataSpaceMapEntry
295    // (MapEntries[0] as DataSpaceMapEntry).Length
296    let length_hole = buffer.length_field();
297    // MapEntries[0].ReferenceComponentCount
298    buffer.extend(&u32::to_le_bytes(1));
299    // MapEntries[0].ReferenceComponents[0].ReferenceComponentType
300    buffer.extend(&u32::to_le_bytes(0));
301    // MapEntries[0].ReferenceComponents[0].ReferenceComponent
302    write_unicode_lp_p4(&mut buffer, component);
303    // MapEntries[0].DataSpaceName
304    write_unicode_lp_p4(&mut buffer, name);
305
306    buffer.back_patch(length_hole);
307
308    buffer.into_bytes()
309}
310
311/// Write a `DataSpaceDefinition`, as defined in 2.1.7, to a buffer, clearing
312/// any previous contents and returning a read-only slice to the resulting
313/// bytes.
314fn 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    // HeaderLength
320    buffer.extend(&u32::to_le_bytes(8));
321    // TransformReferenceCount
322    buffer.extend(&u32::to_le_bytes(1));
323    // TransformReferences[0]
324    write_unicode_lp_p4(&mut buffer, name);
325
326    buffer.into_bytes()
327}
328
329/// Write a `TransformInfoHeader`, as defined in 2.1.8, and then an
330/// `EncryptionTransformInfo`, as defined in 2.1.9, to a buffer, clearing any
331/// previous contents and returning a read-only slice to the resulting bytes.
332fn 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    // type: TransformInfoHeader
343    // TransformLength
344    let transform_length_hole = buffer.length_field();
345    // TransformType
346    buffer.extend(&u32::to_le_bytes(1));
347    // TransformID
348    write_unicode_lp_p4(&mut buffer, id);
349    buffer.back_patch(transform_length_hole);
350
351    // TransformName
352    write_unicode_lp_p4(&mut buffer, name);
353    // ReaderVersion
354    write_version(&mut buffer, 1, 0);
355    // UpdaterVersion
356    write_version(&mut buffer, 1, 0);
357    // WriterVersion
358    write_version(&mut buffer, 1, 0);
359
360    // type: EncryptionTransformInfo
361    // EncryptionName (null)
362    buffer.extend(&u32::to_le_bytes(0));
363    // EncryptionBlockSize. What this value should actually be in the standard
364    // is at best underspecified, and the actual value is taken from files
365    // encrypted by the reference implementation.
366    buffer.extend(&u32::to_le_bytes(0));
367    // CipherMode
368    buffer.extend(&u32::to_le_bytes(0));
369    // Reserved
370    buffer.extend(&u32::to_le_bytes(4));
371
372    buffer.into_bytes()
373}
374
375/// Produce the SHA512 hash of the concatenation of any number of byte slices.
376#[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
386/// A type that can be used as a password. Passwords are encoded as UTF16LE, so
387/// types that can directly return those codepoints without reencoding are
388/// preferable.
389pub trait Password {
390    /// Encode the password as UTF16.
391    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
436/// Encrypt data with the first 16 bytes of an initialisation vector using
437/// AES256 CBC.
438///
439/// # Panics
440/// Panics if `iv` is less than 16 bytes, or if `data` isn't a multiple of 16
441/// bytes (since the block size of AES256 is 16 bytes).
442fn 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
452/// Inverse of [`encrypt`].
453fn 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
463/// Get the IV based on the salt & block key.
464fn 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
471/// The necessary data for encrypting single chunks.
472struct ChunkEncryptionContext {
473    key_salt: [u8; 16],
474    intermediate_key: [u8; 32],
475}
476
477/// A wrapper for a given buffer or file type that implements the ECMA376 Agile
478/// encryption as described in [MS-OFFCRYPTO](https://msopenspecs.azureedge.net/files/MS-OFFCRYPTO/[MS-OFFCRYPTO].pdf).
479///
480/// This type makes sure that no unencrypted data ever hits the underlying
481/// writer, at some performance cost & increased memory usage.
482///
483/// The resulting file is only guaranteed to be valid once this type is either
484/// dropped, [`Ecma376AgileWriter::encrypt`], [`Ecma376AgileWriter::into_inner`]
485/// or [`Ecma376AgileWriter::flush`] are called.
486pub struct Ecma376AgileWriter<F: Read + Write + Seek> {
487    cfb: Option<CompoundFile<F>>,
488    /// The internal buffering to make sure no unencrypted data ever hits the
489    /// underlying reader.
490    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    /// Create a new [`Ecma376AgileWriter`].
500    ///
501    /// `file` should initially be empty.
502    ///
503    /// # Encryption Safety
504    /// This type ONLY encrypts the written data once it is either dropped or
505    /// [`Self::into_inner`] is called.
506    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        // NOTE: The standard requires the length of this to be the salt length,
571        // however actual files encrypted by the reference implementation use
572        // 64 bytes.
573        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    /// Write the `EncryptionInfo` for Agile Encryption, as defined in 2.3.4.10,
599    /// to the provided stream using the HMAC value that resulted from
600    /// encrypting the full data stream.
601    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        // type: EncryptionInfo for Agile Encryption
619        // EncryptionVersionInfo = 0x04u16, 0x04u16
620        // Reserved: 0x40u32
621        // And then a bunch of XML
622
623        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    /// Retrieve the inner reader/writer.
667    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    /// The same as calling [`Ecma376AgileWriter::flush`] & then dropping the
675    /// writer.
676    pub fn finalize(self) -> io::Result<()> {
677        self.into_inner().map(|_| ())
678    }
679
680    /// Renamed to [`Ecma376AgileWriter::finalize`].
681    #[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    // Write the length for the encrypted package & the encryption info, and
700    // flush the encrypted package as well as the cfb file.
701    fn flush(&mut self) -> io::Result<()> {
702        let mut cfb = self.cfb.take().unwrap();
703
704        if !self.dirty {
705            // Flushing in that case is unnecessary.
706            // Flush the `cfb` just to be sure that flushes arrive in the underlying writer if that
707            // is - for whatever reason - depended upon
708            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        // `write_inner` flushes the inner writer first:
717        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        // Put the `cfb` back
745        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}