summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNikhil Benesch <nikhil.benesch@gmail.com>2020-12-13 20:06:16 -0500
committerJustus Winter <justus@sequoia-pgp.org>2021-01-05 15:05:27 +0100
commit54b76abe3d42a0037d12609a4448a81ed547f06d (patch)
tree357be1add88308a2bca7bf7b6d36ccc4392b8bf7
parent2786957fd6c03ec18d2bd5765c46b6aceb549e1a (diff)
openpgp: Make crypto backends responsible for IV.
- Adjust the interface of crypto::symmetric::Mode so that the crypto backend is responsible for managing the IV rather than the caller. - The new API is one step towards facilitating a RustCrypto backend for Sequoia (see #333), as RustCrypto does not expose the IV modifications to the caller. - As a bonus, this commit introduces proper support for ECB mode. Previously callers that wanted ECB mode would request CBC mode, then hackily zero out the IV on each call. Nettle actually has proper support for ECB mode, just via a slightly different API.
-rw-r--r--openpgp/src/crypto/backend/cng/symmetric.rs65
-rw-r--r--openpgp/src/crypto/backend/nettle/symmetric.rs239
-rw-r--r--openpgp/src/crypto/ecdh.rs16
-rw-r--r--openpgp/src/crypto/symmetric.rs61
-rw-r--r--openpgp/src/packet/skesk.rs12
5 files changed, 194 insertions, 199 deletions
diff --git a/openpgp/src/crypto/backend/cng/symmetric.rs b/openpgp/src/crypto/backend/cng/symmetric.rs
index d3215eec..27694f52 100644
--- a/openpgp/src/crypto/backend/cng/symmetric.rs
+++ b/openpgp/src/crypto/backend/cng/symmetric.rs
@@ -3,21 +3,34 @@ use std::sync::Mutex;
use win_crypto_ng::symmetric as cng;
+use crate::crypto::mem::Protected;
use crate::crypto::symmetric::Mode;
use crate::{Error, Result};
use crate::types::SymmetricAlgorithm;
+struct KeyWrapper {
+ key: Mutex<cng::SymmetricAlgorithmKey>,
+ iv: Option<Protected>,
+}
+
+impl KeyWrapper {
+ fn new(key: cng::SymmetricAlgorithmKey, iv: Option<Vec<u8>>) -> KeyWrapper {
+ KeyWrapper {
+ key: Mutex::new(key),
+ iv: iv.map(|iv| iv.into()),
+ }
+ }
+}
-impl Mode for Mutex<cng::SymmetricAlgorithmKey> {
+impl Mode for KeyWrapper {
fn block_size(&self) -> usize {
- self.lock().expect("Mutex not to be poisoned")
+ self.key.lock().expect("Mutex not to be poisoned")
.block_size().expect("CNG not to fail internally")
}
fn encrypt(
&mut self,
- iv: &mut [u8],
dst: &mut [u8],
src: &[u8],
) -> Result<()> {
@@ -36,16 +49,14 @@ impl Mode for Mutex<cng::SymmetricAlgorithmKey> {
};
let len = std::cmp::min(src.len(), dst.len());
- // NOTE: `None` IV is required for ECB mode but we don't ever use it.
let buffer = cng::SymmetricAlgorithmKey::encrypt(
- &*self.lock().expect("Mutex not to be poisoned"),
- Some(iv), src, None)?;
+ &*self.key.lock().expect("Mutex not to be poisoned"),
+ self.iv.as_deref_mut(), src, None)?;
Ok(dst[..len].copy_from_slice(&buffer.as_slice()[..len]))
}
fn decrypt(
&mut self,
- iv: &mut [u8],
dst: &mut [u8],
src: &[u8],
) -> Result<()> {
@@ -64,10 +75,9 @@ impl Mode for Mutex<cng::SymmetricAlgorithmKey> {
};
let len = std::cmp::min(src.len(), dst.len());
- // NOTE: `None` IV is required for ECB mode but we don't ever use it.
let buffer = cng::SymmetricAlgorithmKey::decrypt(
- &*self.lock().expect("Mutex not to be poisoned"),
- Some(iv), src, None)?;
+ &*self.key.lock().expect("Mutex not to be poisoned"),
+ self.iv.as_deref_mut(), src, None)?;
dst[..len].copy_from_slice(&buffer.as_slice()[..len]);
Ok(())
@@ -149,7 +159,7 @@ impl SymmetricAlgorithm {
}
/// Creates a symmetric cipher context for encrypting in CFB mode.
- pub(crate) fn make_encrypt_cfb(self, key: &[u8]) -> Result<Box<dyn Mode>> {
+ pub(crate) fn make_encrypt_cfb(self, key: &[u8], iv: Vec<u8>) -> Result<Box<dyn Mode>> {
let (algo, _) = TryFrom::try_from(self)?;
let algo = cng::SymmetricAlgorithm::open(algo, cng::ChainingMode::Cfb)?;
@@ -158,37 +168,26 @@ impl SymmetricAlgorithm {
// set to 8-bit CFB)
key.set_msg_block_len(key.block_size()?)?;
- Ok(Box::new(Mutex::new(key)))
+ Ok(Box::new(KeyWrapper::new(key, Some(iv))))
}
/// Creates a symmetric cipher context for decrypting in CFB mode.
- pub(crate) fn make_decrypt_cfb(self, key: &[u8]) -> Result<Box<dyn Mode>> {
- Self::make_encrypt_cfb(self, key)
+ pub(crate) fn make_decrypt_cfb(self, key: &[u8], iv: Vec<u8>) -> Result<Box<dyn Mode>> {
+ Self::make_encrypt_cfb(self, key, iv)
}
- /// Creates a Nettle context for encrypting in CBC mode.
- pub(crate) fn make_encrypt_cbc(self, key: &[u8]) -> Result<Box<dyn Mode>> {
+ /// Creates a symmetric cipher context for encrypting in ECB mode.
+ pub(crate) fn make_encrypt_ecb(self, key: &[u8]) -> Result<Box<dyn Mode>> {
let (algo, _) = TryFrom::try_from(self)?;
- let algo = cng::SymmetricAlgorithm::open(algo, cng::ChainingMode::Cbc)?;
+ let algo = cng::SymmetricAlgorithm::open(algo, cng::ChainingMode::Ecb)?;
+ let key = algo.new_key(key)?;
- Ok(Box::new(Mutex::new(
- algo.new_key(key).expect(
- "CNG to successfully create a symmetric key for valid/supported algorithm"
- )
- )))
+ Ok(Box::new(KeyWrapper::new(key, None)))
}
- /// Creates a Nettle context for decrypting in CBC mode.
- pub(crate) fn make_decrypt_cbc(self, key: &[u8]) -> Result<Box<dyn Mode>> {
- let (algo, _) = TryFrom::try_from(self)?;
-
- let algo = cng::SymmetricAlgorithm::open(algo, cng::ChainingMode::Cbc)?;
-
- Ok(Box::new(Mutex::new(
- algo.new_key(key).expect(
- "CNG to successfully create a symmetric key for valid/supported algorithm"
- )
- )))
+ /// Creates a symmetric cipher context for decrypting in ECB mode.
+ pub(crate) fn make_decrypt_ecb(self, key: &[u8]) -> Result<Box<dyn Mode>> {
+ Self::make_encrypt_ecb(self, key)
}
}
diff --git a/openpgp/src/crypto/backend/nettle/symmetric.rs b/openpgp/src/crypto/backend/nettle/symmetric.rs
index 8ce4cdc6..72acae58 100644
--- a/openpgp/src/crypto/backend/nettle/symmetric.rs
+++ b/openpgp/src/crypto/backend/nettle/symmetric.rs
@@ -1,34 +1,81 @@
use nettle::cipher::{self, Cipher};
use nettle::mode::{self};
+use crate::crypto::mem::Protected;
use crate::crypto::symmetric::Mode;
use crate::{Error, Result};
use crate::types::SymmetricAlgorithm;
-impl<T: nettle::mode::Mode + Send + Sync> Mode for T {
+struct ModeWrapper<M>
+{
+ mode: M,
+ iv: Protected,
+}
+
+impl<M> ModeWrapper<M>
+where
+ M: nettle::mode::Mode + Send + Sync + 'static,
+{
+ fn new(mode: M, iv: Vec<u8>) -> Box<dyn Mode> {
+ Box::new(ModeWrapper {
+ mode,
+ iv: iv.into(),
+ })
+ }
+}
+
+impl<M> Mode for ModeWrapper<M>
+where
+ M: nettle::mode::Mode + Send + Sync,
+{
+ fn block_size(&self) -> usize {
+ self.mode.block_size()
+ }
+
+ fn encrypt(
+ &mut self,
+ dst: &mut [u8],
+ src: &[u8],
+ ) -> Result<()> {
+ self.mode.encrypt(&mut self.iv, dst, src)?;
+ Ok(())
+ }
+
+ fn decrypt(
+ &mut self,
+ dst: &mut [u8],
+ src: &[u8],
+ ) -> Result<()> {
+ self.mode.decrypt(&mut self.iv, dst, src)?;
+ Ok(())
+ }
+}
+
+impl<C> Mode for C
+where
+ C: Cipher + Send + Sync,
+{
fn block_size(&self) -> usize {
- self.block_size()
+ C::BLOCK_SIZE
}
fn encrypt(
&mut self,
- iv: &mut [u8],
dst: &mut [u8],
src: &[u8],
) -> Result<()> {
- self.encrypt(iv, dst, src)
- .map_err(Into::into)
+ self.encrypt(dst, src);
+ Ok(())
}
fn decrypt(
&mut self,
- iv: &mut [u8],
dst: &mut [u8],
src: &[u8],
) -> Result<()> {
- self.decrypt(iv, dst, src)
- .map_err(Into::into)
+ self.decrypt(dst, src);
+ Ok(())
}
}
@@ -99,150 +146,110 @@ impl SymmetricAlgorithm {
}
/// Creates a Nettle context for encrypting in CFB mode.
- pub(crate) fn make_encrypt_cfb(self, key: &[u8]) -> Result<Box<dyn Mode>> {
+ pub(crate) fn make_encrypt_cfb(self, key: &[u8], iv: Vec<u8>) -> Result<Box<dyn Mode>> {
match self {
SymmetricAlgorithm::TripleDES =>
- Ok(Box::new(
- mode::Cfb::<cipher::Des3>::with_encrypt_key(&key[..])?)),
+ Ok(ModeWrapper::new(
+ mode::Cfb::<cipher::Des3>::with_encrypt_key(key)?, iv)),
SymmetricAlgorithm::CAST5 =>
- Ok(Box::new(
- mode::Cfb::<cipher::Cast128>::with_encrypt_key(&key[..])?)),
+ Ok(ModeWrapper::new(
+ mode::Cfb::<cipher::Cast128>::with_encrypt_key(key)?, iv)),
SymmetricAlgorithm::Blowfish =>
- Ok(Box::new(
- mode::Cfb::<cipher::Blowfish>::with_encrypt_key(&key[..])?)),
+ Ok(ModeWrapper::new(
+ mode::Cfb::<cipher::Blowfish>::with_encrypt_key(key)?, iv)),
SymmetricAlgorithm::AES128 =>
- Ok(Box::new(
- mode::Cfb::<cipher::Aes128>::with_encrypt_key(&key[..])?)),
+ Ok(ModeWrapper::new(
+ mode::Cfb::<cipher::Aes128>::with_encrypt_key(key)?, iv)),
SymmetricAlgorithm::AES192 =>
- Ok(Box::new(
- mode::Cfb::<cipher::Aes192>::with_encrypt_key(&key[..])?)),
+ Ok(ModeWrapper::new(
+ mode::Cfb::<cipher::Aes192>::with_encrypt_key(key)?, iv)),
SymmetricAlgorithm::AES256 =>
- Ok(Box::new(
- mode::Cfb::<cipher::Aes256>::with_encrypt_key(&key[..])?)),
+ Ok(ModeWrapper::new(
+ mode::Cfb::<cipher::Aes256>::with_encrypt_key(key)?, iv)),
SymmetricAlgorithm::Twofish =>
- Ok(Box::new(
- mode::Cfb::<cipher::Twofish>::with_encrypt_key(&key[..])?)),
+ Ok(ModeWrapper::new(
+ mode::Cfb::<cipher::Twofish>::with_encrypt_key(key)?, iv)),
SymmetricAlgorithm::Camellia128 =>
- Ok(Box::new(
- mode::Cfb::<cipher::Camellia128>::with_encrypt_key(&key[..])?)),
+ Ok(ModeWrapper::new(
+ mode::Cfb::<cipher::Camellia128>::with_encrypt_key(key)?, iv)),
SymmetricAlgorithm::Camellia192 =>
- Ok(Box::new(
- mode::Cfb::<cipher::Camellia192>::with_encrypt_key(&key[..])?)),
+ Ok(ModeWrapper::new(
+ mode::Cfb::<cipher::Camellia192>::with_encrypt_key(key)?, iv)),
SymmetricAlgorithm::Camellia256 =>
- Ok(Box::new(
- mode::Cfb::<cipher::Camellia256>::with_encrypt_key(&key[..])?)),
+ Ok(ModeWrapper::new(
+ mode::Cfb::<cipher::Camellia256>::with_encrypt_key(key)?, iv)),
_ => Err(Error::UnsupportedSymmetricAlgorithm(self).into()),
}
}
/// Creates a Nettle context for decrypting in CFB mode.
- pub(crate) fn make_decrypt_cfb(self, key: &[u8]) -> Result<Box<dyn Mode>> {
+ pub(crate) fn make_decrypt_cfb(self, key: &[u8], iv: Vec<u8>) -> Result<Box<dyn Mode>> {
match self {
SymmetricAlgorithm::TripleDES =>
- Ok(Box::new(
- mode::Cfb::<cipher::Des3>::with_decrypt_key(&key[..])?)),
+ Ok(ModeWrapper::new(
+ mode::Cfb::<cipher::Des3>::with_decrypt_key(key)?, iv)),
SymmetricAlgorithm::CAST5 =>
- Ok(Box::new(
- mode::Cfb::<cipher::Cast128>::with_decrypt_key(&key[..])?)),
+ Ok(ModeWrapper::new(
+ mode::Cfb::<cipher::Cast128>::with_decrypt_key(key)?, iv)),
SymmetricAlgorithm::Blowfish =>
- Ok(Box::new(
- mode::Cfb::<cipher::Blowfish>::with_decrypt_key(&key[..])?)),
+ Ok(ModeWrapper::new(
+ mode::Cfb::<cipher::Blowfish>::with_decrypt_key(key)?, iv)),
SymmetricAlgorithm::AES128 =>
- Ok(Box::new(
- mode::Cfb::<cipher::Aes128>::with_decrypt_key(&key[..])?)),
+ Ok(ModeWrapper::new(
+ mode::Cfb::<cipher::Aes128>::with_decrypt_key(key)?, iv)),
SymmetricAlgorithm::AES192 =>
- Ok(Box::new(
- mode::Cfb::<cipher::Aes192>::with_decrypt_key(&key[..])?)),
+ Ok(ModeWrapper::new(
+ mode::Cfb::<cipher::Aes192>::with_decrypt_key(key)?, iv)),
SymmetricAlgorithm::AES256 =>
- Ok(Box::new(
- mode::Cfb::<cipher::Aes256>::with_decrypt_key(&key[..])?)),
+ Ok(ModeWrapper::new(
+ mode::Cfb::<cipher::Aes256>::with_decrypt_key(key)?, iv)),
SymmetricAlgorithm::Twofish =>
- Ok(Box::new(
- mode::Cfb::<cipher::Twofish>::with_decrypt_key(&key[..])?)),
+ Ok(ModeWrapper::new(
+ mode::Cfb::<cipher::Twofish>::with_decrypt_key(key)?, iv)),
SymmetricAlgorithm::Camellia128 =>
- Ok(Box::new(
- mode::Cfb::<cipher::Camellia128>::with_decrypt_key(&key[..])?)),
+ Ok(ModeWrapper::new(
+ mode::Cfb::<cipher::Camellia128>::with_decrypt_key(key)?, iv)),
SymmetricAlgorithm::Camellia192 =>
- Ok(Box::new(
- mode::Cfb::<cipher::Camellia192>::with_decrypt_key(&key[..])?)),
+ Ok(ModeWrapper::new(
+ mode::Cfb::<cipher::Camellia192>::with_decrypt_key(key)?, iv)),
SymmetricAlgorithm::Camellia256 =>
- Ok(Box::new(
- mode::Cfb::<cipher::Camellia256>::with_decrypt_key(&key[..])?)),
+ Ok(ModeWrapper::new(
+ mode::Cfb::<cipher::Camellia256>::with_decrypt_key(key)?, iv)),
_ => Err(Error::UnsupportedSymmetricAlgorithm(self).into())
}
}
- /// Creates a Nettle context for encrypting in CBC mode.
- pub(crate) fn make_encrypt_cbc(self, key: &[u8]) -> Result<Box<dyn Mode>> {
+ /// Creates a Nettle context for encrypting in ECB mode.
+ pub(crate) fn make_encrypt_ecb(self, key: &[u8]) -> Result<Box<dyn Mode>> {
match self {
- SymmetricAlgorithm::TripleDES =>
- Ok(Box::new(
- mode::Cbc::<cipher::Des3>::with_encrypt_key(&key[..])?)),
- SymmetricAlgorithm::CAST5 =>
- Ok(Box::new(
- mode::Cbc::<cipher::Cast128>::with_encrypt_key(&key[..])?)),
- SymmetricAlgorithm::Blowfish =>
- Ok(Box::new(
- mode::Cbc::<cipher::Blowfish>::with_encrypt_key(&key[..])?)),
- SymmetricAlgorithm::AES128 =>
- Ok(Box::new(
- mode::Cbc::<cipher::Aes128>::with_encrypt_key(&key[..])?)),
- SymmetricAlgorithm::AES192 =>
- Ok(Box::new(
- mode::Cbc::<cipher::Aes192>::with_encrypt_key(&key[..])?)),
- SymmetricAlgorithm::AES256 =>
- Ok(Box::new(
- mode::Cbc::<cipher::Aes256>::with_encrypt_key(&key[..])?)),
- SymmetricAlgorithm::Twofish =>
- Ok(Box::new(
- mode::Cbc::<cipher::Twofish>::with_encrypt_key(&key[..])?)),
- SymmetricAlgorithm::Camellia128 =>
- Ok(Box::new(
- mode::Cbc::<cipher::Camellia128>::with_encrypt_key(&key[..])?)),
- SymmetricAlgorithm::Camellia192 =>
- Ok(Box::new(
- mode::Cbc::<cipher::Camellia192>::with_encrypt_key(&key[..])?)),
- SymmetricAlgorithm::Camellia256 =>
- Ok(Box::new(
- mode::Cbc::<cipher::Camellia256>::with_encrypt_key(&key[..])?)),
- _ => Err(Error::UnsupportedSymmetricAlgorithm(self).into()),
+ SymmetricAlgorithm::TripleDES => Ok(Box::new(cipher::Des3::with_encrypt_key(key)?)),
+ SymmetricAlgorithm::CAST5 => Ok(Box::new(cipher::Cast128::with_encrypt_key(key)?)),
+ SymmetricAlgorithm::Blowfish => Ok(Box::new(cipher::Blowfish::with_encrypt_key(key)?)),
+ SymmetricAlgorithm::AES128 => Ok(Box::new(cipher::Aes128::with_encrypt_key(key)?)),
+ SymmetricAlgorithm::AES192 => Ok(Box::new(cipher::Aes192::with_encrypt_key(key)?)),
+ SymmetricAlgorithm::AES256 => Ok(Box::new(cipher::Aes256::with_encrypt_key(key)?)),
+ SymmetricAlgorithm::Twofish => Ok(Box::new(cipher::Twofish::with_encrypt_key(key)?)),
+ SymmetricAlgorithm::Camellia128 => Ok(Box::new(cipher::Camellia128::with_encrypt_key(key)?)),
+ SymmetricAlgorithm::Camellia192 => Ok(Box::new(cipher::Camellia192::with_encrypt_key(key)?)),
+ SymmetricAlgorithm::Camellia256 => Ok(Box::new(cipher::Camellia256::with_encrypt_key(key)?)),
+ _ => Err(Error::UnsupportedSymmetricAlgorithm(self).into())
}
}
- /// Creates a Nettle context for decrypting in CBC mode.
- pub(crate) fn make_decrypt_cbc(self, key: &[u8]) -> Result<Box<dyn Mode>> {
+ /// Creates a Nettle context for decrypting in ECB mode.
+ pub(crate) fn make_decrypt_ecb(self, key: &[u8]) -> Result<Box<dyn Mode>> {
match self {
- SymmetricAlgorithm::TripleDES =>
- Ok(Box::new(
- mode::Cbc::<cipher::Des3>::with_decrypt_key(&key[..])?)),
- SymmetricAlgorithm::CAST5 =>
- Ok(Box::new(
- mode::Cbc::<cipher::Cast128>::with_decrypt_key(&key[..])?)),
- SymmetricAlgorithm::Blowfish =>
- Ok(Box::new(
- mode::Cbc::<cipher::Blowfish>::with_decrypt_key(&key[..])?)),
- SymmetricAlgorithm::AES128 =>
- Ok(Box::new(
- mode::Cbc::<cipher::Aes128>::with_decrypt_key(&key[..])?)),
- SymmetricAlgorithm::AES192 =>
- Ok(Box::new(
- mode::Cbc::<cipher::Aes192>::with_decrypt_key(&key[..])?)),
- SymmetricAlgorithm::AES256 =>
- Ok(Box::new(
- mode::Cbc::<cipher::Aes256>::with_decrypt_key(&key[..])?)),
- SymmetricAlgorithm::Twofish =>
- Ok(Box::new(
- mode::Cbc::<cipher::Twofish>::with_decrypt_key(&key[..])?)),
- SymmetricAlgorithm::Camellia128 =>
- Ok(Box::new(
- mode::Cbc::<cipher::Camellia128>::with_decrypt_key(&key[..])?)),
- SymmetricAlgorithm::Camellia192 =>
- Ok(Box::new(
- mode::Cbc::<cipher::Camellia192>::with_decrypt_key(&key[..])?)),
- SymmetricAlgorithm::Camellia256 =>
- Ok(Box::new(
- mode::Cbc::<cipher::Camellia256>::with_decrypt_key(&key[..])?)),
- _ => Err(Error::UnsupportedSymmetricAlgorithm(self).into()),
+ SymmetricAlgorithm::TripleDES => Ok(Box::new(cipher::Des3::with_decrypt_key(key)?)),
+ SymmetricAlgorithm::CAST5 => Ok(Box::new(cipher::Cast128::with_decrypt_key(key)?)),
+ SymmetricAlgorithm::Blowfish => Ok(Box::new(cipher::Blowfish::with_decrypt_key(key)?)),
+ SymmetricAlgorithm::AES128 => Ok(Box::new(cipher::Aes128::with_decrypt_key(key)?)),
+ SymmetricAlgorithm::AES192 => Ok(Box::new(cipher::Aes192::with_decrypt_key(key)?)),
+ SymmetricAlgorithm::AES256 => Ok(Box::new(cipher::Aes256::with_decrypt_key(key)?)),
+ SymmetricAlgorithm::Twofish => Ok(Box::new(cipher::Twofish::with_decrypt_key(key)?)),
+ SymmetricAlgorithm::Camellia128 => Ok(Box::new(cipher::Camellia128::with_decrypt_key(key)?)),
+ SymmetricAlgorithm::Camellia192 => Ok(Box::new(cipher::Camellia192::with_decrypt_key(key)?)),
+ SymmetricAlgorithm::Camellia256 => Ok(Box::new(cipher::Camellia256::with_decrypt_key(key)?)),
+ _ => Err(Error::UnsupportedSymmetricAlgorithm(self).into())
}
}
}
diff --git a/openpgp/src/crypto/ecdh.rs b/openpgp/src/crypto/ecdh.rs
index 84b8660e..5ed7c203 100644
--- a/openpgp/src/crypto/ecdh.rs
+++ b/openpgp/src/crypto/ecdh.rs
@@ -209,10 +209,8 @@ fn aes_key_wrap(algo: SymmetricAlgorithm, key: &Protected,
return Err(Error::InvalidArgument("Bad key size".into()).into());
}
- // We need ECB for the algorithm. However, there is no nettle::Mode:ECB,
- // so to work around this, we use CBC, and always use an all-zero IV.
let mut cipher = match algo {
- AES128 | AES192 | AES256 => algo.make_encrypt_cbc(key)?,
+ AES128 | AES192 | AES256 => algo.make_encrypt_ecb(key)?,
_ => return Err(Error::UnsupportedSymmetricAlgorithm(algo).into()),
};
@@ -235,7 +233,6 @@ fn aes_key_wrap(algo: SymmetricAlgorithm, key: &Protected,
let mut b = [0; 16];
let mut tmp = [0; 16];
- let mut iv: Protected = vec![0; cipher.block_size()].into();
// 2) Calculate intermediate values.
@@ -246,8 +243,7 @@ fn aes_key_wrap(algo: SymmetricAlgorithm, key: &Protected,
// B = AES(K, A | R[i])
write_be_u64(&mut tmp[..8], a);
&mut tmp[8..].copy_from_slice(&r[8 * i..8 * (i + 1)]);
- iv.iter_mut().for_each(|p| *p = 0); // Turn CBC into ECB.
- cipher.encrypt(&mut iv, &mut b, &tmp)?;
+ cipher.encrypt(&mut b, &tmp)?;
// A = MSB(64, B) ^ t where t = (n*j)+i
a = read_be_u64(&b[..8]) ^ ((n * j) + i + 1) as u64;
@@ -288,10 +284,8 @@ fn aes_key_unwrap(algo: SymmetricAlgorithm, key: &Protected,
return Err(Error::InvalidArgument("Bad key size".into()).into());
}
- // We need ECB for the algorithm. However, there is no nettle::Mode:ECB,
- // so to work around this, we use CBC, and always use an all-zero IV.
let mut cipher = match algo {
- AES128 | AES192 | AES256 => algo.make_decrypt_cbc(key)?,
+ AES128 | AES192 | AES256 => algo.make_decrypt_ecb(key)?,
_ => return Err(Error::UnsupportedSymmetricAlgorithm(algo).into()),
};
@@ -316,7 +310,6 @@ fn aes_key_unwrap(algo: SymmetricAlgorithm, key: &Protected,
let mut b = [0; 16];
let mut tmp = [0; 16];
- let mut iv: Protected = vec![0; cipher.block_size()].into();
// For j = 5 to 0
for j in (0..=5).rev() {
@@ -327,8 +320,7 @@ fn aes_key_unwrap(algo: SymmetricAlgorithm, key: &Protected,
&mut tmp[8..].copy_from_slice(&r[8 * i..8 * (i + 1)]);
// (Note that our i runs from n-1 to 0 instead of n to
// 1, hence the index shift.
- iv.iter_mut().for_each(|p| *p = 0); // Turn CBC into ECB.
- cipher.decrypt(&mut iv, &mut b, &tmp)?;
+ cipher.decrypt(&mut b, &tmp)?;
// A = MSB(64, B)
a = read_be_u64(&b[..8]);
diff --git a/openpgp/src/crypto/symmetric.rs b/openpgp/src/crypto/symmetric.rs
index 381cbe95..2c2ccab3 100644
--- a/openpgp/src/crypto/symmetric.rs
+++ b/openpgp/src/crypto/symmetric.rs
@@ -17,24 +17,20 @@ pub(crate) trait Mode: Send + Sync {
/// Block size of the underlying cipher in bytes.
fn block_size(&self) -> usize;
- /// Encrypt a single block `src` using the initialization vector `iv` to
- /// a ciphertext block `dst`. Both `iv` and dst` are updated.
- /// The buffer `iv`, `dst` and `src` are expected to be at least as large as
+ /// Encrypt a single block `src` to a ciphertext block `dst`.
+ /// The `dst` and `src` buffers are expected to be at least as large as
/// the block size of the underlying cipher.
fn encrypt(
&mut self,
- iv: &mut [u8],
dst: &mut [u8],
src: &[u8],
) -> Result<()>;
- /// Decrypt a single ciphertext block `src` using the initialization vector
- /// `iv` to a plaintext block `dst`. Both `iv` and dst` are updated.
- /// The buffer `iv`, `dst` and `src` are expected to be at least as large as
+ /// Decrypt a single ciphertext block `src` to a plaintext block `dst`.
+ /// The `dst` and `src` buffers are expected to be at least as large as
/// the block size of the underlying cipher.
fn decrypt(
&mut self,
- iv: &mut [u8],
dst: &mut [u8],
src: &[u8],
) -> Result<()>;
@@ -47,7 +43,6 @@ pub struct Decryptor<R: io::Read> {
dec: Box<dyn Mode>,
block_size: usize,
- iv: Vec<u8>,
// Up to a block of unread data.
buffer: Vec<u8>,
}
@@ -57,14 +52,14 @@ impl<R: io::Read> Decryptor<R> {
/// Instantiate a new symmetric decryptor. `reader` is the source
/// to wrap.
pub fn new(algo: SymmetricAlgorithm, key: &[u8], source: R) -> Result<Self> {
- let dec = algo.make_decrypt_cfb(key)?;
let block_size = algo.block_size()?;
+ let iv = vec![0; block_size];
+ let dec = algo.make_decrypt_cfb(key, iv)?;
Ok(Decryptor {
source,
dec,
block_size,
- iv: vec![0u8; block_size],
buffer: Vec::with_capacity(block_size),
})
}
@@ -140,8 +135,7 @@ impl<R: io::Read> io::Read for Decryptor<R> {
Err(e) => return Err(e),
}
- self.dec.decrypt(&mut self.iv,
- &mut plaintext[pos..pos + to_copy],
+ self.dec.decrypt(&mut plaintext[pos..pos + to_copy],
&ciphertext[..])
.map_err(|e| io::Error::new(io::ErrorKind::InvalidInput,
format!("{}", e)))?;
@@ -179,7 +173,7 @@ impl<R: io::Read> io::Read for Decryptor<R> {
}
vec_truncate(&mut self.buffer, ciphertext.len());
- self.dec.decrypt(&mut self.iv, &mut self.buffer, &ciphertext[..])
+ self.dec.decrypt(&mut self.buffer, &ciphertext[..])
.map_err(|e| io::Error::new(io::ErrorKind::InvalidInput,
format!("{}", e)))?;
@@ -312,7 +306,6 @@ pub struct Encryptor<W: io::Write> {
cipher: Box<dyn Mode>,
block_size: usize,
- iv: Vec<u8>,
// Up to a block of unencrypted data.
buffer: Vec<u8>,
// A place to write encrypted data into.
@@ -323,8 +316,9 @@ assert_send_and_sync!(Encryptor<W> where W: io::Write);
impl<W: io::Write> Encryptor<W> {
/// Instantiate a new symmetric encryptor.
pub fn new(algo: SymmetricAlgorithm, key: &[u8], sink: W) -> Result<Self> {
- let cipher = algo.make_encrypt_cfb(key)?;
let block_size = algo.block_size()?;
+ let iv = vec![0; block_size];
+ let cipher = algo.make_encrypt_cfb(key, iv)?;
let mut scratch = Vec::with_capacity(block_size);
unsafe { scratch.set_len(block_size); }
@@ -332,7 +326,6 @@ impl<W: io::Write> Encryptor<W> {
inner: Some(sink),
cipher,
block_size,
- iv: vec![0u8; block_size],
buffer: Vec::with_capacity(block_size),
scratch,
})
@@ -343,7 +336,7 @@ impl<W: io::Write> Encryptor<W> {
if let Some(mut inner) = self.inner.take() {
if self.buffer.len() > 0 {
unsafe { self.scratch.set_len(self.buffer.len()) }
- self.cipher.encrypt(&mut self.iv, &mut self.scratch, &self.buffer)?;
+ self.cipher.encrypt(&mut self.scratch, &self.buffer)?;
crate::vec_truncate(&mut self.buffer, 0);
inner.write_all(&self.scratch)?;
}
@@ -384,7 +377,7 @@ impl<W: io::Write> io::Write for Encryptor<W> {
// And possibly encrypt the block.
if self.buffer.len() == self.block_size {
- self.cipher.encrypt(&mut self.iv, &mut self.scratch, &self.buffer)
+ self.cipher.encrypt(&mut self.scratch, &self.buffer)
.map_err(|e| io::Error::new(io::ErrorKind::InvalidInput,
format!("{}", e)))?;
crate::vec_truncate(&mut self.buffer, 0);
@@ -397,7 +390,7 @@ impl<W: io::Write> io::Write for Encryptor<W> {
for block in buf.chunks(self.block_size) {
if block.len() == self.block_size {
// Complete block.
- self.cipher.encrypt(&mut self.iv, &mut self.scratch, block)
+ self.cipher.encrypt(&mut self.scratch, block)
.map_err(|e| io::Error::new(io::ErrorKind::InvalidInput,
format!("{}", e)))?;
inner.write_all(&self.scratch)?;
@@ -445,37 +438,41 @@ mod tests {
let algo = SymmetricAlgorithm::AES128;
let key = &hex::decode("2b7e151628aed2a6abf7158809cf4f3c").unwrap();
assert_eq!(key.len(), 16);
- // Ensure we use CFB128 by default
- let mut cfb = algo.make_encrypt_cfb(&key).unwrap();
- let mut iv = hex::decode("000102030405060708090A0B0C0D0E0F").unwrap();
+ // Ensure we use CFB128 by default
+ let iv = hex::decode("000102030405060708090A0B0C0D0E0F").unwrap();
+ let mut cfb = algo.make_encrypt_cfb(&key, iv).unwrap();