// 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;