sequoia_openpgp/crypto/
symmetric.rs

1//! Unauthenticated symmetric encryption and decryption.
2//!
3//! This module provides a uniform streaming interface to
4//! unauthenticated symmetric encryption and decryption using
5//! different block ciphers and padding modes.
6//!
7//! Note: this is a very low-level interface.  It is not about OpenPGP
8//! encryption or decryption.  If you are looking for that, see
9//! [`crate::serialize::stream::Encryptor`] and
10//! [`crate::parse::stream::Decryptor`] instead.
11//!
12//! # Examples
13//!
14//! ```rust
15//! # use std::io::{Read, Write};
16//! # use sequoia_openpgp::crypto::SessionKey;
17//! # use sequoia_openpgp::crypto::SymmetricAlgorithm;
18//! # use sequoia_openpgp::crypto::symmetric::*;
19//! # use sequoia_openpgp::parse::buffered_reader;
20//! # fn main() -> sequoia_openpgp::Result<()> {
21//! let text = b"Hello World :)";
22//! let algo = SymmetricAlgorithm::AES128;
23//! let key = SessionKey::new(algo.key_size()?)?;
24//!
25//! // Encrypt the `text`.
26//! let mut ciphertext = Vec::new();
27//! let mut encryptor = Encryptor::new(
28//!     algo, BlockCipherMode::CFB, PaddingMode::None,
29//!     &key, None, &mut ciphertext)?;
30//! encryptor.write_all(text)?;
31//! encryptor.finalize()?;
32//!
33//! // Decrypt the `ciphertext`.
34//! let mut plaintext = Vec::new();
35//! let reader = buffered_reader::Memory::with_cookie(
36//!     &ciphertext, Default::default());
37//!
38//! let mut decryptor = Decryptor::new(
39//!     algo, BlockCipherMode::CFB, UnpaddingMode::None,
40//!     &key, None, reader)?;
41//!
42//! decryptor.read_to_end(&mut plaintext)?;
43//!
44//! // Check that we recovered it.
45//! assert_eq!(&plaintext[..], text);
46//! # Ok(()) }
47//! ```
48
49use std::io;
50use std::cmp;
51use std::fmt;
52
53use crate::{Error, Result};
54use crate::SymmetricAlgorithm;
55use crate::vec_resize;
56use crate::{
57    crypto::SessionKey,
58    parse::Cookie,
59};
60
61use buffered_reader::BufferedReader;
62
63/// Block cipher mode of operation.
64///
65/// Block modes govern how a block cipher processes data spanning
66/// multiple blocks.
67#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
68#[non_exhaustive]
69pub enum BlockCipherMode {
70    /// Full-block cipher feedback mode.
71    CFB,
72
73    /// Cipher block chaining.
74    CBC,
75
76    /// Electronic codebook mode.
77    ///
78    /// Note: do not use as-is.  Patterns in the plaintext will be
79    /// visible as patterns in the ciphertext.  Mind the penguin!
80    ECB,
81}
82
83impl BlockCipherMode {
84    /// Returns whether the mode requires padding.
85    ///
86    /// Some modes only operate on complete blocks, so if the
87    /// plaintext's length is not a multiple of the symmetric
88    /// algorithm's block size, padding is required.
89    pub fn requires_padding(&self) -> bool {
90        match self {
91            BlockCipherMode::CFB => false,
92            BlockCipherMode::CBC => true,
93            BlockCipherMode::ECB => true,
94        }
95    }
96}
97
98/// Padding mode for encryption.
99#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
100#[non_exhaustive]
101pub enum PaddingMode {
102    /// No padding.
103    ///
104    /// If the [`BlockCipherMode`] requires padding of incomplete
105    /// final blocks (see [`BlockCipherMode::requires_padding`]), and
106    /// you chose no padding, you need to ensure that the plaintext's
107    /// length is a multiple of the symmetric algorithm's block size.
108    /// Otherwise, an error is returned.
109    None,
110}
111
112/// Padding mode for decryption.
113#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
114#[non_exhaustive]
115pub enum UnpaddingMode {
116    /// No padding.
117    ///
118    /// If the [`BlockCipherMode`] requires padding of incomplete
119    /// final blocks (see [`BlockCipherMode::requires_padding`]),
120    /// padding is required unless the plaintext's length is a
121    /// multiple of the symmetric algorithm's block size.  Otherwise,
122    /// an error is returned.
123    None,
124}
125
126/// A context representing symmetric algorithm state and block cipher
127/// mode.
128pub(crate) trait Context: Send + Sync {
129    /// Encrypt a single block `src` to a ciphertext block `dst`.
130    /// The `dst` and `src` buffers are expected to be at least as large as
131    /// the block size of the underlying cipher.
132    fn encrypt(
133        &mut self,
134        dst: &mut [u8],
135        src: &[u8],
136    ) -> Result<()>;
137
138    /// Decrypt a single ciphertext block `src` to a plaintext block `dst`.
139    /// The `dst` and `src` buffers are expected to be at least as large as
140    /// the block size of the underlying cipher.
141    fn decrypt(
142        &mut self,
143        dst: &mut [u8],
144        src: &[u8],
145    ) -> Result<()>;
146}
147
148/// A `Read`er for decrypting symmetrically encrypted data.
149pub(crate) struct InternalDecryptor<'a> {
150    // The encrypted data.
151    source: Box<dyn BufferedReader<Cookie> + 'a>,
152
153    mode: BlockCipherMode,
154    padding: UnpaddingMode,
155    dec: Box<dyn Context>,
156    block_size: usize,
157    // Up to a block of unread data.
158    buffer: Vec<u8>,
159}
160assert_send_and_sync!(InternalDecryptor<'_>);
161
162impl<'a> InternalDecryptor<'a> {
163    /// Instantiate a new symmetric decryptor.
164    pub fn new<R>(algo: SymmetricAlgorithm,
165                  mode: BlockCipherMode,
166                  padding: UnpaddingMode,
167                  key: &SessionKey,
168                  iv: Option<&[u8]>,
169                  source: R)
170                  -> Result<Self>
171    where
172        R: BufferedReader<Cookie> + 'a,
173    {
174        use crate::crypto::backend::{Backend, interface::Symmetric};
175        let block_size = algo.block_size()?;
176        let dec = Backend::decryptor(algo, mode, key.as_protected(), iv)?;
177
178        Ok(InternalDecryptor {
179            source: source.into_boxed(),
180            mode,
181            padding,
182            dec,
183            block_size,
184            buffer: Vec::with_capacity(block_size),
185        })
186    }
187}
188
189// Note: this implementation tries *very* hard to make sure we don't
190// gratuitiously do a short read.  Specifically, if the return value
191// is less than `plaintext.len()`, then it is either because we
192// reached the end of the input or an error occurred.
193impl<'a> io::Read for InternalDecryptor<'a> {
194    fn read(&mut self, plaintext: &mut [u8]) -> io::Result<usize> {
195        let mut pos = 0;
196
197        // 1. Copy any buffered data.
198        if !self.buffer.is_empty() {
199            let to_copy = cmp::min(self.buffer.len(), plaintext.len());
200            plaintext[..to_copy].copy_from_slice(&self.buffer[..to_copy]);
201            crate::vec_drain_prefix(&mut self.buffer, to_copy);
202            pos = to_copy;
203        }
204
205        if pos == plaintext.len() {
206            return Ok(pos);
207        }
208
209        // 2. Decrypt as many whole blocks as `plaintext` can hold.
210        let mut to_copy
211            = ((plaintext.len() - pos) / self.block_size) *  self.block_size;
212        let result = self.source.data_consume(to_copy);
213        let short_read;
214        let ciphertext = match result {
215            Ok(data) => {
216                short_read = data.len() < to_copy;
217                to_copy = data.len().min(to_copy);
218                &data[..to_copy]
219            },
220            // We encountered an error, but we did read some.
221            Err(_) if pos > 0 => return Ok(pos),
222            Err(e) => return Err(e),
223        };
224
225        // Avoid trying to decrypt empty ciphertexts.  Some backends
226        // might not like that, for example Botan's CBC mode.
227        if ! ciphertext.is_empty() {
228            // Possibly deal with padding.
229            match self.padding {
230                UnpaddingMode::None => if self.mode.requires_padding()
231                    && ciphertext.len() % self.block_size > 0
232                {
233                    return Err(io::Error::new(
234                        io::ErrorKind::UnexpectedEof,
235                        Error::InvalidOperation(
236                            "incomplete last block".into())));
237                },
238            }
239
240            self.dec.decrypt(&mut plaintext[pos..pos + to_copy],
241                             ciphertext)
242                .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput,
243                                            format!("{}", e)))?;
244
245            // Possibly deal with padding.
246            match self.padding {
247                UnpaddingMode::None => (),
248            }
249
250            pos += to_copy;
251        }
252
253        if short_read || pos == plaintext.len() {
254            return Ok(pos);
255        }
256
257        // 3. The last bit is a partial block.  Buffer it.
258        let mut to_copy = plaintext.len() - pos;
259        assert!(0 < to_copy);
260        assert!(to_copy < self.block_size);
261
262        let to_read = self.block_size;
263        let result = self.source.data_consume(to_read);
264        let ciphertext = match result {
265            Ok(data) => {
266                // Make sure we don't read more than is available.
267                to_copy = cmp::min(to_copy, data.len());
268                &data[..data.len().min(to_read)]
269            },
270            // We encountered an error, but we did read some.
271            Err(_) if pos > 0 => return Ok(pos),
272            Err(e) => return Err(e),
273        };
274        assert!(ciphertext.len() <= self.block_size);
275
276        // Avoid trying to decrypt empty ciphertexts.  Some backends
277        // might not like that, for example Botan's CBC mode.
278        if ciphertext.is_empty() {
279            return Ok(pos);
280        }
281
282        vec_resize(&mut self.buffer, ciphertext.len());
283
284        // Possibly deal with padding.
285        match self.padding {
286            UnpaddingMode::None => if self.mode.requires_padding()
287                && ciphertext.len() % self.block_size > 0
288            {
289                return Err(io::Error::new(
290                    io::ErrorKind::UnexpectedEof,
291                    Error::InvalidOperation(
292                        "incomplete last block".into())));
293            },
294        }
295
296        self.dec.decrypt(&mut self.buffer, ciphertext)
297            .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput,
298                                        format!("{}", e)))?;
299
300        // Possibly deal with padding.
301        match self.padding {
302            UnpaddingMode::None => (),
303        }
304
305        plaintext[pos..pos + to_copy].copy_from_slice(&self.buffer[..to_copy]);
306        crate::vec_drain_prefix(&mut self.buffer, to_copy);
307
308        pos += to_copy;
309
310        Ok(pos)
311    }
312}
313
314/// A `BufferedReader` that decrypts symmetrically-encrypted data as
315/// it is read.
316pub struct Decryptor<'a> {
317    reader: buffered_reader::Generic<InternalDecryptor<'a>, Cookie>,
318}
319
320impl<'a> Decryptor<'a> {
321    /// Instantiate a new symmetric decryptor.
322    ///
323    /// If `iv` is `None`, and the given `mode` requires an IV, an
324    /// all-zero IV is used.
325    pub fn new<R>(algo: SymmetricAlgorithm,
326                  mode: BlockCipherMode,
327                  padding: UnpaddingMode,
328                  key: &SessionKey,
329                  iv: Option<&[u8]>,
330                  source: R)
331                  -> Result<Self>
332    where
333        R: BufferedReader<Cookie> + 'a,
334    {
335        Self::with_cookie(
336            algo, mode, padding, key, iv, source, Default::default())
337    }
338
339    /// Like [`Decryptor::new`], but sets a cookie.
340    pub fn with_cookie<R>(algo: SymmetricAlgorithm,
341                          mode: BlockCipherMode,
342                          padding: UnpaddingMode,
343                          key: &SessionKey,
344                          iv: Option<&[u8]>,
345                          reader: R,
346                          cookie: Cookie)
347                          -> Result<Self>
348    where
349        R: BufferedReader<Cookie> + 'a,
350    {
351        Ok(Decryptor {
352            reader: buffered_reader::Generic::with_cookie(
353                InternalDecryptor::new(algo, mode, padding, key, iv, reader)?,
354                None, cookie),
355        })
356    }
357}
358
359impl<'a> io::Read for Decryptor<'a> {
360    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
361        self.reader.read(buf)
362    }
363}
364
365impl<'a> fmt::Display for Decryptor<'a> {
366    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
367        write!(f, "Decryptor")
368    }
369}
370
371impl<'a> fmt::Debug for Decryptor<'a> {
372    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
373        f.debug_struct("Decryptor")
374            .field("reader", &self.get_ref().unwrap())
375            .finish()
376    }
377}
378
379impl<'a> BufferedReader<Cookie> for Decryptor<'a> {
380    fn buffer(&self) -> &[u8] {
381        self.reader.buffer()
382    }
383
384    fn data(&mut self, amount: usize) -> io::Result<&[u8]> {
385        self.reader.data(amount)
386    }
387
388    fn data_hard(&mut self, amount: usize) -> io::Result<&[u8]> {
389        self.reader.data_hard(amount)
390    }
391
392    fn data_eof(&mut self) -> io::Result<&[u8]> {
393        self.reader.data_eof()
394    }
395
396    fn consume(&mut self, amount: usize) -> &[u8] {
397        self.reader.consume(amount)
398    }
399
400    fn data_consume(&mut self, amount: usize)
401                    -> io::Result<&[u8]> {
402        self.reader.data_consume(amount)
403    }
404
405    fn data_consume_hard(&mut self, amount: usize) -> io::Result<&[u8]> {
406        self.reader.data_consume_hard(amount)
407    }
408
409    fn read_be_u16(&mut self) -> io::Result<u16> {
410        self.reader.read_be_u16()
411    }
412
413    fn read_be_u32(&mut self) -> io::Result<u32> {
414        self.reader.read_be_u32()
415    }
416
417    fn steal(&mut self, amount: usize) -> io::Result<Vec<u8>> {
418        self.reader.steal(amount)
419    }
420
421    fn steal_eof(&mut self) -> io::Result<Vec<u8>> {
422        self.reader.steal_eof()
423    }
424
425    fn get_mut(&mut self) -> Option<&mut dyn BufferedReader<Cookie>> {
426        Some(&mut self.reader.reader_mut().source)
427    }
428
429    fn get_ref(&self) -> Option<&dyn BufferedReader<Cookie>> {
430        Some(&self.reader.reader_ref().source)
431    }
432
433    fn into_inner<'b>(self: Box<Self>)
434            -> Option<Box<dyn BufferedReader<Cookie> + 'b>> where Self: 'b {
435        Some(self.reader.into_reader().source.into_boxed())
436    }
437
438    fn cookie_set(&mut self, cookie: Cookie) -> Cookie {
439        self.reader.cookie_set(cookie)
440    }
441
442    fn cookie_ref(&self) -> &Cookie {
443        self.reader.cookie_ref()
444    }
445
446    fn cookie_mut(&mut self) -> &mut Cookie {
447        self.reader.cookie_mut()
448    }
449}
450
451/// A `Write`r that symmetrically encrypts data as it is written.
452pub struct Encryptor<W: io::Write> {
453    inner: Option<W>,
454
455    mode: BlockCipherMode,
456    padding: PaddingMode,
457    cipher: Box<dyn Context>,
458    block_size: usize,
459    // Up to a block of unencrypted data.
460    buffer: Vec<u8>,
461    // A place to write encrypted data into.
462    scratch: Vec<u8>,
463}
464assert_send_and_sync!(Encryptor<W> where W: io::Write);
465
466impl<W: io::Write> Encryptor<W> {
467    /// Instantiate a new symmetric encryptor.
468    ///
469    /// If `iv` is `None`, and the given `mode` requires an IV, an
470    /// all-zero IV is used.
471    pub fn new(algo: SymmetricAlgorithm,
472               mode: BlockCipherMode,
473               padding: PaddingMode,
474               key: &SessionKey,
475               iv: Option<&[u8]>,
476               sink: W) -> Result<Self> {
477        use crate::crypto::backend::{Backend, interface::Symmetric};
478        let block_size = algo.block_size()?;
479        let cipher =
480            Backend::encryptor(algo, mode, key.as_protected(), iv)?;
481
482        Ok(Encryptor {
483            inner: Some(sink),
484            mode,
485            padding,
486            cipher,
487            block_size,
488            buffer: Vec::with_capacity(block_size),
489            scratch: vec![0; 4096],
490        })
491    }
492
493    /// Finish encryption and write last partial block.
494    pub fn finalize(mut self) -> Result<W> {
495        self.finalize_intern()
496    }
497
498    /// Like [`Self::finalize`], but with a mutable reference.
499    ///
500    /// This can be used in [`Self::drop`], whereas [`Self::finalize`]
501    /// consumes self, and is convenient for callers because consuming
502    /// self makes Rust understand that any borrow on the writer
503    /// terminates.
504    fn finalize_intern(&mut self) -> Result<W> {
505        if let Some(mut inner) = self.inner.take() {
506            if !self.buffer.is_empty() {
507                let n = self.buffer.len();
508                assert!(n < self.block_size);
509
510                // Possibly deal with padding.
511                match self.padding {
512                    PaddingMode::None => if self.mode.requires_padding()
513                    {
514                        return Err(Error::InvalidOperation(
515                            "incomplete last block".into())
516                                   .into());
517                    },
518                }
519
520                self.cipher.encrypt(&mut self.scratch[..n], &self.buffer)?;
521
522                // Possibly deal with padding.
523                match self.padding {
524                    PaddingMode::None => (),
525                }
526
527                crate::vec_truncate(&mut self.buffer, 0);
528                inner.write_all(&self.scratch[..n])?;
529                crate::vec_truncate(&mut self.scratch, 0);
530            }
531            Ok(inner)
532        } else {
533            Err(io::Error::new(io::ErrorKind::BrokenPipe,
534                               "Inner writer was taken").into())
535        }
536    }
537
538    /// Acquires a reference to the underlying writer.
539    pub(crate) fn get_ref(&self) -> Option<&W> {
540        self.inner.as_ref()
541    }
542
543    /// Acquires a mutable reference to the underlying writer.
544    #[allow(dead_code)]
545    pub(crate) fn get_mut(&mut self) -> Option<&mut W> {
546        self.inner.as_mut()
547    }
548}
549
550impl<W: io::Write> io::Write for Encryptor<W> {
551    fn write(&mut self, mut buf: &[u8]) -> io::Result<usize> {
552        if self.inner.is_none() {
553            return Err(io::Error::new(io::ErrorKind::BrokenPipe,
554                                      "Inner writer was taken"));
555        }
556        let inner = self.inner.as_mut().unwrap();
557        let amount = buf.len();
558
559        // First, fill the buffer if there is something in it.
560        if !self.buffer.is_empty() {
561            let n = cmp::min(buf.len(), self.block_size - self.buffer.len());
562            self.buffer.extend_from_slice(&buf[..n]);
563            assert!(self.buffer.len() <= self.block_size);
564            buf = &buf[n..];
565
566            // And possibly encrypt the block.
567            if self.buffer.len() == self.block_size {
568                self.cipher.encrypt(&mut self.scratch[..self.block_size],
569                                    &self.buffer)
570                    .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput,
571                                                format!("{}", e)))?;
572                crate::vec_truncate(&mut self.buffer, 0);
573                inner.write_all(&self.scratch[..self.block_size])?;
574            }
575        }
576
577        // Then, encrypt all whole blocks.
578        let whole_blocks = (buf.len() / self.block_size) * self.block_size;
579        if whole_blocks > 0 {
580            // Encrypt whole blocks.
581            if self.scratch.len() < whole_blocks {
582                vec_resize(&mut self.scratch, whole_blocks);
583            }
584
585            self.cipher.encrypt(&mut self.scratch[..whole_blocks],
586                                &buf[..whole_blocks])
587                .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput,
588                                            format!("{}", e)))?;
589            inner.write_all(&self.scratch[..whole_blocks])?;
590        }
591
592        // Stash rest for later.
593        assert!(buf.is_empty() || self.buffer.is_empty());
594        self.buffer.extend_from_slice(&buf[whole_blocks..]);
595        assert!(self.buffer.len() < self.block_size);
596
597        Ok(amount)
598    }
599
600    fn flush(&mut self) -> io::Result<()> {
601        // It is not clear how we can implement this, because we can
602        // only operate on block sizes.  We will, however, ask our
603        // inner writer to flush.
604        if let Some(ref mut inner) = self.inner {
605            inner.flush()
606        } else {
607            Err(io::Error::new(io::ErrorKind::BrokenPipe,
608                               "Inner writer was taken"))
609        }
610    }
611}
612
613impl<W: io::Write> Drop for Encryptor<W> {
614    fn drop(&mut self) {
615        // Unfortunately, we cannot handle errors here.  If error
616        // handling is a concern, call finish() and properly handle
617        // errors there.
618        let _ = self.finalize_intern();
619    }
620}
621
622#[cfg(test)]
623mod tests {
624    use super::*;
625    use std::io::{Cursor, Read, Write};
626
627    #[test]
628    fn smoke_test() {
629        use crate::crypto::mem::Protected;
630        use crate::crypto::symmetric::BlockCipherMode;
631        use crate::crypto::backend::{Backend, interface::Symmetric};
632
633        use crate::fmt::hex;
634
635        let algo = SymmetricAlgorithm::AES128;
636        let key: Protected =
637            hex::decode("2b7e151628aed2a6abf7158809cf4f3c").unwrap().into();
638        assert_eq!(key.len(), 16);
639
640        // Ensure we use CFB128 by default
641        let iv = hex::decode("000102030405060708090A0B0C0D0E0F").unwrap();
642        let mut cfb =
643            Backend::encryptor(algo, BlockCipherMode::CFB, &key, Some(&iv)).unwrap();
644        let msg = hex::decode("6bc1bee22e409f96e93d7e117393172a").unwrap();
645        let mut dst = vec![0; msg.len()];
646        cfb.encrypt(&mut dst, &*msg).unwrap();
647        assert_eq!(&dst[..16], &*hex::decode("3b3fd92eb72dad20333449f8e83cfb4a").unwrap());
648
649        // 32-byte long message
650        let iv = hex::decode("000102030405060708090A0B0C0D0E0F").unwrap();
651        let mut cfb =
652            Backend::encryptor(algo, BlockCipherMode::CFB, &key, Some(&iv)).unwrap();
653        let msg = b"This is a very important message";
654        let mut dst = vec![0; msg.len()];
655        cfb.encrypt(&mut dst, &*msg).unwrap();
656        assert_eq!(&dst, &hex::decode(
657            "04960ebfb9044196bb29418ce9d6cc0939d5ccb1d0712fa8e45fe5673456fded"
658        ).unwrap());
659
660        // 33-byte (uneven) long message
661        let iv = hex::decode("000102030405060708090A0B0C0D0E0F").unwrap();
662        let mut cfb =
663            Backend::encryptor(algo, BlockCipherMode::CFB, &key, Some(&iv)).unwrap();
664        let msg = b"This is a very important message!";
665        let mut dst = vec![0; msg.len()];
666        cfb.encrypt(&mut dst, &*msg).unwrap();
667        assert_eq!(&dst, &hex::decode(
668            "04960ebfb9044196bb29418ce9d6cc0939d5ccb1d0712fa8e45fe5673456fded0b"
669        ).unwrap());
670
671        // 33-byte (uneven) long message, chunked
672        let iv = hex::decode("000102030405060708090A0B0C0D0E0F").unwrap();
673        let mut cfb =
674            Backend::encryptor(algo, BlockCipherMode::CFB, &key, Some(&iv)).unwrap();
675        let mut dst = vec![0; msg.len()];
676        for (mut dst, msg) in dst.chunks_mut(16).zip(msg.chunks(16)) {
677            cfb.encrypt(&mut dst, msg).unwrap();
678        }
679        assert_eq!(&dst, &hex::decode(
680            "04960ebfb9044196bb29418ce9d6cc0939d5ccb1d0712fa8e45fe5673456fded0b"
681        ).unwrap());
682    }
683
684    /// This test is designed to test the buffering logic in Decryptor
685    /// by reading directly from it (i.e. without any buffering
686    /// introduced by the Decryptor or any other source
687    /// of buffering).
688    #[test]
689    fn decryptor() {
690        for algo in [SymmetricAlgorithm::AES128,
691                     SymmetricAlgorithm::AES192,
692                     SymmetricAlgorithm::AES256].iter() {
693            // The keys are [key.len() - 1, 0, 0, 0, ...].
694            let mut key = vec![0u8; algo.key_size().unwrap()];
695            key[0] = key.len() as u8 - 1;
696            let key = key.into();
697
698            let filename = &format!(
699                    "raw/a-cypherpunks-manifesto.aes{}.key_is_key_len_dec1_as_le",
700                algo.key_size().unwrap() * 8);
701            let ciphertext = buffered_reader::Memory::with_cookie(
702                crate::tests::file(filename), Default::default());
703            let decryptor = InternalDecryptor::new(
704                *algo, BlockCipherMode::CFB, UnpaddingMode::None,
705                &key, None, ciphertext).unwrap();
706
707            // Read bytewise to test the buffer logic.
708            let mut plaintext = Vec::new();
709            for b in decryptor.bytes() {
710                plaintext.push(b.unwrap());
711            }
712
713            assert_eq!(crate::tests::manifesto(), &plaintext[..]);
714        }
715    }
716
717    /// This test is designed to test the buffering logic in Encryptor
718    /// by writing directly to it.
719    #[test]
720    fn encryptor() {
721        for algo in [SymmetricAlgorithm::AES128,
722                     SymmetricAlgorithm::AES192,
723                     SymmetricAlgorithm::AES256].iter() {
724            // The keys are [key.len() - 1, 0, 0, 0, ...].
725            let mut key = vec![0u8; algo.key_size().unwrap()];
726            key[0] = key.len() as u8 - 1;
727            let key = key.into();
728
729            let mut ciphertext = Vec::new();
730            {
731                let mut encryptor = Encryptor::new(
732                    *algo, BlockCipherMode::CFB, PaddingMode::None,
733                    &key, None, &mut ciphertext).unwrap();
734
735                // Write bytewise to test the buffer logic.
736                for b in crate::tests::manifesto().chunks(1) {
737                    encryptor.write_all(b).unwrap();
738                }
739            }
740
741            let filename = format!(
742                "raw/a-cypherpunks-manifesto.aes{}.key_is_key_len_dec1_as_le",
743                algo.key_size().unwrap() * 8);
744            let mut cipherfile = Cursor::new(crate::tests::file(&filename));
745            let mut reference = Vec::new();
746            cipherfile.read_to_end(&mut reference).unwrap();
747            assert_eq!(&reference[..], &ciphertext[..]);
748        }
749    }
750
751    /// This test tries to encrypt, then decrypt some data.
752    #[test]
753    fn roundtrip() {
754        for algo in SymmetricAlgorithm::variants()
755                     .filter(|x| x.is_supported()) {
756          for mode in [BlockCipherMode::CFB,
757                       BlockCipherMode::CBC,
758                       BlockCipherMode::ECB] {
759            eprintln!("Testing {:?}/{:?}", algo, mode);
760
761            let bs = algo.block_size().unwrap();
762            let text = if mode.requires_padding() {
763                // For modes requiring padding, make sure the payload
764                // is a multiple of the block size, so that we don't
765                // in fact require padding.
766                let l = (crate::tests::manifesto().len() / bs) * bs;
767                &crate::tests::manifesto()[..l]
768            } else {
769                crate::tests::manifesto()
770            };
771
772            let key = SessionKey::new(algo.key_size().unwrap()).unwrap();
773
774            let mut ciphertext = Vec::new();
775            let mut encryptor = Encryptor::new(
776                algo, mode, PaddingMode::None,
777                &key, None, &mut ciphertext).unwrap();
778
779            encryptor.write_all(text).unwrap();
780            encryptor.finalize().unwrap();
781
782            let mut plaintext = Vec::new();
783            let reader = buffered_reader::Memory::with_cookie(
784                &ciphertext, Default::default());
785
786            let mut decryptor = InternalDecryptor::new(
787                algo, mode, UnpaddingMode::None,
788                &key, None, reader).unwrap();
789
790            decryptor.read_to_end(&mut plaintext).unwrap();
791
792            assert_eq!(&plaintext[..], text);
793          }
794        }
795    }
796}