rc_crypto/
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::error::*;
6use nss::pbkdf2::pbkdf2_key_derive;
7pub use nss::pbkdf2::HashAlgorithm;
8/// Extend passwords using pbkdf2, based on the following [rfc](https://www.ietf.org/rfc/rfc2898.txt) it runs the NSS implementation
9/// # Arguments
10///
11///  * `passphrase` - The password to stretch
12///  * `salt` - A salt to use in the generation process
13///  * `iterations` - The number of iterations the hashing algorithm will run on each section of the key
14///  * `hash_algorithm` - The hash algorithm to use
15///  * `out` - The slice the algorithm will populate
16///
17/// # Examples
18///
19/// ```
20/// use rc_crypto::pbkdf2;
21/// use nss::ensure_initialized;
22/// ensure_initialized();
23/// let password = b"password";
24/// let salt = b"salt";
25/// let mut out = vec![0u8; 32];
26/// let iterations = 2; // Real code should have a MUCH higher number of iterations (Think 1000+)
27/// pbkdf2::derive(password, salt, iterations, pbkdf2::HashAlgorithm::SHA256, &mut out).unwrap(); // Oh oh should handle the error!
28/// assert_eq!(hex::encode(out), "ae4d0c95af6b46d32d0adff928f06dd02a303f8ef3c251dfd6e2d85a95474c43");
29//
30///```
31///
32/// # Errors
33///
34/// Could possibly return an error if the HMAC algorithm fails, or if the NSS algorithm returns an error
35pub fn derive(
36    passphrase: &[u8],
37    salt: &[u8],
38    iterations: u32,
39    hash_algorithm: HashAlgorithm,
40    out: &mut [u8],
41) -> Result<()> {
42    pbkdf2_key_derive(passphrase, salt, iterations, hash_algorithm, out)?;
43    Ok(())
44}
45
46#[cfg(test)]
47mod tests {
48    use super::*;
49    use nss::ensure_initialized;
50
51    #[test]
52    fn test_generate_correct_out() {
53        ensure_initialized();
54        let expected = "120fb6cffcf8b32c43e7225256c4f837a86548c92ccc35480805987cb70be17b";
55        let mut out = vec![0u8; 32];
56        let password = b"password";
57        let salt = b"salt";
58        derive(password, salt, 1, HashAlgorithm::SHA256, &mut out).unwrap();
59        assert_eq!(expected, hex::encode(out));
60    }
61
62    #[test]
63    fn test_longer_key() {
64        ensure_initialized();
65        let expected = "120fb6cffcf8b32c43e7225256c4f837a86548c92ccc35480805987cb70be17b4dbf3a2f3dad3377264bb7b8e8330d4efc7451418617dabef683735361cdc18c";
66        let password = b"password";
67        let salt = b"salt";
68        let mut out = vec![0u8; 64];
69        derive(password, salt, 1, HashAlgorithm::SHA256, &mut out).unwrap();
70        assert_eq!(expected, hex::encode(out));
71    }
72
73    #[test]
74    fn test_more_iterations() {
75        ensure_initialized();
76        let expected = "ae4d0c95af6b46d32d0adff928f06dd02a303f8ef3c251dfd6e2d85a95474c43";
77        let password = b"password";
78        let salt = b"salt";
79        let mut out = vec![0u8; 32];
80        derive(password, salt, 2, HashAlgorithm::SHA256, &mut out).unwrap();
81        assert_eq!(expected, hex::encode(out));
82    }
83
84    #[test]
85    fn test_odd_length() {
86        ensure_initialized();
87        let expected = "ad35240ac683febfaf3cd49d845473fbbbaa2437f5f82d5a415ae00ac76c6bfccf";
88        let password = b"password";
89        let salt = b"salt";
90        let mut out = vec![0u8; 33];
91        derive(password, salt, 3, HashAlgorithm::SHA256, &mut out).unwrap();
92        assert_eq!(expected, hex::encode(out));
93    }
94
95    #[test]
96    fn test_nulls() {
97        ensure_initialized();
98        let expected = "e25d526987819f966e324faa4a";
99        let password = b"passw\x00rd";
100        let salt = b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
101        let mut out = vec![0u8; 13];
102        derive(password, salt, 5, HashAlgorithm::SHA256, &mut out).unwrap();
103        assert_eq!(expected, hex::encode(out));
104    }
105
106    #[test]
107    fn test_password_null() {
108        ensure_initialized();
109        let expected = "62384466264daadc4144018c6bd864648272b34da8980d31521ffcce92ae003b";
110        let password = b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
111        let salt = b"salt";
112        let mut out = vec![0u8; 32];
113        derive(password, salt, 2, HashAlgorithm::SHA256, &mut out).unwrap();
114        assert_eq!(expected, hex::encode(out));
115    }
116
117    #[test]
118    fn test_empty_password() {
119        ensure_initialized();
120        let expected = "f135c27993baf98773c5cdb40a5706ce6a345cde61b000a67858650cd6a324d7";
121        let mut out = vec![0u8; 32];
122        let password = b"";
123        let salt = b"salt";
124        derive(password, salt, 1, HashAlgorithm::SHA256, &mut out).unwrap();
125        assert_eq!(expected, hex::encode(out));
126    }
127
128    #[test]
129    fn test_empty_salt() {
130        ensure_initialized();
131        let expected = "c1232f10f62715fda06ae7c0a2037ca19b33cf103b727ba56d870c11f290a2ab";
132        let mut out = vec![0u8; 32];
133        let password = b"password";
134        let salt = b"";
135        derive(password, salt, 1, HashAlgorithm::SHA256, &mut out).unwrap();
136        assert_eq!(expected, hex::encode(out));
137    }
138
139    #[test]
140    fn test_tiny_out() {
141        ensure_initialized();
142        let expected = "12";
143        let mut out = vec![0u8; 1];
144        let password = b"password";
145        let salt = b"salt";
146        derive(password, salt, 1, HashAlgorithm::SHA256, &mut out).unwrap();
147        assert_eq!(expected, hex::encode(out));
148    }
149
150    #[test]
151    fn test_rejects_zero_iterations() {
152        ensure_initialized();
153        let mut out = vec![0u8; 32];
154        let password = b"password";
155        let salt = b"salt";
156        assert!(derive(password, salt, 0, HashAlgorithm::SHA256, &mut out).is_err());
157    }
158
159    #[test]
160    fn test_rejects_empty_out() {
161        ensure_initialized();
162        let mut out = vec![0u8; 0];
163        let password = b"password";
164        let salt = b"salt";
165        assert!(derive(password, salt, 1, HashAlgorithm::SHA256, &mut out).is_err());
166    }
167
168    #[test]
169    fn test_rejects_gaigantic_salt() {
170        ensure_initialized();
171        if (u32::MAX as usize) < usize::MAX {
172            let salt = vec![0; (u32::MAX as usize) + 1];
173            let mut out = vec![0u8; 1];
174            let password = b"password";
175            assert!(derive(password, &salt, 1, HashAlgorithm::SHA256, &mut out).is_err());
176        }
177    }
178    #[test]
179    fn test_rejects_gaigantic_password() {
180        ensure_initialized();
181        if (u32::MAX as usize) < usize::MAX {
182            let password = vec![0; (u32::MAX as usize) + 1];
183            let mut out = vec![0u8; 1];
184            let salt = b"salt";
185            assert!(derive(&password, salt, 1, HashAlgorithm::SHA256, &mut out).is_err());
186        }
187    }
188
189    #[test]
190    fn test_rejects_gaigantic_out() {
191        ensure_initialized();
192        if (u32::MAX as usize) < usize::MAX {
193            let password = b"password";
194            let mut out = vec![0; (u32::MAX as usize) + 1];
195            let salt = b"salt";
196            assert!(derive(password, salt, 1, HashAlgorithm::SHA256, &mut out).is_err());
197        }
198    }
199
200    #[test]
201    fn test_rejects_gaigantic_iterations() {
202        ensure_initialized();
203        let password = b"password";
204        let mut out = vec![0; 32];
205        let salt = b"salt";
206        assert!(derive(password, salt, u32::MAX, HashAlgorithm::SHA256, &mut out).is_err());
207    }
208}