rust_scrypt/
lib.rs

1//! # C bindings to `Scrypt` key derivation function
2//! specified in (RPC 7914)[https://tools.ietf.org/html/rfc7914])
3
4#![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///The Scrypt parameter values
26#[derive(Clone, Copy, Debug)]
27pub struct ScryptParams {
28    /// Number of iterations
29    pub n: u64,
30
31    /// Block size for the underlying hash
32    pub r: u32,
33
34    /// Parallelization factor
35    pub p: u32,
36}
37
38impl ScryptParams {
39    
40    ///Create a new instance of ScryptParams
41    /// 
42    /// # Arguments:
43    /// log_n - The log2 of the Scrypt parameter N
44    /// r - The Scrypt parameter r
45    /// p - The Scrypt parameter p
46    /// 
47    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
58/// Derive fixed size key for given `salt` and `passphrase`
59///
60/// #Arguments:
61/// passwd - password to be derived
62/// salt - byte array with salt
63/// params - parameters for scrypt into `ScryptParams`
64/// output - resulting byte slice
65///
66pub 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, &params, &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, &params, &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, &params, &mut buf);
136
137        assert_eq!(
138            "52a5dacfcf80e5111d2c7fbed177113a1b48a882b066a017f2c856086680fac7\
139             43ae0dd1ba325be061003ec144f1cad75ddbadd7bb01d22970b9904720b6ba27",
140            encode(buf.as_ref())
141        );
142    }
143}