summaryrefslogtreecommitdiffstats
path: root/openpgp/src/crypto/backend/rust/symmetric.rs
diff options
context:
space:
mode:
authorNeal H. Walfield <neal@pep.foundation>2023-04-28 12:32:23 +0200
committerNeal H. Walfield <neal@pep.foundation>2023-05-03 12:37:24 +0200
commit4ec75df65e1e8646ede928dd8475ed0b681cfdae (patch)
tree50f54acb0553576eda0bcf979399113f6207513c /openpgp/src/crypto/backend/rust/symmetric.rs
parent4980fd66a7e7db7d7b91f86a7ae1af42b6245478 (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.rs426
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(())
}
}