1#![allow(non_snake_case)]
17
18use crate::util::ops::{ incr, add2 };
19
20use super::sha256::pbkdf2_sha256;
21use crate::util::{ Error, make_conf_error };
22
23#[inline]
25fn le32dec(p: &[u8]) -> u32 {
26 (p[0] as u32) + ((p[1] as u32) << 8) +
27 ((p[2] as u32) << 16) + ((p[3] as u32) << 24)
28}
29
30#[inline]
32fn le32enc(p: &mut [u8], x: u32) {
33 p[0] = (x & 0xff) as u8;
34 p[1] = ((x >> 8) & 0xff) as u8;
35 p[2] = ((x >> 16) & 0xff) as u8;
36 p[3] = ((x >> 24) & 0xff) as u8;
37}
38
39macro_rules! R {
41 ($a: expr, $b: expr) => ((($a) << ($b)) | (($a) >> (32 - ($b))))
42}
43
44fn salsa20_8(B: &mut [u8]) {
48
49 let mut B32: [u32; 16] = [0; 16];
51 for i in 0..16 {
52 B32[i] = le32dec(&B[i*4..4+i*4]);
53 }
54
55 let mut x: [u32; 16] = [0; 16];
57 for i in 0..16 {
58 x[i] = B32[i];
59 }
60 for _ in 0..4 {
61 x[ 4] ^= R!(add2!(x[ 0],x[12]), 7); x[ 8] ^= R!(add2!(x[ 4],x[ 0]), 9);
63 x[12] ^= R!(add2!(x[ 8],x[ 4]),13); x[ 0] ^= R!(add2!(x[12],x[ 8]),18);
64
65 x[ 9] ^= R!(add2!(x[ 5],x[ 1]), 7); x[13] ^= R!(add2!(x[ 9],x[ 5]), 9);
66 x[ 1] ^= R!(add2!(x[13],x[ 9]),13); x[ 5] ^= R!(add2!(x[ 1],x[13]),18);
67
68 x[14] ^= R!(add2!(x[10],x[ 6]), 7); x[ 2] ^= R!(add2!(x[14],x[10]), 9);
69 x[ 6] ^= R!(add2!(x[ 2],x[14]),13); x[10] ^= R!(add2!(x[ 6],x[ 2]),18);
70
71 x[ 3] ^= R!(add2!(x[15],x[11]), 7); x[ 7] ^= R!(add2!(x[ 3],x[15]), 9);
72 x[11] ^= R!(add2!(x[ 7],x[ 3]),13); x[15] ^= R!(add2!(x[11],x[ 7]),18);
73
74 x[ 1] ^= R!(add2!(x[ 0],x[ 3]), 7); x[ 2] ^= R!(add2!(x[ 1],x[ 0]), 9);
76 x[ 3] ^= R!(add2!(x[ 2],x[ 1]),13); x[ 0] ^= R!(add2!(x[ 3],x[ 2]),18);
77
78 x[ 6] ^= R!(add2!(x[ 5],x[ 4]), 7); x[ 7] ^= R!(add2!(x[ 6],x[ 5]), 9);
79 x[ 4] ^= R!(add2!(x[ 7],x[ 6]),13); x[ 5] ^= R!(add2!(x[ 4],x[ 7]),18);
80
81 x[11] ^= R!(add2!(x[10],x[ 9]), 7); x[ 8] ^= R!(add2!(x[11],x[10]), 9);
82 x[ 9] ^= R!(add2!(x[ 8],x[11]),13); x[10] ^= R!(add2!(x[ 9],x[ 8]),18);
83
84 x[12] ^= R!(add2!(x[15],x[14]), 7); x[13] ^= R!(add2!(x[12],x[15]), 9);
85 x[14] ^= R!(add2!(x[13],x[12]),13); x[15] ^= R!(add2!(x[14],x[13]),18);
86 }
87
88 for i in 0..16 {
90 incr!( B32[i], x[i] );
91 }
92
93 for i in 0..16 {
95 le32enc(&mut B[4*i..4+4*i], B32[i]);
96 }
97}
98
99fn blkcpy(dest: &mut [u8], src: &[u8], len: usize) {
101 for i in 0..len {
102 dest[i] = src[i];
103 }
104}
105
106fn blkxor(dest: &mut [u8], src: &[u8], len: usize) {
108 for i in 0..len {
109 dest[i] ^= src[i];
110 }
111}
112
113fn blockmix_salsa8(B: &mut [u8], Y: &mut [u8], r: usize) {
118 let mut X: [u8; 64] = [0; 64];
119
120 blkcpy(&mut X, &B[(2 * r - 1) * 64 ..], 64);
122
123 for i in 0..2*r {
125 blkxor(&mut X, &B[i * 64 ..], 64);
127 salsa20_8(&mut X);
128
129 blkcpy(&mut Y[i * 64 ..], &X, 64);
131 }
132
133 for i in 0..r {
135 blkcpy(&mut B[i * 64 ..], &Y[(i * 2) * 64 ..], 64);
136 }
137 for i in 0..r {
138 blkcpy(&mut B[(i + r) * 64 ..], &Y[(i * 2 + 1) * 64 ..], 64);
139 }
140}
141
142#[inline]
144fn le64dec(p: &[u8]) -> u64 {
145 (p[0] as u64) + ((p[1] as u64) << 8) +
146 ((p[2] as u64) << 16) + ((p[3] as u64) << 24) +
147 ((p[4] as u64) << 32) + ((p[5] as u64) << 40) +
148 ((p[6] as u64) << 48) + ((p[7] as u64) << 56)
149}
150
151fn integerify(B: &[u8], r: usize) -> u64 {
155 let X = &B[(2 * r - 1) * 64 ..];
156 le64dec(X)
157}
158
159struct ProgressIndicator<'a> {
160 completed: u32,
161 delta_percent: u32,
162 delta_n: u32,
163 progress_cb: &'a dyn Fn(u32) -> (),
164}
165
166impl ProgressIndicator<'_> {
167
168 fn new<'a>(
169 N: u32, p: u32, start_percent: u32, progress_cb: &'a dyn Fn(u32) -> ()
170 ) -> ProgressIndicator {
171 (progress_cb)(start_percent);
172 let total_n = 2*N*p;
173 let total_percent = 100 - start_percent;
174 let (delta_n, delta_percent) = if total_n < total_percent {
175 (1, total_percent/total_n)
176 } else {
177 (total_n/total_percent, 1)
178 };
179 ProgressIndicator {
180 completed: start_percent,
181 delta_n: delta_n,
182 delta_percent: delta_percent,
183 progress_cb: progress_cb,
184 }
185 }
186
187 fn addDelta(&mut self) -> () {
188 if self.completed <= 100 - self.delta_percent {
189 self.completed += self.delta_percent;
190 (self.progress_cb)(self.completed);
191 }
192 }
193
194}
195
196fn smix(
203 B: &mut [u8], r: usize, N: usize, V: &mut [u8], X: &mut [u8], Y: &mut [u8],
204 progress: &mut ProgressIndicator
205) {
206 let mut i_for_progress_report = progress.delta_n;
207
208 blkcpy(X, B, 128 * r);
210
211 for i in 0..N {
213 blkcpy(&mut V[i * (128 * r) ..], X, 128 * r);
215
216 blockmix_salsa8(X, Y, r);
218
219 if i as u32 == i_for_progress_report {
220 progress.addDelta();
221 i_for_progress_report += progress.delta_n;
222 }
223 }
224
225 i_for_progress_report = progress.delta_n;
226
227 for i in 0..N {
229 let j = (integerify(X, r) as usize) & (N - 1);
231
232 blkxor(X, &V[j * (128 * r) ..], 128 * r);
234 blockmix_salsa8(X, Y, r);
235
236 if i as u32 == i_for_progress_report {
237 progress.addDelta();
238 i_for_progress_report += progress.delta_n;
239 }
240 }
241
242 blkcpy(B, X, 128 * r);
244}
245
246fn allocate_byte_array(len: usize) -> Vec<u8> {
247 let mut v: Vec<u8> = Vec::with_capacity(len);
248 unsafe {
249 v.set_len(len);
250 }
251 v
252}
253
254pub fn scrypt(
268 passwd: &[u8], salt: &[u8], logN: u8, r: usize, p: usize, dk_len: usize,
269 progress_cb: &dyn Fn(u32) -> ()
270) -> Result<Vec<u8>, Error> {
271 if r * p >= R_TIMES_P_LIMIT {
278 return Err(make_conf_error("r * p is too big".to_string()));
279 }
280 if dk_len > DK_LEN_LIMIT {
281 return Err(make_conf_error("dkLen is too big".to_string()));
282 }
283 if logN > 31 {
284 return Err(make_conf_error("logN is too big".to_string()));
285 }
286
287 let N = pow_of_2(logN as u32);
288
289 let mut B = allocate_byte_array(128 * r * p);
291 let mut X = allocate_byte_array(128 * r);
292 let mut Y = allocate_byte_array(128 * r);
293 let mut V = allocate_byte_array(128 * r * N);
294
295 pbkdf2_sha256(passwd, salt, 1, &mut B);
297 let mut progress = ProgressIndicator::new(
298 N as u32, p as u32, 3, progress_cb);
299
300 for i in 0..p {
302 smix(&mut B[i * 128 * r ..], r, N, &mut V, &mut X, &mut Y, &mut progress);
304 }
305
306 let mut buf = allocate_byte_array(dk_len);
308 pbkdf2_sha256(passwd, &B, 1, &mut buf);
309 progress_cb(100);
310
311 Ok(buf)
313}
314
315#[inline]
316const fn pow_of_2(power: u32) -> usize {
317 2usize.pow(power)
318}
319
320const R_TIMES_P_LIMIT: usize = pow_of_2(30);
321
322const DK_LEN_LIMIT: usize = if usize::MAX > 0xffffffff {
323 (pow_of_2(32) - 1) * 32
324} else { usize::MAX };
325
326#[cfg(test)]
327mod tests {
328
329 use::std::cell::Cell;
330 use std::mem;
331 use super::{ allocate_byte_array, scrypt };
332 use crate::util::verify::compare;
333
334 #[test]
335 fn show_funky_allocation_in_os() {
336 assert_eq!(8, mem::size_of::<usize>());
337 let x = allocate_byte_array(128);
338 assert!(x.capacity() == 128);
339 assert_eq!(x.len(), 128);
340 let gb = 1024*1024*1024 as usize;
341 let mut big = allocate_byte_array(gb);
342 assert_eq!(big.capacity(), gb);
343 assert_eq!(big.len(), gb);
344 big[gb-234] = 89;
345 big[gb-1] = 70;
346 }
347
348 #[test]
352 fn with_logn_4_r_1_p_1() {
353 let P = "".as_bytes();
354 let S = "".as_bytes();
355 let logN: u8 = 4;
356 let r: usize = 1;
357 let p: usize = 1;
358 let expectation = [
359 0x77, 0xd6, 0x57, 0x62, 0x38, 0x65, 0x7b, 0x20, 0x3b, 0x19,
360 0xca, 0x42, 0xc1, 0x8a, 0x04, 0x97, 0xf1, 0x6b, 0x48, 0x44,
361 0xe3, 0x07, 0x4a, 0xe8, 0xdf, 0xdf, 0xfa, 0x3f, 0xed, 0xe2,
362 0x14, 0x42, 0xfc, 0xd0, 0x06, 0x9d, 0xed, 0x09, 0x48, 0xf8,
363 0x32, 0x6a, 0x75, 0x3a, 0x0f, 0xc8, 0x1f, 0x17, 0xe8, 0xd3,
364 0xe0, 0xfb, 0x2e, 0x0d, 0x36, 0x28, 0xcf, 0x35, 0xe2, 0x0c,
365 0x38, 0xd1, 0x89, 0x06 ];
366 let hlen = expectation.len();
367 let progress = Cell::new(0 as u32);
368 let h = scrypt(P, S, logN, r, p, hlen, & |p| {
369 assert!(p >= progress.get());
370 progress.set(p);
371 print!(" {}%", p);
372 }).unwrap();
373 assert!(compare(&h, &expectation));
374 assert!(progress.get() > 0);
375 }
376
377 #[test]
381 fn with_logn_10_r_8_p_16() {
382 let P = "password".as_bytes();
383 let S = "NaCl".as_bytes();
384 let logN: u8 = 10;
385 let r: usize = 8;
386 let p: usize = 16;
387 let expectation = [
388 0xfd, 0xba, 0xbe, 0x1c, 0x9d, 0x34, 0x72, 0x00, 0x78, 0x56,
389 0xe7, 0x19, 0x0d, 0x01, 0xe9, 0xfe, 0x7c, 0x6a, 0xd7, 0xcb,
390 0xc8, 0x23, 0x78, 0x30, 0xe7, 0x73, 0x76, 0x63, 0x4b, 0x37,
391 0x31, 0x62, 0x2e, 0xaf, 0x30, 0xd9, 0x2e, 0x22, 0xa3, 0x88,
392 0x6f, 0xf1, 0x09, 0x27, 0x9d, 0x98, 0x30, 0xda, 0xc7, 0x27,
393 0xaf, 0xb9, 0x4a, 0x83, 0xee, 0x6d, 0x83, 0x60, 0xcb, 0xdf,
394 0xa2, 0xcc, 0x06, 0x40 ];
395 let hlen = expectation.len();
396 let progress = Cell::new(0 as u32);
397 let h = scrypt(P, S, logN, r, p, hlen, & |p| {
398 assert!(p >= progress.get());
399 progress.set(p);
400 print!(" {}%", p);
401 }).unwrap();
402 assert!(compare(&h, &expectation));
403 assert!(progress.get() > 0);
404 }
405
406 #[test]
410 fn with_logn_14_r_8_p_1() {
411 let P = "pleaseletmein".as_bytes();
412 let S = "SodiumChloride".as_bytes();
413 let logN: u8 = 14;
414 let r: usize = 8;
415 let p: usize = 1;
416 let expectation = [
417 0x70, 0x23, 0xbd, 0xcb, 0x3a, 0xfd, 0x73, 0x48, 0x46, 0x1c,
418 0x06, 0xcd, 0x81, 0xfd, 0x38, 0xeb, 0xfd, 0xa8, 0xfb, 0xba,
419 0x90, 0x4f, 0x8e, 0x3e, 0xa9, 0xb5, 0x43, 0xf6, 0x54, 0x5d,
420 0xa1, 0xf2, 0xd5, 0x43, 0x29, 0x55, 0x61, 0x3f, 0x0f, 0xcf,
421 0x62, 0xd4, 0x97, 0x05, 0x24, 0x2a, 0x9a, 0xf9, 0xe6, 0x1e,
422 0x85, 0xdc, 0x0d, 0x65, 0x1e, 0x40, 0xdf, 0xcf, 0x01, 0x7b,
423 0x45, 0x57, 0x58, 0x87 ];
424 let hlen = expectation.len();
425 let progress = Cell::new(0 as u32);
426 let h = scrypt(P, S, logN, r, p, hlen, & |p| {
427 assert!(p >= progress.get());
428 progress.set(p);
429 print!(" {}%", p);
430 }).unwrap();
431 assert!(compare(&h, &expectation));
432 assert!(progress.get() > 0);
433 }
434
435 #[test]
439 fn with_logn_20_r_8_p_1() {
440 let P = "pleaseletmein".as_bytes();
441 let S = "SodiumChloride".as_bytes();
442 let logN: u8 = 20;
443 let r: usize = 8;
444 let p: usize = 1;
445 let expectation = [
446 0x21, 0x01, 0xcb, 0x9b, 0x6a, 0x51, 0x1a, 0xae, 0xad, 0xdb,
447 0xbe, 0x09, 0xcf, 0x70, 0xf8, 0x81, 0xec, 0x56, 0x8d, 0x57,
448 0x4a, 0x2f, 0xfd, 0x4d, 0xab, 0xe5, 0xee, 0x98, 0x20, 0xad,
449 0xaa, 0x47, 0x8e, 0x56, 0xfd, 0x8f, 0x4b, 0xa5, 0xd0, 0x9f,
450 0xfa, 0x1c, 0x6d, 0x92, 0x7c, 0x40, 0xf4, 0xc3, 0x37, 0x30,
451 0x40, 0x49, 0xe8, 0xa9, 0x52, 0xfb, 0xcb, 0xf4, 0x5c, 0x6f,
452 0xa7, 0x7a, 0x41, 0xa4 ];
453 let hlen = expectation.len();
454 let progress = Cell::new(0 as u32);
455 let h = scrypt(P, S, logN, r, p, hlen, & |p| {
456 assert!(p >= progress.get());
457 progress.set(p);
458 print!(" {}%", p);
459 }).unwrap();
460 assert!(compare(&h, &expectation));
461 assert!(progress.get() > 0);
462 }
463
464}