From 7ad3208937622d1a87e4eebc2dc341ec33efcae6 Mon Sep 17 00:00:00 2001 From: Nathaniel McCallum Date: Mon, 29 Apr 2019 17:45:12 -0400 Subject: [PATCH] Fix output size check for stream ciphers The previous output size check presumed a block cipher. Therefore, it enforced an unnecessary extra byte in the case of stream ciphers. This patch ensures that our size checks don't force the caller to overallocate for stream ciphers. --- openssl/src/symm.rs | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/openssl/src/symm.rs b/openssl/src/symm.rs index 4d78a352..726917a5 100644 --- a/openssl/src/symm.rs +++ b/openssl/src/symm.rs @@ -492,12 +492,16 @@ impl Crypter { /// /// # Panics /// - /// Panics if `output.len() < input.len() + block_size` where - /// `block_size` is the block size of the cipher (see `Cipher::block_size`), - /// or if `output.len() > c_int::max_value()`. + /// Panics for stream ciphers if `output.len() < input.len()`. + /// + /// Panics for block ciphers if `output.len() < input.len() + block_size`, + /// where `block_size` is the block size of the cipher (see `Cipher::block_size`). + /// + /// Panics if `output.len() > c_int::max_value()`. pub fn update(&mut self, input: &[u8], output: &mut [u8]) -> Result { unsafe { - assert!(output.len() >= input.len() + self.block_size); + let block_size = if self.block_size > 1 { self.block_size } else { 0 }; + assert!(output.len() >= input.len() + block_size); assert!(output.len() <= c_int::max_value() as usize); let mut outl = output.len() as c_int; let inl = input.len() as c_int; @@ -523,10 +527,11 @@ impl Crypter { /// /// # Panics /// - /// Panics if `output` is less than the cipher's block size. + /// Panics for block ciphers if `output.len() < block_size`, + /// where `block_size` is the block size of the cipher (see `Cipher::block_size`). pub fn finalize(&mut self, output: &mut [u8]) -> Result { unsafe { - assert!(output.len() >= self.block_size); + if self.block_size > 1 { assert!(output.len() >= self.block_size); } let mut outl = cmp::min(output.len(), c_int::max_value() as usize) as c_int; cvt(ffi::EVP_CipherFinal( @@ -753,6 +758,22 @@ mod tests { use super::*; use hex::{self, FromHex}; + #[test] + fn test_stream_cipher_output() { + let key = [0u8; 16]; + let iv = [0u8; 16]; + let mut c = super::Crypter::new( + super::Cipher::aes_128_ctr(), + super::Mode::Encrypt, + &key, + Some(&iv), + ).unwrap(); + + assert_eq!(c.update(&[0u8; 15], &mut [0u8; 15]).unwrap(), 15); + assert_eq!(c.update(&[0u8; 1], &mut [0u8; 1]).unwrap(), 1); + assert_eq!(c.finalize(&mut [0u8; 0]).unwrap(), 0); + } + // Test vectors from FIPS-197: // http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf #[test]