What changed, and why it matters
This commit is a code cleanup in the Trezor firmware's Rust cryptography code. It replaces hand-written memory-clearing code with a standard library feature called ZeroizeOnDrop. The goal is the same: erase sensitive cryptographic data from memory when objects are destroyed. There is no evidence this commit fixes an active security bug; it is a defensive hardening and refactoring change.
No immediate action required. Treat as routine defensive refactoring. Review that ZeroizeOnDrop is correctly derived for all fields containing sensitive data and that the zeroize_derive feature does not introduce unwanted dependencies or code size increases in the embedded firmware build.
Security signals we found
Use of zeroize/ZeroizeOnDrop for sensitive cryptographic material
Removal of manual Drop implementations that zeroized buffers
No functional change to cryptographic operations or memory safety semantics
Defensive hardening against potential memory disclosure of key material
Evidence from the diff
The commit refactors four Rust crypto modules (curve25519, hmac, sha256, sha512) to use the zeroize crate’s derive macros (Zeroize and ZeroizeOnDrop) instead of manually implementing Drop to call zeroize(). Cargo.toml files are updated to enable the zeroize_derive feature. Functionally, the code still attempts to clear sensitive buffers on drop, but now relies on a well-maintained crate’s macro rather than custom implementations. No algorithmic or API changes are present.
Changed components
core/embed/rust/src/crypto/curve25519.rscore/embed/rust/src/crypto/hmac.rscore/embed/rust/src/crypto/sha256.rscore/embed/rust/src/crypto/sha512.rscore/embed/Cargo.tomlcore/embed/rust/Cargo.tomlcore/embed/Cargo.lockInspect captured patch +26 / −37
diff --git a/core/embed/Cargo.lock b/core/embed/Cargo.lock
index 724ca9e7..b0bc9688 100644
--- a/core/embed/Cargo.lock
+++ b/core/embed/Cargo.lock
@@ -1107,6 +1107,20 @@ name = "zeroize"
version = "1.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0"
+dependencies = [
+ "zeroize_derive",
+]
+
+[[package]]
+name = "zeroize_derive"
+version = "1.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
[[package]]
name = "zlib-rs"
diff --git a/core/embed/Cargo.toml b/core/embed/Cargo.toml
index 1896c619..9f41c69e 100644
--- a/core/embed/Cargo.toml
+++ b/core/embed/Cargo.toml
@@ -88,7 +88,7 @@ trezor-tjpgdec = { version = "0.1.0", path = "../../rust/trezor-tjpgdec" }
ufmt = "0.2.0"
unsize = "1.1.0"
without-alloc = "0.2.2"
-zeroize = { version = "1.8.2", default-features = false }
+zeroize = { version = "1.8.2", default-features = false, features = ["zeroize_derive"] }
models = { path = "models" }
rtl = { path = "rtl" }
diff --git a/core/embed/rust/Cargo.toml b/core/embed/rust/Cargo.toml
index c6e1d73f..d8498f22 100644
--- a/core/embed/rust/Cargo.toml
+++ b/core/embed/rust/Cargo.toml
@@ -7,7 +7,7 @@ build = "build.rs"
[features]
default = ["layout_bolt"]
-crypto = ["zeroize"]
+crypto = ["dep:zeroize"]
layout_bolt = []
layout_caesar = []
layout_delizia = []
@@ -114,10 +114,10 @@ trezor-tjpgdec.workspace = true
ufmt.workspace = true
unsize.workspace = true
without-alloc.workspace = true
-zeroize = { workspace = true, optional = true }
io = { workspace = true, optional = true }
upymod = { workspace = true, optional = true }
+zeroize = { workspace = true, optional = true }
[build-dependencies]
bindgen.workspace = true
diff --git a/core/embed/rust/src/crypto/curve25519.rs b/core/embed/rust/src/crypto/curve25519.rs
index 7185f927..27cea648 100644
--- a/core/embed/rust/src/crypto/curve25519.rs
+++ b/core/embed/rust/src/crypto/curve25519.rs
@@ -1,27 +1,17 @@
-use zeroize::Zeroize;
+use zeroize::{Zeroize, ZeroizeOnDrop};
use super::ffi;
+#[derive(Zeroize, ZeroizeOnDrop)]
pub struct Point {
bytes: [u8; 32],
}
-impl Drop for Point {
- fn drop(&mut self) {
- self.bytes.zeroize()
- }
-}
-
+#[derive(Zeroize, ZeroizeOnDrop)]
pub struct Scalar {
bytes: [u8; 32],
}
-impl Drop for Scalar {
- fn drop(&mut self) {
- self.bytes.zeroize()
- }
-}
-
impl Scalar {
pub fn from_bytes(bytes: [u8; 32]) -> Self {
let mut res = Self { bytes };
diff --git a/core/embed/rust/src/crypto/hmac.rs b/core/embed/rust/src/crypto/hmac.rs
index b47ee61d..1631de80 100644
--- a/core/embed/rust/src/crypto/hmac.rs
+++ b/core/embed/rust/src/crypto/hmac.rs
@@ -1,6 +1,6 @@
use core::pin::Pin;
-use zeroize::Zeroize as _;
+use zeroize::{Zeroize, ZeroizeOnDrop};
use super::{
ffi,
@@ -10,6 +10,7 @@ use super::{
pub const DIGEST_SIZE: usize = ffi::SHA256_DIGEST_LENGTH as usize;
pub type Digest = [u8; DIGEST_SIZE];
+#[derive(Zeroize, ZeroizeOnDrop)]
pub struct HmacSha256<'a> {
ctx: Pin<&'a mut Memory<ffi::HMAC_SHA256_CTX>>,
}
@@ -37,12 +38,6 @@ impl<'a> HmacSha256<'a> {
}
}
-impl Drop for HmacSha256<'_> {
- fn drop(&mut self) {
- self.ctx.zeroize();
- }
-}
-
pub fn digest_into(key: &[u8], data: &[u8], out: &mut Digest) {
init_ctx!(HmacSha256, ctx, key);
ctx.update(data);
diff --git a/core/embed/rust/src/crypto/sha256.rs b/core/embed/rust/src/crypto/sha256.rs
index 8b7bb695..9fb387d7 100644
--- a/core/embed/rust/src/crypto/sha256.rs
+++ b/core/embed/rust/src/crypto/sha256.rs
@@ -1,6 +1,6 @@
use core::pin::Pin;
-use zeroize::Zeroize as _;
+use zeroize::{Zeroize, ZeroizeOnDrop};
use super::{
ffi,
@@ -10,6 +10,7 @@ use super::{
pub const DIGEST_SIZE: usize = ffi::SHA256_DIGEST_LENGTH as usize;
pub type Digest = [u8; DIGEST_SIZE];
+#[derive(Zeroize, ZeroizeOnDrop)]
pub struct Sha256<'a> {
ctx: Pin<&'a mut Memory<ffi::SHA256_CTX>>,
}
@@ -37,12 +38,6 @@ impl<'a> Sha256<'a> {
}
}
-impl Drop for Sha256<'_> {
- fn drop(&mut self) {
- self.ctx.zeroize();
- }
-}
-
pub fn digest_into(data: &[u8], out: &mut Digest) {
init_ctx!(Sha256, ctx);
ctx.update(data);
diff --git a/core/embed/rust/src/crypto/sha512.rs b/core/embed/rust/src/crypto/sha512.rs
index 999ce017..b2b5522a 100644
--- a/core/embed/rust/src/crypto/sha512.rs
+++ b/core/embed/rust/src/crypto/sha512.rs
@@ -5,11 +5,12 @@ use super::{
memory::{init_ctx, Memory},
};
-use zeroize::Zeroize as _;
+use zeroize::{Zeroize, ZeroizeOnDrop};
pub const DIGEST_SIZE: usize = ffi::SHA512_DIGEST_LENGTH as usize;
pub type Digest = [u8; DIGEST_SIZE];
+#[derive(Zeroize, ZeroizeOnDrop)]
pub struct Sha512<'a> {
ctx: Pin<&'a mut Memory<ffi::SHA512_CTX>>,
}
@@ -38,12 +39,6 @@ impl<'a> Sha512<'a> {
}
}
-impl Drop for Sha512<'_> {
- fn drop(&mut self) {
- self.ctx.zeroize();
- }
-}
-
pub fn digest_into(data: &[u8], out: &mut Digest) {
init_ctx!(Sha512, ctx);
ctx.update(data);
Why this scored 18/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.