blob: 36f215863992332921f455c33a0b02aba18b963c [file] [log] [blame]
// Copyright 2018 Google LLC
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.
//! Key Derivation Functions (KDFs).
//!
//! KDFs are low-level primitives often used to construct higher-level
//! protocols. Unless you're sure that this is what you need, you should
//! probably be using something else. In particular:
//! - If you need password verification, see the [`password`] module.
//!
//! *This module is available if Mundane is built with the `kdf` feature.*
//!
//! [`password`]: ::password
use std::num::NonZeroU32;
use boringssl;
use hash::Hasher;
/// The PBKDF2 Key Derivation Function.
///
/// `pbkdf2` computes `iter` iterations of PBKDF2 of `password` and `salt`,
/// using an HMAC based on the hash function `H`. It stores the result in
/// `out_key`. Note that PBKDF2 can produce variable-length output, so it will
/// always fill the entirety of `out_key` regardless of its length.
///
/// PBKDF2 is defined in RSA Security LLC's Public Key Cryptography Standards #5
/// (PKCS #5) v2.0. For details, see [RFC 2898 Section 5.2].
///
/// # Security
///
/// While PBKDF2 can produce any amount of key output, the entropy of its output
/// is bounded by the internal state. Be careful that the output key has enough
/// entropy for your needs. See [RFC 2898 Appendix B.1] for a discussion on
/// calculating the effective entropy of PBKDF2. Also remember that new attacks
/// are sometimes discovered, and it is your responsibility to keep up with the
/// latest attacks; RFC 2898's analysis may not be valid forever!
///
/// [RFC 2898 Section 5.2]: https://tools.ietf.org/html/rfc2898#section-5.2
/// [RFC 2898 Appendix B.1]: https://tools.ietf.org/html/rfc2898#appendix-B.1
pub fn pbkdf2<H: Hasher>(password: &[u8], salt: &[u8], iters: NonZeroU32, out_key: &mut [u8]) {
// PKCS5_PBKDF2_HMAC can only fail on OOM or if iters is 0.
boringssl::pkcs5_pbkdf2_hmac(password, salt, iters.get(), &H::evp_md(), out_key).unwrap();
}
#[cfg(feature = "insecure")]
pub(crate) mod insecure_pbkdf2_hmac_sha1 {
use std::num::NonZeroU32;
#[allow(deprecated)]
use hash::InsecureSha1;
use kdf::pbkdf2;
/// INSECURE: The PBKDF2 Key Derivation Function over HMAC-SHA1.
///
/// # Security
///
/// PBKDF2-HMAC-SHA1 is considered insecure, and should only be used for
/// compatibility with legacy applications.
///
/// # Behavior
///
/// `pbkdf2_hmac_sha1` computes `iter` iterations of PBKDF2-HMAC-SHA1 of
/// `password` and `salt`. It stores the result in `out_key`.
///
/// PBKDF2 is defined in RSA Security LLC's Public Key Cryptography
/// Standards #5 (PKCS #5) v2.0. For details, see [RFC 2898 Section 5.2].
///
/// # Further Security Considerations
///
/// While PBKDF2 can produce any amount of key output, the entropy of its
/// output is bounded by the internal state. Be careful that the output key
/// has enough entropy for your needs. See [RFC 2898 Appendix B.1] for a
/// discussion on calculating the effective entropy of PBKDF2, but keep in
/// mind that SHA-1's insecurities may affect this analysis! Also remember
/// that new attacks are sometimes discovered, and it is your responsibility
/// to keep up with the latest attacks; RFC 2898's analysis may not be valid
/// forever!
///
/// [RFC 2898 Section 5.2]: https://tools.ietf.org/html/rfc2898#section-5.2
/// [RFC 2898 Appendix B.1]: https://tools.ietf.org/html/rfc2898#appendix-B.1
#[deprecated(note = "PBKDF2-HMAC-SHA1 is considered insecure")]
pub fn insecure_pbkdf2_hmac_sha1(
password: &[u8],
salt: &[u8],
iters: NonZeroU32,
out_key: &mut [u8],
) {
#[allow(deprecated)]
pbkdf2::<InsecureSha1>(password, salt, iters, out_key)
}
}
#[cfg(test)]
mod tests {
use super::*;
use hash::*;
#[test]
fn test_smoke() {
for password_len in 0..8 {
for salt_len in 0..8 {
for iters in 1..8 {
for out_key_len in 0..8 {
fn test<H: Hasher>(
password_len: usize,
salt_len: usize,
iters: u32,
out_key_len: usize,
) {
let password = [0, 1, 2, 3, 4, 5, 6, 7];
let salt = [0, 1, 2, 3, 4, 5, 6, 7];
let mut out_key_0 = [0; 8];
let mut out_key_1 = [0; 8];
pbkdf2::<H>(
&password[..password_len],
&salt[..salt_len],
NonZeroU32::new(iters).unwrap(),
&mut out_key_0[..out_key_len],
);
pbkdf2::<H>(
&password[..password_len],
&salt[..salt_len],
NonZeroU32::new(iters).unwrap(),
&mut out_key_1[..out_key_len],
);
assert_eq!(&out_key_0[..out_key_len], &out_key_1[..out_key_len]);
}
test::<Sha256>(password_len, salt_len, iters, out_key_len);
test::<Sha384>(password_len, salt_len, iters, out_key_len);
test::<Sha512>(password_len, salt_len, iters, out_key_len);
}
}
}
}
}
}