mundane/kdf.rs
1// Copyright 2020 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Key Derivation Functions (KDFs).
6//!
7//! KDFs are low-level primitives often used to construct higher-level
8//! protocols. Unless you're sure that this is what you need, you should
9//! probably be using something else. In particular:
10//! - If you need password verification, see the [`password`] module.
11//!
12//! *This module is available if Mundane is built with the `kdf` feature.*
13//!
14//! [`password`]: ::password
15
16use std::num::NonZeroU32;
17
18use boringssl;
19use hash::Hasher;
20
21/// The PBKDF2 Key Derivation Function.
22///
23/// `pbkdf2` computes `iter` iterations of PBKDF2 of `password` and `salt`,
24/// using an HMAC based on the hash function `H`. It stores the result in
25/// `out_key`. Note that PBKDF2 can produce variable-length output, so it will
26/// always fill the entirety of `out_key` regardless of its length.
27///
28/// PBKDF2 is defined in RSA Security LLC's Public Key Cryptography Standards #5
29/// (PKCS #5) v2.0. For details, see [RFC 2898 Section 5.2].
30///
31/// # Security
32///
33/// While PBKDF2 can produce any amount of key output, the entropy of its output
34/// is bounded by the internal state. Be careful that the output key has enough
35/// entropy for your needs. See [RFC 2898 Appendix B.1] for a discussion on
36/// calculating the effective entropy of PBKDF2. Also remember that new attacks
37/// are sometimes discovered, and it is your responsibility to keep up with the
38/// latest attacks; RFC 2898's analysis may not be valid forever!
39///
40/// [RFC 2898 Section 5.2]: https://tools.ietf.org/html/rfc2898#section-5.2
41/// [RFC 2898 Appendix B.1]: https://tools.ietf.org/html/rfc2898#appendix-B.1
42pub fn pbkdf2<H: Hasher>(password: &[u8], salt: &[u8], iters: NonZeroU32, out_key: &mut [u8]) {
43 // PKCS5_PBKDF2_HMAC can only fail on OOM or if iters is 0.
44 boringssl::pkcs5_pbkdf2_hmac(password, salt, iters.get(), &H::evp_md(), out_key).unwrap();
45}
46
47#[cfg(feature = "insecure")]
48pub(crate) mod insecure_pbkdf2_hmac_sha1 {
49 use std::num::NonZeroU32;
50
51 #[allow(deprecated)]
52 use hash::InsecureSha1;
53 use kdf::pbkdf2;
54
55 /// INSECURE: The PBKDF2 Key Derivation Function over HMAC-SHA1.
56 ///
57 /// # Security
58 ///
59 /// PBKDF2-HMAC-SHA1 is considered insecure, and should only be used for
60 /// compatibility with legacy applications.
61 ///
62 /// # Behavior
63 ///
64 /// `pbkdf2_hmac_sha1` computes `iter` iterations of PBKDF2-HMAC-SHA1 of
65 /// `password` and `salt`. It stores the result in `out_key`.
66 ///
67 /// PBKDF2 is defined in RSA Security LLC's Public Key Cryptography
68 /// Standards #5 (PKCS #5) v2.0. For details, see [RFC 2898 Section 5.2].
69 ///
70 /// # Further Security Considerations
71 ///
72 /// While PBKDF2 can produce any amount of key output, the entropy of its
73 /// output is bounded by the internal state. Be careful that the output key
74 /// has enough entropy for your needs. See [RFC 2898 Appendix B.1] for a
75 /// discussion on calculating the effective entropy of PBKDF2, but keep in
76 /// mind that SHA-1's insecurities may affect this analysis! Also remember
77 /// that new attacks are sometimes discovered, and it is your responsibility
78 /// to keep up with the latest attacks; RFC 2898's analysis may not be valid
79 /// forever!
80 ///
81 /// [RFC 2898 Section 5.2]: https://tools.ietf.org/html/rfc2898#section-5.2
82 /// [RFC 2898 Appendix B.1]: https://tools.ietf.org/html/rfc2898#appendix-B.1
83 #[deprecated(note = "PBKDF2-HMAC-SHA1 is considered insecure")]
84 pub fn insecure_pbkdf2_hmac_sha1(
85 password: &[u8],
86 salt: &[u8],
87 iters: NonZeroU32,
88 out_key: &mut [u8],
89 ) {
90 #[allow(deprecated)]
91 pbkdf2::<InsecureSha1>(password, salt, iters, out_key)
92 }
93}
94
95#[cfg(test)]
96mod tests {
97 use super::*;
98 use hash::*;
99
100 #[test]
101 fn test_smoke() {
102 for password_len in 0..8 {
103 for salt_len in 0..8 {
104 for iters in 1..8 {
105 for out_key_len in 0..8 {
106 fn test<H: Hasher>(
107 password_len: usize,
108 salt_len: usize,
109 iters: u32,
110 out_key_len: usize,
111 ) {
112 let password = [0, 1, 2, 3, 4, 5, 6, 7];
113 let salt = [0, 1, 2, 3, 4, 5, 6, 7];
114 let mut out_key_0 = [0; 8];
115 let mut out_key_1 = [0; 8];
116
117 pbkdf2::<H>(
118 &password[..password_len],
119 &salt[..salt_len],
120 NonZeroU32::new(iters).unwrap(),
121 &mut out_key_0[..out_key_len],
122 );
123 pbkdf2::<H>(
124 &password[..password_len],
125 &salt[..salt_len],
126 NonZeroU32::new(iters).unwrap(),
127 &mut out_key_1[..out_key_len],
128 );
129 assert_eq!(&out_key_0[..out_key_len], &out_key_1[..out_key_len]);
130 }
131
132 test::<Sha256>(password_len, salt_len, iters, out_key_len);
133 test::<Sha384>(password_len, salt_len, iters, out_key_len);
134 test::<Sha512>(password_len, salt_len, iters, out_key_len);
135 }
136 }
137 }
138 }
139 }
140}