1use std;
16use std::iter::repeat;
17use std::io;
18use std::mem::size_of;
19use cryptoutil::copy_memory;
20
21use rand::{OsRng, Rng};
22use base64;
23
24use cryptoutil::{read_u32_le, read_u32v_le, write_u32_le};
25use hmac::Hmac;
26use pbkdf2::pbkdf2;
27use sha2::Sha256;
28use util::fixed_time_eq;
29
30fn salsa20_8(input: &[u8], output: &mut [u8]) {
32
33 let mut x = [0u32; 16];
34 read_u32v_le(&mut x, input);
35
36 let rounds = 8;
37
38 macro_rules! run_round (
39 ($($set_idx:expr, $idx_a:expr, $idx_b:expr, $rot:expr);*) => { {
40 $( x[$set_idx] ^= x[$idx_a].wrapping_add(x[$idx_b]).rotate_left($rot); )*
41 } }
42 );
43
44 for _ in 0..rounds / 2 {
45 run_round!(
46 0x4, 0x0, 0xc, 7;
47 0x8, 0x4, 0x0, 9;
48 0xc, 0x8, 0x4, 13;
49 0x0, 0xc, 0x8, 18;
50 0x9, 0x5, 0x1, 7;
51 0xd, 0x9, 0x5, 9;
52 0x1, 0xd, 0x9, 13;
53 0x5, 0x1, 0xd, 18;
54 0xe, 0xa, 0x6, 7;
55 0x2, 0xe, 0xa, 9;
56 0x6, 0x2, 0xe, 13;
57 0xa, 0x6, 0x2, 18;
58 0x3, 0xf, 0xb, 7;
59 0x7, 0x3, 0xf, 9;
60 0xb, 0x7, 0x3, 13;
61 0xf, 0xb, 0x7, 18;
62 0x1, 0x0, 0x3, 7;
63 0x2, 0x1, 0x0, 9;
64 0x3, 0x2, 0x1, 13;
65 0x0, 0x3, 0x2, 18;
66 0x6, 0x5, 0x4, 7;
67 0x7, 0x6, 0x5, 9;
68 0x4, 0x7, 0x6, 13;
69 0x5, 0x4, 0x7, 18;
70 0xb, 0xa, 0x9, 7;
71 0x8, 0xb, 0xa, 9;
72 0x9, 0x8, 0xb, 13;
73 0xa, 0x9, 0x8, 18;
74 0xc, 0xf, 0xe, 7;
75 0xd, 0xc, 0xf, 9;
76 0xe, 0xd, 0xc, 13;
77 0xf, 0xe, 0xd, 18
78 )
79 }
80
81 for i in 0..16 {
82 write_u32_le(
83 &mut output[i * 4..(i + 1) * 4],
84 x[i].wrapping_add(read_u32_le(&input[i * 4..(i + 1) * 4])));
85 }
86}
87
88fn xor(x: &[u8], y: &[u8], output: &mut [u8]) {
89 for ((out, &x_i), &y_i) in output.iter_mut().zip(x.iter()).zip(y.iter()) {
90 *out = x_i ^ y_i;
91 }
92}
93
94fn scrypt_block_mix(input: &[u8], output: &mut [u8]) {
98 let mut x = [0u8; 64];
99 copy_memory(&input[input.len() - 64..], &mut x);
100
101 let mut t = [0u8; 64];
102
103 for (i, chunk) in input.chunks(64).enumerate() {
104 xor(&x, chunk, &mut t);
105 salsa20_8(&t, &mut x);
106 let pos = if i % 2 == 0 { (i / 2) * 64 } else { (i / 2) * 64 + input.len() / 2 };
107 copy_memory(&x, &mut output[pos..pos + 64]);
108 }
109}
110
111fn scrypt_ro_mix(b: &mut [u8], v: &mut [u8], t: &mut [u8], n: usize) {
117 fn integerify(x: &[u8], n: usize) -> usize {
118 let mask = n - 1;
121 let result = (read_u32_le(&x[x.len() - 64..x.len() - 60]) as usize) & mask;
124 result
125 }
126
127 let len = b.len();
128
129 for chunk in v.chunks_mut(len) {
130 copy_memory(b, chunk);
131 scrypt_block_mix(chunk, b);
132 }
133
134 for _ in 0..n {
135 let j = integerify(b, n);
136 xor(b, &v[j * len..(j + 1) * len], t);
137 scrypt_block_mix(t, b);
138 }
139}
140
141#[derive(Clone, Copy)]
145pub struct ScryptParams {
146 log_n: u8,
147 r: u32,
148 p: u32
149}
150
151impl ScryptParams {
152 pub fn new(log_n: u8, r: u32, p: u32) -> ScryptParams {
163 assert!(r > 0);
164 assert!(p > 0);
165 assert!(log_n > 0);
166 assert!((log_n as usize) < size_of::<usize>() * 8);
167 assert!(size_of::<usize>() >= size_of::<u32>() || (r <= std::usize::MAX as u32 && p < std::usize::MAX as u32));
168
169 let r = r as usize;
170 let p = p as usize;
171
172 let n: usize = 1 << log_n;
173
174 let r128 = match r.checked_mul(128) {
176 Some(x) => x,
177 None => panic!("Invalid Scrypt parameters.")
178 };
179
180 match r128.checked_mul(n) {
182 Some(_) => { },
183 None => panic!("Invalid Scrypt parameters.")
184 };
185
186 match r128.checked_mul(p) {
188 Some(_) => { },
189 None => panic!("Invalid Scrypt parameters.")
190 };
191
192 assert!((log_n as usize) < r * 16);
196
197 assert!(r * p < 0x40000000);
202
203 ScryptParams {
204 log_n: log_n,
205 r: r as u32,
206 p: p as u32
207 }
208 }
209}
210
211pub fn scrypt(password: &[u8], salt: &[u8], params: &ScryptParams, output: &mut [u8]) {
223 assert!(output.len() > 0);
226 assert!(output.len() / 32 <= 0xffffffff);
227
228 let n = 1 << params.log_n;
230 let r128 = (params.r as usize) * 128;
231 let pr128 = (params.p as usize) * r128;
232 let nr128 = n * r128;
233
234 let mut mac = Hmac::new(Sha256::new(), password);
235
236 let mut b: Vec<u8> = repeat(0).take(pr128).collect();
237 pbkdf2(&mut mac, salt, 1, &mut b);
238
239 let mut v: Vec<u8> = repeat(0).take(nr128).collect();
240 let mut t: Vec<u8> = repeat(0).take(r128).collect();
241
242 for chunk in &mut b.chunks_mut(r128) {
243 scrypt_ro_mix(chunk, &mut v, &mut t, n);
244 }
245
246 pbkdf2(&mut mac, &*b, 1, output);
247}
248
249pub fn scrypt_simple(password: &str, params: &ScryptParams) -> io::Result<String> {
272 let mut rng = try!(OsRng::new());
273
274 let salt: Vec<u8> = rng.gen_iter::<u8>().take(16).collect();
276
277 let mut dk = [0u8; 32];
279
280 scrypt(password.as_bytes(), &*salt, params, &mut dk);
281
282 let mut result = "$rscrypt$".to_string();
283 if params.r < 256 && params.p < 256 {
284 result.push_str("0$");
285 let mut tmp = [0u8; 3];
286 tmp[0] = params.log_n;
287 tmp[1] = params.r as u8;
288 tmp[2] = params.p as u8;
289 result.push_str(&*base64::encode_config(&tmp, base64::STANDARD));
290 } else {
291 result.push_str("1$");
292 let mut tmp = [0u8; 9];
293 tmp[0] = params.log_n;
294 write_u32_le(&mut tmp[1..5], params.r);
295 write_u32_le(&mut tmp[5..9], params.p);
296 result.push_str(&*base64::encode_config(&tmp, base64::STANDARD));
297 }
298 result.push('$');
299 result.push_str(&*base64::encode_config(&salt, base64::STANDARD));
300 result.push('$');
301 result.push_str(&*base64::encode_config(&dk, base64::STANDARD));
302 result.push('$');
303
304 Ok(result)
305}
306
307pub fn scrypt_check(password: &str, hashed_value: &str) -> Result<bool, &'static str> {
318 static ERR_STR: &'static str = "Hash is not in Rust Scrypt format.";
319
320 let mut iter = hashed_value.split('$');
321
322 match iter.next() {
324 Some(x) => if x != "" { return Err(ERR_STR); },
325 None => return Err(ERR_STR)
326 }
327
328 match iter.next() {
330 Some(t) => if t != "rscrypt" { return Err(ERR_STR); },
331 None => return Err(ERR_STR)
332 }
333
334 let params: ScryptParams;
336 match iter.next() {
337 Some(fstr) => {
338 let pvec = match iter.next() {
341 Some(pstr) => match base64::decode(pstr) {
342 Ok(x) => x,
343 Err(_) => return Err(ERR_STR)
344 },
345 None => return Err(ERR_STR)
346 };
347 match fstr {
348 "0" => {
349 if pvec.len() != 3 { return Err(ERR_STR); }
350 let log_n = pvec[0];
351 let r = pvec[1] as u32;
352 let p = pvec[2] as u32;
353 params = ScryptParams::new(log_n, r, p);
354 }
355 "1" => {
356 if pvec.len() != 9 { return Err(ERR_STR); }
357 let log_n = pvec[0];
358 let mut pval = [0u32; 2];
359 read_u32v_le(&mut pval, &pvec[1..9]);
360 params = ScryptParams::new(log_n, pval[0], pval[1]);
361 }
362 _ => return Err(ERR_STR)
363 }
364 }
365 None => return Err(ERR_STR)
366 }
367
368 let salt = match iter.next() {
370 Some(sstr) => match base64::decode(sstr) {
371 Ok(salt) => salt,
372 Err(_) => return Err(ERR_STR)
373 },
374 None => return Err(ERR_STR)
375 };
376
377 let hash = match iter.next() {
379 Some(hstr) => match base64::decode(hstr) {
380 Ok(hash) => hash,
381 Err(_) => return Err(ERR_STR)
382 },
383 None => return Err(ERR_STR)
384 };
385
386 match iter.next() {
388 Some(x) => if x != "" { return Err(ERR_STR); },
389 None => return Err(ERR_STR)
390 }
391
392 match iter.next() {
394 Some(_) => return Err(ERR_STR),
395 None => { }
396 }
397
398 let mut output: Vec<u8> = repeat(0).take(hash.len()).collect();
399 scrypt(password.as_bytes(), &*salt, ¶ms, &mut output);
400
401 Ok(fixed_time_eq(&*output, &*hash))
406}
407
408#[cfg(test)]
409mod test {
410 use std::iter::repeat;
411
412 use scrypt::{scrypt, scrypt_simple, scrypt_check, ScryptParams};
413
414 struct Test {
415 password: &'static str,
416 salt: &'static str,
417 log_n: u8,
418 r: u32,
419 p: u32,
420 expected: Vec<u8>
421 }
422
423 fn tests() -> Vec<Test> {
426 vec![
427 Test {
428 password: "",
429 salt: "",
430 log_n: 4,
431 r: 1,
432 p: 1,
433 expected: vec![
434 0x77, 0xd6, 0x57, 0x62, 0x38, 0x65, 0x7b, 0x20,
435 0x3b, 0x19, 0xca, 0x42, 0xc1, 0x8a, 0x04, 0x97,
436 0xf1, 0x6b, 0x48, 0x44, 0xe3, 0x07, 0x4a, 0xe8,
437 0xdf, 0xdf, 0xfa, 0x3f, 0xed, 0xe2, 0x14, 0x42,
438 0xfc, 0xd0, 0x06, 0x9d, 0xed, 0x09, 0x48, 0xf8,
439 0x32, 0x6a, 0x75, 0x3a, 0x0f, 0xc8, 0x1f, 0x17,
440 0xe8, 0xd3, 0xe0, 0xfb, 0x2e, 0x0d, 0x36, 0x28,
441 0xcf, 0x35, 0xe2, 0x0c, 0x38, 0xd1, 0x89, 0x06 ]
442 },
443 Test {
444 password: "password",
445 salt: "NaCl",
446 log_n: 10,
447 r: 8,
448 p: 16,
449 expected: vec![
450 0xfd, 0xba, 0xbe, 0x1c, 0x9d, 0x34, 0x72, 0x00,
451 0x78, 0x56, 0xe7, 0x19, 0x0d, 0x01, 0xe9, 0xfe,
452 0x7c, 0x6a, 0xd7, 0xcb, 0xc8, 0x23, 0x78, 0x30,
453 0xe7, 0x73, 0x76, 0x63, 0x4b, 0x37, 0x31, 0x62,
454 0x2e, 0xaf, 0x30, 0xd9, 0x2e, 0x22, 0xa3, 0x88,
455 0x6f, 0xf1, 0x09, 0x27, 0x9d, 0x98, 0x30, 0xda,
456 0xc7, 0x27, 0xaf, 0xb9, 0x4a, 0x83, 0xee, 0x6d,
457 0x83, 0x60, 0xcb, 0xdf, 0xa2, 0xcc, 0x06, 0x40 ]
458 },
459 Test {
460 password: "pleaseletmein",
461 salt: "SodiumChloride",
462 log_n: 14,
463 r: 8,
464 p: 1,
465 expected: vec![
466 0x70, 0x23, 0xbd, 0xcb, 0x3a, 0xfd, 0x73, 0x48,
467 0x46, 0x1c, 0x06, 0xcd, 0x81, 0xfd, 0x38, 0xeb,
468 0xfd, 0xa8, 0xfb, 0xba, 0x90, 0x4f, 0x8e, 0x3e,
469 0xa9, 0xb5, 0x43, 0xf6, 0x54, 0x5d, 0xa1, 0xf2,
470 0xd5, 0x43, 0x29, 0x55, 0x61, 0x3f, 0x0f, 0xcf,
471 0x62, 0xd4, 0x97, 0x05, 0x24, 0x2a, 0x9a, 0xf9,
472 0xe6, 0x1e, 0x85, 0xdc, 0x0d, 0x65, 0x1e, 0x40,
473 0xdf, 0xcf, 0x01, 0x7b, 0x45, 0x57, 0x58, 0x87 ]
474 },
475 ]
476 }
477
478 #[test]
479 fn test_scrypt() {
480 let tests = tests();
481 for t in tests.iter() {
482 let mut result: Vec<u8> = repeat(0).take(t.expected.len()).collect();
483 let params = ScryptParams::new(t.log_n, t.r, t.p);
484 scrypt(t.password.as_bytes(), t.salt.as_bytes(), ¶ms, &mut result);
485 assert!(result == t.expected);
486 }
487 }
488
489 fn test_scrypt_simple(log_n: u8, r: u32, p: u32) {
490 let password = "password";
491
492 let params = ScryptParams::new(log_n, r, p);
493 let out1 = scrypt_simple(password, ¶ms).unwrap();
494 let out2 = scrypt_simple(password, ¶ms).unwrap();
495
496 assert!(out1 != out2);
499
500 match scrypt_check(password, &out1[..]) {
501 Ok(r) => assert!(r),
502 Err(_) => panic!()
503 }
504 match scrypt_check(password, &out2[..]) {
505 Ok(r) => assert!(r),
506 Err(_) => panic!()
507 }
508
509 match scrypt_check("wrong", &out1[..]) {
510 Ok(r) => assert!(!r),
511 Err(_) => panic!()
512 }
513 match scrypt_check("wrong", &out2[..]) {
514 Ok(r) => assert!(!r),
515 Err(_) => panic!()
516 }
517 }
518
519 #[test]
520 fn test_scrypt_simple_compact() {
521 test_scrypt_simple(7, 8, 1);
523 }
524
525 #[test]
526 fn test_scrypt_simple_expanded() {
527 test_scrypt_simple(3, 1, 256);
529 }
530}