scrypt/
lib.rs

1//! This crate implements the Scrypt key derivation function as specified
2//! in \[1\].
3//!
4//! If you are only using the low-level [`scrypt`] function instead of the
5//! higher-level [`Scrypt`] struct to produce/verify hash strings,
6//! it's recommended to disable default features in your `Cargo.toml`:
7//!
8//! ```toml
9//! [dependencies]
10//! scrypt = { version = "0.2", default-features = false }
11//! ```
12//!
13//! # Usage (simple with default params)
14//!
15//! ```
16//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
17//! # #[cfg(all(feature = "simple", feature = "std"))]
18//! # {
19//! use scrypt::{
20//!     password_hash::{
21//!         rand_core::OsRng,
22//!         PasswordHash, PasswordHasher, PasswordVerifier, SaltString
23//!     },
24//!     Scrypt
25//! };
26//!
27//! let password = b"hunter42"; // Bad password; don't actually use!
28//! let salt = SaltString::generate(&mut OsRng);
29//!
30//! // Hash password to PHC string ($scrypt$...)
31//! let password_hash = Scrypt.hash_password(password, &salt)?.to_string();
32//!
33//! // Verify password against PHC string
34//! let parsed_hash = PasswordHash::new(&password_hash)?;
35//! assert!(Scrypt.verify_password(password, &parsed_hash).is_ok());
36//! # }
37//! # Ok(())
38//! # }
39//! ```
40//!
41//! # References
42//! \[1\] - [C. Percival. Stronger Key Derivation Via Sequential
43//! Memory-Hard Functions](http://www.tarsnap.com/scrypt/scrypt.pdf)
44
45#![no_std]
46#![cfg_attr(docsrs, feature(doc_cfg))]
47#![doc(
48    html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg",
49    html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg"
50)]
51
52#[macro_use]
53extern crate alloc;
54#[cfg(feature = "std")]
55extern crate std;
56
57use pbkdf2::pbkdf2_hmac;
58use sha2::Sha256;
59
60/// Errors for `scrypt` operations.
61pub mod errors;
62mod params;
63mod romix;
64
65#[cfg(feature = "simple")]
66mod simple;
67
68pub use crate::params::Params;
69
70#[cfg(feature = "simple")]
71pub use password_hash;
72
73#[cfg(feature = "simple")]
74pub use crate::simple::{Scrypt, ALG_ID};
75
76/// The scrypt key derivation function.
77///
78/// # Arguments
79/// - `password` - The password to process as a byte vector
80/// - `salt` - The salt value to use as a byte vector
81/// - `params` - The ScryptParams to use
82/// - `output` - The resulting derived key is returned in this byte vector.
83///   **WARNING: Make sure to compare this value in constant time!**
84///
85/// # Return
86/// `Ok(())` if calculation is successful and `Err(InvalidOutputLen)` if
87/// `output` does not satisfy the following condition:
88/// `output.len() > 0 && output.len() <= (2^32 - 1) * 32`.
89pub fn scrypt(
90    password: &[u8],
91    salt: &[u8],
92    params: &Params,
93    output: &mut [u8],
94) -> Result<(), errors::InvalidOutputLen> {
95    // This check required by Scrypt:
96    // check output.len() > 0 && output.len() <= (2^32 - 1) * 32
97    if output.is_empty() || output.len() / 32 > 0xffff_ffff {
98        return Err(errors::InvalidOutputLen);
99    }
100
101    // The checks in the ScryptParams constructor guarantee
102    // that the following is safe:
103    let n = 1 << params.log_n;
104    let r128 = (params.r as usize) * 128;
105    let pr128 = (params.p as usize) * r128;
106    let nr128 = n * r128;
107
108    let mut b = vec![0u8; pr128];
109    pbkdf2_hmac::<Sha256>(password, salt, 1, &mut b);
110
111    let mut v = vec![0u8; nr128];
112    let mut t = vec![0u8; r128];
113
114    for chunk in &mut b.chunks_mut(r128) {
115        romix::scrypt_ro_mix(chunk, &mut v, &mut t, n);
116    }
117
118    pbkdf2_hmac::<Sha256>(password, &b, 1, output);
119    Ok(())
120}