From cb8284c801b30e1f5dc94c02cd6056354d0fd1ee Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Fri, 27 Oct 2023 21:49:30 -0700 Subject: [PATCH 1/6] Initial commit for KBKDF --- Cargo.lock | 17 ++ Cargo.toml | 3 +- kbkdf/Cargo.toml | 29 ++++ kbkdf/src/lib.rs | 384 ++++++++++++++++++++++++++++++++++++++++++++ kbkdf/src/sealed.rs | 13 ++ 5 files changed, 445 insertions(+), 1 deletion(-) create mode 100644 kbkdf/Cargo.toml create mode 100644 kbkdf/src/lib.rs create mode 100644 kbkdf/src/sealed.rs diff --git a/Cargo.lock b/Cargo.lock index 1d81c45..6cac293 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -62,6 +62,12 @@ dependencies = [ "subtle", ] +[[package]] +name = "divrem" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69dde51e8fef5e12c1d65e0929b03d66e4c0c18282bc30ed2ca050ad6f44dd82" + [[package]] name = "generic-array" version = "0.14.7" @@ -117,6 +123,17 @@ dependencies = [ "digest", ] +[[package]] +name = "kbkdf" +version = "0.1.0" +dependencies = [ + "digest", + "divrem", + "hex-literal 0.2.2", + "hmac", + "sha2", +] + [[package]] name = "libc" version = "0.2.148" diff --git a/Cargo.toml b/Cargo.toml index f310c26..028fd91 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,8 @@ [workspace] members = [ - "hkdf", "concat-kdf", + "hkdf", + "kbkdf", ] [profile.dev] diff --git a/kbkdf/Cargo.toml b/kbkdf/Cargo.toml new file mode 100644 index 0000000..e4c2b4a --- /dev/null +++ b/kbkdf/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "kbkdf" +version = "0.1.0" +edition = "2018" +authors = ["RustCrypto Developers"] +license = "MIT OR Apache-2.0" +homepage = "https://github.com/RustCrypto/KDFs/" +repository = "https://github.com/RustCrypto/KDFs/" +description = "HMAC-based Extract-and-Expand Key Derivation Function (HKDF)" +keywords = ["crypto", "HKDF", "KDF"] +categories = ["cryptography", "no-std"] +readme = "README.md" + +[dependencies] +digest = "0.10" +hmac = "0.12.1" +# divrem can be dropped with MSRV >= 1.73 +divrem = "1.0.0" + +[dev-dependencies] +hex-literal = "0.2.2" +sha2 = "0.10" + +[features] +std = ["hmac/std"] + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] diff --git a/kbkdf/src/lib.rs b/kbkdf/src/lib.rs new file mode 100644 index 0000000..e805e8e --- /dev/null +++ b/kbkdf/src/lib.rs @@ -0,0 +1,384 @@ +//! An implementation of KBKDF, the (Key Based Key Derivation Function. +//! +//! This function is described in section 4 of [NIST SP 800-108r1, Recommendation +//! for Key Derivation Using Pseudorandom Functions][1] +//! +//! [1]: https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-108r1.pdf + +#![no_std] +#![cfg_attr(docsrs, feature(doc_cfg))] +#![recursion_limit = "128"] + +#[cfg(feature = "std")] +extern crate std; + +use core::{fmt, marker::PhantomData, num::Wrapping, ops::Mul}; +use digest::{ + consts::{U32, U8}, + crypto_common::KeySizeUser, + generic_array::{typenum::Unsigned, ArrayLength, GenericArray}, + typenum::op, + KeyInit, Mac, +}; +use divrem::DivCeil; + +mod sealed; + +#[derive(Debug, PartialEq)] +pub enum Error { + // TODO(baloo): we can probably move that to a compilation error via use of typenum + InvalidRequestSize, +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Error::InvalidRequestSize => write!( + f, + "Request output size is too large for the value of R specified" + ), + } + } +} + +#[cfg(feature = "std")] +mod std_error { + use super::Error; + use std::error; + + impl error::Error for Error {} +} + +// Helper structure along with [`KbkdfUser`] to compute values of L and H. +struct KbkdfCore { + _marker: PhantomData<(OutputLen, PrfOutputLen)>, +} + +trait KbkdfUser { + // L - An integer specifying the requested length (in bits) of the derived keying material + // KOUT. L is represented as a bit string when it is an input to a key-derivation function. The + // length of the bit string is specified by the encoding method for the input data. + type L; + + // h - An integer that indicates the length (in bits) of the output of a single invocation of the + // PRF. + type H; +} + +impl KbkdfUser for KbkdfCore +where + OutputLen: ArrayLength + Mul, + >::Output: Unsigned, + PrfOutputLen: ArrayLength + Mul, + >::Output: Unsigned, +{ + type L = op!(OutputLen * U8); + type H = op!(PrfOutputLen * U8); +} + +/// [`Kbkdf`] is a trait representing a mode of KBKDF. +/// It takes multiple arguments: +/// - Prf - the Pseudorandom Function to derive keys from +/// - K - the expected output length of the newly derived key +/// - R - An integer (1 <= r <= 32) that indicates the length of the binary encoding of the counter i +/// as an integer in the interval [1, 2r − 1]. +pub trait Kbkdf +where + Prf: Mac + KeyInit, + K: KeySizeUser, + K::KeySize: ArrayLength + Mul, + >::Output: Unsigned, + Prf::OutputSize: ArrayLength + Mul, + >::Output: Unsigned, +{ + /// Derives `key` from `kin` and other parameters. + fn derive( + &self, + kin: &GenericArray, + use_l: bool, + use_separator: bool, + label: &[u8], + context: &[u8], + ) -> Result, Error> { + // n - An integer whose value is the number of iterations of the PRF needed to generate L + // bits of keying material + let n: u32 = Wrapping( as KbkdfUser>::L::U32) + .div_ceil(Wrapping( + as KbkdfUser>::H::U32, + )) + .0; + + if n as usize > 2usize.pow(R::U32) - 1 { + return Err(Error::InvalidRequestSize); + } + + let mut output = GenericArray::::default(); + let mut builder = output.as_mut_slice(); + + let mut ki = None; + self.input_iv(&mut ki); + + for counter in 1..=n { + let mut h = ::new(kin); + + if Self::FEEDBACK_KI { + if let Some(ki) = ki { + h.update(ki.as_slice()); + } + } + + // counter encoded as big endian u32 + // Type parameter R encodes how large the value is to be (either U8, U16, U24, or U32) + // + // counter = 1u32 ([0, 0, 0, 1]) + // \-------/ + // R = u24 + h.update(&counter.to_be_bytes()[(4 - R::USIZE / 8)..]); + + // Fixed input data + h.update(label); + if use_separator { + h.update(&[0]); + } + h.update(context); + if use_l { + h.update( + &( as KbkdfUser>::L::U32).to_be_bytes() + [..], + ); + } + + let buf = h.finalize().into_bytes(); + ki = Some(buf.clone()); + + let remaining = usize::min(buf.len(), builder.len()); + + builder[..remaining].copy_from_slice(&buf[..remaining]); + builder = &mut builder[remaining..]; + } + + assert_eq!(builder.len(), 0, "output has uninitialized bytes"); + + Ok(output) + } + + /// Input the IV in the PRF + fn input_iv(&self, _ki: &mut Option>) {} + + /// Whether the KI should be reinjected every round. + const FEEDBACK_KI: bool = false; +} + +pub struct Counter { + _marker: PhantomData<(Prf, K, R)>, +} + +impl Default for Counter { + fn default() -> Self { + Self { + _marker: PhantomData, + } + } +} + +impl Kbkdf for Counter +where + Prf: Mac + KeyInit, + K: KeySizeUser, + K::KeySize: ArrayLength + Mul, + >::Output: Unsigned, + Prf::OutputSize: ArrayLength + Mul, + >::Output: Unsigned, + R: sealed::R, +{ +} + +pub struct Feedback<'a, Prf, K, R = U32> +where + Prf: Mac, +{ + iv: Option<&'a GenericArray>, + _marker: PhantomData<(Prf, K, R)>, +} + +impl<'a, Prf, K, R> Feedback<'a, Prf, K, R> +where + Prf: Mac, +{ + pub fn new(iv: Option<&'a GenericArray>) -> Self { + Self { + iv, + _marker: PhantomData, + } + } +} + +impl<'a, Prf, K, R> Kbkdf for Feedback<'a, Prf, K, R> +where + Prf: Mac + KeyInit, + K: KeySizeUser, + K::KeySize: ArrayLength + Mul, + >::Output: Unsigned, + Prf::OutputSize: ArrayLength + Mul, + >::Output: Unsigned, + R: sealed::R, +{ + fn input_iv(&self, ki: &mut Option>) { + if let Some(iv) = self.iv { + *ki = Some(iv.clone()) + } + } + + const FEEDBACK_KI: bool = true; +} + +#[cfg(test)] +mod tests { + use super::{Counter, Feedback, GenericArray, Kbkdf}; + use digest::consts::*; + use hex_literal::hex; + + #[derive(Debug)] + struct KnownValue { + key: &'static [u8], + iv: Option<&'static [u8]>, + use_l: bool, + label: &'static [u8], + context: &'static [u8], + use_separator: bool, + expected: &'static [u8], + } + + static KNOWN_VALUES_COUNTER_HMAC_SHA256: &[KnownValue] = &[ + KnownValue { + iv: None, + use_l: false, + use_separator: false, + label: &[], + context: &[], + key: &hex!( + " + 241C3FBAABEDE87601B1C778B24F9A32 742A14FE34DA61D77E8352EF9D6C7FC8 + E335E32344E21D7DC0CD627D7E2FF973 992611F372C5D3DD91C100F2C6DB2CAF + " + ), + expected: &hex!( + " + 0FBF4313B2F1AF1F98C9763FE7F816CD 6464234F7C524F0C4ACDF66F287B01EB + 82D3A90CEF26EE996EE4F0295FA7FA36 1E2E85DC710A236974E1ABBC342F4E23 + D9A8F6B1ADC4C48332C5ED88C42FDCFB BA34CF70F1EA599908FBE35E2C121E0D + BFD94D45C70FC9D9CCB899E439D21F88 D3924EF5EC8613E5C386DE7B22427FC4 + " + ), + }, + KnownValue { + iv: None, + use_l: true, + use_separator: true, + label: &[0x22, 0x33], + context: &[0x0, 0x11], + key: &hex!( + " + 241C3FBAABEDE87601B1C778B24F9A32 742A14FE34DA61D77E8352EF9D6C7FC8 + E335E32344E21D7DC0CD627D7E2FF973 992611F372C5D3DD91C100F2C6DB2CAF + " + ), + expected: &hex!( + " + 7F21415C8ED32102BE3C284E970B3DF4 5FCE9F7464FC6616ED59AC1F1ECA0565 + 8E2868C57974293A79D49B576C4083C3 48AD07508E8A673D0F6B496ED444E0DE + 80AE1F146F8C2CBFE09F1D04516338DE 9E5284236FE29CB2D71A183B7573DFE7 + 0A8321ADAAF6FC2EDC73C228289948DD 3230D56E7A9103E2736957B326ACE921 + " + ), + }, + ]; + + static KNOWN_VALUES_FEEDBACK_HMAC_SHA256: &[KnownValue] = &[ + KnownValue { + iv: Some(b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), + use_l: true, + use_separator: true, + label: &[0x22, 0x33], + context: &[0x0, 0x11], + key: &hex!( + " + 241C3FBAABEDE87601B1C778B24F9A32 742A14FE34DA61D77E8352EF9D6C7FC8 + E335E32344E21D7DC0CD627D7E2FF973 992611F372C5D3DD91C100F2C6DB2CAF + " + ), + expected: &hex!( + " + C8C8E79188DB5732B52F81111E2982BD 479865EF98E90A823926BC0EA1EB173B + 21CA03B80228A6A1E27BE64DA382F1B7 ADFF97CF43598AF2435827B2F6E78DD5 + F9CBCC4948775451AD2BD44A9DBE2EE4 6FA5A73463E10142A3A1228183B45BC8 + D3831AA13EED6F94E8F221FACBC80F8B D19BDF06EC82DE7AE0FE0EE37CA51FF2 + " + ), + }, + KnownValue { + iv: None, + use_l: true, + use_separator: true, + label: &[0x22, 0x33], + context: &[0x0, 0x11], + key: &hex!( + " + 241C3FBAABEDE87601B1C778B24F9A32 742A14FE34DA61D77E8352EF9D6C7FC8 + E335E32344E21D7DC0CD627D7E2FF973 992611F372C5D3DD91C100F2C6DB2CAF + " + ), + expected: &hex!( + " + 7F21415C8ED32102BE3C284E970B3DF4 5FCE9F7464FC6616ED59AC1F1ECA0565 + B0BDCC163BF8119490B0B82715FF3EF1 B52DF9A81BC836BA6FC5168C08CE837B + 0CB7C18D1C47459DF6A05C16C140109E 8FC15D0EC9541FC41E127EBBDBC48CDE + 93E8909855F9070E9B709A497D31A825 3E3CB4EEB1C18586277B2F76E4BF9FF0 + " + ), + }, + ]; + + #[test] + fn test_static_values_counter() { + type HmacSha256 = hmac::Hmac; + type HmacSha512 = hmac::Hmac; + + let counter = Counter::::default(); + for (v, i) in KNOWN_VALUES_COUNTER_HMAC_SHA256.iter().zip(0..) { + assert_eq!( + counter.derive( + GenericArray::from_slice(v.key), + v.use_l, + v.use_separator, + v.label, + v.context, + ), + Ok(GenericArray::<_, U128>::from_slice(v.expected).clone()), + "key derivation failed for (index: {i}):\n{v:x?}" + ); + } + } + + #[test] + fn test_static_values_feedback() { + type HmacSha256 = hmac::Hmac; + type HmacSha512 = hmac::Hmac; + + for (v, i) in KNOWN_VALUES_FEEDBACK_HMAC_SHA256.iter().zip(0..) { + let feedback = + Feedback::::new(v.iv.map(GenericArray::from_slice)); + assert_eq!( + feedback.derive( + GenericArray::from_slice(v.key), + v.use_l, + v.use_separator, + v.label, + v.context, + ), + Ok(GenericArray::<_, U128>::from_slice(v.expected).clone()), + "key derivation failed for (index: {i}):\n{v:x?}" + ); + } + } +} diff --git a/kbkdf/src/sealed.rs b/kbkdf/src/sealed.rs new file mode 100644 index 0000000..afa8213 --- /dev/null +++ b/kbkdf/src/sealed.rs @@ -0,0 +1,13 @@ + use digest::{ + consts::{U16, U24, U32, U8}, + generic_array::typenum::Unsigned, + }; + + /// Marker used to register valid values for R in the KBKDF + pub trait R: Unsigned {} + + impl R for U8 {} + impl R for U16 {} + impl R for U24 {} + impl R for U32 {} + From 0a994890554c1e5604066e21af540fbe3a516919 Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Sun, 29 Oct 2023 14:31:56 -0700 Subject: [PATCH 2/6] cleanup --- kbkdf/src/lib.rs | 3 +-- kbkdf/src/sealed.rs | 21 ++++++++++----------- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/kbkdf/src/lib.rs b/kbkdf/src/lib.rs index e805e8e..026681a 100644 --- a/kbkdf/src/lib.rs +++ b/kbkdf/src/lib.rs @@ -7,7 +7,6 @@ #![no_std] #![cfg_attr(docsrs, feature(doc_cfg))] -#![recursion_limit = "128"] #[cfg(feature = "std")] extern crate std; @@ -82,7 +81,7 @@ where /// - K - the expected output length of the newly derived key /// - R - An integer (1 <= r <= 32) that indicates the length of the binary encoding of the counter i /// as an integer in the interval [1, 2r − 1]. -pub trait Kbkdf +pub trait Kbkdf where Prf: Mac + KeyInit, K: KeySizeUser, diff --git a/kbkdf/src/sealed.rs b/kbkdf/src/sealed.rs index afa8213..da2167b 100644 --- a/kbkdf/src/sealed.rs +++ b/kbkdf/src/sealed.rs @@ -1,13 +1,12 @@ - use digest::{ - consts::{U16, U24, U32, U8}, - generic_array::typenum::Unsigned, - }; +use digest::{ + consts::{U16, U24, U32, U8}, + generic_array::typenum::Unsigned, +}; - /// Marker used to register valid values for R in the KBKDF - pub trait R: Unsigned {} - - impl R for U8 {} - impl R for U16 {} - impl R for U24 {} - impl R for U32 {} +/// Marker used to register valid values for R in the KBKDF +pub trait R: Unsigned {} +impl R for U8 {} +impl R for U16 {} +impl R for U24 {} +impl R for U32 {} From 83e5d576657db728f8294766715100c18f7d2b66 Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Sun, 29 Oct 2023 14:33:54 -0700 Subject: [PATCH 3/6] add CI --- .github/workflows/kbkdf.yml | 60 +++++++++++++++++++++++++++++++++++++ kbkdf/Cargo.toml | 1 + 2 files changed, 61 insertions(+) create mode 100644 .github/workflows/kbkdf.yml diff --git a/.github/workflows/kbkdf.yml b/.github/workflows/kbkdf.yml new file mode 100644 index 0000000..4f2f1c9 --- /dev/null +++ b/.github/workflows/kbkdf.yml @@ -0,0 +1,60 @@ +name: kbkdf + +on: + pull_request: + paths: + - "kbkdf/**" + - "Cargo.*" + push: + branches: master + +defaults: + run: + working-directory: kbkdf + +env: + CARGO_INCREMENTAL: 0 + RUSTFLAGS: "-Dwarnings" + +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + rust: + - 1.65.0 # MSRV + - stable + target: + - thumbv7em-none-eabi + - wasm32-unknown-unknown + steps: + - uses: actions/checkout@v4 + - uses: RustCrypto/actions/cargo-cache@master + - uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ matrix.rust }} + targets: ${{ matrix.target }} + - run: cargo build --no-default-features --target ${{ matrix.target }} + + minimal-versions: + uses: RustCrypto/actions/.github/workflows/minimal-versions.yml@master + with: + working-directory: ${{ github.workflow }} + + test: + runs-on: ubuntu-latest + strategy: + matrix: + rust: + - 1.65.0 # MSRV + - stable + steps: + - uses: actions/checkout@v4 + - uses: RustCrypto/actions/cargo-cache@master + - uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ matrix.rust }} + - run: cargo check --all-features + - run: cargo test --no-default-features + - run: cargo test + - run: cargo test --all-features diff --git a/kbkdf/Cargo.toml b/kbkdf/Cargo.toml index e4c2b4a..8e86d05 100644 --- a/kbkdf/Cargo.toml +++ b/kbkdf/Cargo.toml @@ -10,6 +10,7 @@ description = "HMAC-based Extract-and-Expand Key Derivation Function (HKDF)" keywords = ["crypto", "HKDF", "KDF"] categories = ["cryptography", "no-std"] readme = "README.md" +rust-version = "1.65" [dependencies] digest = "0.10" From 013eec6c66dfead093c9b14bc4ed5ef48bdafb57 Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Sun, 29 Oct 2023 14:38:32 -0700 Subject: [PATCH 4/6] cleanup --- kbkdf/Cargo.toml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/kbkdf/Cargo.toml b/kbkdf/Cargo.toml index 8e86d05..9b77eb2 100644 --- a/kbkdf/Cargo.toml +++ b/kbkdf/Cargo.toml @@ -13,14 +13,15 @@ readme = "README.md" rust-version = "1.65" [dependencies] -digest = "0.10" -hmac = "0.12.1" +digest = { version = "0.10", default-features = false, features = ["mac"] } + # divrem can be dropped with MSRV >= 1.73 divrem = "1.0.0" [dev-dependencies] hex-literal = "0.2.2" -sha2 = "0.10" +hmac = { version = "0.12.1", default-features = false } +sha2 = { version = "0.10", default-features = false } [features] std = ["hmac/std"] From 9df77b415f121a6ef70a2e90633c8100cc1da9b4 Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Sun, 29 Oct 2023 22:46:48 -0700 Subject: [PATCH 5/6] double-pipeline support --- kbkdf/src/lib.rs | 169 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 134 insertions(+), 35 deletions(-) diff --git a/kbkdf/src/lib.rs b/kbkdf/src/lib.rs index 026681a..d055dc5 100644 --- a/kbkdf/src/lib.rs +++ b/kbkdf/src/lib.rs @@ -93,7 +93,8 @@ where /// Derives `key` from `kin` and other parameters. fn derive( &self, - kin: &GenericArray, + //kin: &GenericArray, + kin: &[u8], use_l: bool, use_separator: bool, label: &[u8], @@ -116,9 +117,24 @@ where let mut ki = None; self.input_iv(&mut ki); + let mut a = { + let mut h = ::new_from_slice(kin).unwrap(); + h.update(label); + h.update(&[0]); + h.update(context); + h.finalize().into_bytes() + }; for counter in 1..=n { - let mut h = ::new(kin); + if counter > 1 { + a = { + let mut h = ::new_from_slice(kin).unwrap(); + h.update(a.as_slice()); + h.finalize().into_bytes() + }; + } + + let mut h = ::new_from_slice(kin).unwrap(); if Self::FEEDBACK_KI { if let Some(ki) = ki { @@ -126,13 +142,17 @@ where } } - // counter encoded as big endian u32 - // Type parameter R encodes how large the value is to be (either U8, U16, U24, or U32) - // - // counter = 1u32 ([0, 0, 0, 1]) - // \-------/ - // R = u24 - h.update(&counter.to_be_bytes()[(4 - R::USIZE / 8)..]); + if Self::DOUBLE_PIPELINE { + h.update(a.as_slice()); + } else { + // counter encoded as big endian u32 + // Type parameter R encodes how large the value is to be (either U8, U16, U24, or U32) + // + // counter = 1u32 ([0, 0, 0, 1]) + // \-------/ + // R = u24 + h.update(&counter.to_be_bytes()[(4 - R::USIZE / 8)..]); + } // Fixed input data h.update(label); @@ -166,6 +186,8 @@ where /// Whether the KI should be reinjected every round. const FEEDBACK_KI: bool = false; + + const DOUBLE_PIPELINE: bool = false; } pub struct Counter { @@ -231,10 +253,41 @@ where const FEEDBACK_KI: bool = true; } +pub struct DoublePipeline +where + Prf: Mac, +{ + _marker: PhantomData<(Prf, K, R)>, +} + +impl Default for DoublePipeline +where + Prf: Mac, +{ + fn default() -> Self { + Self { + _marker: PhantomData, + } + } +} + +impl Kbkdf for DoublePipeline +where + Prf: Mac + KeyInit, + K: KeySizeUser, + K::KeySize: ArrayLength + Mul, + >::Output: Unsigned, + Prf::OutputSize: ArrayLength + Mul, + >::Output: Unsigned, + R: sealed::R, +{ + const DOUBLE_PIPELINE: bool = true; +} + #[cfg(test)] mod tests { - use super::{Counter, Feedback, GenericArray, Kbkdf}; - use digest::consts::*; + use super::{Counter, DoublePipeline, Feedback, GenericArray, Kbkdf}; + use digest::{consts::*, crypto_common::KeySizeUser}; use hex_literal::hex; #[derive(Debug)] @@ -293,6 +346,44 @@ mod tests { }, ]; + #[test] + fn test_static_values_counter() { + type HmacSha256 = hmac::Hmac; + type HmacSha512 = hmac::Hmac; + + let counter = Counter::::default(); + for (v, i) in KNOWN_VALUES_COUNTER_HMAC_SHA256.iter().zip(0..) { + assert_eq!( + counter.derive(v.key, v.use_l, v.use_separator, v.label, v.context,), + Ok(GenericArray::<_, _>::from_slice(v.expected).clone()), + "key derivation failed for (index: {i}):\n{v:x?}" + ); + } + } + + #[test] + fn test_counter_kbkdfvs() { + type HmacSha256 = hmac::Hmac; + struct MockOutput; + + impl KeySizeUser for MockOutput { + type KeySize = U32; + } + + let counter = Counter::::default(); + // KDFCTR_gen.txt count 15 + assert_eq!( + counter.derive( + &hex!("43eef6d824fd820405626ab9b6d79f1fd04e126ab8e17729e3afc7cb5af794f8"), + false, + false, + &hex!("5e269b5a7bdedcc3e875e2725693a257fc60011af7dcd68a3358507fe29b0659ca66951daa05a15032033650bc58a27840f8fbe9f4088b9030738f68"), + &[], + ), + Ok(GenericArray::<_, _>::from_slice(&hex!("f0a339ecbcae6add1afb27da3ba40a1320c6427a58afb9dc366b219b7eb29ecf")).clone()), + ); + } + static KNOWN_VALUES_FEEDBACK_HMAC_SHA256: &[KnownValue] = &[ KnownValue { iv: Some(b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), @@ -339,43 +430,51 @@ mod tests { ]; #[test] - fn test_static_values_counter() { + fn test_static_values_feedback() { type HmacSha256 = hmac::Hmac; type HmacSha512 = hmac::Hmac; - let counter = Counter::::default(); - for (v, i) in KNOWN_VALUES_COUNTER_HMAC_SHA256.iter().zip(0..) { + for (v, i) in KNOWN_VALUES_FEEDBACK_HMAC_SHA256.iter().zip(0..) { + let feedback = + Feedback::::new(v.iv.map(GenericArray::from_slice)); assert_eq!( - counter.derive( - GenericArray::from_slice(v.key), - v.use_l, - v.use_separator, - v.label, - v.context, - ), - Ok(GenericArray::<_, U128>::from_slice(v.expected).clone()), + feedback.derive(v.key, v.use_l, v.use_separator, v.label, v.context,), + Ok(GenericArray::<_, _>::from_slice(v.expected).clone()), "key derivation failed for (index: {i}):\n{v:x?}" ); } } + static KNOWN_VALUES_DOUBLE_PIPELINE_HMAC_SHA256: &[KnownValue] = &[KnownValue { + iv: None, + use_l: false, //true, + use_separator: true, + label: &hex!("921ab061920b191de12f746ac9de08"), + context: &hex!("4f2c20f01775e27bcacdc21ee4a5ff0387758f36d8ec71c7a8c8208284f650b611837e"), + key: &hex!("7d4f86fdfd1c4ba04c674a68d60316d12c99c1b1f44f0a8e02bd2601377ebcd9"), + expected: &hex!( + " + 506bc2ba51410b2a6e7c05d33891520d dd5f702ad3d6203d76d8dae1216d0783 + d8c59fae2e821d8eff2d8ddd93a6741c 8f144fb96e9ca7d7c532468f213f5efe + " + ), + }]; + #[test] - fn test_static_values_feedback() { + fn test_static_values_double_pipeline() { type HmacSha256 = hmac::Hmac; - type HmacSha512 = hmac::Hmac; - for (v, i) in KNOWN_VALUES_FEEDBACK_HMAC_SHA256.iter().zip(0..) { - let feedback = - Feedback::::new(v.iv.map(GenericArray::from_slice)); + struct MockOutput; + + impl KeySizeUser for MockOutput { + type KeySize = U64; + } + + for (v, i) in KNOWN_VALUES_DOUBLE_PIPELINE_HMAC_SHA256.iter().zip(0..) { + let dbl_pipeline = DoublePipeline::::default(); assert_eq!( - feedback.derive( - GenericArray::from_slice(v.key), - v.use_l, - v.use_separator, - v.label, - v.context, - ), - Ok(GenericArray::<_, U128>::from_slice(v.expected).clone()), + dbl_pipeline.derive(v.key, v.use_l, v.use_separator, v.label, v.context,), + Ok(GenericArray::<_, _>::from_slice(v.expected).clone()), "key derivation failed for (index: {i}):\n{v:x?}" ); } From d453b6911484fa96ca6e9920aae867de97f15dbd Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Sun, 29 Oct 2023 22:59:10 -0700 Subject: [PATCH 6/6] fixup cargo.toml --- kbkdf/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kbkdf/Cargo.toml b/kbkdf/Cargo.toml index 9b77eb2..863f625 100644 --- a/kbkdf/Cargo.toml +++ b/kbkdf/Cargo.toml @@ -6,8 +6,8 @@ authors = ["RustCrypto Developers"] license = "MIT OR Apache-2.0" homepage = "https://github.com/RustCrypto/KDFs/" repository = "https://github.com/RustCrypto/KDFs/" -description = "HMAC-based Extract-and-Expand Key Derivation Function (HKDF)" -keywords = ["crypto", "HKDF", "KDF"] +description = "Key Derivation Using Pseudorandom Function (KBKDF)" +keywords = ["crypto", "KBKDF", "KDF"] categories = ["cryptography", "no-std"] readme = "README.md" rust-version = "1.65"