Clear the SHA-256 and HMAC states on drop

Turn on the opt-in zeroize features of sha2 and hmac. With them, the
SHA-256 state that hashes each Diffie-Hellman result clears itself when
dropped, and so do the two SHA-256 cores and the block buffer inside the
HMAC that HKDF runs on when deriving the chaining key and the session
keys. Without the features those states were left in memory.

hmac's zeroize feature only forwards to digest's, which sha2's already
turns on, so in today's build the hmac entry adds nothing; it keeps the
HMAC inside hkdf cleared if sha2 ever stops forwarding. A test asserts
at compile time that the hasher and the HMAC's hash core implement
ZeroizeOnDrop, so dropping sha2's feature fails the build.
This commit is contained in:
Johnathan Corgan
2026-10-01 22:41:14 +00:00
parent af67aae5fa
commit 74bba4499a
3 changed files with 20 additions and 1 deletions
Generated
+3
View File
@@ -333,6 +333,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa"
dependencies = [ dependencies = [
"hybrid-array", "hybrid-array",
"zeroize",
] ]
[[package]] [[package]]
@@ -1028,6 +1029,7 @@ dependencies = [
"const-oid", "const-oid",
"crypto-common 0.2.2", "crypto-common 0.2.2",
"ctutils", "ctutils",
"zeroize",
] ]
[[package]] [[package]]
@@ -1175,6 +1177,7 @@ dependencies = [
"futures", "futures",
"hex", "hex",
"hkdf", "hkdf",
"hmac 0.13.0",
"libc", "libc",
"libm", "libm",
"mdns-sd", "mdns-sd",
+5 -1
View File
@@ -22,8 +22,12 @@ profiling = []
[dependencies] [dependencies]
ratatui = "0.30" ratatui = "0.30"
secp256k1 = { version = "0.30", features = ["rand", "global-context"] } secp256k1 = { version = "0.30", features = ["rand", "global-context"] }
sha2 = "0.11" # The `zeroize` features clear the SHA-256 and HMAC states on drop. `hmac`'s
# feature only forwards to `digest`'s, which `sha2`'s also turns on; it is
# listed so the HMAC inside `hkdf` keeps it if `sha2`'s ever stops doing so.
sha2 = { version = "0.11", features = ["zeroize"] }
hkdf = "0.13" hkdf = "0.13"
hmac = { version = "0.13", features = ["zeroize"] }
ring = "0.17" ring = "0.17"
libm = "0.2" libm = "0.2"
zeroize = { version = "1.9", features = ["zeroize_derive"] } zeroize = { version = "1.9", features = ["zeroize_derive"] }
+12
View File
@@ -915,3 +915,15 @@ fn test_xk_invalid_msg3_size() {
.is_err() .is_err()
); );
} }
/// The `zeroize` features of `sha2` and `hmac` are on, so the SHA-256 state
/// that hashes each Diffie-Hellman result, and the two SHA-256 cores inside
/// the HMAC that HKDF runs on, are cleared when dropped. Without `sha2`'s
/// feature this does not compile; `hmac`'s forwards to the same `digest`
/// feature, so dropping it alone changes nothing while `sha2`'s is on.
#[test]
fn test_sha256_states_used_by_hashing_and_hkdf_are_cleared_on_drop() {
fn clears_on_drop<T: zeroize::ZeroizeOnDrop>() {}
clears_on_drop::<sha2::Sha256>();
clears_on_drop::<<sha2::Sha256 as hmac::EagerHash>::Core>();
}