- : 0 %
- : 0 %
- : 0 %
- : 0 %
- : 0 %
- : 0 %
- : 0 %
- : 0 %
- : 0 %
- : 0 %
- : 0 %
- : 0 %
- : 0 %
- : 0 %
- : 0 %
- : 0 %
- : 0 %
- : 0 %
- : 80 %
- : 80 %
- : 80 %
- : 80 %
- : 80 %
- : 80 %
- : 80 %
- : 80 %
- : 80 %
- : 80 %
- : 80 %
- : 79 %
- : 79 %
- : 79 %
- : 79 %
- : 79 %
- : 79 %
- : 79 %
- : 79 %
- : 79 %
- : 79 %
- : 79 %
- : 79 %
- : 79 %
- : 79 %
- : 79 %
- : 79 %
- : 78 %
- : 78 %
- : 78 %
- : 78 %
- : 78 %
- : 78 %
- : 78 %
- : 78 %
- : 78 %
- : 78 %
- : 78 %
- : 78 %
- : 78 %
- : 78 %
- : 78 %
- : 78 %
- : 78 %
- : 78 %
- : 78 %
- : 78 %
- : 78 %
- : 78 %
- : 50 %
- : 50 %
- : 50 %
- : 50 %
- : 50 %
- : 50 %
- : 50 %
- : 50 %
- : 50 %
- : 50 %
- : 50 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
- : 54 %
Source code
Revision control
Copy as Markdown
Other Tools
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
use crate::LockstoreError;
use nss_rs::hmac::HmacAlgorithm;
use zeroize::Zeroizing;
pub const PBKDF2_ITERATIONS: u32 = 600_000;
pub const PBKDF2_SALT_SIZE: usize = 16;
/// PBKDF2-HMAC-SHA256 (RFC 8018 §5.2) via NSS's PBKDF2 primitive.
pub fn derive_kek(
password: &[u8],
salt: &[u8],
iterations: u32,
key_size: usize,
) -> Result<Zeroizing<Vec<u8>>, LockstoreError> {
if iterations == 0 {
return Err(LockstoreError::InvalidConfiguration(
"PBKDF2 iterations must be > 0".to_string(),
));
}
if key_size == 0 {
return Err(LockstoreError::InvalidConfiguration(
"PBKDF2 key_size must be > 0".to_string(),
));
}
// NSS derives the key internally, so no HMAC intermediates are held
// in Rust; wrap the returned key in `Zeroizing` so this
// password-derived secret is wiped from memory on drop.
nss_rs::pbkdf2::pbkdf2(
&HmacAlgorithm::HMAC_SHA2_256,
password,
salt,
iterations,
key_size,
)
.map(Zeroizing::new)
.map_err(|e| LockstoreError::Encryption(format!("PBKDF2 failed: {e}")))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn rfc_6070_vector_1() {
// RFC 6070 defines PBKDF2-HMAC-SHA1 test vectors; RFC 7914 §11 / many
// references provide PBKDF2-HMAC-SHA256 vectors. Using a common one:
// password="password", salt="salt", iter=1, dkLen=32.
let dk = derive_kek(b"password", b"salt", 1, 32).unwrap();
let expected = [
0x12, 0x0f, 0xb6, 0xcf, 0xfc, 0xf8, 0xb3, 0x2c, 0x43, 0xe7, 0x22, 0x52, 0x56, 0xc4,
0xf8, 0x37, 0xa8, 0x65, 0x48, 0xc9, 0x2c, 0xcc, 0x35, 0x48, 0x08, 0x05, 0x98, 0x7c,
0xb7, 0x0b, 0xe1, 0x7b,
];
assert_eq!(&dk[..], &expected[..]);
}
#[test]
fn rfc_7914_vector_iter_2() {
let dk = derive_kek(b"password", b"salt", 2, 32).unwrap();
let expected = [
0xae, 0x4d, 0x0c, 0x95, 0xaf, 0x6b, 0x46, 0xd3, 0x2d, 0x0a, 0xdf, 0xf9, 0x28, 0xf0,
0x6d, 0xd0, 0x2a, 0x30, 0x3f, 0x8e, 0xf3, 0xc2, 0x51, 0xdf, 0xd6, 0xe2, 0xd8, 0x5a,
0x95, 0x47, 0x4c, 0x43,
];
assert_eq!(&dk[..], &expected[..]);
}
#[test]
fn deterministic_across_calls() {
let a = derive_kek(b"hello", b"saltysalt0000000", 10_000, 32).unwrap();
let b = derive_kek(b"hello", b"saltysalt0000000", 10_000, 32).unwrap();
assert_eq!(&a[..], &b[..]);
}
#[test]
fn different_salt_different_key() {
let a = derive_kek(b"hello", b"saltysalt0000000", 10_000, 32).unwrap();
let b = derive_kek(b"hello", b"saltysalt0000001", 10_000, 32).unwrap();
assert_ne!(&a[..], &b[..]);
}
}