aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGard Kylling <[email protected]>2024-07-08 09:54:05 +0200
committerJack O'Connor <[email protected]>2024-07-17 08:42:36 -0700
commit84a4ec319a69682bb84efdcfd3ab376a310d4f6e (patch)
tree978f9f3b266c63a38208e0a4416a3328051ed663
parent39e962e2bddf00a1786755c43c095c25b3b73a93 (diff)
Manually implement `Zeroize`
Removes dependence on proc-macros when enabling the zeroize feature.
-rw-r--r--Cargo.toml2
-rw-r--r--src/lib.rs92
2 files changed, 86 insertions, 8 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 3235400..41bb1ff 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -103,7 +103,7 @@ digest = { version = "0.10.1", features = [ "mac" ], optional = true }
memmap2 = { version = "0.9", optional = true }
rayon-core = { version = "1.12.1", optional = true }
serde = { version = "1.0", default-features = false, features = ["derive"], optional = true }
-zeroize = { version = "1", default-features = false, features = ["zeroize_derive"], optional = true }
+zeroize = { version = "1", default-features = false, optional = true }
[dev-dependencies]
hmac = "0.12.0"
diff --git a/src/lib.rs b/src/lib.rs
index d64e18f..066b925 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -138,6 +138,8 @@ use arrayvec::{ArrayString, ArrayVec};
use core::cmp;
use core::fmt;
use platform::{Platform, MAX_SIMD_DEGREE, MAX_SIMD_DEGREE_OR_2};
+#[cfg(feature = "zeroize")]
+use zeroize::Zeroize;
/// The number of bytes in a [`Hash`](struct.Hash.html), 32.
pub const OUT_LEN: usize = 32;
@@ -216,7 +218,6 @@ fn counter_high(counter: u64) -> u32 {
/// [`from_hex`]: #method.from_hex
/// [`Display`]: https://doc.rust-lang.org/std/fmt/trait.Display.html
/// [`FromStr`]: https://doc.rust-lang.org/std/str/trait.FromStr.html
-#[cfg_attr(feature = "zeroize", derive(zeroize::Zeroize))]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[derive(Clone, Copy, Hash)]
pub struct Hash([u8; OUT_LEN]);
@@ -305,6 +306,15 @@ impl core::str::FromStr for Hash {
}
}
+#[cfg(feature = "zeroize")]
+impl Zeroize for Hash {
+ fn zeroize(&mut self) {
+ // Destructuring to trigger compile error as a reminder to update this impl.
+ let Self(bytes) = self;
+ bytes.zeroize();
+ }
+}
+
// A proper implementation of constant time equality is tricky, and we get it from the
// constant_time_eq crate instead of rolling our own. However, that crate isn't compatible with
// Miri, so we roll our own just for that.
@@ -416,7 +426,6 @@ impl std::error::Error for HexError {}
// Each chunk or parent node can produce either a 32-byte chaining value or, by
// setting the ROOT flag, any number of final output bytes. The Output struct
// captures the state just prior to choosing between those two possibilities.
-#[cfg_attr(feature = "zeroize", derive(zeroize::Zeroize))]
#[derive(Clone)]
struct Output {
input_chaining_value: CVWords,
@@ -424,7 +433,6 @@ struct Output {
block_len: u8,
counter: u64,
flags: u8,
- #[cfg_attr(feature = "zeroize", zeroize(skip))]
platform: Platform,
}
@@ -460,8 +468,28 @@ impl Output {
}
}
+#[cfg(feature = "zeroize")]
+impl Zeroize for Output {
+ fn zeroize(&mut self) {
+ // Destructuring to trigger compile error as a reminder to update this impl.
+ let Self {
+ input_chaining_value,
+ block,
+ block_len,
+ counter,
+ flags,
+ platform: _,
+ } = self;
+
+ input_chaining_value.zeroize();
+ block.zeroize();
+ block_len.zeroize();
+ counter.zeroize();
+ flags.zeroize();
+ }
+}
+
#[derive(Clone)]
-#[cfg_attr(feature = "zeroize", derive(zeroize::Zeroize))]
struct ChunkState {
cv: CVWords,
chunk_counter: u64,
@@ -469,7 +497,6 @@ struct ChunkState {
buf_len: u8,
blocks_compressed: u8,
flags: u8,
- #[cfg_attr(feature = "zeroize", zeroize(skip))]
platform: Platform,
}
@@ -572,6 +599,29 @@ impl fmt::Debug for ChunkState {
}
}
+#[cfg(feature = "zeroize")]
+impl Zeroize for ChunkState {
+ fn zeroize(&mut self) {
+ // Destructuring to trigger compile error as a reminder to update this impl.
+ let Self {
+ cv,
+ chunk_counter,
+ buf,
+ buf_len,
+ blocks_compressed,
+ flags,
+ platform: _,
+ } = self;
+
+ cv.zeroize();
+ chunk_counter.zeroize();
+ buf.zeroize();
+ buf_len.zeroize();
+ blocks_compressed.zeroize();
+ flags.zeroize();
+ }
+}
+
// IMPLEMENTATION NOTE
// ===================
// The recursive function compress_subtree_wide(), implemented below, is the
@@ -985,7 +1035,6 @@ fn parent_node_output(
/// # }
/// ```
#[derive(Clone)]
-#[cfg_attr(feature = "zeroize", derive(zeroize::Zeroize))]
pub struct Hasher {
key: CVWords,
chunk_state: ChunkState,
@@ -1532,6 +1581,22 @@ impl std::io::Write for Hasher {
}
}
+#[cfg(feature = "zeroize")]
+impl Zeroize for Hasher {
+ fn zeroize(&mut self) {
+ // Destructuring to trigger compile error as a reminder to update this impl.
+ let Self {
+ key,
+ chunk_state,
+ cv_stack,
+ } = self;
+
+ key.zeroize();
+ chunk_state.zeroize();
+ cv_stack.zeroize();
+ }
+}
+
/// An incremental reader for extended output, returned by
/// [`Hasher::finalize_xof`](struct.Hasher.html#method.finalize_xof).
///
@@ -1555,7 +1620,6 @@ impl std::io::Write for Hasher {
/// from an unknown position in the output stream to recover its block index. Callers with strong
/// secret keys aren't affected in practice, but secret offsets are a [design
/// smell](https://en.wikipedia.org/wiki/Design_smell) in any case.
-#[cfg_attr(feature = "zeroize", derive(zeroize::Zeroize))]
#[derive(Clone)]
pub struct OutputReader {
inner: Output,
@@ -1667,3 +1731,17 @@ impl std::io::Seek for OutputReader {
Ok(self.position())
}
}
+
+#[cfg(feature = "zeroize")]
+impl Zeroize for OutputReader {
+ fn zeroize(&mut self) {
+ // Destructuring to trigger compile error as a reminder to update this impl.
+ let Self {
+ inner,
+ position_within_block,
+ } = self;
+
+ inner.zeroize();
+ position_within_block.zeroize();
+ }
+}