diff --git a/blake2/Cargo.toml b/blake2/Cargo.toml index b77a9c4c0..9bba9024c 100644 --- a/blake2/Cargo.toml +++ b/blake2/Cargo.toml @@ -18,6 +18,7 @@ crypto-mac = "0.8" digest = "0.9" opaque-debug = "0.3" subtle = { version = ">=2, <2.5", default-features = false } +zeroize = { version = "1.5.7", features = ["zeroize_derive"], default-features = false, optional = true } [dev-dependencies] crypto-mac = { version = "0.8", features = ["dev"] } @@ -39,6 +40,7 @@ blake2s = [] # performance. This feature disables some inlining, improving the performance # of the portable implementation in that specific case. uninline_portable = [] +zeroize = ["zeroize/zeroize_derive"] [package.metadata.docs.rs] all-features = true diff --git a/blake2/src/blake2b.rs b/blake2/src/blake2b.rs index bc1c55a61..6d837bf02 100644 --- a/blake2/src/blake2b.rs +++ b/blake2/src/blake2b.rs @@ -44,26 +44,28 @@ use digest::{ generic_array::GenericArray, BlockInput, FixedOutputDirty, InvalidOutputSize, Reset, Update, VariableOutputDirty, }; +#[cfg(feature = "zeroize")] +use zeroize::ZeroizeOnDrop; pub(crate) type Word = u64; pub(crate) type Count = u128; type Output = GenericArray; /// The max hash length. -pub const OUTBYTES: usize = 8 * size_of::(); +pub const OUTBYTES: usize = 8 * (Word::BITS as usize / 8); /// The max key length. -pub const KEYBYTES: usize = 8 * size_of::(); +pub const KEYBYTES: usize = 8 * (Word::BITS as usize / 8); /// The max salt length. -pub const SALTBYTES: usize = 2 * size_of::(); +pub const SALTBYTES: usize = 2 * (Word::BITS as usize / 8); /// The max personalization length. -pub const PERSONALBYTES: usize = 2 * size_of::(); +pub const PERSONALBYTES: usize = 2 * (Word::BITS as usize / 8); /// The number input bytes passed to each call to the compression function. Small benchmarks need /// to use an even multiple of `BLOCKBYTES`, or else their apparent throughput will be low. -pub const BLOCKBYTES: usize = 16 * size_of::(); +pub const BLOCKBYTES: usize = 16 * (Word::BITS as usize / 8); const IV: [Word; 8] = [ 0x6A09E667F3BCC908, @@ -109,6 +111,7 @@ pub fn blake2b(input: &[u8]) -> Hash { /// Blake2b instance with a fixed output. #[derive(Clone, Default)] +#[cfg_attr(feature = "zeroize", derive(ZeroizeOnDrop))] pub struct Blake2b { params: Params, state: State, @@ -193,6 +196,7 @@ digest::impl_write!(Blake2b); /// Blake2b instance with a variable output. #[derive(Clone, Default)] +#[cfg_attr(feature = "zeroize", derive(ZeroizeOnDrop))] pub struct VarBlake2b { params: Params, state: State, diff --git a/blake2/src/blake2b/backend.rs b/blake2/src/blake2b/backend.rs index 5942eb252..c9a11a12b 100644 --- a/blake2/src/blake2b/backend.rs +++ b/blake2/src/blake2b/backend.rs @@ -9,6 +9,8 @@ mod sse41; use super::*; use arrayref::array_ref; use core::cmp; +#[cfg(feature = "zeroize")] +use zeroize::Zeroize; #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] pub const MAX_DEGREE: usize = 4; @@ -138,6 +140,13 @@ impl Implementation { } } +#[cfg(feature = "zeroize")] +impl Zeroize for Implementation { + fn zeroize(&mut self) { + // Nothing to do. + } +} + pub struct Job<'a, 'b> { pub input: &'a [u8], pub words: &'b mut [Word; 8], @@ -181,6 +190,13 @@ pub enum LastNode { No, } +#[cfg(feature = "zeroize")] +impl Zeroize for LastNode { + fn zeroize(&mut self) { + // Nothing to do. + } +} + impl LastNode { pub fn yes(&self) -> bool { match self { @@ -212,7 +228,7 @@ pub(crate) fn count_low(count: Count) -> Word { } pub(crate) fn count_high(count: Count) -> Word { - (count >> (8 * size_of::())) as Word + (count >> (8 * (Word::BITS as usize / 8))) as Word } #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] diff --git a/blake2/src/blake2b/params.rs b/blake2/src/blake2b/params.rs index 5c1126188..f910edc49 100644 --- a/blake2/src/blake2b/params.rs +++ b/blake2/src/blake2b/params.rs @@ -3,6 +3,8 @@ use super::{ }; use arrayref::array_refs; use core::fmt; +#[cfg(feature = "zeroize")] +use zeroize::ZeroizeOnDrop; /// A parameter builder that exposes all the non-default BLAKE2 features. /// @@ -29,6 +31,7 @@ use core::fmt; /// let mut state = params.to_state(); /// ``` #[derive(Clone)] +#[cfg_attr(feature = "zeroize", derive(ZeroizeOnDrop))] pub struct Params { pub(super) hash_length: u8, pub(super) key_length: u8, diff --git a/blake2/src/blake2b/state.rs b/blake2/src/blake2b/state.rs index 138b8230f..4fb686ede 100644 --- a/blake2/src/blake2b/state.rs +++ b/blake2/src/blake2b/state.rs @@ -2,6 +2,9 @@ use super::{backend, Count, Hash, Params, Word, BLOCKBYTES, OUTBYTES}; use arrayref::mut_array_refs; use core::{cmp, fmt, mem::size_of}; +#[cfg(feature = "zeroize")] +use zeroize::ZeroizeOnDrop; + /// An incremental hasher for BLAKE2b. /// /// To construct a `State` with non-default parameters, see `Params::to_state`. @@ -20,6 +23,7 @@ use core::{cmp, fmt, mem::size_of}; /// assert_eq!(blake2b(b"foobar"), state.finalize()); /// ``` #[derive(Clone)] +#[cfg_attr(feature = "zeroize", derive(ZeroizeOnDrop))] pub struct State { pub(super) words: [Word; 8], pub(super) count: Count, diff --git a/blake2/src/blake2bp.rs b/blake2/src/blake2bp.rs index ad8b7c246..7f61cd337 100644 --- a/blake2/src/blake2bp.rs +++ b/blake2/src/blake2bp.rs @@ -26,6 +26,8 @@ use crate::blake2b::{ many, state, Count, Hash, Word, BLOCKBYTES, KEYBYTES, OUTBYTES, }; use core::{cmp, fmt, mem::size_of}; +#[cfg(feature = "zeroize")] +use zeroize::ZeroizeOnDrop; pub(crate) const DEGREE: usize = 4; @@ -59,6 +61,7 @@ pub fn blake2bp(input: &[u8]) -> Hash { /// let mut state = blake2bp::Params::new().hash_length(32).to_state(); /// ``` #[derive(Clone)] +#[cfg_attr(feature = "zeroize", derive(ZeroizeOnDrop))] pub struct Params { hash_length: u8, key_length: u8, @@ -207,6 +210,7 @@ impl fmt::Debug for Params { /// assert_eq!(expected, &hash.to_hex()); /// ``` #[derive(Clone)] +#[cfg_attr(feature = "zeroize", derive(ZeroizeOnDrop))] pub struct State { leaf_words: [[Word; 8]; DEGREE], root_words: [Word; 8], diff --git a/blake2/src/blake2s.rs b/blake2/src/blake2s.rs index 664cff353..3851ccc62 100644 --- a/blake2/src/blake2s.rs +++ b/blake2/src/blake2s.rs @@ -43,26 +43,28 @@ use digest::{ generic_array::GenericArray, BlockInput, FixedOutputDirty, InvalidOutputSize, Reset, Update, VariableOutputDirty, }; +#[cfg(feature = "zeroize")] +use zeroize::ZeroizeOnDrop; pub(crate) type Word = u32; pub(crate) type Count = u64; type Output = GenericArray; /// The max hash length. -pub const OUTBYTES: usize = 8 * size_of::(); +pub const OUTBYTES: usize = 8 * (Word::BITS as usize / 8); /// The max key length. -pub const KEYBYTES: usize = 8 * size_of::(); +pub const KEYBYTES: usize = 8 * (Word::BITS as usize / 8); /// The max salt length. -pub const SALTBYTES: usize = 2 * size_of::(); +pub const SALTBYTES: usize = 2 * (Word::BITS as usize / 8); /// The max personalization length. -pub const PERSONALBYTES: usize = 2 * size_of::(); +pub const PERSONALBYTES: usize = 2 * (Word::BITS as usize / 8); /// The number input bytes passed to each call to the compression function. Small benchmarks need /// to use an even multiple of `BLOCKBYTES`, or else their apparent throughput will be low. -pub const BLOCKBYTES: usize = 16 * size_of::(); +pub const BLOCKBYTES: usize = 16 * (Word::BITS as usize / 8); const IV: [Word; 8] = [ 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19, @@ -98,6 +100,7 @@ pub fn blake2s(input: &[u8]) -> Hash { /// Blake2s instance with a fixed output. #[derive(Clone, Default)] +#[cfg_attr(feature = "zeroize", derive(ZeroizeOnDrop))] pub struct Blake2s { params: Params, state: State, @@ -182,6 +185,7 @@ digest::impl_write!(Blake2s); /// Blake2s instance with a variable output. #[derive(Clone, Default)] +#[cfg_attr(feature = "zeroize", derive(ZeroizeOnDrop))] pub struct VarBlake2s { params: Params, state: State, diff --git a/blake2/src/blake2s/backend.rs b/blake2/src/blake2s/backend.rs index c9473566d..4da0ff888 100644 --- a/blake2/src/blake2s/backend.rs +++ b/blake2/src/blake2s/backend.rs @@ -9,6 +9,8 @@ mod sse41; use super::*; use arrayref::array_ref; use core::cmp; +#[cfg(feature = "zeroize")] +use zeroize::Zeroize; #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] pub const MAX_DEGREE: usize = 8; @@ -136,6 +138,13 @@ impl Implementation { } } +#[cfg(feature = "zeroize")] +impl Zeroize for Implementation { + fn zeroize(&mut self) { + // Nothing to do. + } +} + pub struct Job<'a, 'b> { pub input: &'a [u8], pub words: &'b mut [Word; 8], @@ -179,6 +188,13 @@ pub enum LastNode { No, } +#[cfg(feature = "zeroize")] +impl Zeroize for LastNode { + fn zeroize(&mut self) { + // Nothing to do. + } +} + impl LastNode { pub fn yes(&self) -> bool { match self { @@ -210,7 +226,7 @@ pub(crate) fn count_low(count: Count) -> Word { } pub(crate) fn count_high(count: Count) -> Word { - (count >> (8 * size_of::())) as Word + (count >> (8 * (Word::BITS as usize / 8))) as Word } #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] diff --git a/blake2/src/blake2s/params.rs b/blake2/src/blake2s/params.rs index 3e6cbc705..97c81ec02 100644 --- a/blake2/src/blake2s/params.rs +++ b/blake2/src/blake2s/params.rs @@ -3,6 +3,8 @@ use super::{ }; use arrayref::array_refs; use core::fmt; +#[cfg(feature = "zeroize")] +use zeroize::ZeroizeOnDrop; /// A parameter builder that exposes all the non-default BLAKE2 features. /// @@ -29,6 +31,7 @@ use core::fmt; /// let mut state = params.to_state(); /// ``` #[derive(Clone)] +#[cfg_attr(feature = "zeroize", derive(ZeroizeOnDrop))] pub struct Params { pub(super) hash_length: u8, pub(super) key_length: u8, diff --git a/blake2/src/blake2s/state.rs b/blake2/src/blake2s/state.rs index 698c4a0d1..e0c7e951c 100644 --- a/blake2/src/blake2s/state.rs +++ b/blake2/src/blake2s/state.rs @@ -1,6 +1,8 @@ use super::{backend, Count, Hash, Params, Word, BLOCKBYTES, OUTBYTES}; use arrayref::mut_array_refs; use core::{cmp, fmt, mem::size_of}; +#[cfg(feature = "zeroize")] +use zeroize::ZeroizeOnDrop; /// An incremental hasher for BLAKE2s. /// @@ -20,6 +22,7 @@ use core::{cmp, fmt, mem::size_of}; /// assert_eq!(blake2s(b"foobar"), state.finalize()); /// ``` #[derive(Clone)] +#[cfg_attr(feature = "zeroize", derive(ZeroizeOnDrop))] pub struct State { pub(super) words: [Word; 8], pub(super) count: Count, diff --git a/blake2/src/blake2sp.rs b/blake2/src/blake2sp.rs index 023d97585..b4731ee05 100644 --- a/blake2/src/blake2sp.rs +++ b/blake2/src/blake2sp.rs @@ -26,6 +26,8 @@ use crate::blake2s::{ many, state, Count, Hash, Word, BLOCKBYTES, KEYBYTES, OUTBYTES, }; use core::{cmp, fmt, mem::size_of}; +#[cfg(feature = "zeroize")] +use zeroize::ZeroizeOnDrop; pub(crate) const DEGREE: usize = 8; @@ -58,6 +60,7 @@ pub fn blake2sp(input: &[u8]) -> Hash { /// let mut state = blake2sp::Params::new().hash_length(32).to_state(); /// ``` #[derive(Clone)] +#[cfg_attr(feature = "zeroize", derive(ZeroizeOnDrop))] pub struct Params { hash_length: u8, key_length: u8, @@ -214,6 +217,7 @@ impl fmt::Debug for Params { /// assert_eq!(expected, &hash.to_hex()); /// ``` #[derive(Clone)] +#[cfg_attr(feature = "zeroize", derive(ZeroizeOnDrop))] pub struct State { leaf_words: [[Word; 8]; DEGREE], root_words: [Word; 8],