What changed, and why it matters
This commit is a routine code cleanup in the BitBox02 hardware wallet firmware. It removes an old wrapper around a C-language SHA-512 function and switches the Rust code to use a pure-Rust SHA-512 implementation from the `bitcoin::hashes` library. It also removes an unused feature flag and simplifies dependencies. There is no direct evidence in the commit that this fixes a security vulnerability.
No immediate security action required. Treat as a normal refactoring commit. If auditing, verify that `bitcoin::hashes` SHA-512 and HMAC-SHA256 outputs match the previous implementations in unit tests, and confirm the removed `use-wally-sha512` feature is no longer referenced in build scripts or CI.
Security signals we found
Removal of C FFI wrapper for SHA-512
Migration to pure-Rust `bitcoin::hashes` SHA-512/HMAC-SHA256 implementations
Dependency simplification: dropping `sha2`, `hmac`, optional `bitbox02` from `bitbox-aes`
No new unsafe code, no input validation changes, no algorithm change
Evidence from the diff
The change removes wally_sha512 FFI remnants. bitbox02::sha512 is deleted because bitcoin::hashes::sha512::Hash::hash is already used internally. bitbox-aes drops its use-wally-sha512 Cargo feature and the sha2/hmac/bitbox02 dependencies, replacing sha2::Sha512 and hmac::SimpleHmac with bitcoin::hashes equivalents. bitbox02-rust/src/hash.rs updates its comment and implementation to reference bitcoin::hashes instead of the C wrapper. The diff is small (+15/-39) and contains no buffer-size changes, no new unsafe blocks, no cryptographic algorithm changes, and no privilege/authorization changes.
Changed components
src/rust/bitbox-aessrc/rust/bitbox02-rust/src/hash.rssrc/rust/bitbox02/src/lib.rsCargo.toml dependency graphs for bitbox-aes, bitbox02-rust, bitbox02-rust-cInspect captured patch +15 / −39
diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock
index 8db59b3..bf3d0a3 100644
--- a/src/rust/Cargo.lock
+++ b/src/rust/Cargo.lock
@@ -91,10 +91,8 @@ dependencies = [
name = "bitbox-aes"
version = "0.1.0"
dependencies = [
- "bitbox02",
+ "bitcoin",
"ctaes",
- "hmac",
- "sha2",
"zeroize",
]
diff --git a/src/rust/bitbox-aes/Cargo.toml b/src/rust/bitbox-aes/Cargo.toml
index 6fff269..ec368ee 100644
--- a/src/rust/bitbox-aes/Cargo.toml
+++ b/src/rust/bitbox-aes/Cargo.toml
@@ -20,16 +20,6 @@ edition = "2024"
license = "Apache-2.0"
[dependencies]
-bitbox02 = { path = "../bitbox02", optional = true }
-sha2 = { workspace = true }
-hmac = { version = "0.12", default-features = false, features = ["reset"] }
+bitcoin = { workspace = true }
ctaes = { version = "0.1.0" }
zeroize = { workspace = true }
-
-[features]
-# We use wally_sha512 over `sha2::Sha512`, which bloats the binary by an additional ~12.7kB (at the
-# time of writing). This should be enabled for production builds until we can get rid of
-# wally_sha512 completely. This feature exists so `cargo test` works.
-use-wally-sha512 = [
- "dep:bitbox02",
-]
diff --git a/src/rust/bitbox-aes/src/lib.rs b/src/rust/bitbox-aes/src/lib.rs
index 02d101e..1ed192a 100644
--- a/src/rust/bitbox-aes/src/lib.rs
+++ b/src/rust/bitbox-aes/src/lib.rs
@@ -19,8 +19,7 @@ extern crate alloc;
use alloc::vec::Vec;
-use hmac::{digest::FixedOutput, Mac, SimpleHmac};
-use sha2::Sha256;
+use bitcoin::hashes::{sha256, Hash, HashEngine, Hmac, HmacEngine};
// AES block size.
const BLOCK_SIZE: usize = 16;
@@ -78,21 +77,14 @@ fn decrypt(key: &[u8; 32], cipher: &[u8]) -> Result<zeroize::Zeroizing<Vec<u8>>,
}
fn sha512(buf: &[u8]) -> [u8; 64] {
- #[cfg(feature = "use-wally-sha512")]
- {
- bitbox02::sha512(buf)
- }
- #[cfg(not(feature = "use-wally-sha512"))]
- {
- use sha2::Digest;
- sha2::Sha512::digest(buf).into()
- }
+ bitcoin::hashes::sha512::Hash::hash(buf).to_byte_array()
}
fn hmac_sha256(key: &[u8], msg: &[u8]) -> [u8; 32] {
- let mut mac = SimpleHmac::<Sha256>::new_from_slice(key).unwrap();
- mac.update(msg);
- mac.finalize_fixed().into()
+ let mut engine = HmacEngine::<sha256::Hash>::new(key);
+ engine.input(msg);
+ let hmac_result: Hmac<sha256::Hash> = Hmac::from_engine(engine);
+ hmac_result.to_byte_array()
}
pub fn encrypt_with_hmac(iv: &[u8; 16], key: &[u8], plain: &[u8]) -> Vec<u8> {
diff --git a/src/rust/bitbox02-rust-c/Cargo.toml b/src/rust/bitbox02-rust-c/Cargo.toml
index 991071d..9c5f841 100644
--- a/src/rust/bitbox02-rust-c/Cargo.toml
+++ b/src/rust/bitbox02-rust-c/Cargo.toml
@@ -25,7 +25,7 @@ crate-type = ["staticlib"]
[dependencies]
bitbox02-rust = { path = "../bitbox02-rust", optional = true }
-bitbox-aes = { path = "../bitbox-aes", features = ["use-wally-sha512"] }
+bitbox-aes = { path = "../bitbox-aes" }
bitbox02 = { path = "../bitbox02", optional = true }
bitbox02-noise = { path = "../bitbox02-noise", optional = true }
util = { path = "../util" }
diff --git a/src/rust/bitbox02-rust/Cargo.toml b/src/rust/bitbox02-rust/Cargo.toml
index 17c6548..1cca60d 100644
--- a/src/rust/bitbox02-rust/Cargo.toml
+++ b/src/rust/bitbox02-rust/Cargo.toml
@@ -65,7 +65,7 @@ default-features = false
features = ["derive"]
[dev-dependencies]
-bitbox-aes = { path = "../bitbox-aes", features = ["use-wally-sha512"] }
+bitbox-aes = { path = "../bitbox-aes" }
[features]
ed25519 = [
diff --git a/src/rust/bitbox02-rust/src/hash.rs b/src/rust/bitbox02-rust/src/hash.rs
index 1ac4069..6a29e50 100644
--- a/src/rust/bitbox02-rust/src/hash.rs
+++ b/src/rust/bitbox02-rust/src/hash.rs
@@ -14,9 +14,9 @@
use alloc::vec::Vec;
-/// Implements the digest traits for Sha512 backing it with the wally_sha512 C function. This is
-/// done to avoid using a second sha512 implementation like `sha2::Sha512`, which bloats the binary
-/// by an additional ~12.7kB (at the time of writing).
+/// Implements the digest traits for Sha512 backing it with bitcoin::hashes. This is done to avoid
+/// using a second sha512 implementation like `sha2::Sha512`, which bloats the binary by an
+/// additional ~12.7kB (at the time of writing).
///
/// This implementation accumulates the data to be hashed in heap, it does **not** hash in a
/// streaming fashion, even when using `update()`.
@@ -35,7 +35,8 @@ impl digest::FixedOutput for Sha512 {
fn finalize_into(self, out: &mut digest::Output<Self>) {
// use digest::Digest;
// out.copy_from_slice(&sha2::Sha512::digest(&self.message));
- out.copy_from_slice(&bitbox02::sha512(&self.message));
+ use bitcoin::hashes::Hash;
+ out.copy_from_slice(bitcoin::hashes::sha512::Hash::hash(&self.message).as_byte_array())
}
}
diff --git a/src/rust/bitbox02/src/lib.rs b/src/rust/bitbox02/src/lib.rs
index 4684ddd..3cf3ba5 100644
--- a/src/rust/bitbox02/src/lib.rs
+++ b/src/rust/bitbox02/src/lib.rs
@@ -241,11 +241,6 @@ pub fn println_stdout(msg: &str) {
}
}
-pub fn sha512(msg: &[u8]) -> [u8; 64] {
- use bitcoin::hashes::Hash;
- bitcoin::hashes::sha512::Hash::hash(msg).to_byte_array()
-}
-
#[cfg(not(feature = "testing"))]
pub fn communication_mode_ble_enabled() -> bool {
unsafe { bitbox02_sys::communication_mode_ble_enabled() }
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.