From 6dc0d0968bc9031817d50c71c5a076f2a683ff32 Mon Sep 17 00:00:00 2001 From: Mark Beinker Date: Mon, 10 Jul 2023 22:52:31 +0200 Subject: [PATCH 01/22] working POC for pkcs#12 kdf --- Cargo.lock | 6 +++- pkcs12/Cargo.toml | 12 ++++++- pkcs12/src/error.rs | 23 +++++++++++++ pkcs12/src/kdf.rs | 83 +++++++++++++++++++++++++++++++++++++++++++++ pkcs12/src/lib.rs | 14 +++++++- pkcs12/tests/kdf.rs | 17 ++++++++++ 6 files changed, 152 insertions(+), 3 deletions(-) create mode 100644 pkcs12/src/error.rs create mode 100644 pkcs12/src/kdf.rs create mode 100644 pkcs12/tests/kdf.rs diff --git a/Cargo.lock b/Cargo.lock index cf8f260ab..6c9bfd4e6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1003,7 +1003,11 @@ dependencies = [ [[package]] name = "pkcs12" -version = "0.0.0" +version = "0.1.0" +dependencies = [ + "hex-literal", + "sha2", +] [[package]] name = "pkcs5" diff --git a/pkcs12/Cargo.toml b/pkcs12/Cargo.toml index 379fbde59..36d68a510 100644 --- a/pkcs12/Cargo.toml +++ b/pkcs12/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pkcs12" -version = "0.0.0" +version = "0.1.0" description = """ Pure Rust implementation of Public-Key Cryptography Standards (PKCS) #12: Personal Information Exchange Syntax v1.1 (RFC7292) @@ -14,6 +14,16 @@ readme = "README.md" edition = "2021" rust-version = "1.65" +[features] +alloc = [] + +[dependencies] +sha2 = "0.10.7" + +[dev-dependencies] +hex-literal = "0.4" + [package.metadata.docs.rs] all-features = true rustdoc-args = ["--cfg", "docsrs"] + diff --git a/pkcs12/src/error.rs b/pkcs12/src/error.rs new file mode 100644 index 000000000..665a697ce --- /dev/null +++ b/pkcs12/src/error.rs @@ -0,0 +1,23 @@ +//! Error types +use core::fmt; + +/// Result type +pub type Result = core::result::Result; + +/// Error type +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[non_exhaustive] +pub enum Error { + /// Given parameters are invalid for this algorithm + InternalError, +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Error::InternalError => { + write!(f, "PKCS#12 internal error") + } + } + } +} diff --git a/pkcs12/src/kdf.rs b/pkcs12/src/kdf.rs new file mode 100644 index 000000000..2907e2dd8 --- /dev/null +++ b/pkcs12/src/kdf.rs @@ -0,0 +1,83 @@ +use alloc::vec::Vec; + +use sha2::{Digest, Sha256}; +use super::Result; + +pub fn str_to_unicode(s: &str) -> Vec { + let mut unicode: Vec = s.encode_utf16().flat_map(|c| c.to_be_bytes().to_vec()).collect(); + unicode.push(0); + unicode.push(0); + unicode +} + +pub enum Pkcs12KeyType { + EncryptionKey=1, + Iv=2, + Mac=3 +} + +pub fn pkcs12_key_gen( + pass: &str, + salt: &[u8], + id: Pkcs12KeyType, + rounds: i32, +) -> Result<[u8; N]> { + let pass_uni = str_to_unicode(pass); + let u = 32; + let v = 64; + let slen = v*((salt.len()+v-1)/v); + let plen = v*((pass_uni.len() + v - 1)/v); + let ilen = slen + plen; + let mut i_tmp = vec![0u8; ilen]; + for i in 0..slen { + i_tmp[i] = salt[i%salt.len()]; + } + for i in slen..ilen { + i_tmp[i] = pass_uni[(i-slen)%pass_uni.len()]; + } + let d_tmp = match id { + Pkcs12KeyType::EncryptionKey => vec![1u8; v], + Pkcs12KeyType::Iv => vec![2u8; v], + Pkcs12KeyType::Mac => vec![3u8; v], + }; + let mut m = N; + let mut n = 0; + let mut out = [0u8; N]; + loop { + let mut hasher = Sha256::new(); + hasher.update(&d_tmp); + hasher.update(&i_tmp); + let mut result = hasher.finalize(); + for _ in 1..rounds { + let mut hasher = Sha256::new(); + hasher.update(&result[0..u]); + result = hasher.finalize(); + } + let min_mu = m.min(u); + out[n..n+min_mu].copy_from_slice(&result[0..min_mu]); + n += min_mu; + m -= min_mu; + if m <= 0 { + break; + } + let mut b_tmp = vec![0u8; v]; + for j in 0..v { + b_tmp[j] = result[j%u]; + } + let mut j=0; + while j=0 { + c += i_tmp[k as usize +j] as u16 + b_tmp[k as usize] as u16; + i_tmp[j+k as usize] = (c&0x00ff) as u8; + c >>= 8; + k -= 1; + } + j += v; + } + } + Ok(out) +} + + diff --git a/pkcs12/src/lib.rs b/pkcs12/src/lib.rs index 7d36dd6f3..2bab2e048 100644 --- a/pkcs12/src/lib.rs +++ b/pkcs12/src/lib.rs @@ -14,4 +14,16 @@ unused_qualifications )] -//! TODO: PKCS#12 crate +//! TODO: complete PKCS#12 crate + +#[cfg(feature="alloc")] +#[macro_use] +extern crate alloc; + +#[cfg(feature="alloc")] +pub mod kdf; + +pub mod error; + +pub use error::Result; + diff --git a/pkcs12/tests/kdf.rs b/pkcs12/tests/kdf.rs new file mode 100644 index 000000000..485c49e1f --- /dev/null +++ b/pkcs12/tests/kdf.rs @@ -0,0 +1,17 @@ +#[cfg(feature="alloc")] +use pkcs12::kdf::pkcs12_key_gen; +use hex_literal::hex; + +const PASS_SHORT: &str = "ge@äheim"; +const SALT_INC: [u8; 8] = [0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8]; + +#[test] +#[cfg(feature="alloc")] +fn pkcs12_key_gen_sha256() { + let iter = 100; + let id = pkcs12::kdf::Pkcs12KeyType::Mac; + assert_eq!(pkcs12_key_gen::<32>(PASS_SHORT, &SALT_INC, id, iter).unwrap(), + hex!("136355ed9434516682534f46d63956db5ff06b844702c2c1f3b46321e2524a4d")); +} + + From e611e76b31450dff4fac1d51664a9a839ff268cb Mon Sep 17 00:00:00 2001 From: Mark Beinker Date: Tue, 11 Jul 2023 23:07:42 +0200 Subject: [PATCH 02/22] allocator version --- pkcs12/src/kdf.rs | 9 +++++---- pkcs12/tests/kdf.rs | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/pkcs12/src/kdf.rs b/pkcs12/src/kdf.rs index 2907e2dd8..81acddb00 100644 --- a/pkcs12/src/kdf.rs +++ b/pkcs12/src/kdf.rs @@ -16,12 +16,13 @@ pub enum Pkcs12KeyType { Mac=3 } -pub fn pkcs12_key_gen( +pub fn pkcs12_key_gen( pass: &str, salt: &[u8], id: Pkcs12KeyType, rounds: i32, -) -> Result<[u8; N]> { + key_len: usize, +) -> Result> { let pass_uni = str_to_unicode(pass); let u = 32; let v = 64; @@ -40,9 +41,9 @@ pub fn pkcs12_key_gen( Pkcs12KeyType::Iv => vec![2u8; v], Pkcs12KeyType::Mac => vec![3u8; v], }; - let mut m = N; + let mut m = key_len; let mut n = 0; - let mut out = [0u8; N]; + let mut out = vec![0u8; key_len]; loop { let mut hasher = Sha256::new(); hasher.update(&d_tmp); diff --git a/pkcs12/tests/kdf.rs b/pkcs12/tests/kdf.rs index 485c49e1f..88d9c957e 100644 --- a/pkcs12/tests/kdf.rs +++ b/pkcs12/tests/kdf.rs @@ -10,7 +10,7 @@ const SALT_INC: [u8; 8] = [0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8]; fn pkcs12_key_gen_sha256() { let iter = 100; let id = pkcs12::kdf::Pkcs12KeyType::Mac; - assert_eq!(pkcs12_key_gen::<32>(PASS_SHORT, &SALT_INC, id, iter).unwrap(), + assert_eq!(pkcs12_key_gen(PASS_SHORT, &SALT_INC, id, iter, 32).unwrap(), hex!("136355ed9434516682534f46d63956db5ff06b844702c2c1f3b46321e2524a4d")); } From e14c270921847d877d6563e185bcc91bbc6139c4 Mon Sep 17 00:00:00 2001 From: Mark Beinker Date: Sat, 15 Jul 2023 10:05:47 +0200 Subject: [PATCH 03/22] more tests, docs, and block size from digest method --- pkcs12/src/kdf.rs | 25 ++++++++++++++++----- pkcs12/tests/kdf.rs | 53 +++++++++++++++++++++++++++++++++++---------- 2 files changed, 61 insertions(+), 17 deletions(-) diff --git a/pkcs12/src/kdf.rs b/pkcs12/src/kdf.rs index 81acddb00..72b5c1596 100644 --- a/pkcs12/src/kdf.rs +++ b/pkcs12/src/kdf.rs @@ -1,8 +1,12 @@ -use alloc::vec::Vec; +/* Implementation of the key derivation function as specified in the PKCS#12 standard + */ -use sha2::{Digest, Sha256}; +use alloc::vec::Vec; +use sha2::{Digest, Sha256, digest::FixedOutputReset}; use super::Result; +/// Transform a utf-8 string in a unicode (utf16) string as binary array. +/// The Utf16 code points are stored in big endian format with two trailing zero bytes. pub fn str_to_unicode(s: &str) -> Vec { let mut unicode: Vec = s.encode_utf16().flat_map(|c| c.to_be_bytes().to_vec()).collect(); unicode.push(0); @@ -10,12 +14,22 @@ pub fn str_to_unicode(s: &str) -> Vec { unicode } +/// Specify the usage type of the generated key +/// This allows to derive distinct encryption keys, IVs and MAC from the same password or text +/// string. pub enum Pkcs12KeyType { + /// Use key for encryption EncryptionKey=1, + /// Use key as initial vector Iv=2, + /// Use key as MAC Mac=3 } +/// Derive a key of length `keylen` from a given password (utf-8 string) +/// and a salt. Password and Salt may have arbitrary length. +/// The id allows to derive distinct key types from the same password. +/// The number of rounds should be 1000 or more, minimum is 1. pub fn pkcs12_key_gen( pass: &str, salt: &[u8], @@ -23,6 +37,7 @@ pub fn pkcs12_key_gen( rounds: i32, key_len: usize, ) -> Result> { + let mut hasher = Sha256::new(); let pass_uni = str_to_unicode(pass); let u = 32; let v = 64; @@ -45,14 +60,12 @@ pub fn pkcs12_key_gen( let mut n = 0; let mut out = vec![0u8; key_len]; loop { - let mut hasher = Sha256::new(); hasher.update(&d_tmp); hasher.update(&i_tmp); - let mut result = hasher.finalize(); + let mut result = hasher.finalize_fixed_reset(); for _ in 1..rounds { - let mut hasher = Sha256::new(); hasher.update(&result[0..u]); - result = hasher.finalize(); + result = hasher.finalize_fixed_reset(); } let min_mu = m.min(u); out[n..n+min_mu].copy_from_slice(&result[0..min_mu]); diff --git a/pkcs12/tests/kdf.rs b/pkcs12/tests/kdf.rs index 88d9c957e..03f493d41 100644 --- a/pkcs12/tests/kdf.rs +++ b/pkcs12/tests/kdf.rs @@ -1,17 +1,48 @@ -#[cfg(feature="alloc")] -use pkcs12::kdf::pkcs12_key_gen; -use hex_literal::hex; - -const PASS_SHORT: &str = "ge@äheim"; -const SALT_INC: [u8; 8] = [0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8]; - #[test] -#[cfg(feature="alloc")] +//#[cfg(feature="alloc")] fn pkcs12_key_gen_sha256() { - let iter = 100; - let id = pkcs12::kdf::Pkcs12KeyType::Mac; - assert_eq!(pkcs12_key_gen(PASS_SHORT, &SALT_INC, id, iter, 32).unwrap(), + use pkcs12::kdf::{pkcs12_key_gen, Pkcs12KeyType}; + use hex_literal::hex; + + const PASS_SHORT: &str = "ge@äheim"; + const SALT_INC: [u8; 8] = [0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8]; + + assert_eq!(pkcs12_key_gen(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 100, 32).unwrap(), + hex!("fae4d4957a3cc781e1180b9d4fb79c1e0c8579b746a3177e5b0768a3118bf863")); + + assert_eq!(pkcs12_key_gen(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Iv, 100, 32).unwrap(), + hex!("e5ff813bc6547de5155b14d2fada85b3201a977349db6e26ccc998d9e8f83d6c")); + + assert_eq!(pkcs12_key_gen(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Mac, 100, 32).unwrap(), hex!("136355ed9434516682534f46d63956db5ff06b844702c2c1f3b46321e2524a4d")); + + assert_eq!(pkcs12_key_gen(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 100, 20).unwrap(), + hex!("fae4d4957a3cc781e1180b9d4fb79c1e0c8579b7")); + + assert_eq!(pkcs12_key_gen(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Iv, 100, 20).unwrap(), + hex!("e5ff813bc6547de5155b14d2fada85b3201a9773")); + + assert_eq!(pkcs12_key_gen(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Mac, 100, 20).unwrap(), + hex!("136355ed9434516682534f46d63956db5ff06b84")); + + assert_eq!(pkcs12_key_gen(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 100, 12).unwrap(), + hex!("fae4d4957a3cc781e1180b9d")); + + assert_eq!(pkcs12_key_gen(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Iv, 100, 12).unwrap(), + hex!("e5ff813bc6547de5155b14d2")); + + assert_eq!(pkcs12_key_gen(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Mac, 100, 12).unwrap(), + hex!("136355ed9434516682534f46")); + + assert_eq!(pkcs12_key_gen(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 1000, 32).unwrap(), + hex!("2b95a0569b63f641fae1efca32e84db3699ab74540628ba66283b58cf5400527")); + + assert_eq!(pkcs12_key_gen(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Iv, 1000, 32).unwrap(), + hex!("6472c0ebad3fab4123e8b5ed7834de21eeb20187b3eff78a7d1cdffa4034851d")); + + assert_eq!(pkcs12_key_gen(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Mac, 1000, 32).unwrap(), + hex!("3f9113f05c30a996c4a516409bdac9d065f44296ccd52bb75de3fcfdbe2bf130")); + } From 6125b8085b6b135fbcae8096176f3f882eb2ef4a Mon Sep 17 00:00:00 2001 From: Mark Beinker Date: Sat, 15 Jul 2023 12:49:11 +0200 Subject: [PATCH 04/22] put tests behind feature flag (again) --- pkcs12/tests/kdf.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkcs12/tests/kdf.rs b/pkcs12/tests/kdf.rs index 03f493d41..eb2acfb28 100644 --- a/pkcs12/tests/kdf.rs +++ b/pkcs12/tests/kdf.rs @@ -1,5 +1,5 @@ #[test] -//#[cfg(feature="alloc")] +#[cfg(feature="alloc")] fn pkcs12_key_gen_sha256() { use pkcs12::kdf::{pkcs12_key_gen, Pkcs12KeyType}; use hex_literal::hex; From 5286894f715ddff61f38417b10e29fdbb9791e70 Mon Sep 17 00:00:00 2001 From: Mark Beinker Date: Sat, 15 Jul 2023 13:50:20 +0200 Subject: [PATCH 05/22] generalize for general digest methods --- Cargo.lock | 11 ++++ pkcs12/Cargo.toml | 4 +- pkcs12/src/error.rs | 2 +- pkcs12/src/kdf.rs | 70 ++++++++++---------- pkcs12/src/lib.rs | 5 +- pkcs12/tests/kdf.rs | 152 ++++++++++++++++++++++++++++++++------------ 6 files changed, 167 insertions(+), 77 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6c9bfd4e6..16a2e0c87 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1005,8 +1005,10 @@ dependencies = [ name = "pkcs12" version = "0.1.0" dependencies = [ + "digest", "hex-literal", "sha2", + "whirlpool", ] [[package]] @@ -1818,6 +1820,15 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "whirlpool" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1ae50671d985c15b3214c7d969b8b520759fb3c8682444bec15ef775335a05c" +dependencies = [ + "digest", +] + [[package]] name = "winapi" version = "0.3.9" diff --git a/pkcs12/Cargo.toml b/pkcs12/Cargo.toml index 36d68a510..0da340825 100644 --- a/pkcs12/Cargo.toml +++ b/pkcs12/Cargo.toml @@ -18,10 +18,12 @@ rust-version = "1.65" alloc = [] [dependencies] -sha2 = "0.10.7" +digest = { version = "0.10.7", features=["alloc"] } [dev-dependencies] hex-literal = "0.4" +sha2 = "0.10.7" +whirlpool = "0.10.4" [package.metadata.docs.rs] all-features = true diff --git a/pkcs12/src/error.rs b/pkcs12/src/error.rs index 665a697ce..860f0171d 100644 --- a/pkcs12/src/error.rs +++ b/pkcs12/src/error.rs @@ -18,6 +18,6 @@ impl fmt::Display for Error { Error::InternalError => { write!(f, "PKCS#12 internal error") } - } + } } } diff --git a/pkcs12/src/kdf.rs b/pkcs12/src/kdf.rs index 72b5c1596..3463a4523 100644 --- a/pkcs12/src/kdf.rs +++ b/pkcs12/src/kdf.rs @@ -1,14 +1,17 @@ /* Implementation of the key derivation function as specified in the PKCS#12 standard */ -use alloc::vec::Vec; -use sha2::{Digest, Sha256, digest::FixedOutputReset}; use super::Result; +use alloc::vec::Vec; +use digest::{core_api::BlockSizeUser, Digest, FixedOutputReset, OutputSizeUser, Update}; /// Transform a utf-8 string in a unicode (utf16) string as binary array. /// The Utf16 code points are stored in big endian format with two trailing zero bytes. pub fn str_to_unicode(s: &str) -> Vec { - let mut unicode: Vec = s.encode_utf16().flat_map(|c| c.to_be_bytes().to_vec()).collect(); + let mut unicode: Vec = s + .encode_utf16() + .flat_map(|c| c.to_be_bytes().to_vec()) + .collect(); unicode.push(0); unicode.push(0); unicode @@ -19,37 +22,42 @@ pub fn str_to_unicode(s: &str) -> Vec { /// string. pub enum Pkcs12KeyType { /// Use key for encryption - EncryptionKey=1, + EncryptionKey = 1, /// Use key as initial vector - Iv=2, + Iv = 2, /// Use key as MAC - Mac=3 + Mac = 3, } -/// Derive a key of length `keylen` from a given password (utf-8 string) -/// and a salt. Password and Salt may have arbitrary length. -/// The id allows to derive distinct key types from the same password. -/// The number of rounds should be 1000 or more, minimum is 1. -pub fn pkcs12_key_gen( +/// Derives `key` of type `id` from `pass` and `salt` with length `key_len` using `rounds` +/// iterations of the algorithm +/// ```rust +/// let key = pkcs12::kdf::derive_key::("top-secret", &[0x1, 0x2, 0x3, 0x4], +/// pkcs12::kdf::Pkcs12KeyType::EncryptionKey, 1000, 32); +/// ``` +pub fn derive_key( pass: &str, salt: &[u8], id: Pkcs12KeyType, rounds: i32, key_len: usize, -) -> Result> { - let mut hasher = Sha256::new(); +) -> Result> +where + D: Digest + FixedOutputReset + BlockSizeUser, +{ + let mut hasher = D::new(); let pass_uni = str_to_unicode(pass); - let u = 32; - let v = 64; - let slen = v*((salt.len()+v-1)/v); - let plen = v*((pass_uni.len() + v - 1)/v); + let u = ::output_size(); + let v = D::block_size(); + let slen = v * ((salt.len() + v - 1) / v); + let plen = v * ((pass_uni.len() + v - 1) / v); let ilen = slen + plen; let mut i_tmp = vec![0u8; ilen]; for i in 0..slen { - i_tmp[i] = salt[i%salt.len()]; + i_tmp[i] = salt[i % salt.len()]; } for i in slen..ilen { - i_tmp[i] = pass_uni[(i-slen)%pass_uni.len()]; + i_tmp[i] = pass_uni[(i - slen) % pass_uni.len()]; } let d_tmp = match id { Pkcs12KeyType::EncryptionKey => vec![1u8; v], @@ -60,15 +68,15 @@ pub fn pkcs12_key_gen( let mut n = 0; let mut out = vec![0u8; key_len]; loop { - hasher.update(&d_tmp); - hasher.update(&i_tmp); + ::update(&mut hasher, &d_tmp); + ::update(&mut hasher, &i_tmp); let mut result = hasher.finalize_fixed_reset(); for _ in 1..rounds { - hasher.update(&result[0..u]); + ::update(&mut hasher, &result[0..u]); result = hasher.finalize_fixed_reset(); } let min_mu = m.min(u); - out[n..n+min_mu].copy_from_slice(&result[0..min_mu]); + out[n..n + min_mu].copy_from_slice(&result[0..min_mu]); n += min_mu; m -= min_mu; if m <= 0 { @@ -76,15 +84,15 @@ pub fn pkcs12_key_gen( } let mut b_tmp = vec![0u8; v]; for j in 0..v { - b_tmp[j] = result[j%u]; + b_tmp[j] = result[j % u]; } - let mut j=0; - while j=0 { - c += i_tmp[k as usize +j] as u16 + b_tmp[k as usize] as u16; - i_tmp[j+k as usize] = (c&0x00ff) as u8; + let mut k: i64 = v as i64 - 1; + while k >= 0 { + c += i_tmp[k as usize + j] as u16 + b_tmp[k as usize] as u16; + i_tmp[j + k as usize] = (c & 0x00ff) as u8; c >>= 8; k -= 1; } @@ -93,5 +101,3 @@ pub fn pkcs12_key_gen( } Ok(out) } - - diff --git a/pkcs12/src/lib.rs b/pkcs12/src/lib.rs index 2bab2e048..5fa813882 100644 --- a/pkcs12/src/lib.rs +++ b/pkcs12/src/lib.rs @@ -16,14 +16,13 @@ //! TODO: complete PKCS#12 crate -#[cfg(feature="alloc")] +#[cfg(feature = "alloc")] #[macro_use] extern crate alloc; -#[cfg(feature="alloc")] +#[cfg(feature = "alloc")] pub mod kdf; pub mod error; pub use error::Result; - diff --git a/pkcs12/tests/kdf.rs b/pkcs12/tests/kdf.rs index eb2acfb28..f913f7668 100644 --- a/pkcs12/tests/kdf.rs +++ b/pkcs12/tests/kdf.rs @@ -1,48 +1,120 @@ #[test] -#[cfg(feature="alloc")] -fn pkcs12_key_gen_sha256() { - use pkcs12::kdf::{pkcs12_key_gen, Pkcs12KeyType}; +//#[cfg(feature="alloc")] +fn pkcs12_key_derive_sha256() { use hex_literal::hex; + use pkcs12::kdf::{derive_key, Pkcs12KeyType}; const PASS_SHORT: &str = "ge@äheim"; const SALT_INC: [u8; 8] = [0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8]; - - assert_eq!(pkcs12_key_gen(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 100, 32).unwrap(), - hex!("fae4d4957a3cc781e1180b9d4fb79c1e0c8579b746a3177e5b0768a3118bf863")); - - assert_eq!(pkcs12_key_gen(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Iv, 100, 32).unwrap(), - hex!("e5ff813bc6547de5155b14d2fada85b3201a977349db6e26ccc998d9e8f83d6c")); - - assert_eq!(pkcs12_key_gen(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Mac, 100, 32).unwrap(), - hex!("136355ed9434516682534f46d63956db5ff06b844702c2c1f3b46321e2524a4d")); - - assert_eq!(pkcs12_key_gen(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 100, 20).unwrap(), - hex!("fae4d4957a3cc781e1180b9d4fb79c1e0c8579b7")); - - assert_eq!(pkcs12_key_gen(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Iv, 100, 20).unwrap(), - hex!("e5ff813bc6547de5155b14d2fada85b3201a9773")); - - assert_eq!(pkcs12_key_gen(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Mac, 100, 20).unwrap(), - hex!("136355ed9434516682534f46d63956db5ff06b84")); - - assert_eq!(pkcs12_key_gen(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 100, 12).unwrap(), - hex!("fae4d4957a3cc781e1180b9d")); - - assert_eq!(pkcs12_key_gen(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Iv, 100, 12).unwrap(), - hex!("e5ff813bc6547de5155b14d2")); - - assert_eq!(pkcs12_key_gen(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Mac, 100, 12).unwrap(), - hex!("136355ed9434516682534f46")); - - assert_eq!(pkcs12_key_gen(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 1000, 32).unwrap(), - hex!("2b95a0569b63f641fae1efca32e84db3699ab74540628ba66283b58cf5400527")); - - assert_eq!(pkcs12_key_gen(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Iv, 1000, 32).unwrap(), - hex!("6472c0ebad3fab4123e8b5ed7834de21eeb20187b3eff78a7d1cdffa4034851d")); - - assert_eq!(pkcs12_key_gen(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Mac, 1000, 32).unwrap(), - hex!("3f9113f05c30a996c4a516409bdac9d065f44296ccd52bb75de3fcfdbe2bf130")); - + + assert_eq!( + derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 100, 32) + .unwrap(), + hex!("fae4d4957a3cc781e1180b9d4fb79c1e0c8579b746a3177e5b0768a3118bf863") + ); + + assert_eq!( + derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Iv, 100, 32).unwrap(), + hex!("e5ff813bc6547de5155b14d2fada85b3201a977349db6e26ccc998d9e8f83d6c") + ); + + assert_eq!( + derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Mac, 100, 32).unwrap(), + hex!("136355ed9434516682534f46d63956db5ff06b844702c2c1f3b46321e2524a4d") + ); + + assert_eq!( + derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 100, 20) + .unwrap(), + hex!("fae4d4957a3cc781e1180b9d4fb79c1e0c8579b7") + ); + + assert_eq!( + derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Iv, 100, 20).unwrap(), + hex!("e5ff813bc6547de5155b14d2fada85b3201a9773") + ); + + assert_eq!( + derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Mac, 100, 20).unwrap(), + hex!("136355ed9434516682534f46d63956db5ff06b84") + ); + + assert_eq!( + derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 100, 12) + .unwrap(), + hex!("fae4d4957a3cc781e1180b9d") + ); + + assert_eq!( + derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Iv, 100, 12).unwrap(), + hex!("e5ff813bc6547de5155b14d2") + ); + + assert_eq!( + derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Mac, 100, 12).unwrap(), + hex!("136355ed9434516682534f46") + ); + + assert_eq!( + derive_key::( + PASS_SHORT, + &SALT_INC, + Pkcs12KeyType::EncryptionKey, + 1000, + 32 + ) + .unwrap(), + hex!("2b95a0569b63f641fae1efca32e84db3699ab74540628ba66283b58cf5400527") + ); + + assert_eq!( + derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Iv, 1000, 32).unwrap(), + hex!("6472c0ebad3fab4123e8b5ed7834de21eeb20187b3eff78a7d1cdffa4034851d") + ); + + assert_eq!( + derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Mac, 1000, 32).unwrap(), + hex!("3f9113f05c30a996c4a516409bdac9d065f44296ccd52bb75de3fcfdbe2bf130") + ); + + assert_eq!( + derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Mac, 1000, 32).unwrap(), + hex!("3f9113f05c30a996c4a516409bdac9d065f44296ccd52bb75de3fcfdbe2bf130") + ); } +#[test] +fn pkcs12_key_derive_sha512() { + use hex_literal::hex; + use pkcs12::kdf::{derive_key, Pkcs12KeyType}; + + const PASS_SHORT: &str = "ge@äheim"; + const SALT_INC: [u8; 8] = [0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8]; + assert_eq!( + derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 100, 32) + .unwrap(), + hex!("b14a9f01bfd9dce4c9d66d2fe9937e5fd9f1afa59e370a6fa4fc81c1cc8ec8ee") + ); +} + +#[test] +fn pkcs12_key_derive_whirlpool() { + use hex_literal::hex; + use pkcs12::kdf::{derive_key, Pkcs12KeyType}; + + const PASS_SHORT: &str = "ge@äheim"; + const SALT_INC: [u8; 8] = [0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8]; + + assert_eq!( + derive_key::( + PASS_SHORT, + &SALT_INC, + Pkcs12KeyType::EncryptionKey, + 100, + 32 + ) + .unwrap(), + hex!("3324282adb468bff0734d3b7e399094ec8500cb5b0a3604055da107577aaf766") + ); +} From 217783b970d66766127edb3661b6b77d59713ab0 Mon Sep 17 00:00:00 2001 From: Mark Beinker Date: Sat, 15 Jul 2023 16:39:18 +0200 Subject: [PATCH 06/22] add reference to RFC7292 --- pkcs12/src/kdf.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkcs12/src/kdf.rs b/pkcs12/src/kdf.rs index 3463a4523..a8d072153 100644 --- a/pkcs12/src/kdf.rs +++ b/pkcs12/src/kdf.rs @@ -1,5 +1,5 @@ -/* Implementation of the key derivation function as specified in the PKCS#12 standard - */ +//! Implementation of the key derivation function +//! [RFC 7292 Appendix B](https://datatracker.ietf.org/doc/html/rfc7292#appendix-B) use super::Result; use alloc::vec::Vec; From 02a8193151ae5205fb7a8b00414f857fb7173447 Mon Sep 17 00:00:00 2001 From: Mark Beinker Date: Sat, 15 Jul 2023 16:52:34 +0200 Subject: [PATCH 07/22] use cfg_if for improved readability --- Cargo.lock | 1 + pkcs12/Cargo.toml | 1 + pkcs12/src/kdf.rs | 2 +- pkcs12/src/lib.rs | 15 ++- pkcs12/tests/kdf.rs | 244 +++++++++++++++++++++++--------------------- 5 files changed, 138 insertions(+), 125 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 16a2e0c87..9ca63f127 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1005,6 +1005,7 @@ dependencies = [ name = "pkcs12" version = "0.1.0" dependencies = [ + "cfg-if", "digest", "hex-literal", "sha2", diff --git a/pkcs12/Cargo.toml b/pkcs12/Cargo.toml index 0da340825..22ea6d780 100644 --- a/pkcs12/Cargo.toml +++ b/pkcs12/Cargo.toml @@ -18,6 +18,7 @@ rust-version = "1.65" alloc = [] [dependencies] +cfg-if = "1.0.0" digest = { version = "0.10.7", features=["alloc"] } [dev-dependencies] diff --git a/pkcs12/src/kdf.rs b/pkcs12/src/kdf.rs index a8d072153..c0d55514f 100644 --- a/pkcs12/src/kdf.rs +++ b/pkcs12/src/kdf.rs @@ -1,4 +1,4 @@ -//! Implementation of the key derivation function +//! Implementation of the key derivation function //! [RFC 7292 Appendix B](https://datatracker.ietf.org/doc/html/rfc7292#appendix-B) use super::Result; diff --git a/pkcs12/src/lib.rs b/pkcs12/src/lib.rs index 5fa813882..eb5659dc6 100644 --- a/pkcs12/src/lib.rs +++ b/pkcs12/src/lib.rs @@ -16,12 +16,17 @@ //! TODO: complete PKCS#12 crate -#[cfg(feature = "alloc")] -#[macro_use] -extern crate alloc; +use cfg_if::cfg_if; -#[cfg(feature = "alloc")] -pub mod kdf; +cfg_if! { + if #[cfg(feature = "alloc")] { + + #[macro_use] + extern crate alloc; + + pub mod kdf; + } +} pub mod error; diff --git a/pkcs12/tests/kdf.rs b/pkcs12/tests/kdf.rs index f913f7668..a157e118f 100644 --- a/pkcs12/tests/kdf.rs +++ b/pkcs12/tests/kdf.rs @@ -1,120 +1,126 @@ -#[test] -//#[cfg(feature="alloc")] -fn pkcs12_key_derive_sha256() { - use hex_literal::hex; - use pkcs12::kdf::{derive_key, Pkcs12KeyType}; - - const PASS_SHORT: &str = "ge@äheim"; - const SALT_INC: [u8; 8] = [0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8]; - - assert_eq!( - derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 100, 32) - .unwrap(), - hex!("fae4d4957a3cc781e1180b9d4fb79c1e0c8579b746a3177e5b0768a3118bf863") - ); - - assert_eq!( - derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Iv, 100, 32).unwrap(), - hex!("e5ff813bc6547de5155b14d2fada85b3201a977349db6e26ccc998d9e8f83d6c") - ); - - assert_eq!( - derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Mac, 100, 32).unwrap(), - hex!("136355ed9434516682534f46d63956db5ff06b844702c2c1f3b46321e2524a4d") - ); - - assert_eq!( - derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 100, 20) - .unwrap(), - hex!("fae4d4957a3cc781e1180b9d4fb79c1e0c8579b7") - ); - - assert_eq!( - derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Iv, 100, 20).unwrap(), - hex!("e5ff813bc6547de5155b14d2fada85b3201a9773") - ); - - assert_eq!( - derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Mac, 100, 20).unwrap(), - hex!("136355ed9434516682534f46d63956db5ff06b84") - ); - - assert_eq!( - derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 100, 12) - .unwrap(), - hex!("fae4d4957a3cc781e1180b9d") - ); - - assert_eq!( - derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Iv, 100, 12).unwrap(), - hex!("e5ff813bc6547de5155b14d2") - ); - - assert_eq!( - derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Mac, 100, 12).unwrap(), - hex!("136355ed9434516682534f46") - ); - - assert_eq!( - derive_key::( - PASS_SHORT, - &SALT_INC, - Pkcs12KeyType::EncryptionKey, - 1000, - 32 - ) - .unwrap(), - hex!("2b95a0569b63f641fae1efca32e84db3699ab74540628ba66283b58cf5400527") - ); - - assert_eq!( - derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Iv, 1000, 32).unwrap(), - hex!("6472c0ebad3fab4123e8b5ed7834de21eeb20187b3eff78a7d1cdffa4034851d") - ); - - assert_eq!( - derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Mac, 1000, 32).unwrap(), - hex!("3f9113f05c30a996c4a516409bdac9d065f44296ccd52bb75de3fcfdbe2bf130") - ); - - assert_eq!( - derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Mac, 1000, 32).unwrap(), - hex!("3f9113f05c30a996c4a516409bdac9d065f44296ccd52bb75de3fcfdbe2bf130") - ); -} - -#[test] -fn pkcs12_key_derive_sha512() { - use hex_literal::hex; - use pkcs12::kdf::{derive_key, Pkcs12KeyType}; - - const PASS_SHORT: &str = "ge@äheim"; - const SALT_INC: [u8; 8] = [0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8]; - - assert_eq!( - derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 100, 32) - .unwrap(), - hex!("b14a9f01bfd9dce4c9d66d2fe9937e5fd9f1afa59e370a6fa4fc81c1cc8ec8ee") - ); -} - -#[test] -fn pkcs12_key_derive_whirlpool() { - use hex_literal::hex; - use pkcs12::kdf::{derive_key, Pkcs12KeyType}; - - const PASS_SHORT: &str = "ge@äheim"; - const SALT_INC: [u8; 8] = [0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8]; - - assert_eq!( - derive_key::( - PASS_SHORT, - &SALT_INC, - Pkcs12KeyType::EncryptionKey, - 100, - 32 - ) - .unwrap(), - hex!("3324282adb468bff0734d3b7e399094ec8500cb5b0a3604055da107577aaf766") - ); +use cfg_if::cfg_if; + +cfg_if! { + if #[cfg(feature="alloc")] { + + #[test] + fn pkcs12_key_derive_sha256() { + use hex_literal::hex; + use pkcs12::kdf::{derive_key, Pkcs12KeyType}; + + const PASS_SHORT: &str = "ge@äheim"; + const SALT_INC: [u8; 8] = [0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8]; + + assert_eq!( + derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 100, 32) + .unwrap(), + hex!("fae4d4957a3cc781e1180b9d4fb79c1e0c8579b746a3177e5b0768a3118bf863") + ); + + assert_eq!( + derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Iv, 100, 32).unwrap(), + hex!("e5ff813bc6547de5155b14d2fada85b3201a977349db6e26ccc998d9e8f83d6c") + ); + + assert_eq!( + derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Mac, 100, 32).unwrap(), + hex!("136355ed9434516682534f46d63956db5ff06b844702c2c1f3b46321e2524a4d") + ); + + assert_eq!( + derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 100, 20) + .unwrap(), + hex!("fae4d4957a3cc781e1180b9d4fb79c1e0c8579b7") + ); + + assert_eq!( + derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Iv, 100, 20).unwrap(), + hex!("e5ff813bc6547de5155b14d2fada85b3201a9773") + ); + + assert_eq!( + derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Mac, 100, 20).unwrap(), + hex!("136355ed9434516682534f46d63956db5ff06b84") + ); + + assert_eq!( + derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 100, 12) + .unwrap(), + hex!("fae4d4957a3cc781e1180b9d") + ); + + assert_eq!( + derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Iv, 100, 12).unwrap(), + hex!("e5ff813bc6547de5155b14d2") + ); + + assert_eq!( + derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Mac, 100, 12).unwrap(), + hex!("136355ed9434516682534f46") + ); + + assert_eq!( + derive_key::( + PASS_SHORT, + &SALT_INC, + Pkcs12KeyType::EncryptionKey, + 1000, + 32 + ) + .unwrap(), + hex!("2b95a0569b63f641fae1efca32e84db3699ab74540628ba66283b58cf5400527") + ); + + assert_eq!( + derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Iv, 1000, 32).unwrap(), + hex!("6472c0ebad3fab4123e8b5ed7834de21eeb20187b3eff78a7d1cdffa4034851d") + ); + + assert_eq!( + derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Mac, 1000, 32).unwrap(), + hex!("3f9113f05c30a996c4a516409bdac9d065f44296ccd52bb75de3fcfdbe2bf130") + ); + + assert_eq!( + derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Mac, 1000, 32).unwrap(), + hex!("3f9113f05c30a996c4a516409bdac9d065f44296ccd52bb75de3fcfdbe2bf130") + ); + } + + #[test] + fn pkcs12_key_derive_sha512() { + use hex_literal::hex; + use pkcs12::kdf::{derive_key, Pkcs12KeyType}; + + const PASS_SHORT: &str = "ge@äheim"; + const SALT_INC: [u8; 8] = [0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8]; + + assert_eq!( + derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 100, 32) + .unwrap(), + hex!("b14a9f01bfd9dce4c9d66d2fe9937e5fd9f1afa59e370a6fa4fc81c1cc8ec8ee") + ); + } + + #[test] + fn pkcs12_key_derive_whirlpool() { + use hex_literal::hex; + use pkcs12::kdf::{derive_key, Pkcs12KeyType}; + + const PASS_SHORT: &str = "ge@äheim"; + const SALT_INC: [u8; 8] = [0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8]; + + assert_eq!( + derive_key::( + PASS_SHORT, + &SALT_INC, + Pkcs12KeyType::EncryptionKey, + 100, + 32 + ) + .unwrap(), + hex!("3324282adb468bff0734d3b7e399094ec8500cb5b0a3604055da107577aaf766") + ); + } + } } From 236b957add40400fb9199f147df50eaec490dcb9 Mon Sep 17 00:00:00 2001 From: Mark Beinker Date: Sat, 15 Jul 2023 17:04:11 +0200 Subject: [PATCH 08/22] apply clippy suggestion --- pkcs12/src/kdf.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkcs12/src/kdf.rs b/pkcs12/src/kdf.rs index c0d55514f..43fbcf4ad 100644 --- a/pkcs12/src/kdf.rs +++ b/pkcs12/src/kdf.rs @@ -78,10 +78,10 @@ where let min_mu = m.min(u); out[n..n + min_mu].copy_from_slice(&result[0..min_mu]); n += min_mu; - m -= min_mu; - if m <= 0 { + if m <= min_mu { break; } + m -= min_mu; let mut b_tmp = vec![0u8; v]; for j in 0..v { b_tmp[j] = result[j % u]; From c6b49287fd21a53e5e791a0a42a773a200c8e819 Mon Sep 17 00:00:00 2001 From: Mark Beinker Date: Sun, 16 Jul 2023 13:11:05 +0200 Subject: [PATCH 09/22] zeroizing temporary secrets, renaming variables for better readability, removing unused error class, code simplifications, and new test cases for very long output keys --- Cargo.lock | 1 + pkcs12/Cargo.toml | 1 + pkcs12/src/error.rs | 23 ----------- pkcs12/src/kdf.rs | 95 ++++++++++++++++++++++++--------------------- pkcs12/src/lib.rs | 3 -- pkcs12/tests/kdf.rs | 48 ++++++++++++----------- 6 files changed, 79 insertions(+), 92 deletions(-) delete mode 100644 pkcs12/src/error.rs diff --git a/Cargo.lock b/Cargo.lock index 9ca63f127..b5899adf7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1010,6 +1010,7 @@ dependencies = [ "hex-literal", "sha2", "whirlpool", + "zeroize", ] [[package]] diff --git a/pkcs12/Cargo.toml b/pkcs12/Cargo.toml index 22ea6d780..b711ed65b 100644 --- a/pkcs12/Cargo.toml +++ b/pkcs12/Cargo.toml @@ -20,6 +20,7 @@ alloc = [] [dependencies] cfg-if = "1.0.0" digest = { version = "0.10.7", features=["alloc"] } +zeroize = "1.6.0" [dev-dependencies] hex-literal = "0.4" diff --git a/pkcs12/src/error.rs b/pkcs12/src/error.rs deleted file mode 100644 index 860f0171d..000000000 --- a/pkcs12/src/error.rs +++ /dev/null @@ -1,23 +0,0 @@ -//! Error types -use core::fmt; - -/// Result type -pub type Result = core::result::Result; - -/// Error type -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -#[non_exhaustive] -pub enum Error { - /// Given parameters are invalid for this algorithm - InternalError, -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Error::InternalError => { - write!(f, "PKCS#12 internal error") - } - } - } -} diff --git a/pkcs12/src/kdf.rs b/pkcs12/src/kdf.rs index 43fbcf4ad..70b5a14b0 100644 --- a/pkcs12/src/kdf.rs +++ b/pkcs12/src/kdf.rs @@ -1,20 +1,22 @@ //! Implementation of the key derivation function //! [RFC 7292 Appendix B](https://datatracker.ietf.org/doc/html/rfc7292#appendix-B) -use super::Result; use alloc::vec::Vec; use digest::{core_api::BlockSizeUser, Digest, FixedOutputReset, OutputSizeUser, Update}; +use zeroize::Zeroize; /// Transform a utf-8 string in a unicode (utf16) string as binary array. /// The Utf16 code points are stored in big endian format with two trailing zero bytes. -pub fn str_to_unicode(s: &str) -> Vec { - let mut unicode: Vec = s - .encode_utf16() - .flat_map(|c| c.to_be_bytes().to_vec()) - .collect(); - unicode.push(0); - unicode.push(0); - unicode +pub fn str_to_unicode(utf8_str: &str) -> Vec { + let mut utf16_bytes = Vec::new(); + // reserve max number of required bytes to avoid re-allocation + utf16_bytes.reserve(utf8_str.len() * 2 + 2); + for code_point in utf8_str.encode_utf16() { + utf16_bytes.extend(code_point.to_be_bytes()); + } + utf16_bytes.push(0); + utf16_bytes.push(0); + utf16_bytes } /// Specify the usage type of the generated key @@ -41,63 +43,68 @@ pub fn derive_key( id: Pkcs12KeyType, rounds: i32, key_len: usize, -) -> Result> +) -> Vec where D: Digest + FixedOutputReset + BlockSizeUser, { - let mut hasher = D::new(); - let pass_uni = str_to_unicode(pass); - let u = ::output_size(); - let v = D::block_size(); - let slen = v * ((salt.len() + v - 1) / v); - let plen = v * ((pass_uni.len() + v - 1) / v); + let mut digest = D::new(); + let mut pass_utf16 = str_to_unicode(pass); + let output_size = ::output_size(); + let block_size = D::block_size(); + let slen = block_size * ((salt.len() + block_size - 1) / block_size); + let plen = block_size * ((pass_utf16.len() + block_size - 1) / block_size); let ilen = slen + plen; - let mut i_tmp = vec![0u8; ilen]; + let mut init_key = vec![0u8; ilen]; for i in 0..slen { - i_tmp[i] = salt[i % salt.len()]; + init_key[i] = salt[i % salt.len()]; } - for i in slen..ilen { - i_tmp[i] = pass_uni[(i - slen) % pass_uni.len()]; + for i in 0..plen { + init_key[slen + i] = pass_utf16[i % pass_utf16.len()]; } - let d_tmp = match id { - Pkcs12KeyType::EncryptionKey => vec![1u8; v], - Pkcs12KeyType::Iv => vec![2u8; v], - Pkcs12KeyType::Mac => vec![3u8; v], + pass_utf16.zeroize(); + + let id_block = match id { + Pkcs12KeyType::EncryptionKey => vec![1u8; block_size], + Pkcs12KeyType::Iv => vec![2u8; block_size], + Pkcs12KeyType::Mac => vec![3u8; block_size], }; + let mut m = key_len; let mut n = 0; let mut out = vec![0u8; key_len]; loop { - ::update(&mut hasher, &d_tmp); - ::update(&mut hasher, &i_tmp); - let mut result = hasher.finalize_fixed_reset(); + ::update(&mut digest, &id_block); + ::update(&mut digest, &init_key); + let mut result = digest.finalize_fixed_reset(); for _ in 1..rounds { - ::update(&mut hasher, &result[0..u]); - result = hasher.finalize_fixed_reset(); + ::update(&mut digest, &result[0..output_size]); + result = digest.finalize_fixed_reset(); } - let min_mu = m.min(u); - out[n..n + min_mu].copy_from_slice(&result[0..min_mu]); - n += min_mu; - if m <= min_mu { + let new_bytes_num = m.min(output_size); + out[n..n + new_bytes_num].copy_from_slice(&result[0..new_bytes_num]); + n += new_bytes_num; + if m <= new_bytes_num { break; } - m -= min_mu; - let mut b_tmp = vec![0u8; v]; - for j in 0..v { - b_tmp[j] = result[j % u]; - } + + // prepare `init_key` for next block if `ouput_size` is smaller than `key_len` + m -= new_bytes_num; let mut j = 0; while j < ilen { let mut c = 1_u16; - let mut k: i64 = v as i64 - 1; - while k >= 0 { - c += i_tmp[k as usize + j] as u16 + b_tmp[k as usize] as u16; - i_tmp[j + k as usize] = (c & 0x00ff) as u8; + let mut k = block_size - 1; + loop { + c += init_key[k + j] as u16 + result[k % output_size] as u16; + init_key[j + k] = (c & 0x00ff) as u8; c >>= 8; + if k == 0 { + break; + } k -= 1; } - j += v; + j += block_size; } } - Ok(out) + init_key.zeroize(); + out } diff --git a/pkcs12/src/lib.rs b/pkcs12/src/lib.rs index eb5659dc6..95782e025 100644 --- a/pkcs12/src/lib.rs +++ b/pkcs12/src/lib.rs @@ -28,6 +28,3 @@ cfg_if! { } } -pub mod error; - -pub use error::Result; diff --git a/pkcs12/tests/kdf.rs b/pkcs12/tests/kdf.rs index a157e118f..b65f63cfb 100644 --- a/pkcs12/tests/kdf.rs +++ b/pkcs12/tests/kdf.rs @@ -12,50 +12,47 @@ cfg_if! { const SALT_INC: [u8; 8] = [0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8]; assert_eq!( - derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 100, 32) - .unwrap(), + derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 100, 32), hex!("fae4d4957a3cc781e1180b9d4fb79c1e0c8579b746a3177e5b0768a3118bf863") ); assert_eq!( - derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Iv, 100, 32).unwrap(), + derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Iv, 100, 32), hex!("e5ff813bc6547de5155b14d2fada85b3201a977349db6e26ccc998d9e8f83d6c") ); assert_eq!( - derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Mac, 100, 32).unwrap(), + derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Mac, 100, 32), hex!("136355ed9434516682534f46d63956db5ff06b844702c2c1f3b46321e2524a4d") ); assert_eq!( - derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 100, 20) - .unwrap(), + derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 100, 20), hex!("fae4d4957a3cc781e1180b9d4fb79c1e0c8579b7") ); assert_eq!( - derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Iv, 100, 20).unwrap(), + derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Iv, 100, 20), hex!("e5ff813bc6547de5155b14d2fada85b3201a9773") ); assert_eq!( - derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Mac, 100, 20).unwrap(), + derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Mac, 100, 20), hex!("136355ed9434516682534f46d63956db5ff06b84") ); assert_eq!( - derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 100, 12) - .unwrap(), + derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 100, 12), hex!("fae4d4957a3cc781e1180b9d") ); assert_eq!( - derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Iv, 100, 12).unwrap(), + derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Iv, 100, 12), hex!("e5ff813bc6547de5155b14d2") ); assert_eq!( - derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Mac, 100, 12).unwrap(), + derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Mac, 100, 12), hex!("136355ed9434516682534f46") ); @@ -66,26 +63,35 @@ cfg_if! { Pkcs12KeyType::EncryptionKey, 1000, 32 - ) - .unwrap(), + ), hex!("2b95a0569b63f641fae1efca32e84db3699ab74540628ba66283b58cf5400527") ); assert_eq!( - derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Iv, 1000, 32).unwrap(), + derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Iv, 1000, 32), hex!("6472c0ebad3fab4123e8b5ed7834de21eeb20187b3eff78a7d1cdffa4034851d") ); assert_eq!( - derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Mac, 1000, 32).unwrap(), + derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Mac, 1000, 32), hex!("3f9113f05c30a996c4a516409bdac9d065f44296ccd52bb75de3fcfdbe2bf130") ); assert_eq!( - derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Mac, 1000, 32).unwrap(), + derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Mac, 1000, 32), hex!("3f9113f05c30a996c4a516409bdac9d065f44296ccd52bb75de3fcfdbe2bf130") ); - } + + assert_eq!( + derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 1000, 100), + hex!("2b95a0569b63f641fae1efca32e84db3699ab74540628ba66283b58cf5400527d8d0ebe2ccbf768c51c4d8fbd1bb156be06c1c59cbb69e44052ffc37376fdb47b2de7f9e543de9d096d8e5474b220410ff1c5d8bb7e5bc0f61baeaa12fd0da1d7a970172") + ); + + assert_eq!( + derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 1000, 200), + hex!("2b95a0569b63f641fae1efca32e84db3699ab74540628ba66283b58cf5400527d8d0ebe2ccbf768c51c4d8fbd1bb156be06c1c59cbb69e44052ffc37376fdb47b2de7f9e543de9d096d8e5474b220410ff1c5d8bb7e5bc0f61baeaa12fd0da1d7a9701729cea6014d7fe62a2ed926dc36b61307f119d64edbceb5a9c58133bbf75ba0bef000a1a5180e4b1de7d89c89528bcb7899a1e46fd4da0d9de8f8e65e8d0d775e33d1247e76d596a34303161b219f39afda448bf518a2835fc5e28f0b55a1b6137a2c70cf7") + ); + } #[test] fn pkcs12_key_derive_sha512() { @@ -96,8 +102,7 @@ cfg_if! { const SALT_INC: [u8; 8] = [0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8]; assert_eq!( - derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 100, 32) - .unwrap(), + derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 100, 32), hex!("b14a9f01bfd9dce4c9d66d2fe9937e5fd9f1afa59e370a6fa4fc81c1cc8ec8ee") ); } @@ -117,8 +122,7 @@ cfg_if! { Pkcs12KeyType::EncryptionKey, 100, 32 - ) - .unwrap(), + ), hex!("3324282adb468bff0734d3b7e399094ec8500cb5b0a3604055da107577aaf766") ); } From 1183d1037325991f20b0ab4947851f0309a94709 Mon Sep 17 00:00:00 2001 From: Mark Beinker Date: Sun, 16 Jul 2023 13:17:29 +0200 Subject: [PATCH 10/22] re-formatting --- pkcs12/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/pkcs12/src/lib.rs b/pkcs12/src/lib.rs index 95782e025..530688d52 100644 --- a/pkcs12/src/lib.rs +++ b/pkcs12/src/lib.rs @@ -27,4 +27,3 @@ cfg_if! { pub mod kdf; } } - From 7e11f4468378fef3b1410014eaaf5fbb98a4df0c Mon Sep 17 00:00:00 2001 From: Mark Beinker Date: Sun, 16 Jul 2023 15:25:50 +0200 Subject: [PATCH 11/22] make str_to_unicode private Co-authored-by: Tony Arcieri --- pkcs12/src/kdf.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkcs12/src/kdf.rs b/pkcs12/src/kdf.rs index 70b5a14b0..e38625da4 100644 --- a/pkcs12/src/kdf.rs +++ b/pkcs12/src/kdf.rs @@ -7,7 +7,7 @@ use zeroize::Zeroize; /// Transform a utf-8 string in a unicode (utf16) string as binary array. /// The Utf16 code points are stored in big endian format with two trailing zero bytes. -pub fn str_to_unicode(utf8_str: &str) -> Vec { +fn str_to_unicode(utf8_str: &str) -> Vec { let mut utf16_bytes = Vec::new(); // reserve max number of required bytes to avoid re-allocation utf16_bytes.reserve(utf8_str.len() * 2 + 2); From 87cc22a41165f75ced82a49b87405c12685ea915 Mon Sep 17 00:00:00 2001 From: Mark Beinker Date: Sun, 16 Jul 2023 15:38:55 +0200 Subject: [PATCH 12/22] apply suggestions from code review --- Cargo.lock | 2 +- pkcs12/Cargo.toml | 2 +- pkcs12/src/kdf.rs | 4 +- pkcs12/tests/kdf.rs | 233 ++++++++++++++++++++++---------------------- 4 files changed, 117 insertions(+), 124 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b5899adf7..9b9ec2a61 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1003,7 +1003,7 @@ dependencies = [ [[package]] name = "pkcs12" -version = "0.1.0" +version = "0.0.0" dependencies = [ "cfg-if", "digest", diff --git a/pkcs12/Cargo.toml b/pkcs12/Cargo.toml index b711ed65b..520356ab1 100644 --- a/pkcs12/Cargo.toml +++ b/pkcs12/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pkcs12" -version = "0.1.0" +version = "0.0.0" description = """ Pure Rust implementation of Public-Key Cryptography Standards (PKCS) #12: Personal Information Exchange Syntax v1.1 (RFC7292) diff --git a/pkcs12/src/kdf.rs b/pkcs12/src/kdf.rs index e38625da4..4ac584814 100644 --- a/pkcs12/src/kdf.rs +++ b/pkcs12/src/kdf.rs @@ -11,11 +11,9 @@ fn str_to_unicode(utf8_str: &str) -> Vec { let mut utf16_bytes = Vec::new(); // reserve max number of required bytes to avoid re-allocation utf16_bytes.reserve(utf8_str.len() * 2 + 2); - for code_point in utf8_str.encode_utf16() { + for code_point in utf8_str.encode_utf16().chain(Some(0)) { utf16_bytes.extend(code_point.to_be_bytes()); } - utf16_bytes.push(0); - utf16_bytes.push(0); utf16_bytes } diff --git a/pkcs12/tests/kdf.rs b/pkcs12/tests/kdf.rs index b65f63cfb..acdfdf659 100644 --- a/pkcs12/tests/kdf.rs +++ b/pkcs12/tests/kdf.rs @@ -1,130 +1,125 @@ -use cfg_if::cfg_if; - -cfg_if! { - if #[cfg(feature="alloc")] { - - #[test] - fn pkcs12_key_derive_sha256() { - use hex_literal::hex; - use pkcs12::kdf::{derive_key, Pkcs12KeyType}; - - const PASS_SHORT: &str = "ge@äheim"; - const SALT_INC: [u8; 8] = [0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8]; - - assert_eq!( - derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 100, 32), - hex!("fae4d4957a3cc781e1180b9d4fb79c1e0c8579b746a3177e5b0768a3118bf863") - ); - - assert_eq!( - derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Iv, 100, 32), - hex!("e5ff813bc6547de5155b14d2fada85b3201a977349db6e26ccc998d9e8f83d6c") - ); - - assert_eq!( - derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Mac, 100, 32), - hex!("136355ed9434516682534f46d63956db5ff06b844702c2c1f3b46321e2524a4d") - ); - - assert_eq!( - derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 100, 20), - hex!("fae4d4957a3cc781e1180b9d4fb79c1e0c8579b7") - ); - - assert_eq!( - derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Iv, 100, 20), - hex!("e5ff813bc6547de5155b14d2fada85b3201a9773") - ); - - assert_eq!( - derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Mac, 100, 20), - hex!("136355ed9434516682534f46d63956db5ff06b84") - ); - - assert_eq!( - derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 100, 12), - hex!("fae4d4957a3cc781e1180b9d") - ); - - assert_eq!( - derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Iv, 100, 12), - hex!("e5ff813bc6547de5155b14d2") - ); - - assert_eq!( - derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Mac, 100, 12), - hex!("136355ed9434516682534f46") - ); - - assert_eq!( - derive_key::( - PASS_SHORT, - &SALT_INC, - Pkcs12KeyType::EncryptionKey, - 1000, - 32 - ), - hex!("2b95a0569b63f641fae1efca32e84db3699ab74540628ba66283b58cf5400527") - ); - - assert_eq!( - derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Iv, 1000, 32), - hex!("6472c0ebad3fab4123e8b5ed7834de21eeb20187b3eff78a7d1cdffa4034851d") - ); - - assert_eq!( - derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Mac, 1000, 32), - hex!("3f9113f05c30a996c4a516409bdac9d065f44296ccd52bb75de3fcfdbe2bf130") - ); - - assert_eq!( - derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Mac, 1000, 32), - hex!("3f9113f05c30a996c4a516409bdac9d065f44296ccd52bb75de3fcfdbe2bf130") - ); - - assert_eq!( +#![cfg(feature = "alloc")] + +#[test] +fn pkcs12_key_derive_sha256() { + use hex_literal::hex; + use pkcs12::kdf::{derive_key, Pkcs12KeyType}; + + const PASS_SHORT: &str = "ge@äheim"; + const SALT_INC: [u8; 8] = [0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8]; + + assert_eq!( + derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 100, 32), + hex!("fae4d4957a3cc781e1180b9d4fb79c1e0c8579b746a3177e5b0768a3118bf863") + ); + + assert_eq!( + derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Iv, 100, 32), + hex!("e5ff813bc6547de5155b14d2fada85b3201a977349db6e26ccc998d9e8f83d6c") + ); + + assert_eq!( + derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Mac, 100, 32), + hex!("136355ed9434516682534f46d63956db5ff06b844702c2c1f3b46321e2524a4d") + ); + + assert_eq!( + derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 100, 20), + hex!("fae4d4957a3cc781e1180b9d4fb79c1e0c8579b7") + ); + + assert_eq!( + derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Iv, 100, 20), + hex!("e5ff813bc6547de5155b14d2fada85b3201a9773") + ); + + assert_eq!( + derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Mac, 100, 20), + hex!("136355ed9434516682534f46d63956db5ff06b84") + ); + + assert_eq!( + derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 100, 12), + hex!("fae4d4957a3cc781e1180b9d") + ); + + assert_eq!( + derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Iv, 100, 12), + hex!("e5ff813bc6547de5155b14d2") + ); + + assert_eq!( + derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Mac, 100, 12), + hex!("136355ed9434516682534f46") + ); + + assert_eq!( + derive_key::( + PASS_SHORT, + &SALT_INC, + Pkcs12KeyType::EncryptionKey, + 1000, + 32 + ), + hex!("2b95a0569b63f641fae1efca32e84db3699ab74540628ba66283b58cf5400527") + ); + + assert_eq!( + derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Iv, 1000, 32), + hex!("6472c0ebad3fab4123e8b5ed7834de21eeb20187b3eff78a7d1cdffa4034851d") + ); + + assert_eq!( + derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Mac, 1000, 32), + hex!("3f9113f05c30a996c4a516409bdac9d065f44296ccd52bb75de3fcfdbe2bf130") + ); + + assert_eq!( + derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Mac, 1000, 32), + hex!("3f9113f05c30a996c4a516409bdac9d065f44296ccd52bb75de3fcfdbe2bf130") + ); + + assert_eq!( derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 1000, 100), hex!("2b95a0569b63f641fae1efca32e84db3699ab74540628ba66283b58cf5400527d8d0ebe2ccbf768c51c4d8fbd1bb156be06c1c59cbb69e44052ffc37376fdb47b2de7f9e543de9d096d8e5474b220410ff1c5d8bb7e5bc0f61baeaa12fd0da1d7a970172") ); - assert_eq!( + assert_eq!( derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 1000, 200), hex!("2b95a0569b63f641fae1efca32e84db3699ab74540628ba66283b58cf5400527d8d0ebe2ccbf768c51c4d8fbd1bb156be06c1c59cbb69e44052ffc37376fdb47b2de7f9e543de9d096d8e5474b220410ff1c5d8bb7e5bc0f61baeaa12fd0da1d7a9701729cea6014d7fe62a2ed926dc36b61307f119d64edbceb5a9c58133bbf75ba0bef000a1a5180e4b1de7d89c89528bcb7899a1e46fd4da0d9de8f8e65e8d0d775e33d1247e76d596a34303161b219f39afda448bf518a2835fc5e28f0b55a1b6137a2c70cf7") ); - } +} - #[test] - fn pkcs12_key_derive_sha512() { - use hex_literal::hex; - use pkcs12::kdf::{derive_key, Pkcs12KeyType}; +#[test] +fn pkcs12_key_derive_sha512() { + use hex_literal::hex; + use pkcs12::kdf::{derive_key, Pkcs12KeyType}; - const PASS_SHORT: &str = "ge@äheim"; - const SALT_INC: [u8; 8] = [0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8]; + const PASS_SHORT: &str = "ge@äheim"; + const SALT_INC: [u8; 8] = [0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8]; - assert_eq!( - derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 100, 32), - hex!("b14a9f01bfd9dce4c9d66d2fe9937e5fd9f1afa59e370a6fa4fc81c1cc8ec8ee") - ); - } - - #[test] - fn pkcs12_key_derive_whirlpool() { - use hex_literal::hex; - use pkcs12::kdf::{derive_key, Pkcs12KeyType}; - - const PASS_SHORT: &str = "ge@äheim"; - const SALT_INC: [u8; 8] = [0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8]; - - assert_eq!( - derive_key::( - PASS_SHORT, - &SALT_INC, - Pkcs12KeyType::EncryptionKey, - 100, - 32 - ), - hex!("3324282adb468bff0734d3b7e399094ec8500cb5b0a3604055da107577aaf766") - ); - } - } + assert_eq!( + derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 100, 32), + hex!("b14a9f01bfd9dce4c9d66d2fe9937e5fd9f1afa59e370a6fa4fc81c1cc8ec8ee") + ); +} + +#[test] +fn pkcs12_key_derive_whirlpool() { + use hex_literal::hex; + use pkcs12::kdf::{derive_key, Pkcs12KeyType}; + + const PASS_SHORT: &str = "ge@äheim"; + const SALT_INC: [u8; 8] = [0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8]; + + assert_eq!( + derive_key::( + PASS_SHORT, + &SALT_INC, + Pkcs12KeyType::EncryptionKey, + 100, + 32 + ), + hex!("3324282adb468bff0734d3b7e399094ec8500cb5b0a3604055da107577aaf766") + ); } From 3dd8ece26a710fe130d7fd139f346724489d36aa Mon Sep 17 00:00:00 2001 From: Mark Beinker Date: Mon, 17 Jul 2023 17:41:55 +0200 Subject: [PATCH 13/22] remove feature flag for alloc Co-authored-by: Tony Arcieri --- pkcs12/src/lib.rs | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/pkcs12/src/lib.rs b/pkcs12/src/lib.rs index 530688d52..ab58c860e 100644 --- a/pkcs12/src/lib.rs +++ b/pkcs12/src/lib.rs @@ -16,14 +16,6 @@ //! TODO: complete PKCS#12 crate -use cfg_if::cfg_if; +extern crate alloc; -cfg_if! { - if #[cfg(feature = "alloc")] { - - #[macro_use] - extern crate alloc; - - pub mod kdf; - } -} +pub mod kdf; From 282baa59bac74845c280308877f291a57559933f Mon Sep 17 00:00:00 2001 From: Mark Beinker Date: Mon, 17 Jul 2023 17:55:27 +0200 Subject: [PATCH 14/22] add test case for 4 byte utf8 codec --- pkcs12/Cargo.toml | 3 --- pkcs12/src/kdf.rs | 2 +- pkcs12/tests/kdf.rs | 26 +++++++++++++++++++++----- 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/pkcs12/Cargo.toml b/pkcs12/Cargo.toml index 520356ab1..d51772343 100644 --- a/pkcs12/Cargo.toml +++ b/pkcs12/Cargo.toml @@ -14,9 +14,6 @@ readme = "README.md" edition = "2021" rust-version = "1.65" -[features] -alloc = [] - [dependencies] cfg-if = "1.0.0" digest = { version = "0.10.7", features=["alloc"] } diff --git a/pkcs12/src/kdf.rs b/pkcs12/src/kdf.rs index 4ac584814..fc4ba1b22 100644 --- a/pkcs12/src/kdf.rs +++ b/pkcs12/src/kdf.rs @@ -1,7 +1,7 @@ //! Implementation of the key derivation function //! [RFC 7292 Appendix B](https://datatracker.ietf.org/doc/html/rfc7292#appendix-B) -use alloc::vec::Vec; +use alloc::{vec, vec::Vec}; use digest::{core_api::BlockSizeUser, Digest, FixedOutputReset, OutputSizeUser, Update}; use zeroize::Zeroize; diff --git a/pkcs12/tests/kdf.rs b/pkcs12/tests/kdf.rs index acdfdf659..f5954dd73 100644 --- a/pkcs12/tests/kdf.rs +++ b/pkcs12/tests/kdf.rs @@ -1,10 +1,13 @@ -#![cfg(feature = "alloc")] - +/// Test cases for the key derivation functions. +/// All test cases have been verified against openssl's method `PKCS12_key_gen_utf8`. +/// See https://github.com/xemwebe/test_pkcs12_kdf for a sample program. +/// + +use hex_literal::hex; +use pkcs12::kdf::{derive_key, Pkcs12KeyType}; + #[test] fn pkcs12_key_derive_sha256() { - use hex_literal::hex; - use pkcs12::kdf::{derive_key, Pkcs12KeyType}; - const PASS_SHORT: &str = "ge@äheim"; const SALT_INC: [u8; 8] = [0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8]; @@ -123,3 +126,16 @@ fn pkcs12_key_derive_whirlpool() { hex!("3324282adb468bff0734d3b7e399094ec8500cb5b0a3604055da107577aaf766") ); } + +#[test] +fn pkcs12_key_derive_special_chars() { + const PASS_SHORT: &str = "🔥"; + const SALT_INC: [u8; 8] = [0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8]; + + assert_eq!( + derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 100, 32), + hex!("d01e72a940b4b1a7a5707fc8264a60cb7606ff9051dedff90930687d2513c006") + ); +} + + From 7537728bf1b7cc57d3000dd73180326e552644eb Mon Sep 17 00:00:00 2001 From: Mark Beinker Date: Mon, 17 Jul 2023 19:06:22 +0200 Subject: [PATCH 15/22] add comments describing the steps of the RFC algorithm --- pkcs12/src/kdf.rs | 51 ++++++++++++++++++++++++++++++++++++++------- pkcs12/tests/kdf.rs | 5 +---- 2 files changed, 45 insertions(+), 11 deletions(-) diff --git a/pkcs12/src/kdf.rs b/pkcs12/src/kdf.rs index fc4ba1b22..120faeb4d 100644 --- a/pkcs12/src/kdf.rs +++ b/pkcs12/src/kdf.rs @@ -49,28 +49,53 @@ where let mut pass_utf16 = str_to_unicode(pass); let output_size = ::output_size(); let block_size = D::block_size(); + + // In the following, the numbered comments relate directly to the algorithm + // described in RFC 7292, Appendix B.2. Actual variable names may differ. + // Comments of the RFC are in enclosed in [] + // + // 1. Construct a string, D (the "diversifier"), by concatenating v/8 + // copies of ID, where v is the block size in bits. + let id_block = match id { + Pkcs12KeyType::EncryptionKey => vec![1u8; block_size], + Pkcs12KeyType::Iv => vec![2u8; block_size], + Pkcs12KeyType::Mac => vec![3u8; block_size], + }; + let slen = block_size * ((salt.len() + block_size - 1) / block_size); let plen = block_size * ((pass_utf16.len() + block_size - 1) / block_size); let ilen = slen + plen; let mut init_key = vec![0u8; ilen]; + // 2. Concatenate copies of the salt together to create a string S of + // length v(ceiling(s/v)) bits (the final copy of the salt may be + // truncated to create S). Note that if the salt is the empty + // string, then so is S. for i in 0..slen { init_key[i] = salt[i % salt.len()]; } + + // 3. Concatenate copies of the password together to create a string P + // of length v(ceiling(p/v)) bits (the final copy of the password + // may be truncated to create P). Note that if the password is the + // empty string, then so is P. for i in 0..plen { init_key[slen + i] = pass_utf16[i % pass_utf16.len()]; } pass_utf16.zeroize(); - let id_block = match id { - Pkcs12KeyType::EncryptionKey => vec![1u8; block_size], - Pkcs12KeyType::Iv => vec![2u8; block_size], - Pkcs12KeyType::Mac => vec![3u8; block_size], - }; + // 4. Set I=S||P to be the concatenation of S and P. + // [already done in `init_key`] let mut m = key_len; let mut n = 0; let mut out = vec![0u8; key_len]; + // 5. Set c=ceiling(n/u) + // 6. For i=1, 2, ..., c, do the following: + // [ Instead of following this approach, we use an infinite loop and + // use the break condition below, if we have produced n bytes for the key] loop { + // 6. A. Set A2=H^r(D||I). (i.e., the r-th hash of D||1, + // H(H(H(... H(D||I)))) ::update(&mut digest, &id_block); ::update(&mut digest, &init_key); let mut result = digest.finalize_fixed_reset(); @@ -78,15 +103,26 @@ where ::update(&mut digest, &result[0..output_size]); result = digest.finalize_fixed_reset(); } + + // 7. Concateate A_1, A_2, ..., A_c together to form a pseudorandom + // bit string, A. + // [ Instead of storing all Ais and concatenating later, we concatenate + // them immediately ] let new_bytes_num = m.min(output_size); out[n..n + new_bytes_num].copy_from_slice(&result[0..new_bytes_num]); n += new_bytes_num; if m <= new_bytes_num { break; } - - // prepare `init_key` for next block if `ouput_size` is smaller than `key_len` m -= new_bytes_num; + + // 6. B. Concatenate copies of Ai to create a string B of length v + // bits (the final copy of Ai may be truncated to create B). + // [ we achieve this on thy fly with the expression `result[k % output_size]` below] + + // 6. C. Treating I as a concatenation I_0, I_1, ..., I_(k-1) of v-bit + // blocks, where k=ceiling(s/v)+ceiling(p/v), modify I by + // setting I_j=(I_j+B+1) mod 2^v for each j. let mut j = 0; while j < ilen { let mut c = 1_u16; @@ -104,5 +140,6 @@ where } } init_key.zeroize(); + // 8. Use the first n bits of A as the output of this entire process. out } diff --git a/pkcs12/tests/kdf.rs b/pkcs12/tests/kdf.rs index f5954dd73..84ab4234a 100644 --- a/pkcs12/tests/kdf.rs +++ b/pkcs12/tests/kdf.rs @@ -2,10 +2,9 @@ /// All test cases have been verified against openssl's method `PKCS12_key_gen_utf8`. /// See https://github.com/xemwebe/test_pkcs12_kdf for a sample program. /// - use hex_literal::hex; use pkcs12::kdf::{derive_key, Pkcs12KeyType}; - + #[test] fn pkcs12_key_derive_sha256() { const PASS_SHORT: &str = "ge@äheim"; @@ -137,5 +136,3 @@ fn pkcs12_key_derive_special_chars() { hex!("d01e72a940b4b1a7a5707fc8264a60cb7606ff9051dedff90930687d2513c006") ); } - - From ebe05c2504f4dc227fb0b6b28caf8c7c64f906a1 Mon Sep 17 00:00:00 2001 From: Mark Beinker Date: Tue, 18 Jul 2023 09:10:17 +0200 Subject: [PATCH 16/22] use more efficient way to allocate utf16 buffer Co-authored-by: Tony Arcieri --- pkcs12/src/kdf.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pkcs12/src/kdf.rs b/pkcs12/src/kdf.rs index 120faeb4d..5dc32a800 100644 --- a/pkcs12/src/kdf.rs +++ b/pkcs12/src/kdf.rs @@ -8,9 +8,7 @@ use zeroize::Zeroize; /// Transform a utf-8 string in a unicode (utf16) string as binary array. /// The Utf16 code points are stored in big endian format with two trailing zero bytes. fn str_to_unicode(utf8_str: &str) -> Vec { - let mut utf16_bytes = Vec::new(); - // reserve max number of required bytes to avoid re-allocation - utf16_bytes.reserve(utf8_str.len() * 2 + 2); + let mut utf16_bytes = Vec::with_capacity(utf8_str.len() * 2 + 2); for code_point in utf8_str.encode_utf16().chain(Some(0)) { utf16_bytes.extend(code_point.to_be_bytes()); } From 8622bfdd3f7bf9856fb3f09b990d50de0d40c601 Mon Sep 17 00:00:00 2001 From: Mark Beinker Date: Wed, 19 Jul 2023 17:05:46 +0200 Subject: [PATCH 17/22] add feature flag kdf --- pkcs12/Cargo.toml | 5 ++++- pkcs12/src/lib.rs | 3 +++ pkcs12/tests/kdf.rs | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/pkcs12/Cargo.toml b/pkcs12/Cargo.toml index d51772343..937fcf674 100644 --- a/pkcs12/Cargo.toml +++ b/pkcs12/Cargo.toml @@ -16,7 +16,7 @@ rust-version = "1.65" [dependencies] cfg-if = "1.0.0" -digest = { version = "0.10.7", features=["alloc"] } +digest = { version = "0.10.7", features=["alloc"], optional = true } zeroize = "1.6.0" [dev-dependencies] @@ -28,3 +28,6 @@ whirlpool = "0.10.4" all-features = true rustdoc-args = ["--cfg", "docsrs"] +[features] +kdf = ["dep:digest"] + diff --git a/pkcs12/src/lib.rs b/pkcs12/src/lib.rs index ab58c860e..7562d9518 100644 --- a/pkcs12/src/lib.rs +++ b/pkcs12/src/lib.rs @@ -16,6 +16,9 @@ //! TODO: complete PKCS#12 crate +#[cfg(feature="kdf")] extern crate alloc; +#[cfg(feature="kdf")] pub mod kdf; + diff --git a/pkcs12/tests/kdf.rs b/pkcs12/tests/kdf.rs index 84ab4234a..6932b059e 100644 --- a/pkcs12/tests/kdf.rs +++ b/pkcs12/tests/kdf.rs @@ -1,3 +1,4 @@ +#![cfg(feature="kdf")] /// Test cases for the key derivation functions. /// All test cases have been verified against openssl's method `PKCS12_key_gen_utf8`. /// See https://github.com/xemwebe/test_pkcs12_kdf for a sample program. From 30960c841fb8248b76ba41ab218722b081999fc0 Mon Sep 17 00:00:00 2001 From: Mark Beinker Date: Wed, 19 Jul 2023 17:53:11 +0200 Subject: [PATCH 18/22] formatting --- pkcs12/src/lib.rs | 5 ++--- pkcs12/tests/kdf.rs | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/pkcs12/src/lib.rs b/pkcs12/src/lib.rs index 7562d9518..29abfabb4 100644 --- a/pkcs12/src/lib.rs +++ b/pkcs12/src/lib.rs @@ -16,9 +16,8 @@ //! TODO: complete PKCS#12 crate -#[cfg(feature="kdf")] +#[cfg(feature = "kdf")] extern crate alloc; -#[cfg(feature="kdf")] +#[cfg(feature = "kdf")] pub mod kdf; - diff --git a/pkcs12/tests/kdf.rs b/pkcs12/tests/kdf.rs index 6932b059e..3c1821331 100644 --- a/pkcs12/tests/kdf.rs +++ b/pkcs12/tests/kdf.rs @@ -1,4 +1,4 @@ -#![cfg(feature="kdf")] +#![cfg(feature = "kdf")] /// Test cases for the key derivation functions. /// All test cases have been verified against openssl's method `PKCS12_key_gen_utf8`. /// See https://github.com/xemwebe/test_pkcs12_kdf for a sample program. From b04da8c528d203f89a9af0380045123ea17b1a7a Mon Sep 17 00:00:00 2001 From: Mark Beinker Date: Thu, 20 Jul 2023 10:30:06 +0200 Subject: [PATCH 19/22] factor out conversion of utf8 string --- pkcs12/src/kdf.rs | 35 ++++++++++++++++++++++++++++------- pkcs12/tests/kdf.rs | 41 +++++++++++++++++++---------------------- 2 files changed, 47 insertions(+), 29 deletions(-) diff --git a/pkcs12/src/kdf.rs b/pkcs12/src/kdf.rs index 5dc32a800..cf2b3a87c 100644 --- a/pkcs12/src/kdf.rs +++ b/pkcs12/src/kdf.rs @@ -3,7 +3,7 @@ use alloc::{vec, vec::Vec}; use digest::{core_api::BlockSizeUser, Digest, FixedOutputReset, OutputSizeUser, Update}; -use zeroize::Zeroize; +use zeroize::{Zeroize, Zeroizing}; /// Transform a utf-8 string in a unicode (utf16) string as binary array. /// The Utf16 code points are stored in big endian format with two trailing zero bytes. @@ -29,22 +29,44 @@ pub enum Pkcs12KeyType { /// Derives `key` of type `id` from `pass` and `salt` with length `key_len` using `rounds` /// iterations of the algorithm +/// `pass` must be a utf8 string. /// ```rust -/// let key = pkcs12::kdf::derive_key::("top-secret", &[0x1, 0x2, 0x3, 0x4], +/// let key = pkcs12::kdf::derive_key_utf8::("top-secret", &[0x1, 0x2, 0x3, 0x4], /// pkcs12::kdf::Pkcs12KeyType::EncryptionKey, 1000, 32); /// ``` -pub fn derive_key( +pub fn derive_key_utf8( pass: &str, salt: &[u8], id: Pkcs12KeyType, rounds: i32, key_len: usize, ) -> Vec +where + D: Digest + FixedOutputReset + BlockSizeUser, +{ + let mut pass_utf16 = Zeroizing::new(str_to_unicode(pass)); + derive_key::(&pass_utf16, salt, id, rounds, key_len) +} + +/// Derives `key` of type `id` from `pass` and `salt` with length `key_len` using `rounds` +/// iterations of the algorithm +/// `pass` must be a unicode (utf16) byte array in big endian order without order mark and with two +/// terminating zero bytes. +/// ```rust +/// let key = pkcs12::kdf::derive_key_utf8::("top-secret", &[0x1, 0x2, 0x3, 0x4], +/// pkcs12::kdf::Pkcs12KeyType::EncryptionKey, 1000, 32); +/// ``` +pub fn derive_key( + pass: &[u8], + salt: &[u8], + id: Pkcs12KeyType, + rounds: i32, + key_len: usize, +) -> Vec where D: Digest + FixedOutputReset + BlockSizeUser, { let mut digest = D::new(); - let mut pass_utf16 = str_to_unicode(pass); let output_size = ::output_size(); let block_size = D::block_size(); @@ -61,7 +83,7 @@ where }; let slen = block_size * ((salt.len() + block_size - 1) / block_size); - let plen = block_size * ((pass_utf16.len() + block_size - 1) / block_size); + let plen = block_size * ((pass.len() + block_size - 1) / block_size); let ilen = slen + plen; let mut init_key = vec![0u8; ilen]; // 2. Concatenate copies of the salt together to create a string S of @@ -77,9 +99,8 @@ where // may be truncated to create P). Note that if the password is the // empty string, then so is P. for i in 0..plen { - init_key[slen + i] = pass_utf16[i % pass_utf16.len()]; + init_key[slen + i] = pass[i % pass.len()]; } - pass_utf16.zeroize(); // 4. Set I=S||P to be the concatenation of S and P. // [already done in `init_key`] diff --git a/pkcs12/tests/kdf.rs b/pkcs12/tests/kdf.rs index 3c1821331..f513aeaa4 100644 --- a/pkcs12/tests/kdf.rs +++ b/pkcs12/tests/kdf.rs @@ -4,7 +4,7 @@ /// See https://github.com/xemwebe/test_pkcs12_kdf for a sample program. /// use hex_literal::hex; -use pkcs12::kdf::{derive_key, Pkcs12KeyType}; +use pkcs12::kdf::{derive_key_utf8, Pkcs12KeyType}; #[test] fn pkcs12_key_derive_sha256() { @@ -12,52 +12,52 @@ fn pkcs12_key_derive_sha256() { const SALT_INC: [u8; 8] = [0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8]; assert_eq!( - derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 100, 32), + derive_key_utf8::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 100, 32), hex!("fae4d4957a3cc781e1180b9d4fb79c1e0c8579b746a3177e5b0768a3118bf863") ); assert_eq!( - derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Iv, 100, 32), + derive_key_utf8::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Iv, 100, 32), hex!("e5ff813bc6547de5155b14d2fada85b3201a977349db6e26ccc998d9e8f83d6c") ); assert_eq!( - derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Mac, 100, 32), + derive_key_utf8::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Mac, 100, 32), hex!("136355ed9434516682534f46d63956db5ff06b844702c2c1f3b46321e2524a4d") ); assert_eq!( - derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 100, 20), + derive_key_utf8::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 100, 20), hex!("fae4d4957a3cc781e1180b9d4fb79c1e0c8579b7") ); assert_eq!( - derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Iv, 100, 20), + derive_key_utf8::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Iv, 100, 20), hex!("e5ff813bc6547de5155b14d2fada85b3201a9773") ); assert_eq!( - derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Mac, 100, 20), + derive_key_utf8::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Mac, 100, 20), hex!("136355ed9434516682534f46d63956db5ff06b84") ); assert_eq!( - derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 100, 12), + derive_key_utf8::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 100, 12), hex!("fae4d4957a3cc781e1180b9d") ); assert_eq!( - derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Iv, 100, 12), + derive_key_utf8::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Iv, 100, 12), hex!("e5ff813bc6547de5155b14d2") ); assert_eq!( - derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Mac, 100, 12), + derive_key_utf8::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Mac, 100, 12), hex!("136355ed9434516682534f46") ); assert_eq!( - derive_key::( + derive_key_utf8::( PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, @@ -68,27 +68,27 @@ fn pkcs12_key_derive_sha256() { ); assert_eq!( - derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Iv, 1000, 32), + derive_key_utf8::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Iv, 1000, 32), hex!("6472c0ebad3fab4123e8b5ed7834de21eeb20187b3eff78a7d1cdffa4034851d") ); assert_eq!( - derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Mac, 1000, 32), + derive_key_utf8::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Mac, 1000, 32), hex!("3f9113f05c30a996c4a516409bdac9d065f44296ccd52bb75de3fcfdbe2bf130") ); assert_eq!( - derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Mac, 1000, 32), + derive_key_utf8::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::Mac, 1000, 32), hex!("3f9113f05c30a996c4a516409bdac9d065f44296ccd52bb75de3fcfdbe2bf130") ); assert_eq!( - derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 1000, 100), + derive_key_utf8::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 1000, 100), hex!("2b95a0569b63f641fae1efca32e84db3699ab74540628ba66283b58cf5400527d8d0ebe2ccbf768c51c4d8fbd1bb156be06c1c59cbb69e44052ffc37376fdb47b2de7f9e543de9d096d8e5474b220410ff1c5d8bb7e5bc0f61baeaa12fd0da1d7a970172") ); assert_eq!( - derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 1000, 200), + derive_key_utf8::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 1000, 200), hex!("2b95a0569b63f641fae1efca32e84db3699ab74540628ba66283b58cf5400527d8d0ebe2ccbf768c51c4d8fbd1bb156be06c1c59cbb69e44052ffc37376fdb47b2de7f9e543de9d096d8e5474b220410ff1c5d8bb7e5bc0f61baeaa12fd0da1d7a9701729cea6014d7fe62a2ed926dc36b61307f119d64edbceb5a9c58133bbf75ba0bef000a1a5180e4b1de7d89c89528bcb7899a1e46fd4da0d9de8f8e65e8d0d775e33d1247e76d596a34303161b219f39afda448bf518a2835fc5e28f0b55a1b6137a2c70cf7") ); } @@ -102,21 +102,18 @@ fn pkcs12_key_derive_sha512() { const SALT_INC: [u8; 8] = [0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8]; assert_eq!( - derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 100, 32), + derive_key_utf8::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 100, 32), hex!("b14a9f01bfd9dce4c9d66d2fe9937e5fd9f1afa59e370a6fa4fc81c1cc8ec8ee") ); } #[test] fn pkcs12_key_derive_whirlpool() { - use hex_literal::hex; - use pkcs12::kdf::{derive_key, Pkcs12KeyType}; - const PASS_SHORT: &str = "ge@äheim"; const SALT_INC: [u8; 8] = [0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8]; assert_eq!( - derive_key::( + derive_key_utf8::( PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, @@ -133,7 +130,7 @@ fn pkcs12_key_derive_special_chars() { const SALT_INC: [u8; 8] = [0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8]; assert_eq!( - derive_key::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 100, 32), + derive_key_utf8::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 100, 32), hex!("d01e72a940b4b1a7a5707fc8264a60cb7606ff9051dedff90930687d2513c006") ); } From f669db876ae2d8228ebc2b0a839666d585cc6dd3 Mon Sep 17 00:00:00 2001 From: Mark Beinker Date: Thu, 20 Jul 2023 10:32:12 +0200 Subject: [PATCH 20/22] formatting --- pkcs12/tests/kdf.rs | 40 +++++++++++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/pkcs12/tests/kdf.rs b/pkcs12/tests/kdf.rs index f513aeaa4..cf10e641c 100644 --- a/pkcs12/tests/kdf.rs +++ b/pkcs12/tests/kdf.rs @@ -12,7 +12,13 @@ fn pkcs12_key_derive_sha256() { const SALT_INC: [u8; 8] = [0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8]; assert_eq!( - derive_key_utf8::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 100, 32), + derive_key_utf8::( + PASS_SHORT, + &SALT_INC, + Pkcs12KeyType::EncryptionKey, + 100, + 32 + ), hex!("fae4d4957a3cc781e1180b9d4fb79c1e0c8579b746a3177e5b0768a3118bf863") ); @@ -27,7 +33,13 @@ fn pkcs12_key_derive_sha256() { ); assert_eq!( - derive_key_utf8::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 100, 20), + derive_key_utf8::( + PASS_SHORT, + &SALT_INC, + Pkcs12KeyType::EncryptionKey, + 100, + 20 + ), hex!("fae4d4957a3cc781e1180b9d4fb79c1e0c8579b7") ); @@ -42,7 +54,13 @@ fn pkcs12_key_derive_sha256() { ); assert_eq!( - derive_key_utf8::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 100, 12), + derive_key_utf8::( + PASS_SHORT, + &SALT_INC, + Pkcs12KeyType::EncryptionKey, + 100, + 12 + ), hex!("fae4d4957a3cc781e1180b9d") ); @@ -102,7 +120,13 @@ fn pkcs12_key_derive_sha512() { const SALT_INC: [u8; 8] = [0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8]; assert_eq!( - derive_key_utf8::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 100, 32), + derive_key_utf8::( + PASS_SHORT, + &SALT_INC, + Pkcs12KeyType::EncryptionKey, + 100, + 32 + ), hex!("b14a9f01bfd9dce4c9d66d2fe9937e5fd9f1afa59e370a6fa4fc81c1cc8ec8ee") ); } @@ -130,7 +154,13 @@ fn pkcs12_key_derive_special_chars() { const SALT_INC: [u8; 8] = [0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8]; assert_eq!( - derive_key_utf8::(PASS_SHORT, &SALT_INC, Pkcs12KeyType::EncryptionKey, 100, 32), + derive_key_utf8::( + PASS_SHORT, + &SALT_INC, + Pkcs12KeyType::EncryptionKey, + 100, + 32 + ), hex!("d01e72a940b4b1a7a5707fc8264a60cb7606ff9051dedff90930687d2513c006") ); } From 23c364a026854310fb1f2cc5f36b3ec696e0faeb Mon Sep 17 00:00:00 2001 From: Mark Beinker Date: Thu, 20 Jul 2023 10:57:31 +0200 Subject: [PATCH 21/22] remove superfluous mut --- pkcs12/src/kdf.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkcs12/src/kdf.rs b/pkcs12/src/kdf.rs index cf2b3a87c..e411324f6 100644 --- a/pkcs12/src/kdf.rs +++ b/pkcs12/src/kdf.rs @@ -44,7 +44,7 @@ pub fn derive_key_utf8( where D: Digest + FixedOutputReset + BlockSizeUser, { - let mut pass_utf16 = Zeroizing::new(str_to_unicode(pass)); + let pass_utf16 = Zeroizing::new(str_to_unicode(pass)); derive_key::(&pass_utf16, salt, id, rounds, key_len) } From bf455d369775559d191df5b9f0d5c369db4a3a61 Mon Sep 17 00:00:00 2001 From: Mark Beinker Date: Thu, 20 Jul 2023 12:31:46 +0200 Subject: [PATCH 22/22] remove superfluous use statement --- pkcs12/tests/kdf.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/pkcs12/tests/kdf.rs b/pkcs12/tests/kdf.rs index cf10e641c..2b40efeb4 100644 --- a/pkcs12/tests/kdf.rs +++ b/pkcs12/tests/kdf.rs @@ -113,9 +113,6 @@ fn pkcs12_key_derive_sha256() { #[test] fn pkcs12_key_derive_sha512() { - use hex_literal::hex; - use pkcs12::kdf::{derive_key, Pkcs12KeyType}; - const PASS_SHORT: &str = "ge@äheim"; const SALT_INC: [u8; 8] = [0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8];