1 //! ECE AES-GCM 128 encrypter/decrypter pipe implementation for Firefox Send v3.
2 
3 use std::cmp::min;
4 use std::io::{self, Read, Write};
5 
6 use byteorder::{BigEndian, ByteOrder};
7 use bytes::BytesMut;
8 #[cfg(feature = "crypto-openssl")]
9 use openssl::symm;
10 #[cfg(feature = "crypto-ring")]
11 use ring::aead;
12 
13 use super::{Crypt, CryptMode};
14 use crate::config::{self, TAG_LEN};
15 use crate::crypto::{hkdf::hkdf, rand_bytes};
16 use crate::pipe::{prelude::*, DEFAULT_BUF_SIZE};
17 
18 /// The default record size in bytes to use for encryption.
19 ///
20 /// This value matches the default configured in the Firefox Send v3 source code.
21 pub const RS: u32 = config::ECE_RECORD_SIZE;
22 
23 /// The crypto key length.
24 const KEY_LEN: usize = 16;
25 
26 /// The crypto nonce length.
27 const NONCE_LEN: usize = 12;
28 
29 /// The length in bytes of the header.
30 pub const HEADER_LEN: u32 = 21;
31 
32 /// The length in bytes of the crypto salt.
33 const SALT_LEN: usize = 16;
34 
35 /// The length in bytes of the record size, as encoded in the ECE header.
36 const RS_LEN: usize = 4;
37 
38 /// The key info text.
39 const KEY_INFO: &str = "Content-Encoding: aes128gcm\0";
40 
41 /// The nonce info text.
42 const NONCE_INFO: &str = "Content-Encoding: nonce\0";
43 
44 /// Something that can encrypt or decrypt given data using ECE.
45 pub struct EceCrypt {
46     /// The crypto mode, make this encrypt or decrypt data.
47     mode: CryptMode,
48 
49     /// The crypto input key material.
50     ikm: Vec<u8>,
51 
52     /// The crypto key if known.
53     key: Option<Vec<u8>>,
54 
55     /// The crypto base nonce if known, chunk nonces are derived from.
56     nonce: Option<Vec<u8>>,
57 
58     /// The crypto salt if known.
59     salt: Option<Vec<u8>>,
60 
61     /// Sequence number of the current chunk.
62     ///
63     /// This number increases when transforming chunks.
64     /// The ciphertext header is excluded from this sequence.
65     seq: u32,
66 
67     /// The number of bytes fed into this crypter.
68     ///
69     /// When encrypting, this corresponds to the number of plaintext bytes (matches `cur`).
70     /// When decrypting, this corresponds to the number of ciphertext bytes including the header.
71     ///
72     /// Used to determine when the last chunk is reached.
73     cur_in: usize,
74 
75     /// The number of encrypted/decrypted plaintext bytes.
76     cur: usize,
77 
78     /// The total size in bytes of the plaintext.
79     len: usize,
80 
81     /// The record size used for crypto chunks.
82     ///
83     /// This value is dynamic and changes depending on the crypto mode and current progress.
84     rs: u32,
85 }
86 
87 impl EceCrypt {
88     /// Construct a new ECE crypter pipe.
89     ///
90     /// It is highly recommended to use the [`encrypt()`](Self::encrypt) and
91     /// [`decrypt()`](Self::decrypt) methods instead for constructing a new crypter.
92     ///
93     /// The size in bytes of the plaintext data must be given as `len`.
94     /// The input key material must be given as `ikm`.
95     /// When encrypting, a `salt` must be specified.
new(mode: CryptMode, len: usize, ikm: Vec<u8>, salt: Option<Vec<u8>>) -> Self96     pub fn new(mode: CryptMode, len: usize, ikm: Vec<u8>, salt: Option<Vec<u8>>) -> Self {
97         Self {
98             mode,
99             ikm,
100             key: None,
101             nonce: None,
102             salt,
103             seq: 0,
104             cur_in: 0,
105             cur: 0,
106             len,
107             rs: RS,
108         }
109     }
110 
111     /// Create an ECE encryptor.
112     ///
113     /// The size in bytes of the plaintext data that is encrypted decrypt must be given as `len`.
114     /// The input key material must be given as `ikm`.
115     /// The `salt` is optional and will be randomly generated if `None`.
encrypt(len: usize, ikm: Vec<u8>, salt: Option<Vec<u8>>) -> Self116     pub fn encrypt(len: usize, ikm: Vec<u8>, salt: Option<Vec<u8>>) -> Self {
117         // Construct the encrypter, generate random salt if not set
118         let mut crypt = Self::new(
119             CryptMode::Encrypt,
120             len,
121             ikm,
122             salt.or_else(|| Some(generate_salt())),
123         );
124 
125         // Derive the key and nonce
126         crypt.derive_key_and_nonce();
127 
128         crypt
129     }
130 
131     /// Create an ECE decryptor.
132     ///
133     /// The size in bytes of the plaintext data that is decrypted decrypt must be given as `len`.
134     /// The input key material must be given as `ikm`.
decrypt(len: usize, ikm: Vec<u8>) -> Self135     pub fn decrypt(len: usize, ikm: Vec<u8>) -> Self {
136         Self::new(CryptMode::Decrypt, len, ikm, None)
137     }
138 
139     /// Get the current desired size of a payload chunk.
140     ///
141     /// This value is dynamic and changes depending on the crypto mode, and the current stage.
142     /// Data passed to the crypter must match the chunk size.
143     #[inline(always)]
chunk_size(&self) -> u32144     fn chunk_size(&self) -> u32 {
145         match self.mode {
146             // Record size with tag length and delimiter
147             CryptMode::Encrypt => self.rs - TAG_LEN as u32 - 1,
148 
149             // Record size, header length for initial header chunk
150             CryptMode::Decrypt => {
151                 if self.has_header() {
152                     self.rs
153                 } else {
154                     HEADER_LEN
155                 }
156             }
157         }
158     }
159 
160     /// Encrypt the given `plaintext` data using this configured crypter.
161     ///
162     /// If a header hasn't been created yet, it is included in the output as well.
163     ///
164     /// This function returns `(read, out)` where `read` represents the number of read bytes from
165     /// `plaintext`, and `out` is a vector of now encrypted bytes.
166     ///
167     /// # Panics
168     ///
169     /// Panics if attempted to write more bytes than the length specified while configuring the
170     /// crypter.
pipe_encrypt(&mut self, input: Vec<u8>) -> (usize, Option<Vec<u8>>)171     fn pipe_encrypt(&mut self, input: Vec<u8>) -> (usize, Option<Vec<u8>>) {
172         // Encrypt the chunk, if the first chunk, the header must be created and prefixed
173         if !self.has_header() {
174             // Create header
175             let mut ciphertext = self.create_header();
176 
177             // Encrypt chunk and append to header base ciphertext
178             let (read, chunk) = self.encrypt_chunk(input);
179             if let Some(chunk) = chunk {
180                 ciphertext.extend_from_slice(&chunk)
181             }
182 
183             // Increase chunk sequence number
184             self.increase_seq();
185 
186             (read, Some(ciphertext))
187         } else {
188             // Encrypt chunk, increase chunk sequence number
189             let result = self.encrypt_chunk(input);
190             self.increase_seq();
191             result
192         }
193     }
194 
195     /// Decrypt the given `ciphertext` using ECE crypto.
196     ///
197     /// If the header has not been read yet, it is parsed first to initialize the proper salt and
198     /// record size.
199     ///
200     /// This function returns `(read, plaintext)` where `read` represents the number of read bytes from
201     /// `ciphertext`, and `out` is a vector of the producted plaintext.
202     ///
203     /// # Panics
204     ///
205     /// Panics if attempted to write more bytes than the length specified while configuring the
206     /// crypter, or if decryption of a chunk failed.
207     /// size.
pipe_decrypt(&mut self, input: &[u8]) -> (usize, Option<Vec<u8>>)208     fn pipe_decrypt(&mut self, input: &[u8]) -> (usize, Option<Vec<u8>>) {
209         // Parse the header before decrypting anything
210         if !self.has_header() {
211             self.parse_header(input);
212             return (input.len(), None);
213         }
214 
215         // Decrypt the chunk, increase chunk sequence number
216         let result = self.decrypt_chunk(input);
217         self.increase_seq();
218         result
219     }
220 
221     /// Encrypt the given `plaintext` chunk data using this configured crypter.
222     ///
223     /// This function returns `(read, out)` where `read` represents the number of read bytes from
224     /// `plaintext`, and `out` is a vector of now encrypted bytes.
225     ///
226     /// # Panics
227     ///
228     /// Panics if attempted to write more bytes than the length specified while configuring the
229     /// crypter.
230     #[inline(always)]
encrypt_chunk(&mut self, mut plaintext: Vec<u8>) -> (usize, Option<Vec<u8>>)231     fn encrypt_chunk(&mut self, mut plaintext: Vec<u8>) -> (usize, Option<Vec<u8>>) {
232         // // Don't allow encrypting more than specified, when tag is obtained
233         // if self.has_tag() && !plaintext.is_empty() {
234         //     panic!("could not write to AES-GCM encrypter, exceeding specified length");
235         // }
236 
237         // Update transformed length
238         let read = plaintext.len();
239         self.cur += read;
240 
241         // Generate the encryption nonce
242         let nonce = self.generate_nonce(self.seq);
243 
244         // Pad the plaintext, encrypt the chunk, append tag
245         pad(&mut plaintext, self.rs as usize, self.is_last());
246 
247         #[cfg(feature = "crypto-openssl")]
248         {
249             // Encrypt the chunk, append tag
250             let mut tag = vec![0u8; TAG_LEN];
251             let mut ciphertext = symm::encrypt_aead(
252                 symm::Cipher::aes_128_gcm(),
253                 self.key
254                     .as_ref()
255                     .expect("failed to encrypt ECE chunk, missing crypto key"),
256                 Some(&nonce),
257                 &[],
258                 &plaintext,
259                 &mut tag,
260             )
261             .expect("failed to encrypt ECE chunk");
262             ciphertext.extend_from_slice(&tag);
263 
264             (read, Some(ciphertext))
265         }
266 
267         #[cfg(feature = "crypto-ring")]
268         {
269             // Prepare sealing key
270             let nonce = aead::Nonce::try_assume_unique_for_key(&nonce)
271                 .expect("failed to encrypt ECE chunk, invalid nonce");
272             let aad = aead::Aad::empty();
273             let key = self
274                 .key
275                 .as_ref()
276                 .expect("failed to encrypt ECE chunk, missing crypto key");
277             let unbound_key = aead::UnboundKey::new(&aead::AES_128_GCM, key).unwrap();
278             let key = aead::LessSafeKey::new(unbound_key);
279 
280             // Seal in place, return sealed
281             key.seal_in_place_append_tag(nonce, aad, &mut plaintext)
282                 .expect("failed to encrypt ECE chunk");
283 
284             (read, Some(plaintext.to_vec()))
285         }
286     }
287 
288     /// Decrypt the given `ciphertext` chunk using ECE crypto.
289     ///
290     /// This function returns `(read, plaintext)` where `read` represents the number of read bytes
291     /// from `ciphertext`, and `out` is a vector of the producted plaintext.
292     ///
293     /// # Panics
294     ///
295     /// Panics if attempted to write more bytes than the length specified while configuring the
296     /// crypter, or if decryption of a chunk failed.
297     #[inline(always)]
decrypt_chunk(&mut self, ciphertext: &[u8]) -> (usize, Option<Vec<u8>>)298     fn decrypt_chunk(&mut self, ciphertext: &[u8]) -> (usize, Option<Vec<u8>>) {
299         // // Don't allow decrypting more than specified, when tag is obtained
300         // if self.has_tag() && !ciphertext.is_empty() {
301         //     panic!("could not write to AES-GCM decrypter, exceeding specified lenght");
302         // }
303 
304         // Generate encryption nonce
305         let nonce = self.generate_nonce(self.seq);
306 
307         #[cfg(feature = "crypto-openssl")]
308         {
309             // Split payload and tag
310             let (payload, tag) = ciphertext.split_at(ciphertext.len() - TAG_LEN);
311 
312             // Decrypt the chunk, and unpad decrypted payload
313             let mut plaintext = symm::decrypt_aead(
314                 symm::Cipher::aes_128_gcm(),
315                 self.key
316                     .as_ref()
317                     .expect("failed to decrypt ECE chunk, missing crypto key"),
318                 Some(&nonce),
319                 &[],
320                 payload,
321                 tag,
322             )
323             .expect("failed to decrypt ECE chunk");
324             unpad(&mut plaintext, self.is_last());
325 
326             // Update transformed length
327             self.cur += plaintext.len();
328 
329             (ciphertext.len(), Some(plaintext))
330         }
331 
332         #[cfg(feature = "crypto-ring")]
333         {
334             // Clone ciphertext so we can modify in-place
335             let mut ciphertext = ciphertext.to_vec();
336 
337             // Prepare opening key
338             let nonce = aead::Nonce::try_assume_unique_for_key(&nonce)
339                 .expect("failed to decrypt ECE chunk, invalid nonce");
340             let aad = aead::Aad::empty();
341             let key = self
342                 .key
343                 .as_ref()
344                 .expect("failed to decrypt ECE chunk, missing crypto key");
345             let unbound_key = aead::UnboundKey::new(&aead::AES_128_GCM, key).unwrap();
346             let key = aead::LessSafeKey::new(unbound_key);
347 
348             // Decrypt the chunk, and unpad decrypted payload
349             let mut plaintext = key
350                 .open_in_place(nonce, aad, &mut ciphertext)
351                 .expect("failed to decrypt ECE chunk")
352                 .to_vec();
353             unpad(&mut plaintext, self.is_last());
354 
355             // Update transformed length
356             self.cur += plaintext.len();
357 
358             (ciphertext.len(), Some(plaintext))
359         }
360     }
361 
362     /// Create the ECE crypto header.
363     ///
364     /// This header includes the salt and record size as configured in this crypter instance.
365     /// The header bytes are returned.
366     ///
367     /// # Panics
368     ///
369     /// Panics if the salt is not set.
370     #[inline(always)]
create_header(&self) -> Vec<u8>371     fn create_header(&self) -> Vec<u8> {
372         // Allocate the header
373         let mut header = Vec::with_capacity(HEADER_LEN as usize);
374 
375         // Add the salt
376         let salt = self
377             .salt
378             .as_ref()
379             .expect("failed to create ECE header, no crypto salt specified");
380         assert_eq!(salt.len(), SALT_LEN);
381         header.extend_from_slice(salt);
382 
383         // Add the record size
384         let mut rs = [0u8; 4];
385         BigEndian::write_u32(&mut rs, self.rs);
386         header.extend_from_slice(&rs);
387 
388         // Add length of unused key ID length
389         header.push(0);
390 
391         header
392     }
393 
394     /// Parse the given header bytes as ECE crypto header.
395     ///
396     /// This function attemts to parse the given header bytes.
397     /// A salt and record size is parsed, a key and nonce are derived from them.
398     /// The values are set in the inner `EceCrypt` instance and are automatically used for further
399     /// decryption.
400     ///
401     /// # Panics
402     ///
403     /// Panics if the given header bytes have an invalid size, or if the given header is not fully
404     /// parsed.
405     #[inline(always)]
parse_header(&mut self, header: &[u8])406     fn parse_header(&mut self, header: &[u8]) {
407         // Assert the header size
408         assert_eq!(
409             header.len() as u32,
410             HEADER_LEN,
411             "failed to decrypt, ECE header is not 21 bytes long",
412         );
413 
414         // Parse the salt, record size and length
415         let (salt, header) = header.split_at(SALT_LEN);
416         let (rs, header) = header.split_at(RS_LEN);
417         self.salt = Some(salt.to_vec());
418         self.rs = BigEndian::read_u32(rs);
419 
420         // Extracted in Send v3 code, but doesn't seem to be used
421         let (key_id_data, header) = header.split_at(1);
422         let key_id_len = key_id_data[0] as usize;
423         let _length = key_id_len + KEY_LEN + 5;
424 
425         // Derive the key and nonce based on extracted salt
426         self.derive_key_and_nonce();
427 
428         // Assert all header bytes have been consumed
429         // If this fails, update `len_encrypted` as well
430         assert!(
431             header.is_empty(),
432             "failed to decrypt, not all ECE header bytes are used",
433         );
434     }
435 
436     /// Derive the crypto key and base nonce.
437     ///
438     /// These are derived based on `self.salt` and `self.ikm`, and must be configured.
439     ///
440     /// # Panics
441     ///
442     /// panics if either `self.salt` or `self.ikm` is not configured.
443     #[inline(always)]
derive_key_and_nonce(&mut self)444     fn derive_key_and_nonce(&mut self) {
445         self.key = Some(hkdf(
446             self.salt.as_ref().map(|s| s.as_slice()),
447             KEY_LEN,
448             &self.ikm,
449             Some(KEY_INFO.as_bytes()),
450         ));
451         self.nonce = Some(hkdf(
452             self.salt.as_ref().map(|s| s.as_slice()),
453             NONCE_LEN,
454             &self.ikm,
455             Some(NONCE_INFO.as_bytes()),
456         ));
457     }
458 
459     /// Generate crypto nonce for sequence with index `seq`.
460     ///
461     /// Each payload chunk uses a different nonce.
462     /// This method generates the nonce to use.
463     #[inline(always)]
generate_nonce(&self, seq: u32) -> Vec<u8>464     fn generate_nonce(&self, seq: u32) -> Vec<u8> {
465         // Get the base nonce which we need to modify
466         let mut nonce = self
467             .nonce
468             .clone()
469             .expect("failed to generate nonce, no base nonce available");
470 
471         // TODO: slice `nonce` only once, use that for mutating
472 
473         let nonce_len = nonce.len();
474         let m = BigEndian::read_u32(&nonce[nonce_len - 4..nonce_len]);
475         let xor = m ^ seq;
476 
477         BigEndian::write_u32(&mut nonce[nonce_len - 4..nonce_len], xor);
478 
479         nonce
480     }
481 
482     /// Check whehter the header is read.
483     ///
484     /// This checks whether the header has been read from the input while decrypting.
485     /// The header contains important information for the rest of the decryption process and must
486     /// be obtained and parsed first.
487     ///
488     /// TODO: better docs
489     #[inline(always)]
has_header(&self) -> bool490     fn has_header(&self) -> bool {
491         match self.mode {
492             CryptMode::Encrypt => self.cur > 0,
493             CryptMode::Decrypt => self.salt.is_some(),
494         }
495     }
496 
497     /// Check if working with the last crypto chunk.
498     ///
499     /// This checks whether all data for the last chunk, determined by the plaintext length in
500     /// bytes, has entered this crypto pipe.
501     #[inline(always)]
is_last(&self) -> bool502     fn is_last(&self) -> bool {
503         self.is_last_with(0)
504     }
505 
506     /// Check if working with the last crypto chunk including given `extra` bytes.
507     ///
508     /// This checks whether all data for the last chunk including `extra`, determined by the
509     /// plaintext length in bytes, has entered this crypto pipe.
510     #[inline(always)]
is_last_with(&self, extra: usize) -> bool511     fn is_last_with(&self, extra: usize) -> bool {
512         self.cur_in + extra >= self.len_in()
513     }
514 
515     /// Increase the chunk sequence number.
516     ///
517     /// Called automatically by the `pipe_encrypt` and `pipe_decrypt` methods when a chunk is read.
518     /// This should never be invoked manually.
519     ///
520     /// # Panics
521     ///
522     /// Panics if the sequence number exceeds the maximum.
523     #[inline(always)]
increase_seq(&mut self)524     fn increase_seq(&mut self) {
525         self.seq = self
526             .seq
527             .checked_add(1)
528             .expect("failed to crypt ECE payload, record sequence number exceeds limit");
529     }
530 }
531 
532 impl Pipe for EceCrypt {
533     type Reader = EceReader;
534     type Writer = EceWriter;
535 
pipe(&mut self, input: &[u8]) -> (usize, Option<Vec<u8>>)536     fn pipe(&mut self, input: &[u8]) -> (usize, Option<Vec<u8>>) {
537         // Increase input byte counter
538         self.cur_in += input.len();
539 
540         // Use mode specific pipe function
541         match self.mode {
542             CryptMode::Encrypt => self.pipe_encrypt(input.to_vec()),
543             CryptMode::Decrypt => self.pipe_decrypt(input),
544         }
545     }
546 }
547 
548 impl Crypt for EceCrypt {}
549 
550 impl PipeLen for EceCrypt {
len_in(&self) -> usize551     fn len_in(&self) -> usize {
552         match self.mode {
553             CryptMode::Encrypt => self.len,
554             CryptMode::Decrypt => len_encrypted(self.len, self.rs as usize),
555         }
556     }
557 
len_out(&self) -> usize558     fn len_out(&self) -> usize {
559         match self.mode {
560             CryptMode::Encrypt => len_encrypted(self.len, self.rs as usize),
561             CryptMode::Decrypt => self.len,
562         }
563     }
564 }
565 
566 pub struct EceReader {
567     crypt: EceCrypt,
568     inner: Box<dyn Read>,
569     buf_in: BytesMut,
570     buf_out: BytesMut,
571 }
572 
573 pub struct EceWriter {
574     crypt: EceCrypt,
575     inner: Box<dyn Write>,
576     buf: BytesMut,
577 }
578 
579 impl PipeRead<EceCrypt> for EceReader {
new(crypt: EceCrypt, inner: Box<dyn Read>) -> Self580     fn new(crypt: EceCrypt, inner: Box<dyn Read>) -> Self {
581         let chunk_size = crypt.chunk_size() as usize;
582 
583         Self {
584             crypt,
585             inner,
586             buf_in: BytesMut::with_capacity(chunk_size),
587             buf_out: BytesMut::with_capacity(DEFAULT_BUF_SIZE),
588         }
589     }
590 }
591 
592 impl PipeWrite<EceCrypt> for EceWriter {
new(crypt: EceCrypt, inner: Box<dyn Write>) -> Self593     fn new(crypt: EceCrypt, inner: Box<dyn Write>) -> Self {
594         let chunk_size = crypt.chunk_size() as usize;
595 
596         Self {
597             crypt,
598             inner,
599             buf: BytesMut::with_capacity(chunk_size),
600         }
601     }
602 }
603 
604 impl Read for EceReader {
read(&mut self, mut buf: &mut [u8]) -> io::Result<usize>605     fn read(&mut self, mut buf: &mut [u8]) -> io::Result<usize> {
606         // Number of bytes written to given buffer
607         let mut total = 0;
608 
609         // Write any output buffer bytes first
610         if !self.buf_out.is_empty() {
611             // Copy as much as possible from inner to output buffer, increase total
612             let write = min(self.buf_out.len(), buf.len());
613             total += write;
614             buf[..write].copy_from_slice(&self.buf_out.split_to(write));
615 
616             // Return if given buffer is full, or slice to unwritten buffer
617             if total >= buf.len() {
618                 return Ok(total);
619             }
620             buf = &mut buf[write..];
621         }
622 
623         // Attempt to fill input buffer if has capacity upto the chunk size
624         let capacity = self.crypt.chunk_size() as usize - self.buf_in.len();
625         if capacity > 0 {
626             // Read from inner to input buffer
627             let mut inner_buf = vec![0u8; capacity];
628             let read = self.inner.read(&mut inner_buf)?;
629             self.buf_in.extend_from_slice(&inner_buf[..read]);
630 
631             // Break if:
632             // - no new data was read
633             // - buffer doesn't have enough data to crypt, while there's data left to read
634             if read == 0 || (read != capacity && !self.crypt.is_last_with(read)) {
635                 return Ok(total);
636             }
637         }
638 
639         // Move input buffer into the crypter
640         let (read, out) = self.crypt.crypt(&self.buf_in);
641         let _ = self.buf_in.split_to(read);
642 
643         // Write any crypter output to given buffer and remaining to output buffer
644         if let Some(out) = out {
645             // Copy as much data as possible from crypter output to read buffer
646             let write = min(out.len(), buf.len());
647             total += write;
648             buf[..write].copy_from_slice(&out[..write]);
649 
650             // Copy remaining bytes into output buffer
651             if write < out.len() {
652                 self.buf_out.extend_from_slice(&out[write..]);
653             }
654 
655             // Return if given buffer is full, or slice to unwritten buffer
656             if write >= buf.len() {
657                 return Ok(total);
658             }
659             buf = &mut buf[write..];
660         }
661 
662         // Try again with remaining given buffer
663         self.read(buf).map(|n| n + total)
664     }
665 }
666 
667 impl Write for EceWriter {
write(&mut self, buf: &[u8]) -> io::Result<usize>668     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
669         // Get the chunk size to use
670         let chunk_size = self.crypt.chunk_size() as usize;
671 
672         // Attempt to fill input buffer if has capacity upto the chunk size
673         let capacity = chunk_size - self.buf.len();
674         let read = min(capacity, buf.len());
675         if capacity > 0 {
676             self.buf.extend_from_slice(&buf[..read]);
677         }
678 
679         // Transform input data through crypter if chunk data is available
680         if self.buf.len() >= chunk_size {
681             let (read, data) = self.crypt.crypt(&self.buf.split_off(0));
682             assert_eq!(read, chunk_size, "ECE crypto did not transform full chunk");
683             if let Some(data) = data {
684                 self.inner.write_all(&data)?;
685             }
686         }
687 
688         // If all expected data is provided, make sure to finish the last partial chunk
689         if self.crypt.is_last_with(self.buf.len()) {
690             if let (_, Some(data)) = self.crypt.crypt(&self.buf.split_off(0)) {
691                 self.inner.write_all(&data)?;
692             }
693         }
694 
695         Ok(read)
696     }
697 
flush(&mut self) -> io::Result<()>698     fn flush(&mut self) -> io::Result<()> {
699         self.inner.flush()
700     }
701 }
702 
703 impl PipeLen for EceReader {
len_in(&self) -> usize704     fn len_in(&self) -> usize {
705         self.crypt.len_in()
706     }
707 
len_out(&self) -> usize708     fn len_out(&self) -> usize {
709         self.crypt.len_out()
710     }
711 }
712 
713 impl ReadLen for EceReader {}
714 
715 impl PipeLen for EceWriter {
len_in(&self) -> usize716     fn len_in(&self) -> usize {
717         self.crypt.len_in()
718     }
719 
len_out(&self) -> usize720     fn len_out(&self) -> usize {
721         self.crypt.len_out()
722     }
723 }
724 
725 impl WriteLen for EceWriter {}
726 
727 unsafe impl Send for EceReader {}
728 unsafe impl Send for EceWriter {}
729 
730 /// Pad a plaintext chunk for ECE encryption.
731 ///
732 /// Padding is a required step for ECE encryption.
733 /// This modifies the block in-place.
734 ///
735 /// The padding length in number of bytes must be passed to `pad_len`.
736 /// If this is the last chunk that will be encrypted, `last` must be `true`.
737 ///
738 /// This internally suffixes a padding delimiter to the block, and the padding bytes itself.
pad(block: &mut Vec<u8>, rs: usize, last: bool)739 fn pad(block: &mut Vec<u8>, rs: usize, last: bool) {
740     // Assert the data fits the records
741     assert!(
742         block.len() + TAG_LEN < rs,
743         "failed to pad ECE ciphertext, data too large for record size"
744     );
745 
746     // Pad chunks with 1 delimiter and zeros, pad last chunk with single 2 delimiter
747     if !last {
748         let mut pad = vec![0u8; rs - block.len() - TAG_LEN];
749         pad[0] = 1;
750         block.extend(pad);
751     } else {
752         block.push(2);
753     }
754 }
755 
756 /// Unpad an decrypted ECE ciphertext chunk.
757 ///
758 /// Unpadding is a required step to transform ECE decrypted data into plain text.
759 /// This modifies the block in-place.
760 ///
761 /// If this is the last chunk that will be decrypted, `last` must be `false`.
unpad(block: &mut Vec<u8>, last: bool)762 fn unpad(block: &mut Vec<u8>, last: bool) {
763     let pos = match block.iter().rposition(|&b| b != 0) {
764         Some(pos) => pos,
765         None => panic!("ciphertext is zero"),
766     };
767     let expected_delim = if last { 2 } else { 1 };
768     assert_eq!(block[pos], expected_delim, "ECE decrypt unpadding failure");
769 
770     // Truncate the padded bytes
771     block.truncate(pos);
772 }
773 
774 /// Generate a random salt for encryption.
generate_salt() -> Vec<u8>775 pub fn generate_salt() -> Vec<u8> {
776     let mut salt = vec![0u8; SALT_LEN];
777     rand_bytes(&mut salt).expect("failed to generate encryption salt");
778     salt
779 }
780 
781 /// Calcualte length of ECE encrypted data.
782 ///
783 /// This function calculates the length in bytes of the ECE ciphertext.
784 /// The record size and length in bytes of the plaintext must be given as `rs` and `len`.
len_encrypted(len: usize, rs: usize) -> usize785 pub fn len_encrypted(len: usize, rs: usize) -> usize {
786     let chunk_meta = TAG_LEN + 1;
787     let chunk_data = rs - chunk_meta;
788     let header = HEADER_LEN as usize;
789     let chunks = (len as f64 / chunk_data as f64).ceil() as usize;
790 
791     header + len + chunk_meta * chunks
792 }
793