summaryrefslogtreecommitdiffstats
path: root/openpgp
diff options
context:
space:
mode:
authorIgor Matuszewski <igor@sequoia-pgp.org>2020-10-05 01:10:30 +0200
committerJustus Winter <justus@sequoia-pgp.org>2020-12-04 16:10:59 +0100
commit6de3f7f02ef14d7d84e6d0a7aff6aaee12444392 (patch)
treefb9544f1e1d54be0bf86ea2a6e4e6edb4b3dac94 /openpgp
parent3dacda4a93b1d3b1ef44484ac2691eec0aa759c9 (diff)
openpgp: Use pure Rust EAX implementation under CNG backend
- Fixes #556.
Diffstat (limited to 'openpgp')
-rw-r--r--openpgp/Cargo.toml3
-rw-r--r--openpgp/src/crypto/aead.rs28
-rw-r--r--openpgp/src/crypto/backend/cng/aead.rs222
-rw-r--r--openpgp/src/crypto/backend/cng/symmetric.rs180
-rw-r--r--openpgp/src/crypto/backend/nettle/aead.rs3
-rw-r--r--openpgp/src/packet/skesk.rs10
6 files changed, 109 insertions, 337 deletions
diff --git a/openpgp/Cargo.toml b/openpgp/Cargo.toml
index 4b1c9463..7edae719 100644
--- a/openpgp/Cargo.toml
+++ b/openpgp/Cargo.toml
@@ -44,10 +44,11 @@ backtrace = "0.3.46"
unicode-normalization = "0.1.9"
[target.'cfg(windows)'.dependencies]
-win-crypto-ng = { version = "0.2", features = ["rand"], optional = true }
+win-crypto-ng = { version = "0.3", features = ["rand", "block-cipher"], optional = true }
num-bigint-dig = { version = "0.6", default-features = false, optional = true }
ed25519-dalek = { version = "1", default-features = false, features = ["rand", "u64_backend"], optional = true }
winapi = { version = "0.3", default-features = false, features = ["bcrypt"], optional = true }
+eax = "0.2"
[target.'cfg(all(target_arch = "wasm32", target_os = "unknown"))'.dependencies]
chrono = { version = "0.4", default-features = false, features = ["std"] }
diff --git a/openpgp/src/crypto/aead.rs b/openpgp/src/crypto/aead.rs
index 17153aa1..ac658046 100644
--- a/openpgp/src/crypto/aead.rs
+++ b/openpgp/src/crypto/aead.rs
@@ -59,6 +59,14 @@ pub trait Aead : seal::Sealed {
fn digest_size(&self) -> usize;
}
+/// Whether AEAD cipher is used for data encryption or decryption.
+pub(crate) enum CipherOp {
+ /// Cipher is used for data encryption.
+ Encrypt,
+ /// Cipher is used for data decryption.
+ Decrypt,
+}
+
impl AEADAlgorithm {
/// Returns the digest size of the AEAD algorithm.
pub fn digest_size(&self) -> Result<usize> {
@@ -168,7 +176,7 @@ impl<'a> Decryptor<'a> {
}
}
- fn make_aead(&mut self) -> Result<Box<dyn Aead>> {
+ fn make_aead(&mut self, op: CipherOp) -> Result<Box<dyn Aead>> {
// The chunk index is XORed into the IV.
let chunk_index: [u8; 8] = self.chunk_index.to_be_bytes();
@@ -189,7 +197,7 @@ impl<'a> Decryptor<'a> {
}
// Instantiate the AEAD cipher.
- let aead = self.aead.context(self.sym_algo, &self.key, &self.iv)?;
+ let aead = self.aead.context(self.sym_algo, &self.key, &self.iv, op)?;
// Restore the IV.
for (i, o) in &mut self.iv[iv_len - 8..].iter_mut()
@@ -265,7 +273,7 @@ impl<'a> Decryptor<'a> {
let final_digest_size = self.digest_size;
for _ in 0..n_chunks {
- let mut aead = self.make_aead()?;
+ let mut aead = self.make_aead(CipherOp::Decrypt)?;
// Digest the associated data.
self.hash_associated_data(&mut aead, false);
@@ -356,7 +364,7 @@ impl<'a> Decryptor<'a> {
if check_final_tag {
// We read the whole ciphertext, now check the final digest.
- let mut aead = self.make_aead()?;
+ let mut aead = self.make_aead(CipherOp::Decrypt)?;
self.hash_associated_data(&mut aead, true);
aead.digest(&mut digest);
@@ -583,7 +591,7 @@ impl<W: io::Write> Encryptor<W> {
}
}
- fn make_aead(&mut self) -> Result<Box<dyn Aead>> {
+ fn make_aead(&mut self, op: CipherOp) -> Result<Box<dyn Aead>> {
// The chunk index is XORed into the IV.
let chunk_index: [u8; 8] = self.chunk_index.to_be_bytes();
@@ -604,7 +612,7 @@ impl<W: io::Write> Encryptor<W> {
}
// Instantiate the AEAD cipher.
- let aead = self.aead.context(self.sym_algo, &self.key, &self.iv)?;
+ let aead = self.aead.context(self.sym_algo, &self.key, &self.iv, op)?;
// Restore the IV.
for (i, o) in &mut self.iv[iv_len - 8..].iter_mut()
@@ -636,7 +644,7 @@ impl<W: io::Write> Encryptor<W> {
// And possibly encrypt the chunk.
if self.buffer.len() == self.chunk_size {
- let mut aead = self.make_aead()?;
+ let mut aead = self.make_aead(CipherOp::Encrypt)?;
self.hash_associated_data(&mut aead, false);
let inner = self.inner.as_mut().unwrap();
@@ -658,7 +666,7 @@ impl<W: io::Write> Encryptor<W> {
for chunk in buf.chunks(self.chunk_size) {
if chunk.len() == self.chunk_size {
// Complete chunk.
- let mut aead = self.make_aead()?;
+ let mut aead = self.make_aead(CipherOp::Encrypt)?;
self.hash_associated_data(&mut aead, false);
let inner = self.inner.as_mut().unwrap();
@@ -686,7 +694,7 @@ impl<W: io::Write> Encryptor<W> {
pub fn finish(&mut self) -> Result<W> {
if let Some(mut inner) = self.inner.take() {
if self.buffer.len() > 0 {
- let mut aead = self.make_aead()?;
+ let mut aead = self.make_aead(CipherOp::Encrypt)?;
self.hash_associated_data(&mut aead, false);
// Encrypt the chunk.
@@ -704,7 +712,7 @@ impl<W: io::Write> Encryptor<W> {
}
// Write final digest.
- let mut aead = self.make_aead()?;
+ let mut aead = self.make_aead(CipherOp::Decrypt)?;
self.hash_associated_data(&mut aead, true);
aead.digest(&mut self.scratch[..self.digest_size]);
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 d30073ca..ff302dad 100644
--- a/openpgp/src/crypto/backend/cng/aead.rs
+++ b/openpgp/src/crypto/backend/cng/aead.rs
@@ -1,16 +1,22 @@
//! Implementation of AEAD using Windows CNG API.
use crate::{Error, Result};
-use crate::crypto::aead::Aead;
+use crate::crypto::aead::{Aead, CipherOp};
use crate::seal;
use crate::types::{AEADAlgorithm, SymmetricAlgorithm};
-use super::symmetric::Ctr;
-use win_crypto_ng::hash::{Hash, HashAlgorithm, MacAlgorithmId};
-use win_crypto_ng::symmetric::SymmetricAlgorithmId;
+use eax::online::{EaxOnline, 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};
-const EAX_BLOCK_SIZE: usize = 16;
-const EAX_DIGEST_SIZE: usize = 16;
+trait GenericArrayExt {
+ const LEN: usize;
+}
+
+impl<T, N: ArrayLength<T>> GenericArrayExt for GenericArray<T, N> {
+ const LEN: usize = N::USIZE;
+}
impl AEADAlgorithm {
pub(crate) fn context(
@@ -18,14 +24,40 @@ impl AEADAlgorithm {
sym_algo: SymmetricAlgorithm,
key: &[u8],
nonce: &[u8],
+ op: CipherOp,
) -> Result<Box<dyn Aead>> {
+
+ let nonce = GenericArray::from_slice(nonce);
+
match self {
AEADAlgorithm::EAX => match sym_algo {
- | SymmetricAlgorithm::AES128
- | SymmetricAlgorithm::AES192
- | SymmetricAlgorithm::AES256 => {
- Ok(Box::new(EaxAes::with_key_and_nonce(key, nonce)?))
- },
+ | SymmetricAlgorithm::AES128 => {
+ let key = GenericArray::from_slice(key);
+ 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::from_slice(key);
+ 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::from_slice(key);
+ 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)),
+ })
+ }
_ => Err(Error::UnsupportedSymmetricAlgorithm(sym_algo).into()),
},
_ => Err(Error::UnsupportedAEADAlgorithm(self.clone()).into()),
@@ -33,135 +65,47 @@ impl AEADAlgorithm {
}
}
-/// EAX-AES mode.
-///
-/// See https://web.cs.ucdavis.edu/~rogaway/papers/eax.pdf.
-struct EaxAes {
- omac_nonce: Vec<u8>,
- omac_data: Hash,
- omac_msg: Hash,
- ctr: Ctr,
-}
-
-impl EaxAes {
- fn with_key_and_nonce(key: &[u8], nonce: &[u8]) -> Result<Self> {
- fn omac_init_with_iv(
- prov: &HashAlgorithm<MacAlgorithmId>,
- key: &[u8],
- iv: u8,
- ) -> Result<Hash> {
- let mut omac = prov.new_mac(key, None)?;
- // Prepend the IV
- omac.hash(&[0; EAX_BLOCK_SIZE - 1])?;
- omac.hash(&[iv])?;
- Ok(omac)
+macro_rules! impl_aead {
+ ($($type: ty),*) => {
+ $(
+ impl Aead for EaxOnline<$type, Encrypt> {
+ fn update(&mut self, ad: &[u8]) { self.update_assoc(ad) }
+ fn digest_size(&self) -> usize { <eax::Tag as GenericArrayExt>::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 = core::cmp::min(dst.len(), src.len());
+ dst[..len].copy_from_slice(&src[..len]);
+ EaxOnline::<$type, Encrypt>::encrypt(self, &mut dst[..len])
+ }
+ fn decrypt(&mut self, _dst: &mut [u8], _src: &[u8]) {
+ panic!("AEAD decryption called in the encryption context")
+ }
}
-
- let provider = HashAlgorithm::open(MacAlgorithmId::AesCmac)?;
- // N ← OMAC_0^K(N)
- let mut omac_nonce = omac_init_with_iv(&provider, key, 0)?;
- omac_nonce.hash(nonce)?;
- let omac_nonce = omac_nonce.finish()?.into_inner();
- // H ← OMAC_1^K(H), init with 1 but hash online associated data later
- let omac_data = omac_init_with_iv(&provider, key, 1)?;
- // C ← OMAC_2^K(C), init with 2 but hash online resulting ciphertext later
- let omac_msg = omac_init_with_iv(&provider, key, 2)?;
-
- let ctr = Ctr::with_cipher_and_iv(SymmetricAlgorithmId::Aes, key, &omac_nonce)?;
-
- Ok(EaxAes { omac_nonce, omac_data, omac_msg, ctr })
- }
-}
-
-
-impl seal::Sealed for EaxAes {}
-impl Aead for EaxAes {
- /// Adds associated data `ad`.
- fn update(&mut self, ad: &[u8]) {
- let _ = self.omac_data.hash(ad);
- }
-
- /// Encrypts one block `src` to `dst`.
- fn encrypt(&mut self, dst: &mut [u8], src: &[u8]) {
- let _ = Ctr::encrypt(&mut self.ctr, dst, src);
- let _ = self.omac_msg.hash(dst);
- }
- /// Decrypts one block `src` to `dst`.
- fn decrypt(&mut self, dst: &mut [u8], src: &[u8]) {
- let _ = self.omac_msg.hash(src);
- let _ = Ctr::decrypt(&mut self.ctr, dst, src);
- }
-
- /// Produce the digest.
- fn digest(&mut self, digest: &mut [u8]) {
- // TODO: It'd be great if wouldn't have to clone
- let omac_data = self.omac_data.clone().finish().unwrap().into_inner();
- let omac_msg = self.omac_msg.clone().finish().unwrap().into_inner();
-
- let (nonce, data, msg) = (self.omac_nonce.iter(), omac_data.iter(), omac_msg.iter());
- for (((out, n), d), m) in digest.iter_mut().zip(nonce).zip(data).zip(msg) {
- *out = n ^ d ^ m;
+ impl seal::Sealed for EaxOnline<$type, Encrypt> {}
+ )*
+ $(
+ impl Aead for EaxOnline<$type, Decrypt> {
+ fn update(&mut self, ad: &[u8]) { self.update_assoc(ad) }
+ fn digest_size(&self) -> usize { <eax::Tag as GenericArrayExt>::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])
+ }
}
- }
-
- /// Length of the digest in bytes.
- fn digest_size(&self) -> usize { EAX_DIGEST_SIZE }
+ impl seal::Sealed for EaxOnline<$type, Decrypt> {}
+ )*
+ };
}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use crate::crypto::aead::Aead;
-
- trait HexSlice: std::borrow::Borrow<str> {
- fn as_hex(&self) -> Vec<u8> {
- let res: Vec<u8> = self.borrow().as_bytes().rchunks(2)
- .map(|slice| std::str::from_utf8(slice).unwrap())
- .map(|chr| u8::from_str_radix(chr, 16).unwrap())
- .rev()
- .collect();
- res
- }
- }
- impl<'a> HexSlice for &'a str {}
-
- #[test]
- fn eax() {
- // Test vectors from https://web.cs.ucdavis.edu/~rogaway/papers/eax.pdf
- let mut eax = EaxAes::with_key_and_nonce(
- &"233952DEE4D5ED5F9B9C6D6FF80FF478".as_hex(),
- &"62EC67F9C3A4A407FCB2A8C49031A8B3".as_hex()
- ).unwrap();
- eax.update(&"6BFB914FD07EAE6B".as_hex());
- let mut digest = [0; 16];
- eax.digest(&mut digest);
- assert_eq!(&digest, &*"E037830E8389F27B025A2D6527E79D01".as_hex());
-
- let mut eax = EaxAes::with_key_and_nonce(
- &"91945D3F4DCBEE0BF45EF52255F095A4".as_hex(),
- &"BECAF043B0A23D843194BA972C66DEBD".as_hex()
- ).unwrap();
- eax.update(&"FA3BFD4806EB53FA".as_hex());
- let mut out = [0; 2];
- eax.encrypt(&mut out, &"F7FB".as_hex());
- let mut digest = [0; 16];
- eax.digest(&mut digest);
- let output = [&out[..], &digest[..]].concat();
- assert_eq!(output, &*"19DD5C4C9331049D0BDAB0277408F67967E5".as_hex());
-
- let mut eax = EaxAes::with_key_and_nonce(
- &"8395FCF1E95BEBD697BD010BC766AAC3".as_hex(),
- &"22E7ADD93CFC6393C57EC0B3C17D6B44".as_hex()
- ).unwrap();
- eax.update(&"126735FCC320D25A".as_hex());
- let mut out1 = [0; 16];
- eax.encrypt(&mut out1, &"CA40D7446E545FFAED3BD12A740A659F".as_hex());
- let mut out2 = [0; 5];
- eax.encrypt(&mut out2, &"FBBB3CEAB7".as_hex());
- let mut digest = [0; 16];
- eax.digest(&mut digest);
- let output = [&out1[..], &out2[..], &digest[..]].concat();
- assert_eq!(output, &*"CB8920F87A6C75CFF39627B56E3ED197C552D295A7CFC46AFC253B4652B1AF3795B124AB6E".as_hex());
- }
-}
+impl_aead!(BlockCipherKey<Aes, U128>, BlockCipherKey<Aes, U192>, BlockCipherKey<Aes, U256>);
diff --git a/openpgp/src/crypto/backend/cng/symmetric.rs b/openpgp/src/crypto/backend/cng/symmetric.rs
index a4a140eb..7d8281e7 100644
--- a/openpgp/src/crypto/backend/cng/symmetric.rs
+++ b/openpgp/src/crypto/backend/cng/symmetric.rs
@@ -68,74 +68,6 @@ impl Mode for cng::SymmetricAlgorithmKey {
}
}
-/// CTR mode using a block cipher. CNG doesn't implement one so roll our own
-/// using CNG's ECB mode.
-pub struct Ctr {
- key: cng::SymmetricAlgorithmKey,
- ctr: Option<Box<[u8]>>,
-}
-
-impl Ctr {
- pub fn with_cipher_and_iv(algo: cng::SymmetricAlgorithmId, key: &[u8], iv: &[u8]) -> Result<Ctr> {
- let algo = cng::SymmetricAlgorithm::open(algo, cng::ChainingMode::Ecb)?;
- let key = algo.new_key(key)?;
- // TODO: Check iv len
- Ok(Ctr { key, ctr: Some(iv.into()) })
- }
-
- pub fn encrypt(&mut self, dst: &mut [u8], src: &[u8]) -> Result<()> {
- let mut ctr = self.ctr.take().unwrap();
- Mode::encrypt(self, &mut ctr, dst, src)?;
- self.ctr = Some(ctr);
- Ok(())
- }
-
- pub fn decrypt(&mut self, dst: &mut [u8], src: &[u8]) -> Result<()> {
- let mut ctr = self.ctr.take().unwrap();
- Mode::decrypt(self, &mut ctr, dst, src)?;
- self.ctr = Some(ctr);
- Ok(())
- }
-}
-
-impl Mode for Ctr {
- fn block_size(&self) -> usize {
- self.key.block_size().expect("CNG not to fail internally")
- }
-
- fn encrypt(&mut self, iv: &mut [u8], dst: &mut [u8], src: &[u8]) -> Result<()> {
- let block = self.block_size();
-
- // Ciphertext_i <- BlockCipher(Counter_i) ⊕ Plaintext_i
- for (dst, src) in dst.chunks_mut(block).zip(src.chunks(block)) {
- let res = cng::SymmetricAlgorithmKey::encrypt(&self.key, None, iv, None)?;
- wrapping_increment_be(iv.as_mut());
-
- for (dst, (res, src)) in dst.iter_mut().zip(res.as_slice().iter().zip(src.iter())) {
- *dst = res ^ src;
- }
- }
-
- Ok(())
- }
-
- fn decrypt(&mut self, iv: &mut [u8], dst: &mut [u8], src: &[u8]) -> Result<()> {
- let block = self.block_size();
-
- // Plaintext_i <- BlockCipher(Counter_i) ⊕ Ciphertext_i
- for (dst, src) in dst.chunks_mut(block).zip(src.chunks(block)) {
- let res = cng::SymmetricAlgorithmKey::encrypt(&self.key, None, iv, None)?;
- wrapping_increment_be(iv.as_mut());
-
- for (dst, (res, src)) in dst.iter_mut().zip(res.as_slice().iter().zip(src.iter())) {
- *dst = res ^ src;
- }
- }
-
- Ok(())
- }
-}
-
#[derive(Debug, thiserror::Error)]
#[error("Unsupported algorithm: {0}")]
pub struct UnsupportedAlgorithm(SymmetricAlgorithm);
@@ -253,115 +185,3 @@ impl SymmetricAlgorithm {
))
}
}
-
-fn wrapping_increment_be(value: &mut [u8]) -> &mut [u8] {
- for val in value.iter_mut().rev() {
- *val = val.wrapping_add(1);
- // Stop carryover
- if *val != 0x00 {
- break;
- }
- }
-
- value
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use std::borrow::Borrow;
-
- trait HexSlice: Borrow<str> {
- fn as_hex(&self) -> Vec<u8> {
- let res: Vec<u8> = self.borrow().as_bytes().rchunks(2)
- .map(|slice| std::str::from_utf8(slice).unwrap())
- .map(|chr| u8::from_str_radix(chr, 16).unwrap())
- .rev()
- .collect();
- res
- }
- }
- impl<'a> HexSlice for &'a str {}
-
- #[test]
- fn hex_slice() {
- assert_eq!("0a".as_hex(), &[0x0A]);
- assert_eq!("a".as_hex(), &[0x0A]);
- assert_eq!("FE0a".as_hex(), &[0xFE, 0x0A]);
- assert_eq!("E0a".as_hex(), &[0x0E, 0x0A]);
- }
-
- #[test]
- fn wrapping_increment_be() {
- assert_eq!(super::wrapping_increment_be(&mut [0x00]), [0x01]);
- assert_eq!(super::wrapping_increment_be(&mut [0xFF, 0xFF]), [0x00, 0x00]);
- assert_eq!(super::wrapping_increment_be(&mut [0xFD, 0xFF]), [0xFE, 0x00]);
-
- let input = &mut "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff".as_hex();
- let expected = &"f0f1f2f3f4f5f6f7f8f9fafbfcfdff00".as_hex();
-
- assert_eq!(super::wrapping_increment_be(input).as_ref(), expected.as_slice());
- }
-
- #[test]
- fn ctr_aes_128() {
- // NIST SP800-38a test vectors
- // F.5.1 CTR-AES128.Encrypt
- let key = &"2b7e151628aed2a6abf7158809cf4f3c".as_hex();
- assert_eq!(key.len(), 16);
- let mut ctr = Ctr::with_cipher_and_iv(
- cng::SymmetricAlgorithmId::Aes,
- key,
- &"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff".as_hex(),
- ).unwrap();
-
- let plain = &"6bc1bee22e409f96e93d7e117393172a".as_hex();
- let mut cipher = vec![0u8; 16];
- ctr.encrypt(&mut cipher, plain).unwrap();
- assert_eq!(&cipher, &"874d6191b620e3261bef6864990db6ce".as_hex());
-
- let plain = &"ae2d8a571e03ac9c9eb76fac45af8e51".as_hex();
- let mut cipher = vec![0u8; 16];
- ctr.encrypt(&mut cipher, plain).unwrap();
- assert_eq!(&cipher, &"9806f66b7970fdff8617187bb9fffdff".as_hex());
-
- let plain = &"30c81c46a35ce411e5fbc1191a0a52ef".as_hex();
- let mut cipher = vec![0u8; 16];
- ctr.encrypt(&mut cipher, plain).unwrap();
- assert_eq!(&cipher, &"5ae4df3edbd5d35e5b4f09020db03eab".as_hex());
-
- let plain = &"f69f2445df4f9b17ad2b417be66c3710".as_hex();
- let mut cipher = vec![0u8; 16];
- ctr.encrypt(&mut cipher, plain).unwrap();
- assert_eq!(&cipher, &"1e031dda2fbe03d1792170a0f3009cee".as_hex());
-
- // F.5.2 CTR-AES128.Decrypt
- let key = &"2b7e151628aed2a6abf7158809cf4f3c".as_hex();
- assert_eq!(key.len(), 16);
- let mut ctr = Ctr::with_cipher_and_iv(
- cng::SymmetricAlgorithmId::Aes,
- key,
- &"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff".as_hex(),
- ).unwrap();
-
- let plain = &"874d6191b620e3261bef6864990db6ce".as_hex();
- let mut cipher = vec![0u8; 16];
- ctr.decrypt(&mut cipher, plain).unwrap();
- assert_eq!(&cipher, &"6bc1bee22e409f96e93d7e117393172a".as_hex());
-
- let plain = &"9806f66b7970fdff8617187bb9fffdff".as_hex();
- let mut cipher = vec![0u8; 16];
- ctr.decrypt(&mut cipher, plain).unwrap();
- assert_eq!(&cipher, &"ae2d8a571e03ac9c9eb76fac45af8e51".as_hex());
-
- let plain = &"5ae4df3edbd5d35e5b4f09020db03eab".as_hex();
- let mut cipher = vec![0u8; 16];
- ctr.decrypt(&mut cipher, plain).unwrap();
- assert_eq!(&cipher, &"30c81c46a35ce411e5fbc1191a0a52ef".as_hex());
-
- let plain = &"1e031dda2fbe03d1792170a0f3009cee".as_hex();
- let mut cipher = vec![0u8; 16];
- ctr.decrypt(&mut cipher, plain).unwrap();
- assert_eq!(&cipher, &"f69f2445df4f9b17ad2b417be66c3710".as_hex());
- }
-}
diff --git a/openpgp/src/crypto/backend/nettle/aead.rs b/openpgp/src/crypto/backend/nettle/aead.rs
index 797dd040..f0b70b53 100644
--- a/openpgp/src/crypto/backend/nettle/aead.rs
+++ b/openpgp/src/crypto/backend/nettle/aead.rs
@@ -3,7 +3,7 @@ use nettle::{aead, cipher};
use crate::{Error, Result};
-use crate::crypto::aead::Aead;
+use crate::crypto::aead::{Aead, CipherOp};
use crate::seal;
use crate::types::{AEADAlgorithm, SymmetricAlgorithm};
@@ -32,6 +32,7 @@ impl AEADAlgorithm {
sym_algo: SymmetricAlgorithm,
key: &[u8],
nonce: &[u8],
+ _op: CipherOp,
) -> Result<Box<dyn Aead>> {
match self {
AEADAlgorithm::EAX => match sym_algo {
diff --git a/openpgp/src/packet/skesk.rs b/openpgp/src/packet/skesk.rs
index ef8c73bb..3d00822f 100644
--- a/openpgp/src/packet/skesk.rs
+++ b/openpgp/src/packet/skesk.rs
@@ -12,8 +12,8 @@ use std::ops::{Deref, DerefMut};
use quickcheck::{Arbitrary, Gen};
use crate::Result;
-use crate::crypto;
-use crate::crypto::S2K;
+use crate::crypto::{self, S2K, Password, SessionKey};
+use crate::crypto::aead::CipherOp;
use crate::Error;
use crate::types::{
AEADAlgorithm,
@@ -21,8 +21,6 @@ use crate::types::{
};
use crate::packet::{self, SKESK};
use crate::Packet;
-use crate::crypto::Password;
-use crate::crypto::SessionKey;
impl SKESK {
/// Derives the key inside this SKESK from `password`. Returns a
@@ -466,7 +464,7 @@ impl SKESK5 {
let key = s2k.derive_key(password, esk_algo.key_size()?)?;
let mut iv = vec![0u8; esk_aead.iv_size()?];
crypto::random(&mut iv);
- let mut ctx = esk_aead.context(esk_algo, &key, &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()];
@@ -503,7 +501,7 @@ impl SKESK5 {
if let Some(ref esk) = self.esk()? {
// Use the derived key to decrypt the ESK.
let mut cipher = self.aead_algo.context(
- self.symmetric_algo(), &key, &self.aead_iv()?)?;
+ self.symmetric_algo(), &key, &self.aead_iv()?, CipherOp::Decrypt)?;
let ad = [0xc3, 5 /* Version. */, self.symmetric_algo().into(),
self.aead_algo.into()];