1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//! 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);
}
}
}
}
}
}