bitbox-core-utils: make salt::hash_data return 32 bytes
What changed, and why it matters
This is a small internal code cleanup in the BitBox02 firmware. It changes a helper function that computes SHA-256 hashes so that it returns a fixed 32-byte array instead of a variable-length vector. The only effects are removing an unnecessary type conversion and making the code clearer. There is no security bug being fixed here.
No security action required. Treat as a normal code-quality refactor during review.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The commit refactors salt::hash_data() in bitbox-core-utils to return Box<Zeroizing<[u8; 32]>> instead of Zeroizing<Vec<u8>>. Because SHA-256 always produces 32 bytes, the previous vector return required callers to use try_into().unwrap() to get a fixed-size array. The new return type eliminates that conversion. Call sites in firmware_c_api.rs and keystore.rs are updated to use hash.as_slice() and pass the fixed array directly. The change is behaviorally equivalent: the same SHA-256 computation is performed and the same 32-byte output is produced.
Changed components
src/rust/bitbox-core-utils/src/salt.rssrc/rust/bitbox02-rust-c/src/firmware_c_api.rssrc/rust/bitbox02-rust/src/keystore.rsInspect captured patch +8 / −8
diff --git a/src/rust/bitbox-core-utils/src/salt.rs b/src/rust/bitbox-core-utils/src/salt.rs
index 76e48fb..81fae63 100644
--- a/src/rust/bitbox-core-utils/src/salt.rs
+++ b/src/rust/bitbox-core-utils/src/salt.rs
@@ -1,9 +1,9 @@
// SPDX-License-Identifier: Apache-2.0
-use alloc::vec::Vec;
+use alloc::boxed::Box;
use bitbox_hal::Memory;
-use sha2::Digest;
+use sha2::{Digest, digest::FixedOutput};
use zeroize::Zeroizing;
/// Creates `SHA256(salt_root || purpose || data)`, where `salt_root` is a persisted value that
@@ -15,15 +15,17 @@ pub fn hash_data(
memory: &mut impl Memory,
data: &[u8],
purpose: &str,
-) -> Result<Zeroizing<Vec<u8>>, ()> {
+) -> Result<Box<Zeroizing<[u8; 32]>>, ()> {
let salt_root = memory.get_salt_root()?;
+ let mut result = Box::new(Zeroizing::new([0u8; 32]));
let mut hasher = sha2::Sha256::new();
hasher.update(salt_root.as_slice());
hasher.update(purpose.as_bytes());
hasher.update(data);
- Ok(Zeroizing::new(hasher.finalize().to_vec()))
+ FixedOutput::finalize_into(hasher, result.as_mut_slice().into());
+ Ok(result)
}
#[cfg(test)]
diff --git a/src/rust/bitbox02-rust-c/src/firmware_c_api.rs b/src/rust/bitbox02-rust-c/src/firmware_c_api.rs
index e77e2b6..b89e3ef 100644
--- a/src/rust/bitbox02-rust-c/src/firmware_c_api.rs
+++ b/src/rust/bitbox02-rust-c/src/firmware_c_api.rs
@@ -38,7 +38,7 @@ pub unsafe extern "C" fn rust_salt_hash_data(
let mut hal = crate::HalImpl::new();
match bitbox_core_utils::salt::hash_data(hal.memory(), data.as_ref(), purpose_str) {
Ok(hash) => {
- hash_out.as_mut()[..32].copy_from_slice(&hash);
+ hash_out.as_mut()[..32].copy_from_slice(hash.as_slice());
true
}
Err(()) => false,
diff --git a/src/rust/bitbox02-rust/src/keystore.rs b/src/rust/bitbox02-rust/src/keystore.rs
index 8aecb9c..2b14e6c 100644
--- a/src/rust/bitbox02-rust/src/keystore.rs
+++ b/src/rust/bitbox02-rust/src/keystore.rs
@@ -697,9 +697,7 @@ pub fn stretch_retained_seed_encryption_key(
let salted_in = bitbox_core_utils::salt::hash_data(hal.memory(), encryption_key, purpose_in)
.map_err(|_| Error::Salt)?;
- let kdf = hal
- .securechip()
- .kdf(salted_in.as_slice().try_into().unwrap())?;
+ let kdf = hal.securechip().kdf(&salted_in)?;
let salted_out = bitbox_core_utils::salt::hash_data(hal.memory(), encryption_key, purpose_out)
.map_err(|_| Error::Salt)?;
Why this scored 15/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.