// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0 > or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT >, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::{os::raw::c_int, ptr::null_mut};
use crate ::{
Error, SECItemBorrowed,
hmac::{HmacAlgorithm, hmac_alg_to_prf_oid},
p11::{
PK11_CreatePBEV2AlgorithmID, PK11_PBEKeyGen, PRBool, SECOID_DestroyAlgorithmID, SECO
idTag,
Slot, SymKey,
},
};
/// Derive a key using PBKDF2.
///
/// Returns the derived key bytes as a `Vec<u8>`.
///
/// # Errors
///
/// Returns an error if inputs have invalid lengths, or if NSS functions fail.
pub fn pbkdf2(
alg: &HmacAlgorithm,
password: &[u8],
salt: &[u8],
iterations: u32,
key_len: usize,
) -> Result<Vec<u8>, Error> {
crate ::init()?;
let iterations = c_int::try_from(iterations)?;
let key_len_int = c_int::try_from(key_len)?;
let mut salt_item = SECItemBorrowed::wrap(salt)?;
let slot = Slot::internal()?;
let mut pw_item = SECItemBorrowed::wrap(password)?;
let algid = unsafe {
PK11_CreatePBEV2AlgorithmID(
SECOidTag::SEC_OID_PKCS5_PBKDF2,
hmac_alg_to_prf_oid(alg),
hmac_alg_to_prf_oid(alg),
key_len_int,
iterations,
salt_item.as_mut(),
)
};
if algid.is_null() {
return Err(Error::last_nss_error());
}
let key_ptr = unsafe {
PK11_PBEKeyGen(
*slot,
algid,
pw_item.as_mut(),
PRBool::from(false ),
null_mut(),
)
};
unsafe {
SECOID_DestroyAlgorithmID(algid, PRBool::from(true ));
}
let key = SymKey::from_ptr(key_ptr)?;
let data = key.key_data()?;
Ok(Vec::from(data))
}
#[ cfg(test)]
mod tests {
use test_fixture::fixture_init;
use super ::*;
#[ test]
fn rfc_7914_vector_1() {
fixture_init();
// RFC 7914 §11 provides PBKDF2-HMAC-SHA256 vectors. Using a common one:
// password="password", salt="salt", iter=1, dkLen=32.
let dk = pbkdf2(&HmacAlgorithm::HMAC_SHA2_256, b"password" , b"salt" , 1 , 32 ).unwrap();
let expected = [
0 x12, 0 x0f, 0 xb6, 0 xcf, 0 xfc, 0 xf8, 0 xb3, 0 x2c, 0 x43, 0 xe7, 0 x22, 0 x52, 0 x56, 0 xc4,
0 xf8, 0 x37, 0 xa8, 0 x65, 0 x48, 0 xc9, 0 x2c, 0 xcc, 0 x35, 0 x48, 0 x08, 0 x05, 0 x98, 0 x7c,
0 xb7, 0 x0b, 0 xe1, 0 x7b,
];
assert_eq!(dk, expected);
}
#[ test]
fn rfc_7914_vector_iter_2() {
fixture_init();
let dk = pbkdf2(&HmacAlgorithm::HMAC_SHA2_256, b"password" , b"salt" , 2 , 32 ).unwrap();
let expected = [
0 xae, 0 x4d, 0 x0c, 0 x95, 0 xaf, 0 x6b, 0 x46, 0 xd3, 0 x2d, 0 x0a, 0 xdf, 0 xf9, 0 x28, 0 xf0,
0 x6d, 0 xd0, 0 x2a, 0 x30, 0 x3f, 0 x8e, 0 xf3, 0 xc2, 0 x51, 0 xdf, 0 xd6, 0 xe2, 0 xd8, 0 x5a,
0 x95, 0 x47, 0 x4c, 0 x43,
];
assert_eq!(dk, expected);
}
#[ test]
fn pbkdf2_sha384_vector() {
fixture_init();
let dk = pbkdf2(&HmacAlgorithm::HMAC_SHA2_384, b"password" , b"salt" , 1 , 20 ).unwrap();
let expected = [
0 xc0, 0 xe1, 0 x4f, 0 x06, 0 xe4, 0 x9e, 0 x32, 0 xd7, 0 x3f, 0 x9f, 0 x52, 0 xdd, 0 xf1, 0 xd0,
0 xc5, 0 xc7, 0 x19, 0 x16, 0 x09, 0 x23,
];
assert_eq!(dk, expected);
}
#[ test]
fn pbkdf2_sha512_vector() {
fixture_init();
let dk = pbkdf2(&HmacAlgorithm::HMAC_SHA2_512, b"password" , b"salt" , 1 , 20 ).unwrap();
let expected = [
0 x86, 0 x7f, 0 x70, 0 xcf, 0 x1a, 0 xde, 0 x02, 0 xcf, 0 xf3, 0 x75, 0 x25, 0 x99, 0 xa3, 0 xa5,
0 x3d, 0 xc4, 0 xaf, 0 x34, 0 xc7, 0 xa6,
];
assert_eq!(dk, expected);
}
#[ test]
fn deterministic_across_calls() {
fixture_init();
let a = pbkdf2(
&HmacAlgorithm::HMAC_SHA2_256,
b"hello" ,
b"saltysalt0000000" ,
10 _000 ,
32 ,
)
.unwrap();
let b = pbkdf2(
&HmacAlgorithm::HMAC_SHA2_256,
b"hello" ,
b"saltysalt0000000" ,
10 _000 ,
32 ,
)
.unwrap();
assert_eq!(a, b);
}
#[ test]
fn different_salt_different_key() {
fixture_init();
let a = pbkdf2(
&HmacAlgorithm::HMAC_SHA2_256,
b"hello" ,
b"saltysalt0000000" ,
10 _000 ,
32 ,
)
.unwrap();
let b = pbkdf2(
&HmacAlgorithm::HMAC_SHA2_256,
b"hello" ,
b"saltysalt0000001" ,
10 _000 ,
32 ,
)
.unwrap();
assert_ne!(a, b);
}
}
Messung V0.5 in Prozent C=90 H=95 G=92
¤ Dauer der Verarbeitung: 0.3 Sekunden
¤
*© Formatika GbR, Deutschland