diff options
Diffstat (limited to 'openpgp/src/crypto/backend/cng/aead.rs')
-rw-r--r-- | openpgp/src/crypto/backend/cng/aead.rs | 222 |
1 files changed, 83 insertions, 139 deletions
diff --git a/openpgp/src/crypto/backend/cng/aead.rs b/openpgp/src/crypto/backend/cng/aead.rs index d30073ca..ff302dad 100644 --- a/openpgp/src/crypto/backend/cng/aead.rs +++ b/openpgp/src/crypto/backend/cng/aead.rs @@ -1,16 +1,22 @@ //! Implementation of AEAD using Windows CNG API. use crate::{Error, Result}; -use crate::crypto::aead::Aead; +use crate::crypto::aead::{Aead, CipherOp}; use crate::seal; use crate::types::{AEADAlgorithm, SymmetricAlgorithm}; -use super::symmetric::Ctr; -use win_crypto_ng::hash::{Hash, HashAlgorithm, MacAlgorithmId}; -use win_crypto_ng::symmetric::SymmetricAlgorithmId; +use eax::online::{EaxOnline, Encrypt, Decrypt}; +use win_crypto_ng::symmetric::{BlockCipherKey, Aes}; +use win_crypto_ng::symmetric::block_cipher::generic_array::{GenericArray, ArrayLength}; +use win_crypto_ng::symmetric::block_cipher::generic_array::typenum::{U128, U192, U256}; -const EAX_BLOCK_SIZE: usize = 16; -const EAX_DIGEST_SIZE: usize = 16; +trait GenericArrayExt { + const LEN: usize; +} + +impl<T, N: ArrayLength<T>> GenericArrayExt for GenericArray<T, N> { + const LEN: usize = N::USIZE; +} impl AEADAlgorithm { pub(crate) fn context( @@ -18,14 +24,40 @@ impl AEADAlgorithm { sym_algo: SymmetricAlgorithm, key: &[u8], nonce: &[u8], + op: CipherOp, ) -> Result<Box<dyn Aead>> { + + let nonce = GenericArray::from_slice(nonce); + match self { AEADAlgorithm::EAX => match sym_algo { - | SymmetricAlgorithm::AES128 - | SymmetricAlgorithm::AES192 - | SymmetricAlgorithm::AES256 => { - Ok(Box::new(EaxAes::with_key_and_nonce(key, nonce)?)) - }, + | SymmetricAlgorithm::AES128 => { + let key = GenericArray::from_slice(key); + Ok(match op { + CipherOp::Encrypt => + Box::new(EaxOnline::<BlockCipherKey<Aes, U128>, Encrypt>::with_key_and_nonce(key, nonce)), + CipherOp::Decrypt => + Box::new(EaxOnline::<BlockCipherKey<Aes, U128>, Decrypt>::with_key_and_nonce(key, nonce)), + }) + } + SymmetricAlgorithm::AES192 => { + let key = GenericArray::from_slice(key); + Ok(match op { + CipherOp::Encrypt => + Box::new(EaxOnline::<BlockCipherKey<Aes, U192>, Encrypt>::with_key_and_nonce(key, nonce)), + CipherOp::Decrypt => + Box::new(EaxOnline::<BlockCipherKey<Aes, U192>, Decrypt>::with_key_and_nonce(key, nonce)), + }) + } + SymmetricAlgorithm::AES256 => { + let key = GenericArray::from_slice(key); + Ok(match op { + CipherOp::Encrypt => + Box::new(EaxOnline::<BlockCipherKey<Aes, U256>, Encrypt>::with_key_and_nonce(key, nonce)), + CipherOp::Decrypt => + Box::new(EaxOnline::<BlockCipherKey<Aes, U256>, Decrypt>::with_key_and_nonce(key, nonce)), + }) + } _ => Err(Error::UnsupportedSymmetricAlgorithm(sym_algo).into()), }, _ => Err(Error::UnsupportedAEADAlgorithm(self.clone()).into()), @@ -33,135 +65,47 @@ impl AEADAlgorithm { } } -/// EAX-AES mode. -/// -/// See https://web.cs.ucdavis.edu/~rogaway/papers/eax.pdf. -struct EaxAes { - omac_nonce: Vec<u8>, - omac_data: Hash, - omac_msg: Hash, - ctr: Ctr, -} - -impl EaxAes { - fn with_key_and_nonce(key: &[u8], nonce: &[u8]) -> Result<Self> { - fn omac_init_with_iv( - prov: &HashAlgorithm<MacAlgorithmId>, - key: &[u8], - iv: u8, - ) -> Result<Hash> { - let mut omac = prov.new_mac(key, None)?; - // Prepend the IV - omac.hash(&[0; EAX_BLOCK_SIZE - 1])?; - omac.hash(&[iv])?; - Ok(omac) +macro_rules! impl_aead { + ($($type: ty),*) => { + $( + impl Aead for EaxOnline<$type, Encrypt> { + fn update(&mut self, ad: &[u8]) { self.update_assoc(ad) } + fn digest_size(&self) -> usize { <eax::Tag as GenericArrayExt>::LEN } + fn digest(&mut self, digest: &mut [u8]) { + let tag = self.tag_clone(); + digest[..tag.len()].copy_from_slice(&tag[..]); + } + fn encrypt(&mut self, dst: &mut [u8], src: &[u8]) { + let len = core::cmp::min(dst.len(), src.len()); + dst[..len].copy_from_slice(&src[..len]); + EaxOnline::<$type, Encrypt>::encrypt(self, &mut dst[..len]) + } + fn decrypt(&mut self, _dst: &mut [u8], _src: &[u8]) { + panic!("AEAD decryption called in the encryption context") + } } - - let provider = HashAlgorithm::open(MacAlgorithmId::AesCmac)?; - // N ← OMAC_0^K(N) - let mut omac_nonce = omac_init_with_iv(&provider, key, 0)?; - omac_nonce.hash(nonce)?; - let omac_nonce = omac_nonce.finish()?.into_inner(); - // H ← OMAC_1^K(H), init with 1 but hash online associated data later - let omac_data = omac_init_with_iv(&provider, key, 1)?; - // C ← OMAC_2^K(C), init with 2 but hash online resulting ciphertext later - let omac_msg = omac_init_with_iv(&provider, key, 2)?; - - let ctr = Ctr::with_cipher_and_iv(SymmetricAlgorithmId::Aes, key, &omac_nonce)?; - - Ok(EaxAes { omac_nonce, omac_data, omac_msg, ctr }) - } -} - - -impl seal::Sealed for EaxAes {} -impl Aead for EaxAes { - /// Adds associated data `ad`. - fn update(&mut self, ad: &[u8]) { - let _ = self.omac_data.hash(ad); - } - - /// Encrypts one block `src` to `dst`. - fn encrypt(&mut self, dst: &mut [u8], src: &[u8]) { - let _ = Ctr::encrypt(&mut self.ctr, dst, src); - let _ = self.omac_msg.hash(dst); - } - /// Decrypts one block `src` to `dst`. - fn decrypt(&mut self, dst: &mut [u8], src: &[u8]) { - let _ = self.omac_msg.hash(src); - let _ = Ctr::decrypt(&mut self.ctr, dst, src); - } - - /// Produce the digest. - fn digest(&mut self, digest: &mut [u8]) { - // TODO: It'd be great if wouldn't have to clone - let omac_data = self.omac_data.clone().finish().unwrap().into_inner(); - let omac_msg = self.omac_msg.clone().finish().unwrap().into_inner(); - - let (nonce, data, msg) = (self.omac_nonce.iter(), omac_data.iter(), omac_msg.iter()); - for (((out, n), d), m) in digest.iter_mut().zip(nonce).zip(data).zip(msg) { - *out = n ^ d ^ m; + impl seal::Sealed for EaxOnline<$type, Encrypt> {} + )* + $( + impl Aead for EaxOnline<$type, Decrypt> { + fn update(&mut self, ad: &[u8]) { self.update_assoc(ad) } + fn digest_size(&self) -> usize { <eax::Tag as GenericArrayExt>::LEN } + fn digest(&mut self, digest: &mut [u8]) { + let tag = self.tag_clone(); + digest[..tag.len()].copy_from_slice(&tag[..]); + } + fn encrypt(&mut self, _dst: &mut [u8], _src: &[u8]) { + panic!("AEAD encryption called in the decryption context") + } + fn decrypt(&mut self, dst: &mut [u8], src: &[u8]) { + let len = core::cmp::min(dst.len(), src.len()); + dst[..len].copy_from_slice(&src[..len]); + self.decrypt_unauthenticated_hazmat(&mut dst[..len]) + } } - } - - /// Length of the digest in bytes. - fn digest_size(&self) -> usize { EAX_DIGEST_SIZE } + impl seal::Sealed for EaxOnline<$type, Decrypt> {} + )* + }; } - -#[cfg(test)] -mod tests { - use super::*; - use crate::crypto::aead::Aead; - - trait HexSlice: std::borrow::Borrow<str> { - fn as_hex(&self) -> Vec<u8> { - let res: Vec<u8> = self.borrow().as_bytes().rchunks(2) - .map(|slice| std::str::from_utf8(slice).unwrap()) - .map(|chr| u8::from_str_radix(chr, 16).unwrap()) - .rev() - .collect(); - res - } - } - impl<'a> HexSlice for &'a str {} - - #[test] - fn eax() { - // Test vectors from https://web.cs.ucdavis.edu/~rogaway/papers/eax.pdf - let mut eax = EaxAes::with_key_and_nonce( - &"233952DEE4D5ED5F9B9C6D6FF80FF478".as_hex(), - &"62EC67F9C3A4A407FCB2A8C49031A8B3".as_hex() - ).unwrap(); - eax.update(&"6BFB914FD07EAE6B".as_hex()); - let mut digest = [0; 16]; - eax.digest(&mut digest); - assert_eq!(&digest, &*"E037830E8389F27B025A2D6527E79D01".as_hex()); - - let mut eax = EaxAes::with_key_and_nonce( - &"91945D3F4DCBEE0BF45EF52255F095A4".as_hex(), - &"BECAF043B0A23D843194BA972C66DEBD".as_hex() - ).unwrap(); - eax.update(&"FA3BFD4806EB53FA".as_hex()); - let mut out = [0; 2]; - eax.encrypt(&mut out, &"F7FB".as_hex()); - let mut digest = [0; 16]; - eax.digest(&mut digest); - let output = [&out[..], &digest[..]].concat(); - assert_eq!(output, &*"19DD5C4C9331049D0BDAB0277408F67967E5".as_hex()); - - let mut eax = EaxAes::with_key_and_nonce( - &"8395FCF1E95BEBD697BD010BC766AAC3".as_hex(), - &"22E7ADD93CFC6393C57EC0B3C17D6B44".as_hex() - ).unwrap(); - eax.update(&"126735FCC320D25A".as_hex()); - let mut out1 = [0; 16]; - eax.encrypt(&mut out1, &"CA40D7446E545FFAED3BD12A740A659F".as_hex()); - let mut out2 = [0; 5]; - eax.encrypt(&mut out2, &"FBBB3CEAB7".as_hex()); - let mut digest = [0; 16]; - eax.digest(&mut digest); - let output = [&out1[..], &out2[..], &digest[..]].concat(); - assert_eq!(output, &*"CB8920F87A6C75CFF39627B56E3ED197C552D295A7CFC46AFC253B4652B1AF3795B124AB6E".as_hex()); - } -} +impl_aead!(BlockCipherKey<Aes, U128>, BlockCipherKey<Aes, U192>, BlockCipherKey<Aes, U256>); |