From d0a3d0f728ea8560e7df0d35db116e153b70ddb8 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Mon, 19 Mar 2018 17:34:51 -0400 Subject: [PATCH] Stub out ChaCha20Poly1305RFC when fuzzing --- src/util/chacha20poly1305rfc.rs | 234 ++++++++++++++++++++------------ 1 file changed, 146 insertions(+), 88 deletions(-) diff --git a/src/util/chacha20poly1305rfc.rs b/src/util/chacha20poly1305rfc.rs index f9391db01..9c86d44b4 100644 --- a/src/util/chacha20poly1305rfc.rs +++ b/src/util/chacha20poly1305rfc.rs @@ -10,93 +10,151 @@ // This is a port of Andrew Moons poly1305-donna // https://github.com/floodyberry/poly1305-donna -use crypto::aead::{AeadEncryptor,AeadDecryptor}; -use crypto::chacha20::ChaCha20; -use crypto::symmetriccipher::SynchronousStreamCipher; -use crypto::poly1305::Poly1305; -use crypto::mac::Mac; -use crypto::util::fixed_time_eq; - -use util::byte_utils; - -#[derive(Clone, Copy)] -pub struct ChaCha20Poly1305RFC { - cipher : ChaCha20, - mac: Poly1305, - finished: bool, - data_len: usize, - aad_len: u64, +#[cfg(not(feature = "fuzztarget"))] +mod real_chachapoly { + use crypto::aead::{AeadEncryptor,AeadDecryptor}; + use crypto::chacha20::ChaCha20; + use crypto::symmetriccipher::SynchronousStreamCipher; + use crypto::poly1305::Poly1305; + use crypto::mac::Mac; + use crypto::util::fixed_time_eq; + + use util::byte_utils; + + #[derive(Clone, Copy)] + pub struct ChaCha20Poly1305RFC { + cipher : ChaCha20, + mac: Poly1305, + finished: bool, + data_len: usize, + aad_len: u64, + } + + impl ChaCha20Poly1305RFC { + #[inline] + fn pad_mac_16(mac: &mut Poly1305, len: usize) { + if len % 16 != 0 { + mac.input(&[0; 16][0..16 - (len % 16)]); + } + } + pub fn new(key: &[u8], nonce: &[u8], aad: &[u8]) -> ChaCha20Poly1305RFC { + assert!(key.len() == 16 || key.len() == 32); + assert!(nonce.len() == 12); + + // Ehh, I'm too lazy to *also* tweak ChaCha20 to make it RFC-compliant + assert!(nonce[0] == 0 && nonce[1] == 0 && nonce[2] == 0 && nonce[3] == 0); + + let mut cipher = ChaCha20::new(key, &nonce[4..]); + let mut mac_key = [0u8; 64]; + let zero_key = [0u8; 64]; + cipher.process(&zero_key, &mut mac_key); + + let mut mac = Poly1305::new(&mac_key[..32]); + mac.input(aad); + ChaCha20Poly1305RFC::pad_mac_16(&mut mac, aad.len()); + + ChaCha20Poly1305RFC { + cipher: cipher, + mac: mac, + finished: false, + data_len: 0, + aad_len: aad.len() as u64, + } + } + } + + impl AeadEncryptor for ChaCha20Poly1305RFC { + fn encrypt(&mut self, input: &[u8], output: &mut [u8], out_tag: &mut [u8]) { + assert!(input.len() == output.len()); + assert!(self.finished == false); + self.cipher.process(input, output); + self.data_len += input.len(); + self.mac.input(output); + ChaCha20Poly1305RFC::pad_mac_16(&mut self.mac, self.data_len); + self.finished = true; + self.mac.input(&byte_utils::le64_to_array(self.aad_len)); + self.mac.input(&byte_utils::le64_to_array(self.data_len as u64)); + self.mac.raw_result(out_tag); + } + } + + impl AeadDecryptor for ChaCha20Poly1305RFC { + fn decrypt(&mut self, input: &[u8], output: &mut [u8], tag: &[u8]) -> bool { + assert!(input.len() == output.len()); + assert!(self.finished == false); + + self.finished = true; + + self.mac.input(input); + + self.data_len += input.len(); + ChaCha20Poly1305RFC::pad_mac_16(&mut self.mac, self.data_len); + self.mac.input(&byte_utils::le64_to_array(self.aad_len)); + self.mac.input(&byte_utils::le64_to_array(self.data_len as u64)); + + let mut calc_tag = [0u8; 16]; + self.mac.raw_result(&mut calc_tag); + if fixed_time_eq(&calc_tag, tag) { + self.cipher.process(input, output); + true + } else { + false + } + } + } } - -impl ChaCha20Poly1305RFC { - #[inline] - fn pad_mac_16(mac: &mut Poly1305, len: usize) { - if len % 16 != 0 { - mac.input(&[0; 16][0..16 - (len % 16)]); - } - } - pub fn new(key: &[u8], nonce: &[u8], aad: &[u8]) -> ChaCha20Poly1305RFC { - assert!(key.len() == 16 || key.len() == 32); - assert!(nonce.len() == 12); - - // Ehh, I'm too lazy to *also* tweak ChaCha20 to make it RFC-compliant - assert!(nonce[0] == 0 && nonce[1] == 0 && nonce[2] == 0 && nonce[3] == 0); - - let mut cipher = ChaCha20::new(key, &nonce[4..]); - let mut mac_key = [0u8; 64]; - let zero_key = [0u8; 64]; - cipher.process(&zero_key, &mut mac_key); - - let mut mac = Poly1305::new(&mac_key[..32]); - mac.input(aad); - ChaCha20Poly1305RFC::pad_mac_16(&mut mac, aad.len()); - - ChaCha20Poly1305RFC { - cipher: cipher, - mac: mac, - finished: false, - data_len: 0, - aad_len: aad.len() as u64, - } - } -} - -impl AeadEncryptor for ChaCha20Poly1305RFC { - fn encrypt(&mut self, input: &[u8], output: &mut [u8], out_tag: &mut [u8]) { - assert!(input.len() == output.len()); - assert!(self.finished == false); - self.cipher.process(input, output); - self.data_len += input.len(); - self.mac.input(output); - ChaCha20Poly1305RFC::pad_mac_16(&mut self.mac, self.data_len); - self.finished = true; - self.mac.input(&byte_utils::le64_to_array(self.aad_len)); - self.mac.input(&byte_utils::le64_to_array(self.data_len as u64)); - self.mac.raw_result(out_tag); - } -} - -impl AeadDecryptor for ChaCha20Poly1305RFC { - fn decrypt(&mut self, input: &[u8], output: &mut [u8], tag: &[u8]) -> bool { - assert!(input.len() == output.len()); - assert!(self.finished == false); - - self.finished = true; - - self.mac.input(input); - - self.data_len += input.len(); - ChaCha20Poly1305RFC::pad_mac_16(&mut self.mac, self.data_len); - self.mac.input(&byte_utils::le64_to_array(self.aad_len)); - self.mac.input(&byte_utils::le64_to_array(self.data_len as u64)); - - let mut calc_tag = [0u8; 16]; - self.mac.raw_result(&mut calc_tag); - if fixed_time_eq(&calc_tag, tag) { - self.cipher.process(input, output); - true - } else { - false - } - } +#[cfg(not(feature = "fuzztarget"))] +pub use self::real_chachapoly::ChaCha20Poly1305RFC; + +#[cfg(feature = "fuzztarget")] +mod fuzzy_chachapoly { + use crypto::aead::{AeadEncryptor,AeadDecryptor}; + + #[derive(Clone, Copy)] + pub struct ChaCha20Poly1305RFC { + tag: [u8; 16], + finished: bool, + } + impl ChaCha20Poly1305RFC { + pub fn new(key: &[u8], nonce: &[u8], _aad: &[u8]) -> ChaCha20Poly1305RFC { + assert!(key.len() == 16 || key.len() == 32); + assert!(nonce.len() == 12); + + // Ehh, I'm too lazy to *also* tweak ChaCha20 to make it RFC-compliant + assert!(nonce[0] == 0 && nonce[1] == 0 && nonce[2] == 0 && nonce[3] == 0); + + let mut tag = [0; 16]; + tag.copy_from_slice(&key[0..16]); + + ChaCha20Poly1305RFC { + tag, + finished: false, + } + } + } + + impl AeadEncryptor for ChaCha20Poly1305RFC { + fn encrypt(&mut self, input: &[u8], output: &mut [u8], out_tag: &mut [u8]) { + assert!(input.len() == output.len()); + assert!(self.finished == false); + + output.copy_from_slice(&input); + out_tag.copy_from_slice(&self.tag); + self.finished = true; + } + } + + impl AeadDecryptor for ChaCha20Poly1305RFC { + fn decrypt(&mut self, input: &[u8], output: &mut [u8], tag: &[u8]) -> bool { + assert!(input.len() == output.len()); + assert!(self.finished == false); + + if tag[..] != self.tag[..] { return false; } + output.copy_from_slice(input); + self.finished = true; + true + } + } } +#[cfg(feature = "fuzztarget")] +pub use self::fuzzy_chachapoly::ChaCha20Poly1305RFC; -- 2.39.5