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