1#![cfg_attr(feature = "dev", feature(plugin))]
5#![cfg_attr(feature = "dev", plugin(clippy))]
6#![allow(non_upper_case_globals)]
7
8use std::mem::size_of;
9
10#[link(name = "scrypt")]
11extern "C" {
12 pub fn crypto_scrypt(
13 passwd: *const u8,
14 passwdlen: usize,
15 salt: *const u8,
16 saltlen: usize,
17 N: u64,
18 r: u32,
19 p: u32,
20 buf: *mut u8,
21 buflen: usize,
22 ) -> ::std::os::raw::c_int;
23}
24
25#[derive(Clone, Copy, Debug)]
27pub struct ScryptParams {
28 pub n: u64,
30
31 pub r: u32,
33
34 pub p: u32,
36}
37
38impl ScryptParams {
39
40 pub fn new(n: u64, r: u32, p: u32) -> ScryptParams {
48 assert!(r > 0);
49 assert!(p > 0);
50 assert!(n > 0);
51 assert!(size_of::<usize>() >= size_of::<u32>() || (r <= std::usize::MAX as u32 && p < std::usize::MAX as u32));
52
53 ScryptParams { n,r, p }
54 }
55
56}
57
58pub fn scrypt(passwd: &[u8], salt: &[u8], params: &ScryptParams, output: &mut [u8]) {
67 unsafe {
68 crypto_scrypt(
69 passwd.as_ptr(),
70 passwd.len(),
71 salt.as_ptr(),
72 salt.len(),
73 params.n,
74 params.r,
75 params.p,
76 output.as_mut_ptr(),
77 output.len(),
78 );
79 }
80}
81
82#[cfg(test)]
83mod tests {
84 extern crate hex;
85
86 use super::*;
87 use tests::hex::{decode, encode};
88
89 const SALT: &str = "fd4acb81182a2c8fa959d180967b374277f2ccf2f7f401cb08d042cc785464b4";
90
91 fn to_bytes<A, T>(slice: &[T]) -> A
92 where
93 A: AsMut<[T]> + Default,
94 T: Clone,
95 {
96 let mut arr = Default::default();
97 <A as AsMut<[T]>>::as_mut(&mut arr).clone_from_slice(slice);
98 arr
99 }
100
101 #[test]
102 fn test_scrypt_128() {
103 let salt: [u8; 32] = to_bytes(&decode(SALT).unwrap());
104 let passwd = "1234567890";
105 let mut buf = [0u8; 16];
106 let params = ScryptParams { n: 2, r: 8, p: 1 };
107
108 scrypt(passwd.as_bytes(), &salt, ¶ms, &mut buf);
109
110 assert_eq!("52a5dacfcf80e5111d2c7fbed177113a", encode(buf.as_ref()));
111 }
112
113 #[test]
114 fn test_scrypt_256() {
115 let salt: [u8; 32] = to_bytes(&decode(SALT).unwrap());
116 let passwd = "1234567890";
117 let mut buf = [0u8; 32];
118 let params = ScryptParams { n: 2, r: 8, p: 1 };
119
120 scrypt(passwd.as_bytes(), &salt, ¶ms, &mut buf);
121
122 assert_eq!(
123 "52a5dacfcf80e5111d2c7fbed177113a1b48a882b066a017f2c856086680fac7",
124 encode(buf.as_ref())
125 );
126 }
127
128 #[test]
129 fn test_scrypt_512() {
130 let salt: [u8; 32] = to_bytes(&decode(SALT).unwrap());
131 let passwd = "1234567890";
132 let mut buf = [0u8; 64];
133 let params = ScryptParams { n: 2, r: 8, p: 1 };
134
135 scrypt(passwd.as_bytes(), &salt, ¶ms, &mut buf);
136
137 assert_eq!(
138 "52a5dacfcf80e5111d2c7fbed177113a1b48a882b066a017f2c856086680fac7\
139 43ae0dd1ba325be061003ec144f1cad75ddbadd7bb01d22970b9904720b6ba27",
140 encode(buf.as_ref())
141 );
142 }
143}