hal/securechip: make kdf input 32 bytes
What changed, and why it matters
This commit is a routine code cleanup, not a security fix. It changes a key-derivation function so it only accepts exactly 32-byte inputs instead of any length up to 127 bytes. The function was already only ever called with 32-byte inputs, so behavior does not change. The stated reason is to make a later code rewrite easier.
No action required; treat as a refactoring commit. Continue normal review of the upcoming async port mentioned in the commit message.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch narrows the kdf trait method and all implementations from msg: &[u8] (previously documented as ‘at most 127 bytes’) to msg: &[u8; 32]. Call sites are updated to convert the existing 32-byte slice with try_into().unwrap(), and test vectors are regenerated for a 32-byte input. No runtime length validation logic is removed; the type system now enforces the length. The commit message frames this as preparation for an async port.
Changed components
hal/securechip trait and implementations (ATECC, Optiga, fake/host, BitBox02, BitBox03)keystore::stretch_retained_seed_encryption_key callerInspect captured patch +15 / −12
diff --git a/src/rust/bitbox-hal/src/securechip.rs b/src/rust/bitbox-hal/src/securechip.rs
index 13fdb4d..d778bb0 100644
--- a/src/rust/bitbox-hal/src/securechip.rs
+++ b/src/rust/bitbox-hal/src/securechip.rs
@@ -77,8 +77,8 @@ pub trait SecureChip {
///
/// This must not increment a monotonic counter.
///
- /// `msg` must be at most 127 bytes long.
- fn kdf(&mut self, msg: &[u8]) -> Result<zeroize::Zeroizing<Vec<u8>>, Error>;
+ /// `msg` must be 32 bytes long.
+ fn kdf(&mut self, msg: &[u8; 32]) -> Result<zeroize::Zeroizing<Vec<u8>>, Error>;
/// Signs a 32-byte attestation challenge and writes the raw 64-byte P-256 signature to
/// `signature`.
diff --git a/src/rust/bitbox-platform-host/src/securechip.rs b/src/rust/bitbox-platform-host/src/securechip.rs
index 8d6dfe9..4880a25 100644
--- a/src/rust/bitbox-platform-host/src/securechip.rs
+++ b/src/rust/bitbox-platform-host/src/securechip.rs
@@ -119,7 +119,7 @@ impl bitbox_hal::SecureChip for FakeSecureChip {
))
}
- fn kdf(&mut self, msg: &[u8]) -> Result<zeroize::Zeroizing<Vec<u8>>, Error> {
+ fn kdf(&mut self, msg: &[u8; 32]) -> Result<zeroize::Zeroizing<Vec<u8>>, Error> {
self.event_counter += 1;
use bitcoin::hashes::{HashEngine, Hmac, HmacEngine, sha256};
diff --git a/src/rust/bitbox-securechip/src/atecc.rs b/src/rust/bitbox-securechip/src/atecc.rs
index e0f1f89..e2dc022 100644
--- a/src/rust/bitbox-securechip/src/atecc.rs
+++ b/src/rust/bitbox-securechip/src/atecc.rs
@@ -79,7 +79,7 @@ pub fn stretch_password(
}
}
-pub fn kdf(msg: &[u8]) -> Result<Zeroizing<Vec<u8>>, Error> {
+pub fn kdf(msg: &[u8; 32]) -> Result<Zeroizing<Vec<u8>>, Error> {
let mut result = Zeroizing::new(vec![0u8; 32]);
let status =
unsafe { bitbox_securechip_sys::atecc_kdf(msg.as_ptr(), msg.len(), result.as_mut_ptr()) };
diff --git a/src/rust/bitbox-securechip/src/optiga.rs b/src/rust/bitbox-securechip/src/optiga.rs
index 50a6974..7acf575 100644
--- a/src/rust/bitbox-securechip/src/optiga.rs
+++ b/src/rust/bitbox-securechip/src/optiga.rs
@@ -88,7 +88,7 @@ pub fn stretch_password(
}
}
-pub fn kdf(msg: &[u8]) -> Result<Zeroizing<Vec<u8>>, Error> {
+pub fn kdf(msg: &[u8; 32]) -> Result<Zeroizing<Vec<u8>>, Error> {
let mut result = Zeroizing::new(vec![0u8; 32]);
let status = unsafe {
bitbox_securechip_sys::optiga_kdf_external(msg.as_ptr(), msg.len(), result.as_mut_ptr())
diff --git a/src/rust/bitbox02-rust/src/keystore.rs b/src/rust/bitbox02-rust/src/keystore.rs
index b4bad8d..8aecb9c 100644
--- a/src/rust/bitbox02-rust/src/keystore.rs
+++ b/src/rust/bitbox02-rust/src/keystore.rs
@@ -697,7 +697,9 @@ 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())?;
+ let kdf = hal
+ .securechip()
+ .kdf(salted_in.as_slice().try_into().unwrap())?;
let salted_out = bitbox_core_utils::salt::hash_data(hal.memory(), encryption_key, purpose_out)
.map_err(|_| Error::Salt)?;
diff --git a/src/rust/bitbox02/src/hal/securechip.rs b/src/rust/bitbox02/src/hal/securechip.rs
index 286e2f3..b2a7ece 100644
--- a/src/rust/bitbox02/src/hal/securechip.rs
+++ b/src/rust/bitbox02/src/hal/securechip.rs
@@ -105,7 +105,7 @@ impl SecureChip for BitBox02SecureChip {
.map_err(to_hal_error)
}
- fn kdf(&mut self, msg: &[u8]) -> Result<zeroize::Zeroizing<Vec<u8>>, Error> {
+ fn kdf(&mut self, msg: &[u8; 32]) -> Result<zeroize::Zeroizing<Vec<u8>>, Error> {
crate::securechip::kdf(msg).map_err(to_hal_error)
}
@@ -259,8 +259,9 @@ mod tests {
#[test]
fn test_kdf() {
let mut securechip = BitBox02SecureChip;
- let result = securechip.kdf(b"stub input").unwrap();
- let expected = hex!("3d7caa0407f18f6b15a6202843c883f326d614996df67940af210d91aff5b9c8");
+ let msg = [0u8; 32];
+ let result = securechip.kdf(&msg).unwrap();
+ let expected = hex!("1c723ccd9597e76deb55f9fd6808014007bcb3d67fc060f1149aefb9be88f423");
assert_eq!(result.as_slice(), expected.as_slice());
}
diff --git a/src/rust/bitbox02/src/securechip/imp.rs b/src/rust/bitbox02/src/securechip/imp.rs
index 3795d25..f1aba91 100644
--- a/src/rust/bitbox02/src/securechip/imp.rs
+++ b/src/rust/bitbox02/src/securechip/imp.rs
@@ -68,7 +68,7 @@ pub fn stretch_password(
/// Perform the secure chip KDF with the message in `msg` and return the zeroizing 32-byte
/// result.
-pub fn kdf(msg: &[u8]) -> Result<Zeroizing<Vec<u8>>, Error> {
+pub fn kdf(msg: &[u8; 32]) -> Result<Zeroizing<Vec<u8>>, Error> {
match backend() {
Backend::Atecc => atecc::kdf(msg),
Backend::Optiga => optiga::kdf(msg),
diff --git a/src/rust/bitbox02/src/securechip/imp_fake.rs b/src/rust/bitbox02/src/securechip/imp_fake.rs
index 3d3d062..24962e9 100644
--- a/src/rust/bitbox02/src/securechip/imp_fake.rs
+++ b/src/rust/bitbox02/src/securechip/imp_fake.rs
@@ -65,7 +65,7 @@ pub fn stretch_password(
/// Perform the secure chip KDF with the message in `msg` and return the zeroizing 32-byte
/// result.
-pub fn kdf(msg: &[u8]) -> Result<Zeroizing<Vec<u8>>, Error> {
+pub fn kdf(msg: &[u8; 32]) -> Result<Zeroizing<Vec<u8>>, Error> {
Ok(Zeroizing::new(hmac_sha256(&KDF_KEY, msg).to_vec()))
}
diff --git a/src/rust/bitbox03/src/securechip.rs b/src/rust/bitbox03/src/securechip.rs
index 9ccf5ae..22a79f5 100644
--- a/src/rust/bitbox03/src/securechip.rs
+++ b/src/rust/bitbox03/src/securechip.rs
@@ -28,7 +28,7 @@ impl hal::securechip::SecureChip for BitBox03SecureChip {
fn kdf(
&mut self,
- _msg: &[u8],
+ _msg: &[u8; 32],
) -> Result<zeroize::Zeroizing<alloc::vec::Vec<u8>>, bitbox_hal::securechip::Error> {
todo!()
}
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.