diff --git a/Cargo.lock b/Cargo.lock index 7d13c9dd..e148b128 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10,6 +10,7 @@ dependencies = [ "cipher", "cpufeatures", "hex-literal", + "zeroize", ] [[package]] @@ -191,6 +192,6 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "zeroize" -version = "1.5.2" +version = "1.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c88870063c39ee00ec285a2f8d6a966e5b6fb2becc4e8dac77ed0d370ed6006" +checksum = "7eb5728b8afd3f280a869ce1d4c554ffaed35f45c231fc41bfbd0381bef50317" diff --git a/aes/Cargo.toml b/aes/Cargo.toml index c7e52200..e8d2baaf 100644 --- a/aes/Cargo.toml +++ b/aes/Cargo.toml @@ -15,6 +15,7 @@ categories = ["cryptography", "no-std"] [dependencies] cfg-if = "1" cipher = "0.4.2" +zeroize = { version = "1.5.4", optional = true, default_features = false } [target.'cfg(any(target_arch = "aarch64", target_arch = "x86_64", target_arch = "x86"))'.dependencies] cpufeatures = "0.2" @@ -25,7 +26,6 @@ hex-literal = "0.3" [features] hazmat = [] # Expose cryptographically hazardous APIs -zeroize = ["cipher/zeroize"] [package.metadata.docs.rs] all-features = true diff --git a/aes/src/armv8.rs b/aes/src/armv8.rs index 6b0bb9b7..4ecc471d 100644 --- a/aes/src/armv8.rs +++ b/aes/src/armv8.rs @@ -122,6 +122,9 @@ macro_rules! define_aes_impl { } } + #[cfg(feature = "zeroize")] + impl zeroize::ZeroizeOnDrop for $name {} + #[doc=$doc] #[doc = "block cipher (encrypt-only)"] #[derive(Clone)] @@ -172,6 +175,17 @@ macro_rules! define_aes_impl { } } + impl Drop for $name_enc { + #[inline] + fn drop(&mut self) { + #[cfg(feature = "zeroize")] + zeroize::Zeroize::zeroize(&mut self.round_keys); + } + } + + #[cfg(feature = "zeroize")] + impl zeroize::ZeroizeOnDrop for $name_enc {} + #[doc=$doc] #[doc = "block cipher (decrypt-only)"] #[derive(Clone)] @@ -235,6 +249,17 @@ macro_rules! define_aes_impl { } } + impl Drop for $name_dec { + #[inline] + fn drop(&mut self) { + #[cfg(feature = "zeroize")] + zeroize::Zeroize::zeroize(&mut self.round_keys); + } + } + + #[cfg(feature = "zeroize")] + impl zeroize::ZeroizeOnDrop for $name_dec {} + pub(crate) struct $name_back_enc<'a>(&'a $name_enc); impl<'a> BlockSizeUser for $name_back_enc<'a> { diff --git a/aes/src/autodetect.rs b/aes/src/autodetect.rs index 8c3b1c12..ac471fab 100644 --- a/aes/src/autodetect.rs +++ b/aes/src/autodetect.rs @@ -180,6 +180,20 @@ macro_rules! define_aes_impl { } } + impl Drop for $name { + #[inline] + fn drop(&mut self) { + if self.token.get() { + unsafe { ManuallyDrop::drop(&mut self.inner.intrinsics) }; + } else { + unsafe { ManuallyDrop::drop(&mut self.inner.soft) }; + }; + } + } + + #[cfg(feature = "zeroize")] + impl zeroize::ZeroizeOnDrop for $name {} + #[doc=$doc] #[doc = "block cipher (encrypt-only)"] pub struct $name_enc { @@ -266,6 +280,20 @@ macro_rules! define_aes_impl { } } + impl Drop for $name_enc { + #[inline] + fn drop(&mut self) { + if self.token.get() { + unsafe { ManuallyDrop::drop(&mut self.inner.intrinsics) }; + } else { + unsafe { ManuallyDrop::drop(&mut self.inner.soft) }; + }; + } + } + + #[cfg(feature = "zeroize")] + impl zeroize::ZeroizeOnDrop for $name_enc {} + #[doc=$doc] #[doc = "block cipher (decrypt-only)"] pub struct $name_dec { @@ -380,6 +408,20 @@ macro_rules! define_aes_impl { f.write_str(stringify!($name_dec)) } } + + impl Drop for $name_dec { + #[inline] + fn drop(&mut self) { + if self.token.get() { + unsafe { ManuallyDrop::drop(&mut self.inner.intrinsics) }; + } else { + unsafe { ManuallyDrop::drop(&mut self.inner.soft) }; + }; + } + } + + #[cfg(feature = "zeroize")] + impl zeroize::ZeroizeOnDrop for $name_dec {} }; } diff --git a/aes/src/lib.rs b/aes/src/lib.rs index c338d6f6..40295a37 100644 --- a/aes/src/lib.rs +++ b/aes/src/lib.rs @@ -159,3 +159,77 @@ use cipher::{ pub type Block = GenericArray; /// Eight 128-bit AES blocks pub type Block8 = GenericArray; + +#[cfg(test)] +mod tests { + #[cfg(feature = "zeroize")] + #[test] + fn zeroize_works() { + use super::soft; + + fn test_for(val: T) { + use core::mem::{size_of, ManuallyDrop}; + + let mut val = ManuallyDrop::new(val); + let ptr = &val as *const _ as *const u8; + let len = size_of::>(); + + unsafe { ManuallyDrop::drop(&mut val) }; + + let slice = unsafe { core::slice::from_raw_parts(ptr, len) }; + + assert!(slice.iter().all(|&byte| byte == 0)); + } + + let key_128 = [42; 16].into(); + let key_192 = [42; 24].into(); + let key_256 = [42; 32].into(); + + use cipher::KeyInit as _; + test_for(soft::Aes128::new(&key_128)); + test_for(soft::Aes128Enc::new(&key_128)); + test_for(soft::Aes128Dec::new(&key_128)); + test_for(soft::Aes192::new(&key_192)); + test_for(soft::Aes192Enc::new(&key_192)); + test_for(soft::Aes192Dec::new(&key_192)); + test_for(soft::Aes256::new(&key_256)); + test_for(soft::Aes256Enc::new(&key_256)); + test_for(soft::Aes256Dec::new(&key_256)); + + #[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), not(aes_force_soft)))] + { + use super::ni; + + cpufeatures::new!(aes_intrinsics, "aes"); + if aes_intrinsics::get() { + test_for(ni::Aes128::new(&key_128)); + test_for(ni::Aes128Enc::new(&key_128)); + test_for(ni::Aes128Dec::new(&key_128)); + test_for(ni::Aes192::new(&key_192)); + test_for(ni::Aes192Enc::new(&key_192)); + test_for(ni::Aes192Dec::new(&key_192)); + test_for(ni::Aes256::new(&key_256)); + test_for(ni::Aes256Enc::new(&key_256)); + test_for(ni::Aes256Dec::new(&key_256)); + } + } + + #[cfg(all(target_arch = "aarch64", aes_armv8, not(aes_force_soft)))] + { + use super::armv8; + + cpufeatures::new!(aes_intrinsics, "aes"); + if aes_intrinsics::get() { + test_for(armv8::Aes128::new(&key_128)); + test_for(armv8::Aes128Enc::new(&key_128)); + test_for(armv8::Aes128Dec::new(&key_128)); + test_for(armv8::Aes192::new(&key_192)); + test_for(armv8::Aes192Enc::new(&key_192)); + test_for(armv8::Aes192Dec::new(&key_192)); + test_for(armv8::Aes256::new(&key_256)); + test_for(armv8::Aes256Enc::new(&key_256)); + test_for(armv8::Aes256Dec::new(&key_256)); + } + } + } +} diff --git a/aes/src/ni.rs b/aes/src/ni.rs index f5bdbbc1..15b49ef5 100644 --- a/aes/src/ni.rs +++ b/aes/src/ni.rs @@ -133,6 +133,9 @@ macro_rules! define_aes_impl { } } + #[cfg(feature = "zeroize")] + impl zeroize::ZeroizeOnDrop for $name {} + #[doc=$doc] #[doc = "block cipher (encrypt-only)"] #[derive(Clone)] @@ -185,6 +188,17 @@ macro_rules! define_aes_impl { } } + impl Drop for $name_enc { + #[inline] + fn drop(&mut self) { + #[cfg(feature = "zeroize")] + zeroize::Zeroize::zeroize(&mut self.round_keys); + } + } + + #[cfg(feature = "zeroize")] + impl zeroize::ZeroizeOnDrop for $name_enc {} + #[doc=$doc] #[doc = "block cipher (decrypt-only)"] #[derive(Clone)] @@ -248,6 +262,17 @@ macro_rules! define_aes_impl { } } + impl Drop for $name_dec { + #[inline] + fn drop(&mut self) { + #[cfg(feature = "zeroize")] + zeroize::Zeroize::zeroize(&mut self.round_keys); + } + } + + #[cfg(feature = "zeroize")] + impl zeroize::ZeroizeOnDrop for $name_dec {} + pub(crate) struct $name_back_enc<'a>(&'a $name_enc); impl<'a> BlockSizeUser for $name_back_enc<'a> { diff --git a/aes/src/soft.rs b/aes/src/soft.rs index 054bbd51..5f90b1e2 100644 --- a/aes/src/soft.rs +++ b/aes/src/soft.rs @@ -112,6 +112,17 @@ macro_rules! define_aes_impl { } } + impl Drop for $name { + #[inline] + fn drop(&mut self) { + #[cfg(feature = "zeroize")] + zeroize::Zeroize::zeroize(&mut self.keys); + } + } + + #[cfg(feature = "zeroize")] + impl zeroize::ZeroizeOnDrop for $name {} + #[doc=$doc] #[doc = "block cipher (encrypt-only)"] #[derive(Clone)] @@ -162,6 +173,9 @@ macro_rules! define_aes_impl { } } + #[cfg(feature = "zeroize")] + impl zeroize::ZeroizeOnDrop for $name_enc {} + #[doc=$doc] #[doc = "block cipher (decrypt-only)"] #[derive(Clone)] @@ -228,6 +242,9 @@ macro_rules! define_aes_impl { } } + #[cfg(feature = "zeroize")] + impl zeroize::ZeroizeOnDrop for $name_dec {} + pub(crate) struct $name_back_enc<'a>(&'a $name); impl<'a> BlockSizeUser for $name_back_enc<'a> {