diff options
author | Justus Winter <justus@sequoia-pgp.org> | 2023-02-28 12:19:05 +0100 |
---|---|---|
committer | Justus Winter <justus@sequoia-pgp.org> | 2023-02-28 13:20:22 +0100 |
commit | f6b4b029930ac93fd6b3efed0128940b4b343fe0 (patch) | |
tree | efefee6c5e48723bfe1b10d6ce179aef478eeac5 | |
parent | 39bf91d6812f499327752803a6ecfada74a9b606 (diff) |
openpgp: Further simplify AEAD abstraction.
- Hand in the additional authenticated data when constructing the
context.
-rw-r--r-- | openpgp/src/crypto/aead.rs | 51 | ||||
-rw-r--r-- | openpgp/src/crypto/backend/cng/aead.rs | 105 | ||||
-rw-r--r-- | openpgp/src/crypto/backend/nettle/aead.rs | 70 | ||||
-rw-r--r-- | openpgp/src/crypto/backend/openssl/aead.rs | 7 | ||||
-rw-r--r-- | openpgp/src/crypto/backend/rust/aead.rs | 89 | ||||
-rw-r--r-- | openpgp/src/packet/skesk.rs | 16 |
6 files changed, 178 insertions, 160 deletions
diff --git a/openpgp/src/crypto/aead.rs b/openpgp/src/crypto/aead.rs index 7b9dc3fb..feee035f 100644 --- a/openpgp/src/crypto/aead.rs +++ b/openpgp/src/crypto/aead.rs @@ -50,9 +50,6 @@ pub(crate) fn chunk_size_usize(chunk_size: u64) -> Result<usize> { /// /// [sealed]: https://rust-lang.github.io/api-guidelines/future-proofing.html#sealed-traits-protect-against-downstream-implementations-c-sealed pub trait Aead : seal::Sealed { - /// Adds associated data `ad`. - fn update(&mut self, ad: &[u8]) -> Result<()>; - /// Encrypts one chunk `src` to `dst` adding a digest. /// /// Note: `dst` must be large enough to accommodate both the @@ -387,13 +384,9 @@ impl<'a, S: Schedule> Decryptor<'a, S> { let mut aead = self.schedule.next_chunk( self.chunk_index, |iv, ad| { - self.aead.context(self.sym_algo, &self.key, iv, + self.aead.context(self.sym_algo, &self.key, ad, iv, CipherOp::Decrypt) - .map(|mut aead| { - aead.update(ad)?; - Ok::<Box<dyn Aead>, anyhow::Error>(aead) - }) - })??; + })?; // Decrypt the chunk and check the tag. let to_decrypt = chunk.len() - self.digest_size; @@ -438,13 +431,9 @@ impl<'a, S: Schedule> Decryptor<'a, S> { let mut aead = self.schedule.final_chunk( self.chunk_index, self.bytes_decrypted, |iv, ad| { - self.aead.context(self.sym_algo, &self.key, iv, + self.aead.context(self.sym_algo, &self.key, ad, iv, CipherOp::Decrypt) - .map(|mut aead| { - aead.update(ad)?; - Ok::<Box<dyn Aead>, anyhow::Error>(aead) - }) - })??; + })?; let final_digest = self.source.data(final_digest_size)?; @@ -656,13 +645,9 @@ impl<W: io::Write, S: Schedule> Encryptor<W, S> { if self.buffer.len() == self.chunk_size { let mut aead = self.schedule.next_chunk(self.chunk_index, |iv, ad| { - self.aead.context(self.sym_algo, &self.key, iv, + self.aead.context(self.sym_algo, &self.key, ad, iv, CipherOp::Encrypt) - .map(|mut aead| { - aead.update(ad)?; - Ok::<Box<dyn Aead>, anyhow::Error>(aead) - }) - })??; + })?; let inner = self.inner.as_mut().unwrap(); @@ -682,13 +667,9 @@ impl<W: io::Write, S: Schedule> Encryptor<W, S> { // Complete chunk. let mut aead = self.schedule.next_chunk(self.chunk_index, |iv, ad| { - self.aead.context(self.sym_algo, &self.key, iv, + self.aead.context(self.sym_algo, &self.key, ad, iv, CipherOp::Encrypt) - .map(|mut aead| { - aead.update(ad)?; - Ok::<Box<dyn Aead>, anyhow::Error>(aead) - }) - })??; + })?; let inner = self.inner.as_mut().unwrap(); @@ -713,13 +694,9 @@ impl<W: io::Write, S: Schedule> Encryptor<W, S> { if !self.buffer.is_empty() { let mut aead = self.schedule.next_chunk(self.chunk_index, |iv, ad| { - self.aead.context(self.sym_algo, &self.key, iv, + self.aead.context(self.sym_algo, &self.key, ad, iv, CipherOp::Encrypt) - .map(|mut aead| { - aead.update(ad)?; - Ok::<Box<dyn Aead>, anyhow::Error>(aead) - }) - })??; + })?; // Encrypt the chunk. unsafe { @@ -741,13 +718,9 @@ impl<W: io::Write, S: Schedule> Encryptor<W, S> { let mut aead = self.schedule.final_chunk( self.chunk_index, self.bytes_encrypted, |iv, ad| { - self.aead.context(self.sym_algo, &self.key, iv, + self.aead.context(self.sym_algo, &self.key, ad, iv, CipherOp::Encrypt) - .map(|mut aead| { - aead.update(ad)?; - Ok::<Box<dyn Aead>, anyhow::Error>(aead) - }) - })??; + })?; aead.encrypt_seal(&mut self.scratch[..self.digest_size], b"")?; inner.write_all(&self.scratch[..self.digest_size])?; diff --git a/openpgp/src/crypto/backend/cng/aead.rs b/openpgp/src/crypto/backend/cng/aead.rs index afc6b7c9..c714efbb 100644 --- a/openpgp/src/crypto/backend/cng/aead.rs +++ b/openpgp/src/crypto/backend/cng/aead.rs @@ -7,7 +7,7 @@ use crate::crypto::mem::secure_cmp; use crate::seal; use crate::types::{AEADAlgorithm, SymmetricAlgorithm}; -use eax::online::{EaxOnline, Encrypt, Decrypt}; +use eax::online::{Eax, 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}; @@ -42,42 +42,67 @@ impl AEADAlgorithm { &self, sym_algo: SymmetricAlgorithm, key: &[u8], + aad: &[u8], nonce: &[u8], op: CipherOp, ) -> Result<Box<dyn Aead>> { match self { AEADAlgorithm::EAX => match sym_algo { - | SymmetricAlgorithm::AES128 => { - let key = GenericArray::try_from_slice(key)?; - let nonce = GenericArray::try_from_slice(nonce)?; - 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::try_from_slice(key)?; - let nonce = GenericArray::try_from_slice(nonce)?; - 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::try_from_slice(key)?; - let nonce = GenericArray::try_from_slice(nonce)?; - 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)), - }) - } + SymmetricAlgorithm::AES128 => match op { + CipherOp::Encrypt => { + let mut ctx = + Eax::<BlockCipherKey<Aes, U128>, Encrypt>::with_key_and_nonce( + GenericArray::try_from_slice(key)?, + GenericArray::try_from_slice(nonce)?); + ctx.update_assoc(aad); + Ok(Box::new(ctx)) + }, + CipherOp::Decrypt => { + let mut ctx = + Eax::<BlockCipherKey<Aes, U128>, Decrypt>::with_key_and_nonce( + GenericArray::try_from_slice(key)?, + GenericArray::try_from_slice(nonce)?); + ctx.update_assoc(aad); + Ok(Box::new(ctx)) + }, + }, + SymmetricAlgorithm::AES192 => match op { + CipherOp::Encrypt => { + let mut ctx = + Eax::<BlockCipherKey<Aes, U192>, Encrypt>::with_key_and_nonce( + GenericArray::try_from_slice(key)?, + GenericArray::try_from_slice(nonce)?); + ctx.update_assoc(aad); + Ok(Box::new(ctx)) + }, + CipherOp::Decrypt => { + let mut ctx = + Eax::<BlockCipherKey<Aes, U192>, Decrypt>::with_key_and_nonce( + GenericArray::try_from_slice(key)?, + GenericArray::try_from_slice(nonce)?); + ctx.update_assoc(aad); + Ok(Box::new(ctx)) + }, + }, + SymmetricAlgorithm::AES256 => match op { + CipherOp::Encrypt => { + let mut ctx = + Eax::<BlockCipherKey<Aes, U256>, Encrypt>::with_key_and_nonce( + GenericArray::try_from_slice(key)?, + GenericArray::try_from_slice(nonce)?); + ctx.update_assoc(aad); + Ok(Box::new(ctx)) + }, + CipherOp::Decrypt => { + let mut ctx = + Eax::<BlockCipherKey<Aes, U256>, Decrypt>::with_key_and_nonce( + GenericArray::try_from_slice(key)?, + GenericArray::try_from_slice(nonce)?); + ctx.update_assoc(aad); + Ok(Box::new(ctx)) + }, + }, _ => Err(Error::UnsupportedSymmetricAlgorithm(sym_algo).into()), }, _ => Err(Error::UnsupportedAEADAlgorithm(self.clone()).into()), @@ -88,11 +113,7 @@ impl AEADAlgorithm { macro_rules! impl_aead { ($($type: ty),*) => { $( - impl Aead for EaxOnline<$type, Encrypt> { - fn update(&mut self, ad: &[u8]) -> Result<()> { - self.update_assoc(ad); - Ok(()) - } + impl Aead for Eax<$type, Encrypt> { fn digest_size(&self) -> usize { <eax::Tag as GenericArrayExt<_, _>>::LEN } @@ -100,7 +121,7 @@ macro_rules! impl_aead { debug_assert_eq!(dst.len(), src.len() + self.digest_size()); let len = core::cmp::min(dst.len(), src.len()); dst[..len].copy_from_slice(&src[..len]); - EaxOnline::<$type, Encrypt>::encrypt(self, &mut dst[..len]); + Eax::<$type, Encrypt>::encrypt(self, &mut dst[..len]); let tag = self.tag_clone(); dst[src.len()..].copy_from_slice(&tag[..]); @@ -110,14 +131,10 @@ macro_rules! impl_aead { panic!("AEAD decryption called in the encryption context") } } - impl seal::Sealed for EaxOnline<$type, Encrypt> {} + impl seal::Sealed for Eax<$type, Encrypt> {} )* $( - impl Aead for EaxOnline<$type, Decrypt> { - fn update(&mut self, ad: &[u8]) -> Result<()> { - self.update_assoc(ad); - Ok(()) - } + impl Aead for Eax<$type, Decrypt> { fn digest_size(&self) -> usize { <eax::Tag as GenericArrayExt<_, _>>::LEN } @@ -138,7 +155,7 @@ macro_rules! impl_aead { Ok(()) } } - impl seal::Sealed for EaxOnline<$type, Decrypt> {} + impl seal::Sealed for Eax<$type, Decrypt> {} )* }; } diff --git a/openpgp/src/crypto/backend/nettle/aead.rs b/openpgp/src/crypto/backend/nettle/aead.rs index df2f0f64..ad6014d7 100644 --- a/openpgp/src/crypto/backend/nettle/aead.rs +++ b/openpgp/src/crypto/backend/nettle/aead.rs @@ -1,7 +1,7 @@ //! Implementation of AEAD using Nettle cryptographic library. use std::cmp::Ordering; -use nettle::{aead, cipher}; +use nettle::{aead::{self, Aead as _}, cipher}; use crate::{Error, Result}; @@ -18,10 +18,6 @@ const DANGER_DISABLE_AUTHENTICATION: bool = false; impl<T: nettle::aead::Aead> seal::Sealed for T {} impl<T: nettle::aead::Aead> Aead for T { - fn update(&mut self, ad: &[u8]) -> Result<()> { - self.update(ad); - Ok(()) - } fn encrypt_seal(&mut self, dst: &mut [u8], src: &[u8]) -> Result<()> { debug_assert_eq!(dst.len(), src.len() + self.digest_size()); self.encrypt(dst, src); @@ -50,32 +46,54 @@ impl AEADAlgorithm { &self, sym_algo: SymmetricAlgorithm, key: &[u8], + aad: &[u8], nonce: &[u8], _op: CipherOp, ) -> Result<Box<dyn Aead>> { match self { AEADAlgorithm::EAX => match sym_algo { - SymmetricAlgorithm::AES128 => Ok(Box::new( - aead::Eax::<cipher::Aes128>::with_key_and_nonce(key, nonce)?, - )), - SymmetricAlgorithm::AES192 => Ok(Box::new( - aead::Eax::<cipher::Aes192>::with_key_and_nonce(key, nonce)?, - )), - SymmetricAlgorithm::AES256 => Ok(Box::new( - aead::Eax::<cipher::Aes256>::with_key_and_nonce(key, nonce)?, - )), - SymmetricAlgorithm::Twofish => Ok(Box::new( - aead::Eax::<cipher::Twofish>::with_key_and_nonce(key, nonce)?, - )), - SymmetricAlgorithm::Camellia128 => Ok(Box::new( - aead::Eax::<cipher::Camellia128>::with_key_and_nonce(key, nonce)?, - )), - SymmetricAlgorithm::Camellia192 => Ok(Box::new( - aead::Eax::<cipher::Camellia192>::with_key_and_nonce(key, nonce)?, - )), - SymmetricAlgorithm::Camellia256 => Ok(Box::new( - aead::Eax::<cipher::Camellia256>::with_key_and_nonce(key, nonce)?, - )), + SymmetricAlgorithm::AES128 => { + let mut ctx = + aead::Eax::<cipher::Aes128>::with_key_and_nonce(key, nonce)?; + ctx.update(aad); + Ok(Box::new(ctx)) + }, + SymmetricAlgorithm::AES192 => { + let mut ctx = + aead::Eax::<cipher::Aes192>::with_key_and_nonce(key, nonce)?; + ctx.update(aad); + Ok(Box::new(ctx)) + }, + SymmetricAlgorithm::AES256 => { + let mut ctx = + aead::Eax::<cipher::Aes256>::with_key_and_nonce(key, nonce)?; + ctx.update(aad); + Ok(Box::new(ctx)) + }, + SymmetricAlgorithm::Twofish => { + let mut ctx = + aead::Eax::<cipher::Twofish>::with_key_and_nonce(key, nonce)?; + ctx.update(aad); + Ok(Box::new(ctx)) + }, + SymmetricAlgorithm::Camellia128 => { + let mut ctx = + aead::Eax::<cipher::Camellia128>::with_key_and_nonce(key, nonce)?; + ctx.update(aad); + Ok(Box::new(ctx)) + }, + SymmetricAlgorithm::Camellia192 => { + let mut ctx = + aead::Eax::<cipher::Camellia192>::with_key_and_nonce(key, nonce)?; + ctx.update(aad); + Ok(Box::new(ctx)) + }, + SymmetricAlgorithm::Camellia256 => { + let mut ctx = + aead::Eax::<cipher::Camellia256>::with_key_and_nonce(key, nonce)?; + ctx.update(aad); + Ok(Box::new(ctx)) + }, _ => Err(Error::UnsupportedSymmetricAlgorithm(sym_algo).into()), }, _ => Err(Error::UnsupportedAEADAlgorithm(*self).into()), diff --git a/openpgp/src/crypto/backend/openssl/aead.rs b/openpgp/src/crypto/backend/openssl/aead.rs index 5e73ff0a..469539c0 100644 --- a/openpgp/src/crypto/backend/openssl/aead.rs +++ b/openpgp/src/crypto/backend/openssl/aead.rs @@ -13,11 +13,6 @@ struct OpenSslContext { } impl Aead for OpenSslContext { - fn update(&mut self, ad: &[u8]) -> Result<()> { - self.ctx.cipher_update(ad, None)?; - Ok(()) - } - fn encrypt_seal(&mut self, dst: &mut [u8], src: &[u8]) -> Result<()> { debug_assert_eq!(dst.len(), src.len() + self.digest_size()); @@ -59,6 +54,7 @@ impl AEADAlgorithm { &self, sym_algo: SymmetricAlgorithm, key: &[u8], + aad: &[u8], nonce: &[u8], op: CipherOp, ) -> Result<Box<dyn Aead>> { @@ -89,6 +85,7 @@ impl AEADAlgorithm { ctx.decrypt_init(None, None, Some(nonce))?, } ctx.set_padding(false); + ctx.cipher_update(aad, None)?; Ok(Box::new(OpenSslContext { ctx, })) diff --git a/openpgp/src/crypto/backend/rust/aead.rs b/openpgp/src/crypto/backend/rust/aead.rs index 5c57e79a..1e4ca4c0 100644 --- a/openpgp/src/crypto/backend/rust/aead.rs +++ b/openpgp/src/crypto/backend/rust/aead.rs @@ -45,11 +45,6 @@ where Cipher: BlockCipher<BlockSize = U16> + NewBlockCipher + Clone, Cipher::ParBlocks: ArrayLength<Block<Cipher>>, { - fn update(&mut self, ad: &[u8]) -> Result<()> { - self.update_assoc(ad); - Ok(()) - } - fn digest_size(&self) -> usize { eax::Tag::LEN } @@ -74,11 +69,6 @@ where Cipher: BlockCipher<BlockSize = U16> + NewBlockCipher + Clone, Cipher::ParBlocks: ArrayLength<Block<Cipher>>, { - fn update(&mut self, ad: &[u8]) -> Result<()> { - self.update_assoc(ad); - Ok(()) - } - fn digest_size(&self) -> usize { eax::Tag::LEN } @@ -114,41 +104,66 @@ impl AEADAlgorithm { &self, sym_algo: SymmetricAlgorithm, key: &[u8], + aad: &[u8], nonce: &[u8], op: CipherOp, ) -> Result<Box<dyn Aead>> { match self { AEADAlgorithm::EAX => match sym_algo { SymmetricAlgorithm::AES128 => match op { - CipherOp::Encrypt => Ok(Box::new( - Eax::<aes::Aes128, Encrypt>::with_key_and_nonce( - GenericArray::try_from_slice(key)?, - GenericArray::try_from_slice(nonce)?))), - CipherOp::Decrypt => Ok(Box::new( - Eax::<aes::Aes128, Decrypt>::with_key_and_nonce( - GenericArray::try_from_slice(key)?, - GenericArray::try_from_slice(nonce)?))), - } + CipherOp::Encrypt => { + let mut ctx = + Eax::<aes::Aes128, Encrypt>::with_key_and_nonce( + GenericArray::try_from_slice(key)?, + GenericArray::try_from_slice(nonce)?); + ctx.update_assoc(aad); + Ok(Box::new(ctx)) + }, + CipherOp::Decrypt => { + let mut ctx = + Eax::<aes::Aes128, Decrypt>::with_key_and_nonce( + GenericArray::try_from_slice(key)?, + GenericArray::try_from_slice(nonce)?); + ctx.update_assoc(aad); + Ok(Box::new(ctx)) + }, + }, SymmetricAlgorithm::AES192 => match op { - CipherOp::Encrypt => Ok(Box::new( - Eax::<aes::Aes192, Encrypt>::with_key_and_nonce( - GenericArray::try_from_slice(key)?, - GenericArray::try_from_slice(nonce)?))), - CipherOp::Decrypt => Ok(Box::new( - Eax::<aes::Aes192, Decrypt>::with_key_and_nonce( - GenericArray::try_from_slice(key)?, - GenericArray::try_from_slice(nonce)?))), - } + CipherOp::Encrypt => { + let mut ctx = + Eax::<aes::Aes192, Encrypt>::with_key_and_nonce( + GenericArray::try_from_slice(key)?, + GenericArray::try_from_slice(nonce)?); + ctx.update_assoc(aad); + Ok(Box::new(ctx)) + }, + CipherOp::Decrypt => { + let mut ctx = + Eax::<aes::Aes192, Decrypt>::with_key_and_nonce( + GenericArray::try_from_slice(key)?, + GenericArray::try_from_slice(nonce)?); + ctx.update_assoc(aad); + Ok(Box::new(ctx)) + }, + }, SymmetricAlgorithm::AES256 => match op { - CipherOp::Encrypt => Ok(Box::new( - Eax::<aes::Aes256, Encrypt>::with_key_and_nonce( - GenericArray::try_from_slice(key)?, - GenericArray::try_from_slice(nonce)?))), - CipherOp::Decrypt => Ok(Box::new( - Eax::<aes::Aes256, Decrypt>::with_key_and_nonce( - GenericArray::try_from_slice(key)?, - GenericArray::try_from_slice(nonce)?))), - } + CipherOp::Encrypt => { + let mut ctx = + Eax::<aes::Aes256, Encrypt>::with_key_and_nonce( + GenericArray::try_from_slice(key)?, + GenericArray::try_from_slice(nonce)?); + ctx.update_assoc(aad); + Ok(Box::new(ctx)) + }, + CipherOp::Decrypt => { + let mut ctx = + Eax::<aes::Aes256, Decrypt>::with_key_and_nonce( + GenericArray::try_from_slice(key)?, + GenericArray::try_from_slice(nonce)?); + ctx.update_assoc(aad); + Ok(Box::new(ctx)) + }, + }, | SymmetricAlgorithm::IDEA | SymmetricAlgorithm::TripleDES | SymmetricAlgorithm::CAST5 diff --git a/openpgp/src/packet/skesk.rs b/openpgp/src/packet/skesk.rs index 694f7496..782511bb 100644 --- a/openpgp/src/packet/skesk.rs +++ b/openpgp/src/packet/skesk.rs @@ -458,11 +458,9 @@ impl SKESK5 { let key = s2k.derive_key(password, esk_algo.key_size()?)?; let mut iv = vec![0u8; esk_aead.nonce_size()?]; crypto::random(&mut iv); - let mut ctx = esk_aead.context(esk_algo, &key, &iv, CipherOp::Encrypt)?; - - // Prepare associated data. - let ad = [0xc3, 5, esk_algo.into(), esk_aead.into()]; - ctx.update(&ad)?; + let aad = [0xc3, 5, esk_algo.into(), esk_aead.into()]; + let mut ctx = esk_aead.context(esk_algo, &key, &aad, &iv, + CipherOp::Encrypt)?; // Encrypt the session key with the KEK. let mut esk_digest = @@ -497,12 +495,12 @@ impl SKESK5 { if let Some(esk) = self.esk()? { // Use the derived key to decrypt the ESK. + let aad = [0xc3, 5 /* Version. */, self.symmetric_algo().into(), + self.aead_algo.into()]; let mut cipher = self.aead_algo.context( - self.symmetric_algo(), &key, self.aead_iv()?, CipherOp::Decrypt)?; + self.symmetric_algo(), &key, &aad, self.aead_iv()?, + CipherOp::Decrypt)?; - let ad = [0xc3, 5 /* Version. */, self.symmetric_algo().into(), - self.aead_algo.into()]; - cipher.update(&ad)?; let mut plain: SessionKey = vec![0; esk.len()].into(); cipher.decrypt_verify(&mut plain, esk, &self.aead_digest[..])?; Ok((SymmetricAlgorithm::Unencrypted, plain)) |