summaryrefslogtreecommitdiffstats
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
parent3dacda4a93b1d3b1ef44484ac2691eec0aa759c9 (diff)
openpgp: Use pure Rust EAX implementation under CNG backend
- Fixes #556.
-rw-r--r--Cargo.lock86
-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
7 files changed, 193 insertions, 339 deletions
diff --git a/Cargo.lock b/Cargo.lock
index ae8b43ee..f699f174 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -16,6 +16,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e"
[[package]]
+name = "aead"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fc95d1bdb8e6666b2b217308eeeb09f2d6728d104be3e31916cc74d15420331"
+dependencies = [
+ "generic-array 0.14.4",
+]
+
+[[package]]
name = "ahash"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -208,6 +217,15 @@ dependencies = [
]
[[package]]
+name = "block-cipher"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f337a3e6da609650eb74e02bc9fac7b735049f7623ab12f2e4c719316fcc7e80"
+dependencies = [
+ "generic-array 0.14.4",
+]
+
+[[package]]
name = "block-padding"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -379,6 +397,16 @@ dependencies = [
]
[[package]]
+name = "cmac"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5220604fe5c112e2851b00da795c72cbb71bf112f2cbd532bdcfb4106eeb320b"
+dependencies = [
+ "crypto-mac",
+ "dbl",
+]
+
+[[package]]
name = "colored"
version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -460,6 +488,17 @@ dependencies = [
]
[[package]]
+name = "crypto-mac"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "58bcd97a54c7ca5ce2f6eb16f6bede5b0ab5f0055fedc17d2f0b4466e21671ca"
+dependencies = [
+ "block-cipher",
+ "generic-array 0.14.4",
+ "subtle",
+]
+
+[[package]]
name = "csv"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -492,6 +531,15 @@ dependencies = [
]
[[package]]
+name = "ctr"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cc03dee3a2843ac6eb4b5fb39cfcf4cb034d078555d1f4a0afbed418b822f3c2"
+dependencies = [
+ "stream-cipher",
+]
+
+[[package]]
name = "curve25519-dalek"
version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -505,6 +553,15 @@ dependencies = [
]
[[package]]
+name = "dbl"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2735145c3b9ba15f2d7a3ae8cdafcbc8c98a7bef7f62afe9d08bd99fbf7130de"
+dependencies = [
+ "generic-array 0.14.4",
+]
+
+[[package]]
name = "diff"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -591,6 +648,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c53dc3a653e0f64081026e4bf048d48fec9fce90c66e8326ca7292df0ff2d82"
[[package]]
+name = "eax"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5f8b7fcdee0a9cc0d80bb9547c4298efddced5744be0018aad97133efeda6474"
+dependencies = [
+ "aead",
+ "block-cipher",
+ "cmac",
+ "ctr",
+ "subtle",
+]
+
+[[package]]
name = "ed25519"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1894,6 +1964,7 @@ dependencies = [
"bzip2",
"chrono",
"dyn-clone",
+ "eax",
"ed25519-dalek",
"flate2",
"idna",
@@ -2119,6 +2190,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
[[package]]
+name = "stream-cipher"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c80e15f898d8d8f25db24c253ea615cc14acf418ff307822995814e7d42cfa89"
+dependencies = [
+ "block-cipher",
+ "generic-array 0.14.4",
+]
+
+[[package]]
name = "string_cache"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2470,10 +2551,11 @@ checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
[[package]]
name = "win-crypto-ng"
-version = "0.2.1"
+version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "436ccff9c9ed3aee7ef0224a4944e103d27cba7add587fbdf61bd745288f6029"
+checksum = "46f32a81d56493638a7f2d1f63e927f6ca706072b3b6c818a8cb071d65a6c9d8"
dependencies = [
+ "block-cipher",
"doc-comment",
"rand_core",
"winapi 0.3.9",
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<()>