diff options
Diffstat (limited to 'openpgp/src/crypto/backend/rust/aead.rs')
-rw-r--r-- | openpgp/src/crypto/backend/rust/aead.rs | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/openpgp/src/crypto/backend/rust/aead.rs b/openpgp/src/crypto/backend/rust/aead.rs new file mode 100644 index 00000000..ab2ca208 --- /dev/null +++ b/openpgp/src/crypto/backend/rust/aead.rs @@ -0,0 +1,134 @@ +//! Implementation of AEAD using pure Rust cryptographic libraries. + +use std::cmp; + +use cipher::{BlockCipher, NewBlockCipher}; +use cipher::block::Block; +use cipher::consts::U16; +use eax::online::{Eax, Encrypt, Decrypt}; +use generic_array::{ArrayLength, GenericArray}; + +use crate::{Error, Result}; +use crate::crypto::aead::{Aead, CipherOp}; +use crate::seal; +use crate::types::{AEADAlgorithm, SymmetricAlgorithm}; + +trait GenericArrayExt { + const LEN: usize; +} + +impl<T, N: ArrayLength<T>> GenericArrayExt for GenericArray<T, N> { + const LEN: usize = N::USIZE; +} + +impl<Cipher> Aead for Eax<Cipher, Encrypt> +where + Cipher: BlockCipher<BlockSize = U16> + NewBlockCipher + Clone, + Cipher::ParBlocks: ArrayLength<Block<Cipher>>, +{ + fn update(&mut self, ad: &[u8]) { + self.update_assoc(ad) + } + + fn digest_size(&self) -> usize { + eax::Tag::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 = cmp::min(dst.len(), src.len()); + dst[..len].copy_from_slice(&src[..len]); + Self::encrypt(self, &mut dst[..len]) + } + + fn decrypt(&mut self, _dst: &mut [u8], _src: &[u8]) { + panic!("AEAD decryption called in the encryption context") + } +} + +impl<Cipher> Aead for Eax<Cipher, Decrypt> +where + Cipher: BlockCipher<BlockSize = U16> + NewBlockCipher + Clone, + Cipher::ParBlocks: ArrayLength<Block<Cipher>>, +{ + fn update(&mut self, ad: &[u8]) { + self.update_assoc(ad) + } + + fn digest_size(&self) -> usize { + eax::Tag::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]) + } +} + +impl<Cipher, Op> seal::Sealed for Eax<Cipher, Op> +where + Cipher: BlockCipher<BlockSize = U16> + NewBlockCipher + Clone, + Cipher::ParBlocks: ArrayLength<Block<Cipher>>, + Op: eax::online::CipherOp, +{} + +impl AEADAlgorithm { + pub(crate) fn context( + &self, + sym_algo: SymmetricAlgorithm, + key: &[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(key.into(), nonce.into()))), + CipherOp::Decrypt => Ok(Box::new( + Eax::<aes::Aes128, Decrypt>::with_key_and_nonce(key.into(), nonce.into()))), + } + SymmetricAlgorithm::AES192 => match op { + CipherOp::Encrypt => Ok(Box::new( + Eax::<aes::Aes192, Encrypt>::with_key_and_nonce(key.into(), nonce.into()))), + CipherOp::Decrypt => Ok(Box::new( + Eax::<aes::Aes192, Decrypt>::with_key_and_nonce(key.into(), nonce.into()))), + } + SymmetricAlgorithm::AES256 => match op { + CipherOp::Encrypt => Ok(Box::new( + Eax::<aes::Aes256, Encrypt>::with_key_and_nonce(key.into(), nonce.into()))), + CipherOp::Decrypt => Ok(Box::new( + Eax::<aes::Aes256, Decrypt>::with_key_and_nonce(key.into(), nonce.into()))), + } + | SymmetricAlgorithm::IDEA + | SymmetricAlgorithm::TripleDES + | SymmetricAlgorithm::CAST5 + | SymmetricAlgorithm::Blowfish + | SymmetricAlgorithm::Twofish + | SymmetricAlgorithm::Camellia128 + | SymmetricAlgorithm::Camellia192 + | SymmetricAlgorithm::Camellia256 + | SymmetricAlgorithm::Private(_) + | SymmetricAlgorithm::Unknown(_) + | SymmetricAlgorithm::Unencrypted => + Err(Error::UnsupportedSymmetricAlgorithm(sym_algo).into()), + }, + AEADAlgorithm::OCB | AEADAlgorithm::Private(_) | AEADAlgorithm::Unknown(_) => + Err(Error::UnsupportedAEADAlgorithm(*self).into()), + } + } +} |