diff options
author | Neal H. Walfield <neal@pep.foundation> | 2023-04-28 12:32:23 +0200 |
---|---|---|
committer | Neal H. Walfield <neal@pep.foundation> | 2023-05-03 12:37:24 +0200 |
commit | 4ec75df65e1e8646ede928dd8475ed0b681cfdae (patch) | |
tree | 50f54acb0553576eda0bcf979399113f6207513c /openpgp/src/crypto/backend/rust/symmetric.rs | |
parent | 4980fd66a7e7db7d7b91f86a7ae1af42b6245478 (diff) |
openpgp: Update rust-crypto dependencies
- Note: `x25519-dalek` is broken. It depends on zeroize `=1.3`, but
crates like rsa depend on newer versions of zeroize.
- See https://github.com/WebAssembly/wasi-crypto/issues/63 ,
https://github.com/dalek-cryptography/x25519-dalek/issues/92 .
- Resolve this by using `x25519-dalek-ng`, which fixes this issue.
This is a common workaround, and is also used by, for instance
OpenMLS:
https://github.com/openmls/openmls/blob/3ff090fd4881cb796d4688f7f174929a7521dbf1/openmls_rust_crypto/README.md?plain=1#L3
- Fixes #910.
Diffstat (limited to 'openpgp/src/crypto/backend/rust/symmetric.rs')
-rw-r--r-- | openpgp/src/crypto/backend/rust/symmetric.rs | 426 |
1 files changed, 351 insertions, 75 deletions
diff --git a/openpgp/src/crypto/backend/rust/symmetric.rs b/openpgp/src/crypto/backend/rust/symmetric.rs index 160cdb4f..30bf7274 100644 --- a/openpgp/src/crypto/backend/rust/symmetric.rs +++ b/openpgp/src/crypto/backend/rust/symmetric.rs @@ -1,24 +1,103 @@ use std::slice; -use block_modes::{BlockMode, Cfb, Ecb}; -use block_padding::ZeroPadding; -use cipher::{BlockCipher, NewBlockCipher}; +use cipher::BlockDecryptMut; +use cipher::BlockEncryptMut; +use cipher::KeyInit; +use cipher::KeyIvInit; use generic_array::{ArrayLength, GenericArray}; -use typenum::Unsigned; use crate::{Error, Result}; use crate::crypto::symmetric::Mode; use crate::types::SymmetricAlgorithm; -macro_rules! impl_mode { +use super::GenericArrayExt; + +enum CfbEncrypt { + Idea(cfb_mode::Encryptor<idea::Idea>), + TripleDES(cfb_mode::Encryptor<des::TdesEde3>), + Cast5(cfb_mode::Encryptor<cast5::Cast5>), + Blowfish(cfb_mode::Encryptor<blowfish::Blowfish>), + Aes128(cfb_mode::Encryptor<aes::Aes128>), + Aes192(cfb_mode::Encryptor<aes::Aes192>), + Aes256(cfb_mode::Encryptor<aes::Aes256>), + Twofish(cfb_mode::Encryptor<twofish::Twofish>), + //Camellia128 + //Camellia192 + //Camellia256 +} + +enum CfbDecrypt { + Idea(cfb_mode::Decryptor<idea::Idea>), + TripleDES(cfb_mode::Decryptor<des::TdesEde3>), + Cast5(cfb_mode::Decryptor<cast5::Cast5>), + Blowfish(cfb_mode::Decryptor<blowfish::Blowfish>), + Aes128(cfb_mode::Decryptor<aes::Aes128>), + Aes192(cfb_mode::Decryptor<aes::Aes192>), + Aes256(cfb_mode::Decryptor<aes::Aes256>), + Twofish(cfb_mode::Decryptor<twofish::Twofish>), + //Camellia128 + //Camellia192 + //Camellia256 +} + +enum EcbEncrypt { + Idea(ecb::Encryptor<idea::Idea>), + TripleDES(ecb::Encryptor<des::TdesEde3>), + Cast5(ecb::Encryptor<cast5::Cast5>), + Blowfish(ecb::Encryptor<blowfish::Blowfish>), + Aes128(ecb::Encryptor<aes::Aes128>), + Aes192(ecb::Encryptor<aes::Aes192>), + Aes256(ecb::Encryptor<aes::Aes256>), + Twofish(ecb::Encryptor<twofish::Twofish>), + //Camellia128 + //Camellia192 + //Camellia256 +} + +enum EcbDecrypt { + Idea(ecb::Decryptor<idea::Idea>), + TripleDES(ecb::Decryptor<des::TdesEde3>), + Cast5(ecb::Decryptor<cast5::Cast5>), + Blowfish(ecb::Decryptor<blowfish::Blowfish>), + Aes128(ecb::Decryptor<aes::Aes128>), + Aes192(ecb::Decryptor<aes::Aes192>), + Aes256(ecb::Decryptor<aes::Aes256>), + Twofish(ecb::Decryptor<twofish::Twofish>), + //Camellia128 + //Camellia192 + //Camellia256 +} + +macro_rules! impl_block_size { ($mode:ident) => { - impl<C> Mode for $mode<C, ZeroPadding> - where - C: BlockCipher + NewBlockCipher + Send + Sync, - { - fn block_size(&self) -> usize { - C::BlockSize::to_usize() + fn block_size(&self) -> usize { + match self { + $mode::Idea(_) => + <idea::Idea as cipher::BlockSizeUser>::block_size(), + $mode::TripleDES(_) => + <des::TdesEde3 as cipher::BlockSizeUser>::block_size(), + $mode::Cast5(_) => + <cast5::Cast5 as cipher::BlockSizeUser>::block_size(), + $mode::Blowfish(_) => + <blowfish::Blowfish as cipher::BlockSizeUser>::block_size(), + $mode::Aes128(_) => + <aes::Aes128 as cipher::BlockSizeUser>::block_size(), + $mode::Aes192(_) => + <aes::Aes192 as cipher::BlockSizeUser>::block_size(), + $mode::Aes256(_) => + <aes::Aes256 as cipher::BlockSizeUser>::block_size(), + $mode::Twofish(_) => + <twofish::Twofish as cipher::BlockSizeUser>::block_size(), } + } + } +} + +macro_rules! impl_enc_mode { + ($mode:ident) => { + impl Mode for $mode + { + impl_block_size!($mode); fn encrypt( &mut self, @@ -31,17 +110,110 @@ macro_rules! impl_mode { if missing > 0 { let mut buf = vec![0u8; src.len() + missing]; buf[..src.len()].copy_from_slice(src); - self.encrypt_blocks(to_blocks(&mut buf)); + match self { + $mode::Idea(m) => { + let blocks = to_blocks(&mut buf); + m.encrypt_blocks_mut(blocks) + } + $mode::TripleDES(m) => { + let blocks = to_blocks(&mut buf); + m.encrypt_blocks_mut(blocks) + } + $mode::Cast5(m) => { + let blocks = to_blocks(&mut buf); + m.encrypt_blocks_mut(blocks) + } + $mode::Blowfish(m) => { + let blocks = to_blocks(&mut buf); + m.encrypt_blocks_mut(blocks) + } + $mode::Aes128(m) => { + let blocks = to_blocks(&mut buf); + m.encrypt_blocks_mut(blocks) + } + $mode::Aes192(m) => { + let blocks = to_blocks(&mut buf); + m.encrypt_blocks_mut(blocks) + } + $mode::Aes256(m) => { + let blocks = to_blocks(&mut buf); + m.encrypt_blocks_mut(blocks) + } + $mode::Twofish(m) => { + let blocks = to_blocks(&mut buf); + m.encrypt_blocks_mut(blocks) + } + } dst.copy_from_slice(&buf[..dst.len()]); } else { dst.copy_from_slice(src); - self.encrypt_blocks(to_blocks(dst)); + match self { + $mode::Idea(m) => { + let blocks = to_blocks(dst); + m.encrypt_blocks_mut(blocks) + } + $mode::TripleDES(m) => { + let blocks = to_blocks(dst); + m.encrypt_blocks_mut(blocks) + } + $mode::Cast5(m) => { + let blocks = to_blocks(dst); + m.encrypt_blocks_mut(blocks) + } + $mode::Blowfish(m) => { + let blocks = to_blocks(dst); + m.encrypt_blocks_mut(blocks) + } + $mode::Aes128(m) => { + let blocks = to_blocks(dst); + m.encrypt_blocks_mut(blocks) + } + $mode::Aes192(m) => { + let blocks = to_blocks(dst); + m.encrypt_blocks_mut(blocks) + } + $mode::Aes256(m) => { + let blocks = to_blocks(dst); + m.encrypt_blocks_mut(blocks) + } + $mode::Twofish(m) => { + let blocks = to_blocks(dst); + m.encrypt_blocks_mut(blocks) + } + } } Ok(()) } fn decrypt( &mut self, + _dst: &mut [u8], + _src: &[u8], + ) -> Result<()> { + Err(anyhow::anyhow!( + "decryption not supported in encryption mode")) + } + } + } +} + +macro_rules! impl_dec_mode { + ($mode:ident) => { + impl Mode for $mode + { + impl_block_size!($mode); + + fn encrypt( + &mut self, + _dst: &mut [u8], + _src: &[u8], + ) -> Result<()> { + Err(anyhow::anyhow!( + "encryption not supported in decryption mode")) + } + + fn decrypt( + &mut self, dst: &mut [u8], src: &[u8], ) -> Result<()> { @@ -51,11 +223,77 @@ macro_rules! impl_mode { if missing > 0 { let mut buf = vec![0u8; src.len() + missing]; buf[..src.len()].copy_from_slice(src); - self.decrypt_blocks(to_blocks(&mut buf)); + match self { + $mode::Idea(m) => { + let blocks = to_blocks(&mut buf); + m.decrypt_blocks_mut(blocks) + } + $mode::TripleDES(m) => { + let blocks = to_blocks(&mut buf); + m.decrypt_blocks_mut(blocks) + } + $mode::Cast5(m) => { + let blocks = to_blocks(&mut buf); + m.decrypt_blocks_mut(blocks) + } + $mode::Blowfish(m) => { + let blocks = to_blocks(&mut buf); + m.decrypt_blocks_mut(blocks) + } + $mode::Aes128(m) => { + let blocks = to_blocks(&mut buf); + m.decrypt_blocks_mut(blocks) + } + $mode::Aes192(m) => { + let blocks = to_blocks(&mut buf); + m.decrypt_blocks_mut(blocks) + } + $mode::Aes256(m) => { + let blocks = to_blocks(&mut buf); + m.decrypt_blocks_mut(blocks) + } + $mode::Twofish(m) => { + let blocks = to_blocks(&mut buf); + m.decrypt_blocks_mut(blocks) + } + } dst.copy_from_slice(&buf[..dst.len()]); } else { dst.copy_from_slice(src); - self.decrypt_blocks(to_blocks(dst)); + match self { + $mode::Idea(m) => { + let blocks = to_blocks(dst); + m.decrypt_blocks_mut(blocks) + } + $mode::TripleDES(m) => { + let blocks = to_blocks(dst); + m.decrypt_blocks_mut(blocks) + } + $mode::Cast5(m) => { + let blocks = to_blocks(dst); + m.decrypt_blocks_mut(blocks) + } + $mode::Blowfish(m) => { + let blocks = to_blocks(dst); + m.decrypt_blocks_mut(blocks) + } + $mode::Aes128(m) => { + let blocks = to_blocks(dst); + m.decrypt_blocks_mut(blocks) + } + $mode::Aes192(m) => { + let blocks = to_blocks(dst); + m.decrypt_blocks_mut(blocks) + } + $mode::Aes256(m) => { + let blocks = to_blocks(dst); + m.decrypt_blocks_mut(blocks) + } + $mode::Twofish(m) => { + let blocks = to_blocks(dst); + m.decrypt_blocks_mut(blocks) + } + } } Ok(()) } @@ -63,8 +301,10 @@ macro_rules! impl_mode { } } -impl_mode!(Cfb); -impl_mode!(Ecb); +impl_enc_mode!(CfbEncrypt); +impl_dec_mode!(CfbDecrypt); +impl_enc_mode!(EcbEncrypt); +impl_dec_mode!(EcbDecrypt); fn to_blocks<N>(data: &mut [u8]) -> &mut [GenericArray<u8, N>] where @@ -77,6 +317,81 @@ where } } +/// Creates a context for encrypting/decrypting in CFB/ECB mode. +macro_rules! make_mode { + ($fn:ident, $enum:ident, $mode:ident::$mode2:ident $(, $iv:ident:$ivt:ty)?) => { + pub(crate) fn $fn(self, key: &[u8], $($iv: $ivt)?) -> Result<Box<dyn Mode>> { + use cipher::generic_array::GenericArray as GA; + + use SymmetricAlgorithm::*; + + match self { + IDEA => { + let key = GA::try_from_slice(&key)?; + $( let $iv = &GA::try_from_slice(&$iv)?; )? + Ok(Box::new($enum::Idea( + $mode::$mode2::<idea::Idea>::new(key $(, $iv)?)))) + }, + TripleDES => { + let key = GA::try_from_slice(&key)?; + $( let $iv = &GA::try_from_slice(&$iv)?; )? + Ok(Box::new($enum::TripleDES( + $mode::$mode2::<des::TdesEde3>::new(key $(, $iv)?)))) + }, + CAST5 => { + let key = GA::try_from_slice(&key)?; + $( let $iv = &GA::try_from_slice(&$iv)?; )? + Ok(Box::new($enum::Cast5( + $mode::$mode2::<cast5::Cast5>::new(key $(, $iv)?)))) + }, + Blowfish => { + // Right... the blowfish constructor expects a 56 + // byte key, but in OpenPGP the key is only 16 + // bytes. + assert_eq!(key.len(), 16); + let mut key = key.to_vec(); + while key.len() < 56 { + key.push(0); + } + let key = GA::try_from_slice(&key)?; + $( let $iv = &GA::try_from_slice(&$iv)?; )? + Ok(Box::new($enum::Blowfish( + $mode::$mode2::<blowfish::Blowfish>::new(key $(, $iv)?)))) + }, + AES128 => { + let key = GA::try_from_slice(&key)?; + $( let $iv = &GA::try_from_slice(&$iv)?; )? + Ok(Box::new($enum::Aes128( + $mode::$mode2::<aes::Aes128>::new(key $(, $iv)?)))) + }, + AES192 => { + let key = GA::try_from_slice(&key)?; + $( let $iv = &GA::try_from_slice(&$iv)?; )? + Ok(Box::new($enum::Aes192( + $mode::$mode2::<aes::Aes192>::new(key $(, $iv)?)))) + }, + AES256 => { + let key = GA::try_from_slice(&key)?; + $( let $iv = &GA::try_from_slice(&$iv)?; )? + Ok(Box::new($enum::Aes256( + $mode::$mode2::<aes::Aes256>::new(key $(, $iv)?)))) + }, + Twofish => { + let key = GA::try_from_slice(&key)?; + $( let $iv = &GA::try_from_slice(&$iv)?; )? + Ok(Box::new($enum::Twofish( + $mode::$mode2::<twofish::Twofish>::new(key $(, $iv)?)))) + }, + Camellia128 | Camellia192 | Camellia256 + | Private(_) | Unknown(_) | Unencrypted => + { + Err(Error::UnsupportedSymmetricAlgorithm(self).into()) + } + } + } + } +} + impl SymmetricAlgorithm { /// Returns whether this algorithm is supported by the crypto backend. pub(crate) fn is_supported_by_backend(&self) -> bool { @@ -99,49 +414,10 @@ impl SymmetricAlgorithm { } } - /// Creates a context for encrypting in CFB mode. - pub(crate) fn make_encrypt_cfb(self, key: &[u8], iv: Vec<u8>) -> Result<Box<dyn Mode>> { - use SymmetricAlgorithm::*; - match self { - IDEA => Ok(Box::new(Cfb::<idea::Idea, ZeroPadding>::new_var(key, &iv)?)), - TripleDES => Ok(Box::new(Cfb::<des::TdesEde3, ZeroPadding>::new_var(key, &iv)?)), - CAST5 => Ok(Box::new(Cfb::<cast5::Cast5, ZeroPadding>::new_var(key, &iv)?)), - Blowfish => Ok(Box::new(Cfb::<blowfish::Blowfish, ZeroPadding>::new_var(key, &iv)?)), - AES128 => Ok(Box::new(Cfb::<aes::Aes128, ZeroPadding>::new_var(key, &iv)?)), - AES192 => Ok(Box::new(Cfb::<aes::Aes192, ZeroPadding>::new_var(key, &iv)?)), - AES256 => Ok(Box::new(Cfb::<aes::Aes256, ZeroPadding>::new_var(key, &iv)?)), - Twofish => Ok(Box::new(Cfb::<twofish::Twofish, ZeroPadding>::new_var(key, &iv)?)), - Camellia128 | Camellia192 | Camellia256 | Private(_) | Unknown(_) | Unencrypted => - Err(Error::UnsupportedSymmetricAlgorithm(self).into()), - } - } - - /// Creates a context for decrypting in CFB mode. - pub(crate) fn make_decrypt_cfb(self, key: &[u8], iv: Vec<u8>) -> Result<Box<dyn Mode>> { - self.make_encrypt_cfb(key, iv) - } - - /// Creates a context for encrypting in ECB mode. - pub(crate) fn make_encrypt_ecb(self, key: &[u8]) -> Result<Box<dyn Mode>> { - use SymmetricAlgorithm::*; - match self { - IDEA => Ok(Box::new(Ecb::<idea::Idea, ZeroPadding>::new_var(key, &[])?)), - TripleDES => Ok(Box::new(Ecb::<des::TdesEde3, ZeroPadding>::new_var(key, &[])?)), - CAST5 => Ok(Box::new(Ecb::<cast5::Cast5, ZeroPadding>::new_var(key, &[])?)), - Blowfish => Ok(Box::new(Ecb::<blowfish::Blowfish, ZeroPadding>::new_var(key, &[])?)), - AES128 => Ok(Box::new(Ecb::<aes::Aes128, ZeroPadding>::new_var(key, &[])?)), - AES192 => Ok(Box::new(Ecb::<aes::Aes192, ZeroPadding>::new_var(key, &[])?)), - AES256 => Ok(Box::new(Ecb::<aes::Aes256, ZeroPadding>::new_var(key, &[])?)), - Twofish => Ok(Box::new(Ecb::<twofish::Twofish, ZeroPadding>::new_var(key, &[])?)), - Camellia128 | Camellia192 | Camellia256 | Private(_) | Unknown(_) | Unencrypted => - Err(Error::UnsupportedSymmetricAlgorithm(self).into()), - } - } - - /// Creates a context for decrypting in ECB mode. - pub(crate) fn make_decrypt_ecb(self, key: &[u8]) -> Result<Box<dyn Mode>> { - self.make_encrypt_ecb(key) - } + make_mode!(make_encrypt_cfb, CfbEncrypt, cfb_mode::Encryptor, iv: Vec<u8>); + make_mode!(make_decrypt_cfb, CfbDecrypt, cfb_mode::Decryptor, iv: Vec<u8>); + make_mode!(make_encrypt_ecb, EcbEncrypt, ecb::Encryptor); + make_mode!(make_decrypt_ecb, EcbDecrypt, ecb::Decryptor); } #[cfg(test)] @@ -153,21 +429,21 @@ mod tests { #[test] fn key_size() -> Result<()> { assert_eq!(SymmetricAlgorithm::IDEA.key_size()?, - <idea::Idea as NewBlockCipher>::KeySize::to_usize()); + <idea::Idea as cipher::KeySizeUser>::key_size()); assert_eq!(SymmetricAlgorithm::TripleDES.key_size()?, - <des::TdesEde3 as NewBlockCipher>::KeySize::to_usize()); + <des::TdesEde3 as cipher::KeySizeUser>::key_size()); assert_eq!(SymmetricAlgorithm::CAST5.key_size()?, - <cast5::Cast5 as NewBlockCipher>::KeySize::to_usize()); + <cast5::Cast5 as cipher::KeySizeUser>::key_size()); // RFC4880, Section 9.2: Blowfish (128 bit key, 16 rounds) assert_eq!(SymmetricAlgorithm::Blowfish.key_size()?, 16); assert_eq!(SymmetricAlgorithm::AES128.key_size()?, - <aes::Aes128 as NewBlockCipher>::KeySize::to_usize()); + <aes::Aes128 as cipher::KeySizeUser>::key_size()); assert_eq!(SymmetricAlgorithm::AES192.key_size()?, - <aes::Aes192 as NewBlockCipher>::KeySize::to_usize()); + <aes::Aes192 as cipher::KeySizeUser>::key_size()); assert_eq!(SymmetricAlgorithm::AES256.key_size()?, - <aes::Aes256 as NewBlockCipher>::KeySize::to_usize()); + <aes::Aes256 as cipher::KeySizeUser>::key_size()); assert_eq!(SymmetricAlgorithm::Twofish.key_size()?, - <twofish::Twofish as NewBlockCipher>::KeySize::to_usize()); + <twofish::Twofish as cipher::KeySizeUser>::key_size()); Ok(()) } @@ -176,21 +452,21 @@ mod tests { #[test] fn block_size() -> Result<()> { assert_eq!(SymmetricAlgorithm::IDEA.block_size()?, - <idea::Idea as BlockCipher>::BlockSize::to_usize()); + <idea::Idea as cipher::BlockSizeUser>::block_size()); assert_eq!(SymmetricAlgorithm::TripleDES.block_size()?, - <des::TdesEde3 as BlockCipher>::BlockSize::to_usize()); + <des::TdesEde3 as cipher::BlockSizeUser>::block_size()); assert_eq!(SymmetricAlgorithm::CAST5.block_size()?, - <cast5::Cast5 as BlockCipher>::BlockSize::to_usize()); + <cast5::Cast5 as cipher::BlockSizeUser>::block_size()); assert_eq!(SymmetricAlgorithm::Blowfish.block_size()?, - <blowfish::Blowfish as BlockCipher>::BlockSize::to_usize()); + <blowfish::Blowfish as cipher::BlockSizeUser>::block_size()); assert_eq!(SymmetricAlgorithm::AES128.block_size()?, - <aes::Aes128 as BlockCipher>::BlockSize::to_usize()); + <aes::Aes128 as cipher::BlockSizeUser>::block_size()); assert_eq!(SymmetricAlgorithm::AES192.block_size()?, - <aes::Aes192 as BlockCipher>::BlockSize::to_usize()); + <aes::Aes192 as cipher::BlockSizeUser>::block_size()); assert_eq!(SymmetricAlgorithm::AES256.block_size()?, - <aes::Aes256 as BlockCipher>::BlockSize::to_usize()); + <aes::Aes256 as cipher::BlockSizeUser>::block_size()); assert_eq!(SymmetricAlgorithm::Twofish.block_size()?, - <twofish::Twofish as BlockCipher>::BlockSize::to_usize()); + <twofish::Twofish as cipher::BlockSizeUser>::block_size()); Ok(()) } } |