Skip to content

Commit 2e70026

Browse files
committed
Merge branch 'rust-u2f-seed'
2 parents bbfcbb7 + fa2791e commit 2e70026

File tree

6 files changed

+34
-43
lines changed

6 files changed

+34
-43
lines changed

src/keystore.c

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -532,21 +532,6 @@ bool keystore_secp256k1_sign(
532532
return true;
533533
}
534534

535-
bool keystore_get_u2f_seed(uint8_t* seed_out)
536-
{
537-
if (keystore_is_locked()) {
538-
return false;
539-
}
540-
uint8_t bip39_seed[64] = {0};
541-
UTIL_CLEANUP_64(bip39_seed);
542-
if (!keystore_copy_bip39_seed(bip39_seed)) {
543-
return false;
544-
}
545-
const uint8_t message[] = "u2f";
546-
rust_hmac_sha256(bip39_seed, 64, message, sizeof(message), seed_out);
547-
return true;
548-
}
549-
550535
#ifdef TESTING
551536
void keystore_mock_unlocked(const uint8_t* seed, size_t seed_len, const uint8_t* bip39_seed)
552537
{

src/keystore.h

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -179,13 +179,6 @@ USE_RESULT bool keystore_secp256k1_sign(
179179
uint8_t* sig_compact_out,
180180
int* recid_out);
181181

182-
/**
183-
* Get the seed to be used for u2f
184-
* @param seed_out Buffer for seed, must be KEYSTORE_U2F_SEED_LENGTH
185-
* @return true if succes
186-
*/
187-
USE_RESULT bool keystore_get_u2f_seed(uint8_t* seed_out);
188-
189182
#ifdef TESTING
190183
/**
191184
* convenience to mock the keystore state (locked, seed) in tests.

src/rust/bitbox02-rust/src/keystore.rs

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,9 @@ use bitbox02::keystore;
2323

2424
use util::bip32::HARDENED;
2525

26-
use crate::hash::Sha512;
2726
use crate::secp256k1::SECP256K1;
2827

29-
use hmac::{Mac, SimpleHmac, digest::FixedOutput};
28+
use bitcoin::hashes::{Hash, HashEngine, Hmac, HmacEngine, sha512};
3029

3130
/// Returns the keystore's seed encoded as a BIP-39 mnemonic.
3231
pub fn get_bip39_mnemonic() -> Result<zeroize::Zeroizing<String>, ()> {
@@ -138,12 +137,12 @@ pub fn root_fingerprint() -> Result<Vec<u8>, ()> {
138137

139138
fn bip85_entropy(keypath: &[u32]) -> Result<zeroize::Zeroizing<Vec<u8>>, ()> {
140139
let priv_key = secp256k1_get_private_key_twice(keypath)?;
141-
let mut mac = SimpleHmac::<Sha512>::new_from_slice(b"bip-entropy-from-k").unwrap();
142-
mac.update(&priv_key);
143-
let mut out = zeroize::Zeroizing::new(vec![0u8; 64]);
144-
let fixed_out: &mut [u8; 64] = out.as_mut_slice().try_into().unwrap();
145-
mac.finalize_into(fixed_out.into());
146-
Ok(out)
140+
141+
let mut engine = HmacEngine::<sha512::Hash>::new(b"bip-entropy-from-k");
142+
engine.input(&priv_key);
143+
Ok(zeroize::Zeroizing::new(
144+
Hmac::from_engine(engine).to_byte_array().to_vec(),
145+
))
147146
}
148147

149148
/// Computes a BIP39 mnemonic according to BIP-85:
@@ -224,6 +223,19 @@ pub fn secp256k1_schnorr_sign(
224223
Ok(sig.serialize())
225224
}
226225

226+
/// Get the seed to be used for u2f
227+
#[cfg(feature = "app-u2f")]
228+
pub fn get_u2f_seed() -> Result<zeroize::Zeroizing<Vec<u8>>, ()> {
229+
let bip39_seed = keystore::copy_bip39_seed()?;
230+
231+
let mut engine = HmacEngine::<bitcoin::hashes::sha256::Hash>::new(&bip39_seed);
232+
// Null-terminator for backwards compatibility from the time when this was coded in C.
233+
engine.input(b"u2f\0");
234+
Ok(zeroize::Zeroizing::new(
235+
Hmac::from_engine(engine).to_byte_array().to_vec(),
236+
))
237+
}
238+
227239
/// # Safety
228240
///
229241
/// keypath pointer has point to a buffer of length `keypath_len` uint32 elements.
@@ -243,6 +255,18 @@ pub unsafe extern "C" fn rust_secp256k1_get_private_key(
243255
}
244256
}
245257

258+
#[cfg(feature = "app-u2f")]
259+
#[unsafe(no_mangle)]
260+
pub extern "C" fn rust_keystore_get_u2f_seed(mut seed_out: util::bytes::BytesMut) -> bool {
261+
match get_u2f_seed() {
262+
Ok(seed) => {
263+
seed_out.as_mut().copy_from_slice(&seed);
264+
true
265+
}
266+
Err(_) => false,
267+
}
268+
}
269+
246270
#[cfg(test)]
247271
mod tests {
248272
use super::*;
@@ -584,7 +608,7 @@ mod tests {
584608
test.expected_xpub,
585609
);
586610
assert_eq!(
587-
hex::encode(keystore::get_u2f_seed().unwrap()),
611+
hex::encode(get_u2f_seed().unwrap()),
588612
test.expected_u2f_seed_hex,
589613
);
590614
}

src/rust/bitbox02-sys/build.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,6 @@ const ALLOWLIST_FNS: &[&str] = &[
7373
"keystore_create_and_store_seed",
7474
"keystore_encrypt_and_store_seed",
7575
"keystore_get_bip39_word",
76-
"keystore_get_u2f_seed",
7776
"keystore_is_locked",
7877
"keystore_lock",
7978
"keystore_mock_unlocked",

src/rust/bitbox02/src/keystore.rs

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -220,16 +220,6 @@ pub fn encrypt_and_store_seed(seed: &[u8], password: &str) -> Result<(), Error>
220220
}
221221
}
222222

223-
// Currently only used in the functional tests below.
224-
#[cfg(feature = "testing")]
225-
pub fn get_u2f_seed() -> Result<zeroize::Zeroizing<Vec<u8>>, ()> {
226-
let mut seed = zeroize::Zeroizing::new([0u8; 32].to_vec());
227-
match unsafe { bitbox02_sys::keystore_get_u2f_seed(seed.as_mut_ptr()) } {
228-
true => Ok(seed),
229-
false => Err(()),
230-
}
231-
}
232-
233223
#[cfg(test)]
234224
mod tests {
235225
use super::*;

src/u2f.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ USE_RESULT static bool _keyhandle_gen(
257257
uint8_t hmac_in[U2F_APPID_SIZE + U2F_NONCE_LENGTH];
258258
uint8_t seed[32];
259259
UTIL_CLEANUP_32(seed);
260-
if (!keystore_get_u2f_seed(seed)) {
260+
if (!rust_keystore_get_u2f_seed(rust_util_bytes_mut(seed, sizeof(seed)))) {
261261
return false;
262262
}
263263

0 commit comments

Comments
 (0)