1use std::iter::repeat;
13use std::io;
14use cryptoutil::copy_memory;
15
16use rand::{OsRng, Rng};
17use base64;
18
19use cryptoutil::{read_u32_be, write_u32_be};
20use hmac::Hmac;
21use mac::Mac;
22use sha2::Sha256;
23use util::fixed_time_eq;
24
25fn calculate_block<M: Mac>(
33 mac: &mut M,
34 salt: &[u8],
35 c: u32,
36 idx: u32,
37 scratch: &mut [u8],
38 block: &mut [u8]) {
39 mac.input(salt);
41 let mut idx_buf = [0u8; 4];
42 write_u32_be(&mut idx_buf, idx);
43 mac.input(&idx_buf);
44 mac.raw_result(block);
45 mac.reset();
46
47 if c > 1 {
51 mac.input(block);
52 mac.raw_result(scratch);
53 mac.reset();
54 for (output, &input) in block.iter_mut().zip(scratch.iter()) {
55 *output ^= input;
56 }
57 }
58
59 for _ in 2..c {
61 mac.input(scratch);
62 mac.raw_result(scratch);
63 mac.reset();
64 for (output, &input) in block.iter_mut().zip(scratch.iter()) {
65 *output ^= input;
66 }
67 }
68}
69
70pub fn pbkdf2<M: Mac>(mac: &mut M, salt: &[u8], c: u32, output: &mut [u8]) {
84 assert!(c > 0);
85
86 let os = mac.output_bytes();
87
88 let mut scratch: Vec<u8> = repeat(0).take(os).collect();
93
94 let mut idx: u32 = 0;
95
96 for chunk in output.chunks_mut(os) {
97 idx = idx.checked_add(1).expect("PBKDF2 size limit exceeded.");
99
100 if chunk.len() == os {
101 calculate_block(mac, salt, c, idx, &mut scratch, chunk);
102 } else {
103 let mut tmp: Vec<u8> = repeat(0).take(os).collect();
104 calculate_block(mac, salt, c, idx, &mut scratch[..], &mut tmp[..]);
105 let chunk_len = chunk.len();
106 copy_memory(&tmp[..chunk_len], chunk);
107 }
108 }
109}
110
111pub fn pbkdf2_simple(password: &str, c: u32) -> io::Result<String> {
132 let mut rng = try!(OsRng::new());
133
134 let salt: Vec<u8> = rng.gen_iter::<u8>().take(16).collect();
136
137 let mut dk = [0u8; 32];
139
140 let mut mac = Hmac::new(Sha256::new(), password.as_bytes());
141
142 pbkdf2(&mut mac, &salt[..], c, &mut dk);
143
144 let mut result = "$rpbkdf2$0$".to_string();
145 let mut tmp = [0u8; 4];
146 write_u32_be(&mut tmp, c);
147 result.push_str(&base64::encode_config(&tmp, base64::STANDARD)[..]);
148 result.push('$');
149 result.push_str(&base64::encode_config(&salt, base64::STANDARD)[..]);
150 result.push('$');
151 result.push_str(&base64::encode_config(&dk, base64::STANDARD)[..]);
152 result.push('$');
153
154 Ok(result)
155}
156
157pub fn pbkdf2_check(password: &str, hashed_value: &str) -> Result<bool, &'static str> {
168 static ERR_STR: &'static str = "Hash is not in Rust PBKDF2 format.";
169
170 let mut iter = hashed_value.split('$');
171
172 match iter.next() {
174 Some(x) => if x != "" { return Err(ERR_STR); },
175 None => return Err(ERR_STR)
176 }
177
178 match iter.next() {
180 Some(t) => if t != "rpbkdf2" { return Err(ERR_STR); },
181 None => return Err(ERR_STR)
182 }
183
184 match iter.next() {
186 Some(fstr) => {
187 match fstr {
188 "0" => { }
189 _ => return Err(ERR_STR)
190 }
191 }
192 None => return Err(ERR_STR)
193 }
194
195 let c = match iter.next() {
197 Some(pstr) => match base64::decode(pstr) {
198 Ok(pvec) => {
199 if pvec.len() != 4 { return Err(ERR_STR); }
200 read_u32_be(&pvec[..])
201 }
202 Err(_) => return Err(ERR_STR)
203 },
204 None => return Err(ERR_STR)
205 };
206
207 let salt = match iter.next() {
209 Some(sstr) => match base64::decode(sstr) {
210 Ok(salt) => salt,
211 Err(_) => return Err(ERR_STR)
212 },
213 None => return Err(ERR_STR)
214 };
215
216 let hash = match iter.next() {
218 Some(hstr) => match base64::decode(hstr) {
219 Ok(hash) => hash,
220 Err(_) => return Err(ERR_STR)
221 },
222 None => return Err(ERR_STR)
223 };
224
225 match iter.next() {
227 Some(x) => if x != "" { return Err(ERR_STR); },
228 None => return Err(ERR_STR)
229 }
230
231 match iter.next() {
233 Some(_) => return Err(ERR_STR),
234 None => { }
235 }
236
237 let mut mac = Hmac::new(Sha256::new(), password.as_bytes());
238
239 let mut output: Vec<u8> = repeat(0).take(hash.len()).collect();
240 pbkdf2(&mut mac, &salt[..], c, &mut output[..]);
241
242 Ok(fixed_time_eq(&output[..], &hash[..]))
247}
248
249#[cfg(test)]
250mod test {
251 use std::iter::repeat;
252
253 use pbkdf2::{pbkdf2, pbkdf2_simple, pbkdf2_check};
254 use hmac::Hmac;
255 use sha1::Sha1;
256
257 struct Test {
258 password: Vec<u8>,
259 salt: Vec<u8>,
260 c: u32,
261 expected: Vec<u8>
262 }
263
264 fn tests() -> Vec<Test> {
268 vec![
269 Test {
270 password: b"password".to_vec(),
271 salt: b"salt".to_vec(),
272 c: 1,
273 expected: vec![
274 0x0c, 0x60, 0xc8, 0x0f, 0x96, 0x1f, 0x0e, 0x71,
275 0xf3, 0xa9, 0xb5, 0x24, 0xaf, 0x60, 0x12, 0x06,
276 0x2f, 0xe0, 0x37, 0xa6 ]
277 },
278 Test {
279 password: b"password".to_vec(),
280 salt: b"salt".to_vec(),
281 c: 2,
282 expected: vec![
283 0xea, 0x6c, 0x01, 0x4d, 0xc7, 0x2d, 0x6f, 0x8c,
284 0xcd, 0x1e, 0xd9, 0x2a, 0xce, 0x1d, 0x41, 0xf0,
285 0xd8, 0xde, 0x89, 0x57 ]
286 },
287 Test {
288 password: b"password".to_vec(),
289 salt: b"salt".to_vec(),
290 c: 4096,
291 expected: vec![
292 0x4b, 0x00, 0x79, 0x01, 0xb7, 0x65, 0x48, 0x9a,
293 0xbe, 0xad, 0x49, 0xd9, 0x26, 0xf7, 0x21, 0xd0,
294 0x65, 0xa4, 0x29, 0xc1 ]
295 },
296 Test {
297 password: b"passwordPASSWORDpassword".to_vec(),
298 salt: b"saltSALTsaltSALTsaltSALTsaltSALTsalt".to_vec(),
299 c: 4096,
300 expected: vec![
301 0x3d, 0x2e, 0xec, 0x4f, 0xe4, 0x1c, 0x84, 0x9b,
302 0x80, 0xc8, 0xd8, 0x36, 0x62, 0xc0, 0xe4, 0x4a,
303 0x8b, 0x29, 0x1a, 0x96, 0x4c, 0xf2, 0xf0, 0x70, 0x38 ]
304 },
305 Test {
306 password: vec![112, 97, 115, 115, 0, 119, 111, 114, 100],
307 salt: vec![115, 97, 0, 108, 116],
308 c: 4096,
309 expected: vec![
310 0x56, 0xfa, 0x6a, 0xa7, 0x55, 0x48, 0x09, 0x9d,
311 0xcc, 0x37, 0xd7, 0xf0, 0x34, 0x25, 0xe0, 0xc3 ]
312 }
313 ]
314 }
315
316 #[test]
317 fn test_pbkdf2() {
318 let tests = tests();
319 for t in tests.iter() {
320 let mut mac = Hmac::new(Sha1::new(), &t.password[..]);
321 let mut result: Vec<u8> = repeat(0).take(t.expected.len()).collect();
322 pbkdf2(&mut mac, &t.salt[..], t.c, &mut result);
323 assert!(result == t.expected);
324 }
325 }
326
327 #[test]
328 fn test_pbkdf2_simple() {
329 let password = "password";
330
331 let out1 = pbkdf2_simple(password, 1024).unwrap();
332 let out2 = pbkdf2_simple(password, 1024).unwrap();
333
334 assert!(out1 != out2);
337
338 match pbkdf2_check(password, &out1[..]) {
339 Ok(r) => assert!(r),
340 Err(_) => panic!()
341 }
342 match pbkdf2_check(password, &out2[..]) {
343 Ok(r) => assert!(r),
344 Err(_) => panic!()
345 }
346
347 match pbkdf2_check("wrong", &out1[..]) {
348 Ok(r) => assert!(!r),
349 Err(_) => panic!()
350 }
351 match pbkdf2_check("wrong", &out2[..]) {
352 Ok(r) => assert!(!r),
353 Err(_) => panic!()
354 }
355 }
356}