X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=src%2Futil%2Fchacha20poly1305rfc.rs;h=1aeaf61d21a4054502cd3ec1e076b67a1bf24c96;hb=394b11c7b55a5a98e0b46aa22ca914693aa2df45;hp=f9391db01f727741c76a4c7c912da37ee30f6df8;hpb=6185a2819090bd077954244c5e2adaab5efcaa1a;p=rust-lightning diff --git a/src/util/chacha20poly1305rfc.rs b/src/util/chacha20poly1305rfc.rs index f9391db0..1aeaf61d 100644 --- a/src/util/chacha20poly1305rfc.rs +++ b/src/util/chacha20poly1305rfc.rs @@ -10,93 +10,169 @@ // 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::symmetriccipher::SynchronousStreamCipher; + use crypto::poly1305::Poly1305; + use crypto::mac::Mac; + use crypto::util::fixed_time_eq; + + pub use crypto::chacha20::ChaCha20; + + 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, ChaCha20}; + +#[cfg(feature = "fuzztarget")] +mod fuzzy_chachapoly { + use crypto::aead::{AeadEncryptor,AeadDecryptor}; + use crypto::symmetriccipher::SynchronousStreamCipher; + + #[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 + } + } + + pub struct ChaCha20 {} + + impl ChaCha20 { + pub fn new(key: &[u8], nonce: &[u8]) -> ChaCha20 { + assert!(key.len() == 16 || key.len() == 32); + assert!(nonce.len() == 8 || nonce.len() == 12); + Self {} + } + } + + impl SynchronousStreamCipher for ChaCha20 { + fn process(&mut self, input: &[u8], output: &mut [u8]) { + output.copy_from_slice(input); + } + } } +#[cfg(feature = "fuzztarget")] +pub use self::fuzzy_chachapoly::{ChaCha20Poly1305RFC, ChaCha20};