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