nss/
pbkdf2.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5use crate::util::{assert_nss_initialized, map_nss_secstatus, sec_item_as_slice, ScopedPtr};
6use crate::{
7    error::*,
8    pk11::{
9        slot::get_internal_slot,
10        types::{AlgorithmID, SymKey},
11    },
12};
13
14// Expose for consumers to choose the hashing algorithm
15// Currently only SHA256 supported
16pub use crate::pk11::context::HashAlgorithm;
17use nss_sys::SECOidTag;
18
19// ***** BASED ON THE FOLLOWING IMPLEMENTATION *****
20// https://searchfox.org/mozilla-central/rev/8ccea36c4fb09412609fb738c722830d7098602b/dom/crypto/WebCryptoTask.cpp#2567
21
22pub fn pbkdf2_key_derive(
23    password: &[u8],
24    salt: &[u8],
25    iterations: u32,
26    hash_algorithm: HashAlgorithm,
27    out: &mut [u8],
28) -> Result<()> {
29    assert_nss_initialized();
30    let oid_tag = match hash_algorithm {
31        HashAlgorithm::SHA256 => SECOidTag::SEC_OID_HMAC_SHA256 as u32,
32        HashAlgorithm::SHA384 => SECOidTag::SEC_OID_HMAC_SHA384 as u32,
33    };
34    let mut sec_salt = nss_sys::SECItem {
35        len: u32::try_from(salt.len())?,
36        data: salt.as_ptr() as *mut u8,
37        type_: 0,
38    };
39    let alg_id = unsafe {
40        AlgorithmID::from_ptr(nss_sys::PK11_CreatePBEV2AlgorithmID(
41            SECOidTag::SEC_OID_PKCS5_PBKDF2 as u32,
42            SECOidTag::SEC_OID_HMAC_SHA1 as u32,
43            oid_tag,
44            i32::try_from(out.len())?,
45            i32::try_from(iterations)?,
46            &mut sec_salt as *mut nss_sys::SECItem,
47        ))?
48    };
49
50    let slot = get_internal_slot()?;
51    let mut sec_pw = nss_sys::SECItem {
52        len: u32::try_from(password.len())?,
53        data: password.as_ptr() as *mut u8,
54        type_: 0,
55    };
56    let sym_key = unsafe {
57        SymKey::from_ptr(nss_sys::PK11_PBEKeyGen(
58            slot.as_mut_ptr(),
59            alg_id.as_mut_ptr(),
60            &mut sec_pw as *mut nss_sys::SECItem,
61            nss_sys::PR_FALSE,
62            std::ptr::null_mut(),
63        ))?
64    };
65    map_nss_secstatus(|| unsafe { nss_sys::PK11_ExtractKeyValue(sym_key.as_mut_ptr()) })?;
66
67    // This doesn't leak, because the SECItem* returned by PK11_GetKeyData
68    // just refers to a buffer managed by `sym_key` which we copy into `buf`
69    let mut key_data = unsafe { *nss_sys::PK11_GetKeyData(sym_key.as_mut_ptr()) };
70    let buf = unsafe { sec_item_as_slice(&mut key_data)? };
71    // Stop panic in swap_with_slice by returning an error if the sizes mismatch
72    if buf.len() != out.len() {
73        return Err(ErrorKind::InternalError.into());
74    }
75    out.swap_with_slice(buf);
76    Ok(())
77}