fix: use concat_kdf crate instead of hand rolled NIST SP 800-56A KDF (#7106)

This commit is contained in:
Dan Cline
2024-03-12 10:52:46 -04:00
committed by GitHub
parent 22d585df17
commit 99711550d8
3 changed files with 38 additions and 16 deletions

10
Cargo.lock generated
View File

@ -1373,6 +1373,15 @@ dependencies = [
"unicode-width",
]
[[package]]
name = "concat-kdf"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d72c1252426a83be2092dd5884a5f6e3b8e7180f6891b6263d2c21b92ec8816"
dependencies = [
"digest 0.10.7",
]
[[package]]
name = "concurrent-queue"
version = "2.4.0"
@ -5821,6 +5830,7 @@ dependencies = [
"block-padding",
"byteorder",
"cipher 0.4.4",
"concat-kdf",
"ctr 0.9.2",
"digest 0.10.7",
"educe",

View File

@ -35,6 +35,7 @@ rand.workspace = true
ctr = "0.9.2"
digest = "0.10.5"
secp256k1 = { workspace = true, features = ["global-context", "rand-std", "recovery"] }
concat-kdf = { version = "0.1.0" }
sha2 = "0.10.6"
sha3 = "0.10.5"
aes = "0.8.1"

View File

@ -36,23 +36,19 @@ fn ecdh_x(public_key: &PublicKey, secret_key: &SecretKey) -> B256 {
B256::from_slice(&secp256k1::ecdh::shared_secret_point(public_key, secret_key)[..32])
}
/// This is the NIST SP 800-56A Concatenation Key Derivation Function (KDF) using SHA-256.
///
/// Internally this uses [`concat_kdf::derive_key_into`] to derive a key into the given `dest`
/// slice.
///
/// # Panics
/// * If the `dest` is empty
/// * If `s1` is empty
/// * If the `dest` len is greater than or equal to the hash output len * the max counter value. In
/// this case, the hash output len is 32 bytes, and the max counter value is 2^32 - 1. So the dest
/// cannot have a len greater than 32 * 2^32 - 1.
fn kdf(secret: B256, s1: &[u8], dest: &mut [u8]) {
// SEC/ISO/Shoup specify counter size SHOULD be equivalent
// to size of hash output, however, it also notes that
// the 4 bytes is okay. NIST specifies 4 bytes.
let mut ctr = 1_u32;
let mut written = 0_usize;
while written < dest.len() {
let mut hasher = Sha256::default();
let ctrs = [(ctr >> 24) as u8, (ctr >> 16) as u8, (ctr >> 8) as u8, ctr as u8];
hasher.update(ctrs);
hasher.update(secret.as_slice());
hasher.update(s1);
let d = hasher.finalize();
dest[written..(written + 32)].copy_from_slice(&d);
written += 32;
ctr += 1;
}
concat_kdf::derive_key_into::<Sha256>(secret.as_slice(), s1, dest).unwrap();
}
#[derive(Educe)]
@ -778,4 +774,19 @@ mod tests {
test_client.read_ack(&mut ack2.to_vec()).unwrap();
test_client.read_ack(&mut ack3.to_vec()).unwrap();
}
#[test]
fn kdf_out_of_bounds() {
// ensures that the kdf method does not panic if the dest is too small
let len_range = 1..65;
for len in len_range {
let mut dest = vec![1u8; len];
kdf(
b256!("7000000000000000000000000000000000000000000000000000000000000007"),
&[0x01, 0x33, 0x70, 0xbe, 0xef],
&mut dest,
);
}
std::hint::black_box(());
}
}