From fb5acb02ee25fe4b320beba877db839b5d325953 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2=20=5BArtyom=20Pavlov=5D?= Date: Wed, 31 Aug 2022 01:48:26 +0300 Subject: [PATCH] pbkdf2: add new wrapper functions --- Cargo.lock | 45 ++++---- bcrypt-pbkdf/src/lib.rs | 5 +- pbkdf2/CHANGELOG.md | 4 + pbkdf2/Cargo.toml | 3 +- pbkdf2/src/lib.rs | 186 ++++++++++++++++++++++++++----- pbkdf2/src/simple.rs | 9 +- pbkdf2/tests/data/1.c.bin | 1 - pbkdf2/tests/data/1.output.bin | 1 - pbkdf2/tests/data/1.password.bin | 1 - pbkdf2/tests/data/1.salt.bin | 1 - pbkdf2/tests/data/2.c.bin | 1 - pbkdf2/tests/data/2.output.bin | 1 - pbkdf2/tests/data/2.password.bin | 1 - pbkdf2/tests/data/2.salt.bin | 1 - pbkdf2/tests/data/3.c.bin | 1 - pbkdf2/tests/data/3.output.bin | Bin 20 -> 0 bytes pbkdf2/tests/data/3.password.bin | 1 - pbkdf2/tests/data/3.salt.bin | 1 - pbkdf2/tests/data/4.c.bin | 1 - pbkdf2/tests/data/4.output.bin | 1 - pbkdf2/tests/data/4.password.bin | 1 - pbkdf2/tests/data/4.salt.bin | 1 - pbkdf2/tests/data/5.c.bin | 1 - pbkdf2/tests/data/5.output.bin | 1 - pbkdf2/tests/data/5.password.bin | Bin 9 -> 0 bytes pbkdf2/tests/data/5.salt.bin | Bin 5 -> 0 bytes pbkdf2/tests/gost.rs | 89 --------------- pbkdf2/tests/lib.rs | 39 ------- pbkdf2/tests/mod.rs | 117 +++++++++++++++++++ scrypt/Cargo.toml | 3 +- scrypt/src/lib.rs | 7 +- 31 files changed, 315 insertions(+), 209 deletions(-) delete mode 100644 pbkdf2/tests/data/1.c.bin delete mode 100644 pbkdf2/tests/data/1.output.bin delete mode 100644 pbkdf2/tests/data/1.password.bin delete mode 100644 pbkdf2/tests/data/1.salt.bin delete mode 100644 pbkdf2/tests/data/2.c.bin delete mode 100644 pbkdf2/tests/data/2.output.bin delete mode 100644 pbkdf2/tests/data/2.password.bin delete mode 100644 pbkdf2/tests/data/2.salt.bin delete mode 100644 pbkdf2/tests/data/3.c.bin delete mode 100644 pbkdf2/tests/data/3.output.bin delete mode 100644 pbkdf2/tests/data/3.password.bin delete mode 100644 pbkdf2/tests/data/3.salt.bin delete mode 100644 pbkdf2/tests/data/4.c.bin delete mode 100644 pbkdf2/tests/data/4.output.bin delete mode 100644 pbkdf2/tests/data/4.password.bin delete mode 100644 pbkdf2/tests/data/4.salt.bin delete mode 100644 pbkdf2/tests/data/5.c.bin delete mode 100644 pbkdf2/tests/data/5.output.bin delete mode 100644 pbkdf2/tests/data/5.password.bin delete mode 100644 pbkdf2/tests/data/5.salt.bin delete mode 100644 pbkdf2/tests/gost.rs delete mode 100644 pbkdf2/tests/lib.rs create mode 100644 pbkdf2/tests/mod.rs diff --git a/Cargo.lock b/Cargo.lock index e42c7367..ce92416d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -101,18 +101,18 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.2" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" +checksum = "dc948ebb96241bb40ab73effeb80d9f93afaad49359d159a5e61be51619fe813" dependencies = [ "libc", ] [[package]] name = "crossbeam-channel" -version = "0.5.5" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c02a4d71819009c192cf4872265391563fd6a84c81ff2c0f2a7026ca4c1d85c" +checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" dependencies = [ "cfg-if", "crossbeam-utils", @@ -120,9 +120,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" +checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" dependencies = [ "cfg-if", "crossbeam-epoch", @@ -131,9 +131,9 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.9" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07db9d94cbd326813772c968ccd25999e5f8ae22f4f8d1b11effa37ef6ce281d" +checksum = "045ebe27666471bb549370b4b0b3e51b07f56325befa4284db65fc89c02511b1" dependencies = [ "autocfg", "cfg-if", @@ -145,9 +145,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.9" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ff1f980957787286a554052d03c7aee98d99cc32e09f6d45f0a814133c87978" +checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc" dependencies = [ "cfg-if", "once_cell", @@ -165,9 +165,9 @@ dependencies = [ [[package]] name = "crypto-common" -version = "0.1.3" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", "typenum", @@ -186,15 +186,15 @@ dependencies = [ [[package]] name = "either" -version = "1.6.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" +checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" [[package]] name = "generic-array" -version = "0.14.5" +version = "0.14.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" +checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" dependencies = [ "typenum", "version_check", @@ -246,9 +246,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.126" +version = "0.2.132" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" +checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5" [[package]] name = "memoffset" @@ -271,9 +271,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.12.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225" +checksum = "074864da206b4973b84eb91683020dbefd6a8c3f0f38e054d93954e891935e4e" [[package]] name = "password-hash" @@ -379,7 +379,6 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" name = "scrypt" version = "0.11.0-pre" dependencies = [ - "hmac", "password-hash", "pbkdf2", "salsa20", @@ -408,9 +407,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.2" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" +checksum = "899bf02746a2c92bf1053d9327dadb252b01af1f81f90cdb902411f518bc7215" dependencies = [ "cfg-if", "cpufeatures", diff --git a/bcrypt-pbkdf/src/lib.rs b/bcrypt-pbkdf/src/lib.rs index cefcc497..f9f89122 100644 --- a/bcrypt-pbkdf/src/lib.rs +++ b/bcrypt-pbkdf/src/lib.rs @@ -152,8 +152,9 @@ pub fn bcrypt_pbkdf( &mut stack_buf[..stride * BHASH_OUTPUT_SIZE] }; - // Run the regular PBKDF2 algorithm with bhash as the MAC. - pbkdf2::pbkdf2::(&Sha512::digest(passphrase), salt, rounds, generated); + // Run the regular PBKDF2 algorithm with bhash as the PRF. + pbkdf2::pbkdf2::(&Sha512::digest(passphrase), salt, rounds, generated) + .expect("Bhash can be initialized with any key length"); // Apply the bcrypt_pbkdf non-linear transformation on the output. for (i, out_byte) in output.iter_mut().enumerate() { diff --git a/pbkdf2/CHANGELOG.md b/pbkdf2/CHANGELOG.md index b18dba7d..92cc8269 100644 --- a/pbkdf2/CHANGELOG.md +++ b/pbkdf2/CHANGELOG.md @@ -8,8 +8,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased ### Changed - `simple` feature is no longer enabled by default ([#336]) +- Add new wrapper functions: `pbkdf2_array`, `pbkdf2_hmac`, and +`pbkdf2_hmac_array`. `pbkdf2` and `pbkdf2_array` now return +`Result<(), InvalidLength>` instead of unwrapping it internally. ([#337]) [#336]: https://github.com/RustCrypto/password-hashes/pull/336 +[#337]: https://github.com/RustCrypto/password-hashes/pull/337 ## 0.11.0 (2022-03-28) ### Changed diff --git a/pbkdf2/Cargo.toml b/pbkdf2/Cargo.toml index 3227659f..767932e0 100644 --- a/pbkdf2/Cargo.toml +++ b/pbkdf2/Cargo.toml @@ -24,12 +24,13 @@ sha2 = { version = "0.10", default-features = false, optional = true } [dev-dependencies] hmac = "0.12" -hex-literal = "0.3" +hex-literal = "0.3.3" sha1 = { version = "0.10", package = "sha-1" } sha2 = "0.10" streebog = "0.10" [features] +default = ["hmac"] parallel = ["rayon", "std"] simple = ["hmac", "password-hash", "sha2"] std = ["password-hash/std"] diff --git a/pbkdf2/src/lib.rs b/pbkdf2/src/lib.rs index 504fd048..1151fdfd 100644 --- a/pbkdf2/src/lib.rs +++ b/pbkdf2/src/lib.rs @@ -1,26 +1,48 @@ //! This crate implements the PBKDF2 key derivation function as specified //! in [RFC 2898](https://tools.ietf.org/html/rfc2898). //! -//! If you are only using the low-level [`pbkdf2`] function instead of the -//! higher-level [`Pbkdf2`] struct to produce/verify hash strings, -//! it's recommended to disable default features in your `Cargo.toml`: +//! # Examples //! -//! ```toml -//! [dependencies] -//! pbkdf2 = { version = "0.11", default-features = false } +//! PBKDF2 is defined in terms of a keyed pseudo-random function (PRF). Most +//! commonly HMAC is used as this PRF. In such cases you can use [`pbkdf2_hmac`] +//! and [`pbkdf2_hmac_array`] functions. The former accepts a byte slice which +//! gets filled with generated key, while the former returns an array with +//! generated key of requested length. +//! +//! ``` +//! # #[cfg(feature = "hmac")] { +//! use hex_literal::hex; +//! use pbkdf2::{pbkdf2_hmac, pbkdf2_hmac_array}; +//! use sha2::Sha256; +//! +//! let password = b"password"; +//! let salt = b"salt"; +//! // number of iterations +//! let n = 4096; +//! // Expected value of generated key +//! let expected = hex!("c5e478d59288c841aa530db6845c4c8d962893a0"); +//! +//! let mut key1 = [0u8; 20]; +//! pbkdf2_hmac::(password, salt, n, &mut key1); +//! assert_eq!(key1, expected); +//! +//! let key2 = pbkdf2_hmac_array::(password, salt, n); +//! assert_eq!(key2, expected); +//! # } //! ``` //! -//! # Usage (simple with default params) +//! If you want to use a different PRF, then you can use [`pbkdf2`][crate::pbkdf2] +//! and [`pbkdf2_array`] functions. //! -//! Note: this example requires the `rand_core` crate with the `std` feature -//! enabled for `rand_core::OsRng` (embedded platforms can substitute their -//! own RNG) +//! This crates also provides the high-level password-hashing API through +//! the [`Pbkdf2`] struct and traits defined in the +//! [`password-hash`][password_hash] crate. //! //! Add the following to your crate's `Cargo.toml` to import it: //! //! ```toml //! [dependencies] -//! pbkdf2 = "0.10" +//! pbkdf2 = { version = "0.12", features = ["simple"] } //! rand_core = { version = "0.6", features = ["std"] } //! ``` //! @@ -78,7 +100,15 @@ pub use crate::simple::{Algorithm, Params, Pbkdf2}; #[cfg(feature = "parallel")] use rayon::prelude::*; -use digest::{generic_array::typenum::Unsigned, FixedOutput, KeyInit, Update}; +use digest::{generic_array::typenum::Unsigned, FixedOutput, InvalidLength, KeyInit, Update}; + +#[cfg(feature = "hmac")] +use digest::{ + block_buffer::Eager, + core_api::{BlockSizeUser, BufferKindUser, CoreProxy, FixedOutputCore, UpdateCore}, + generic_array::typenum::{IsLess, Le, NonZero, U256}, + HashMarker, +}; #[inline(always)] fn xor(res: &mut [u8], salt: &[u8]) { @@ -89,7 +119,7 @@ fn xor(res: &mut [u8], salt: &[u8]) { #[inline(always)] fn pbkdf2_body(i: u32, chunk: &mut [u8], prf: &PRF, salt: &[u8], rounds: u32) where - PRF: KeyInit + Update + FixedOutput + Clone, + PRF: Update + FixedOutput + Clone, { for v in chunk.iter_mut() { *v = 0; @@ -114,34 +144,136 @@ where } } -/// Generic implementation of PBKDF2 algorithm. -#[cfg(not(feature = "parallel"))] +/// Generic implementation of PBKDF2 algorithm which accepts an arbitrary keyed PRF. +/// +/// ``` +/// use hex_literal::hex; +/// use pbkdf2::pbkdf2; +/// use hmac::Hmac; +/// use sha2::Sha256; +/// +/// let mut buf = [0u8; 20]; +/// pbkdf2::>(b"password", b"salt", 4096, &mut buf) +/// .expect("HMAC can be initialized with any key length"); +/// assert_eq!(buf, hex!("c5e478d59288c841aa530db6845c4c8d962893a0")); +/// ``` #[inline] -pub fn pbkdf2(password: &[u8], salt: &[u8], rounds: u32, res: &mut [u8]) +pub fn pbkdf2( + password: &[u8], + salt: &[u8], + rounds: u32, + res: &mut [u8], +) -> Result<(), InvalidLength> where PRF: KeyInit + Update + FixedOutput + Clone + Sync, { let n = PRF::OutputSize::to_usize(); // note: HMAC can be initialized with keys of any size, // so this panic never happens with it - let prf = PRF::new_from_slice(password).expect("PRF initialization failure"); + let prf = PRF::new_from_slice(password)?; - for (i, chunk) in res.chunks_mut(n).enumerate() { - pbkdf2_body(i as u32, chunk, &prf, salt, rounds); + #[cfg(not(feature = "parallel"))] + { + for (i, chunk) in res.chunks_mut(n).enumerate() { + pbkdf2_body(i as u32, chunk, &prf, salt, rounds); + } + } + #[cfg(feature = "parallel")] + { + res.par_chunks_mut(n).enumerate().for_each(|(i, chunk)| { + pbkdf2_body(i as u32, chunk, &prf, salt, rounds); + }); } + + Ok(()) } -/// Generic implementation of PBKDF2 algorithm. -#[cfg(feature = "parallel")] +/// A variant of the [`pbkdf2`][crate::pbkdf2] function which returns an array +/// instead of filling an input slice. +/// +/// ``` +/// use hex_literal::hex; +/// use pbkdf2::pbkdf2_array; +/// use hmac::Hmac; +/// use sha2::Sha256; +/// +/// let res = pbkdf2_array::, 20>(b"password", b"salt", 4096) +/// .expect("HMAC can be initialized with any key length"); +/// assert_eq!(res, hex!("c5e478d59288c841aa530db6845c4c8d962893a0")); +/// ``` #[inline] -pub fn pbkdf2(password: &[u8], salt: &[u8], rounds: u32, res: &mut [u8]) +pub fn pbkdf2_array( + password: &[u8], + salt: &[u8], + rounds: u32, +) -> Result<[u8; N], InvalidLength> where PRF: KeyInit + Update + FixedOutput + Clone + Sync, { - let n = PRF::OutputSize::to_usize(); - let prf = PRF::new_from_slice(password).expect("PRF initialization failure"); + let mut buf = [0u8; N]; + pbkdf2::(password, salt, rounds, &mut buf).map(|()| buf) +} + +/// A variant of the [`pbkdf2`][crate::pbkdf2] function which uses HMAC for PRF. +/// It's generic over (eager) hash functions. +/// +/// ``` +/// use hex_literal::hex; +/// use pbkdf2::pbkdf2_hmac; +/// use sha2::Sha256; +/// +/// let mut buf = [0u8; 20]; +/// pbkdf2_hmac::(b"password", b"salt", 4096, &mut buf); +/// assert_eq!(buf, hex!("c5e478d59288c841aa530db6845c4c8d962893a0")); +/// ``` +#[cfg(feature = "hmac")] +#[cfg_attr(docsrs, doc(cfg(feature = "hmac")))] +pub fn pbkdf2_hmac(password: &[u8], salt: &[u8], rounds: u32, res: &mut [u8]) +where + D: CoreProxy, + D::Core: Sync + + HashMarker + + UpdateCore + + FixedOutputCore + + BufferKindUser + + Default + + Clone, + ::BlockSize: IsLess, + Le<::BlockSize, U256>: NonZero, +{ + crate::pbkdf2::>(password, salt, rounds, res) + .expect("HMAC can be initialized with any key length"); +} - res.par_chunks_mut(n).enumerate().for_each(|(i, chunk)| { - pbkdf2_body(i as u32, chunk, &prf, salt, rounds); - }); +/// A variant of the [`pbkdf2_hmac`] function which returns an array +/// instead of filling an input slice. +/// +/// ``` +/// use hex_literal::hex; +/// use pbkdf2::pbkdf2_hmac_array; +/// use sha2::Sha256; +/// +/// assert_eq!( +/// pbkdf2_hmac_array::(b"password", b"salt", 4096), +/// hex!("c5e478d59288c841aa530db6845c4c8d962893a0"), +/// ); +/// ``` +#[cfg(feature = "hmac")] +#[cfg_attr(docsrs, doc(cfg(feature = "hmac")))] +pub fn pbkdf2_hmac_array(password: &[u8], salt: &[u8], rounds: u32) -> [u8; N] +where + D: CoreProxy, + D::Core: Sync + + HashMarker + + UpdateCore + + FixedOutputCore + + BufferKindUser + + Default + + Clone, + ::BlockSize: IsLess, + Le<::BlockSize, U256>: NonZero, +{ + let mut buf = [0u8; N]; + pbkdf2_hmac::(password, salt, rounds, &mut buf); + buf } diff --git a/pbkdf2/src/simple.rs b/pbkdf2/src/simple.rs index 6f6b9edd..624bba56 100644 --- a/pbkdf2/src/simple.rs +++ b/pbkdf2/src/simple.rs @@ -1,8 +1,7 @@ //! Implementation of the `password-hash` crate API. -use crate::pbkdf2; +use crate::pbkdf2_hmac; use core::{cmp::Ordering, fmt, str::FromStr}; -use hmac::Hmac; use password_hash::{ errors::InvalidValue, Decimal, Error, Ident, Output, ParamsString, PasswordHash, PasswordHasher, Result, Salt, @@ -52,9 +51,9 @@ impl PasswordHasher for Pbkdf2 { let output = Output::init_with(params.output_length, |out| { let f = match algorithm { #[cfg(feature = "sha1")] - Algorithm::Pbkdf2Sha1 => pbkdf2::>, - Algorithm::Pbkdf2Sha256 => pbkdf2::>, - Algorithm::Pbkdf2Sha512 => pbkdf2::>, + Algorithm::Pbkdf2Sha1 => pbkdf2_hmac::, + Algorithm::Pbkdf2Sha256 => pbkdf2_hmac::, + Algorithm::Pbkdf2Sha512 => pbkdf2_hmac::, }; f(password, salt_bytes, params.rounds, out); diff --git a/pbkdf2/tests/data/1.c.bin b/pbkdf2/tests/data/1.c.bin deleted file mode 100644 index 56a6051c..00000000 --- a/pbkdf2/tests/data/1.c.bin +++ /dev/null @@ -1 +0,0 @@ -1 \ No newline at end of file diff --git a/pbkdf2/tests/data/1.output.bin b/pbkdf2/tests/data/1.output.bin deleted file mode 100644 index e97fff18..00000000 --- a/pbkdf2/tests/data/1.output.bin +++ /dev/null @@ -1 +0,0 @@ - `��q�$�`/�7� \ No newline at end of file diff --git a/pbkdf2/tests/data/1.password.bin b/pbkdf2/tests/data/1.password.bin deleted file mode 100644 index 7aa311ad..00000000 --- a/pbkdf2/tests/data/1.password.bin +++ /dev/null @@ -1 +0,0 @@ -password \ No newline at end of file diff --git a/pbkdf2/tests/data/1.salt.bin b/pbkdf2/tests/data/1.salt.bin deleted file mode 100644 index acdf61b5..00000000 --- a/pbkdf2/tests/data/1.salt.bin +++ /dev/null @@ -1 +0,0 @@ -salt \ No newline at end of file diff --git a/pbkdf2/tests/data/2.c.bin b/pbkdf2/tests/data/2.c.bin deleted file mode 100644 index d8263ee9..00000000 --- a/pbkdf2/tests/data/2.c.bin +++ /dev/null @@ -1 +0,0 @@ -2 \ No newline at end of file diff --git a/pbkdf2/tests/data/2.output.bin b/pbkdf2/tests/data/2.output.bin deleted file mode 100644 index 794dd831..00000000 --- a/pbkdf2/tests/data/2.output.bin +++ /dev/null @@ -1 +0,0 @@ -�lM�-o���*�A��މW \ No newline at end of file diff --git a/pbkdf2/tests/data/2.password.bin b/pbkdf2/tests/data/2.password.bin deleted file mode 100644 index 7aa311ad..00000000 --- a/pbkdf2/tests/data/2.password.bin +++ /dev/null @@ -1 +0,0 @@ -password \ No newline at end of file diff --git a/pbkdf2/tests/data/2.salt.bin b/pbkdf2/tests/data/2.salt.bin deleted file mode 100644 index acdf61b5..00000000 --- a/pbkdf2/tests/data/2.salt.bin +++ /dev/null @@ -1 +0,0 @@ -salt \ No newline at end of file diff --git a/pbkdf2/tests/data/3.c.bin b/pbkdf2/tests/data/3.c.bin deleted file mode 100644 index 1b18a99c..00000000 --- a/pbkdf2/tests/data/3.c.bin +++ /dev/null @@ -1 +0,0 @@ -4096 \ No newline at end of file diff --git a/pbkdf2/tests/data/3.output.bin b/pbkdf2/tests/data/3.output.bin deleted file mode 100644 index 0818153b2f1dec4255876c6a6d78c049f409d243..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20 ccmeZfsASxp>M?8ITF;wm-xV*UF3~&)09VWjQUCw| diff --git a/pbkdf2/tests/data/3.password.bin b/pbkdf2/tests/data/3.password.bin deleted file mode 100644 index 7aa311ad..00000000 --- a/pbkdf2/tests/data/3.password.bin +++ /dev/null @@ -1 +0,0 @@ -password \ No newline at end of file diff --git a/pbkdf2/tests/data/3.salt.bin b/pbkdf2/tests/data/3.salt.bin deleted file mode 100644 index acdf61b5..00000000 --- a/pbkdf2/tests/data/3.salt.bin +++ /dev/null @@ -1 +0,0 @@ -salt \ No newline at end of file diff --git a/pbkdf2/tests/data/4.c.bin b/pbkdf2/tests/data/4.c.bin deleted file mode 100644 index 1b18a99c..00000000 --- a/pbkdf2/tests/data/4.c.bin +++ /dev/null @@ -1 +0,0 @@ -4096 \ No newline at end of file diff --git a/pbkdf2/tests/data/4.output.bin b/pbkdf2/tests/data/4.output.bin deleted file mode 100644 index 2620fe5a..00000000 --- a/pbkdf2/tests/data/4.output.bin +++ /dev/null @@ -1 +0,0 @@ -=.�O������6b��J�)�L��p8 \ No newline at end of file diff --git a/pbkdf2/tests/data/4.password.bin b/pbkdf2/tests/data/4.password.bin deleted file mode 100644 index e27630e8..00000000 --- a/pbkdf2/tests/data/4.password.bin +++ /dev/null @@ -1 +0,0 @@ -passwordPASSWORDpassword \ No newline at end of file diff --git a/pbkdf2/tests/data/4.salt.bin b/pbkdf2/tests/data/4.salt.bin deleted file mode 100644 index c9284ea5..00000000 --- a/pbkdf2/tests/data/4.salt.bin +++ /dev/null @@ -1 +0,0 @@ -saltSALTsaltSALTsaltSALTsaltSALTsalt \ No newline at end of file diff --git a/pbkdf2/tests/data/5.c.bin b/pbkdf2/tests/data/5.c.bin deleted file mode 100644 index 1b18a99c..00000000 --- a/pbkdf2/tests/data/5.c.bin +++ /dev/null @@ -1 +0,0 @@ -4096 \ No newline at end of file diff --git a/pbkdf2/tests/data/5.output.bin b/pbkdf2/tests/data/5.output.bin deleted file mode 100644 index 47b4243d..00000000 --- a/pbkdf2/tests/data/5.output.bin +++ /dev/null @@ -1 +0,0 @@ -V�j�UH ��7��4%�� \ No newline at end of file diff --git a/pbkdf2/tests/data/5.password.bin b/pbkdf2/tests/data/5.password.bin deleted file mode 100644 index 71c30a878a020b981eee777bcbd7ee0034e507b4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9 QcmXR&EG}j!&o4>=01-(8bN~PV diff --git a/pbkdf2/tests/data/5.salt.bin b/pbkdf2/tests/data/5.salt.bin deleted file mode 100644 index 614c05dd4aa8881114622b5c77f6124dbd751bde..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5 McmXR;WXLH200k5QwEzGB diff --git a/pbkdf2/tests/gost.rs b/pbkdf2/tests/gost.rs deleted file mode 100644 index a007cf83..00000000 --- a/pbkdf2/tests/gost.rs +++ /dev/null @@ -1,89 +0,0 @@ -//! Test vectors from R 50.1.111-2016: -//! https://tc26.ru/standard/rs/Р 50.1.111-2016.pdf -use hex_literal::hex; - -#[test] -#[rustfmt::skip] -fn gost_test() { - let pbkdf2 = pbkdf2::pbkdf2::>; - let mut res64 = [0u8; 64]; - let mut res100 = [0u8; 100]; - - pbkdf2(b"password", b"salt", 1, &mut res64); - assert_eq!( - res64, - hex!(" - 64770af7f748c3b1c9ac831dbcfd85c2 - 6111b30a8a657ddc3056b80ca73e040d - 2854fd36811f6d825cc4ab66ec0a68a4 - 90a9e5cf5156b3a2b7eecddbf9a16b47 - "), - ); - - pbkdf2(b"password", b"salt", 2, &mut res64); - assert_eq!( - res64, - hex!(" - 5a585bafdfbb6e8830d6d68aa3b43ac0 - 0d2e4aebce01c9b31c2caed56f0236d4 - d34b2b8fbd2c4e89d54d46f50e47d45b - bac301571743119e8d3c42ba66d348de - "), - ); - - pbkdf2(b"password", b"salt", 4096, &mut res64); - assert_eq!( - res64, - hex!(" - e52deb9a2d2aaff4e2ac9d47a41f34c2 - 0376591c67807f0477e32549dc341bc7 - 867c09841b6d58e29d0347c996301d55 - df0d34e47cf68f4e3c2cdaf1d9ab86c3 - "), - ); - - // this test passes, but takes more than 1 minute to - // execute in release mode - /* - pbkdf2(b"password", b"salt", 16777216, &mut res64); - assert_eq!( - res64, - hex!(" - 49e4843bba76e300afe24c4d23dc7392 - def12f2c0e244172367cd70a8982ac36 - 1adb601c7e2a314e8cb7b1e9df840e36 - ab5615be5d742b6cf203fb55fdc48071 - "), - ); - */ - - pbkdf2( - b"passwordPASSWORDpassword", - b"saltSALTsaltSALTsaltSALTsaltSALTsalt", - 4096, - &mut res100, - ); - assert_eq!( - res100, - hex!(" - b2d8f1245fc4d29274802057e4b54e0a - 0753aa22fc53760b301cf008679e58fe - 4bee9addcae99ba2b0b20f431a9c5e50 - f395c89387d0945aedeca6eb4015dfc2 - bd2421ee9bb71183ba882ceebfef259f - 33f9e27dc6178cb89dc37428cf9cc52a - 2baa2d3a - "), - ); - - pbkdf2(b"pass\0word", b"sa\0lt", 4096, &mut res64); - assert_eq!( - res64, - hex!(" - 50df062885b69801a3c10248eb0a27ab - 6e522ffeb20c991c660f001475d73a4e - 167f782c18e97e92976d9c1d970831ea - 78ccb879f67068cdac1910740844e830 - "), - ); -} diff --git a/pbkdf2/tests/lib.rs b/pbkdf2/tests/lib.rs deleted file mode 100644 index 2da7e820..00000000 --- a/pbkdf2/tests/lib.rs +++ /dev/null @@ -1,39 +0,0 @@ -use hmac::Hmac; -use sha1::Sha1; - -#[derive(Debug)] -pub struct Test { - pub name: &'static str, - pub password: &'static [u8], - pub salt: &'static [u8], - pub c: &'static str, - pub output: &'static [u8], -} - -#[macro_export] -macro_rules! new_tests { - ( $( $name:expr ),* ) => { - [$( - Test { - name: $name, - password: include_bytes!(concat!("data/", $name, ".password.bin")), - salt: include_bytes!(concat!("data/", $name, ".salt.bin")), - c: include_str!(concat!("data/", $name, ".c.bin")), - output: include_bytes!(concat!("data/", $name, ".output.bin")), - }, - )*] - }; -} - -#[test] -fn rfc6070() { - let tests = new_tests!("1", "2", "3", "4", "5"); - let mut buf = [0u8; 25]; - for test in &tests { - let c = test.c.parse().unwrap(); - println!("c: {:?}", test); - let n = test.output.len(); - pbkdf2::pbkdf2::>(test.password, test.salt, c, &mut buf[..n]); - assert_eq!(&buf[..n], test.output); - } -} diff --git a/pbkdf2/tests/mod.rs b/pbkdf2/tests/mod.rs new file mode 100644 index 00000000..4edb0717 --- /dev/null +++ b/pbkdf2/tests/mod.rs @@ -0,0 +1,117 @@ +#![cfg(feature = "hmac")] +use hex_literal::hex; +use pbkdf2::pbkdf2_hmac_array as f; +use sha1::Sha1; +use streebog::Streebog512; + +/// Tests from RFC 6070: +/// https://www.rfc-editor.org/rfc/rfc6070 +#[test] +fn rfc6070() { + assert_eq!( + f::(b"password", b"salt", 1), + hex!("0c60c80f961f0e71f3a9b524af6012062fe037a6"), + ); + assert_eq!( + f::(b"password", b"salt", 2), + hex!("ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957"), + ); + assert_eq!( + f::(b"password", b"salt", 4096), + hex!("4b007901b765489abead49d926f721d065a429c1"), + ); + // this test passes, but takes a long time to execute + /* + assert_eq!( + f::(b"password", b"salt", 16777216), + hex!("eefe3d61cd4da4e4e9945b3d6ba2158c2634e984"), + ); + */ + assert_eq!( + f::( + b"passwordPASSWORDpassword", + b"saltSALTsaltSALTsaltSALTsaltSALTsalt", + 4096 + ), + hex!("3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038"), + ); + assert_eq!( + f::(b"pass\0word", b"sa\0lt", 4096), + hex!("56fa6aa75548099dcc37d7f03425e0c3"), + ); +} + +/// Test vectors from R 50.1.111-2016: +/// https://tc26.ru/standard/rs/Р 50.1.111-2016.pdf +#[test] +fn gost() { + assert_eq!( + f::(b"password", b"salt", 1), + hex!( + "64770af7f748c3b1c9ac831dbcfd85c2" + "6111b30a8a657ddc3056b80ca73e040d" + "2854fd36811f6d825cc4ab66ec0a68a4" + "90a9e5cf5156b3a2b7eecddbf9a16b47" + ), + ); + + assert_eq!( + f::(b"password", b"salt", 2), + hex!( + "5a585bafdfbb6e8830d6d68aa3b43ac0" + "0d2e4aebce01c9b31c2caed56f0236d4" + "d34b2b8fbd2c4e89d54d46f50e47d45b" + "bac301571743119e8d3c42ba66d348de" + ), + ); + + assert_eq!( + f::(b"password", b"salt", 4096), + hex!( + "e52deb9a2d2aaff4e2ac9d47a41f34c2" + "0376591c67807f0477e32549dc341bc7" + "867c09841b6d58e29d0347c996301d55" + "df0d34e47cf68f4e3c2cdaf1d9ab86c3" + ), + ); + + // this test passes, but takes a long time to execute + /* + assert_eq!( + f::(b"password", b"salt", 16777216), + hex!( + "49e4843bba76e300afe24c4d23dc7392" + "def12f2c0e244172367cd70a8982ac36" + "1adb601c7e2a314e8cb7b1e9df840e36" + "ab5615be5d742b6cf203fb55fdc48071" + ), + ); + */ + + assert_eq!( + f::( + b"passwordPASSWORDpassword", + b"saltSALTsaltSALTsaltSALTsaltSALTsalt", + 4096, + ), + hex!( + "b2d8f1245fc4d29274802057e4b54e0a" + "0753aa22fc53760b301cf008679e58fe" + "4bee9addcae99ba2b0b20f431a9c5e50" + "f395c89387d0945aedeca6eb4015dfc2" + "bd2421ee9bb71183ba882ceebfef259f" + "33f9e27dc6178cb89dc37428cf9cc52a" + "2baa2d3a" + ), + ); + + assert_eq!( + f::(b"pass\0word", b"sa\0lt", 4096), + hex!( + "50df062885b69801a3c10248eb0a27ab" + "6e522ffeb20c991c660f001475d73a4e" + "167f782c18e97e92976d9c1d970831ea" + "78ccb879f67068cdac1910740844e830" + ), + ); +} diff --git a/scrypt/Cargo.toml b/scrypt/Cargo.toml index 51f87ca5..a59f2c29 100644 --- a/scrypt/Cargo.toml +++ b/scrypt/Cargo.toml @@ -13,8 +13,7 @@ edition = "2021" rust-version = "1.57" [dependencies] -hmac = "0.12.1" -pbkdf2 = { version = "=0.12.0-pre", default-features = false, path = "../pbkdf2" } +pbkdf2 = { version = "=0.12.0-pre", path = "../pbkdf2" } salsa20 = { version = "0.10.2", default-features = false } sha2 = { version = "0.10", default-features = false } diff --git a/scrypt/src/lib.rs b/scrypt/src/lib.rs index 9d7ccc10..7c452473 100644 --- a/scrypt/src/lib.rs +++ b/scrypt/src/lib.rs @@ -54,8 +54,7 @@ extern crate alloc; #[cfg(feature = "std")] extern crate std; -use hmac::Hmac; -use pbkdf2::pbkdf2; +use pbkdf2::pbkdf2_hmac; use sha2::Sha256; /// Errors for `scrypt` operations. @@ -107,7 +106,7 @@ pub fn scrypt( let nr128 = n * r128; let mut b = vec![0u8; pr128]; - pbkdf2::>(password, salt, 1, &mut b); + pbkdf2_hmac::(password, salt, 1, &mut b); let mut v = vec![0u8; nr128]; let mut t = vec![0u8; r128]; @@ -116,6 +115,6 @@ pub fn scrypt( romix::scrypt_ro_mix(chunk, &mut v, &mut t, n); } - pbkdf2::>(password, &b, 1, output); + pbkdf2_hmac::(password, &b, 1, output); Ok(()) }