From 478f2837cdc088a2d3ada818d6941a2d3063578b Mon Sep 17 00:00:00 2001 From: lbeder Date: Thu, 29 Jun 2023 18:07:34 +0100 Subject: [PATCH] Support resuming previous derivations --- Cargo.lock | 32 +++++++++- Cargo.toml | 4 +- README.md | 63 +++++++++++++++----- src/main.rs | 111 +++++++++++++++++++++++++++------- src/scrypt_kdf.rs | 149 +++++++++++++++++++++++++++------------------- 5 files changed, 259 insertions(+), 100 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 58e511c..4a23a38 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -296,6 +296,16 @@ dependencies = [ "typenum", ] +[[package]] +name = "ctrlc" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a011bbe2c35ce9c1f143b7af6f94f29a167beb4cd1d29e6740ce836f723120e" +dependencies = [ + "nix", + "windows-sys 0.48.0", +] + [[package]] name = "digest" version = "0.10.7" @@ -610,6 +620,18 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "nix" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" +dependencies = [ + "bitflags", + "cfg-if", + "libc", + "static_assertions", +] + [[package]] name = "object" version = "0.30.4" @@ -833,15 +855,17 @@ dependencies = [ [[package]] name = "scrypt-kdf" -version = "0.12.0" +version = "0.13.0" dependencies = [ "better-panic", "clap", "color-backtrace", "colored", "crossterm", + "ctrlc", "hex", "humantime", + "lazy_static", "mimalloc", "pbr", "rpassword", @@ -917,6 +941,12 @@ version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "strsim" version = "0.10.0" diff --git a/Cargo.toml b/Cargo.toml index 806ce7b..fb8fa17 100755 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ authors = ["Leonid Beder "] edition = "2021" name = "scrypt-kdf" -version = "0.12.0" +version = "0.13.0" [dependencies] better-panic = "0.3.0" @@ -10,11 +10,13 @@ clap = { version = "4.3.5", features = ["derive", "string"] } color-backtrace = "0.5.1" colored = "2.0.0" crossterm = "0.26.1" +ctrlc = { version = "3.4.0", features = ["termination"] } hex = "0.4.3" humantime = "2.1.0" mimalloc = { version = "0.1.37", default-features = false } rpassword = "7.2.0" scrypt = "0.11.0" +lazy_static = "1.4.0" [dependencies.pbr] git = "https://github.com/lbeder/pb.git" diff --git a/README.md b/README.md index b983475..5cc989b 100755 --- a/README.md +++ b/README.md @@ -28,12 +28,14 @@ Derive a key using Scrypt KDF Usage: scrypt-kdf derive [OPTIONS] Options: - -i, --iterations Number of iterations (must be greater than 0 and less than or equal to 4294967295) [default: 100] - -n CPU/memory cost parameter (must be less than 64) [default: 20] - -r Block size parameter, which fine-tunes sequential memory read size and performance (must be greater than 0 and less than or equal to 4294967295) [default: 8] - -p

Parallelization parameter (must be greater than 0 and less than 4294967295) [default: 1] - -l, --length Length of the derived result (must be greater than 9 and less than or equal to 64) [default: 16] - -h, --help Print help + -i, --iterations Number of iterations (must be greater than 0 and less than or equal to 4294967295) [default: 100] + -n CPU/memory cost parameter (must be less than 64) [default: 20] + -r Block size parameter, which fine-tunes sequential memory read size and performance (must be greater than 0 and less than or equal to 4294967295) [default: 8] + -p

Parallelization parameter (must be greater than 0 and less than 4294967295) [default: 1] + -l, --length Length of the derived result (must be greater than 9 and less than or equal to 64) [default: 16] + --offset Start the derivation from this index. In order to use it, you also have to specify the intermediary offset data in hex format [default: 0] + --offset-data Start the derivation with this intermediary data in hex format + -h, --help Print help ``` ### Printing Test Vectors @@ -123,16 +125,14 @@ Now you can build it: cargo build --release --target=x86_64-pc-windows-gnu ``` -## Example +## Examples Let's try to derive the key for the secret `test`, using the salt `salt`: > scrypt-kdf derive ```sh -Scrypt KDF v0.10.0 - -Parameters: Scrypt (log_n: 20, r: 8, p: 1, len: 16) +Parameters: Scrypt (log_n: 20, r: 8, p: 1, length: 16) Enter your salt: salt Enter your secret: 🔑 @@ -150,12 +150,47 @@ Enter your secret again: 🔑 Processing: 100 / 100 [=======================================================================================================================================] 100.00 % -Key is (please highlight to see): -16e27a594f879ec5edbc3c1995907b49 +Key is (please highlight to see): ff08101f061aa670158601bf5be5efa6 Finished in 3m 29s ``` +### Resuming Previous Derivation + +To help with resuming previously stopped derivations, we're registering a `CTRL_C`, `CTRL_BREAK`, `SIGINT`, `SIGTERM`, and `SIGHUP` termination handler which will output the intermediary result (if possible). + +For example, if we will abort the previous derivation after the `60th` iteration, the tool will output: + +```sh +Parameters: Scrypt (log_n: 20, r: 8, p: 1, length: 16) + +Enter your salt: salt +Enter your secret: 🔑 +Enter your secret again: 🔑 + +Processing: 60 / 100 [==========================================================================>-------------------------------------------------] 60.00 % 1m + +Terminated. To resume, please specify --offset 60 and --offset-data (please highlight to see) 2262d7c10e3806a4926a895f7cf9502b +``` + +You can then use this output to resume the previous derivation by specifying a starting offset and data like so: + +> scrypt-kdf derive --offset 60 --offset-data 2262d7c10e3806a4926a895f7cf9502b + +```sh +Parameters: Scrypt (log_n: 20, r: 8, p: 1, length: 16) + +Enter your salt: salt + +Resuming from iteration 60 with intermediary offset data 2262d7c10e3806a4926a895f7cf9502b. Secret input isn't be required + +Processing: 40 / 40 [===============================================================================================================================] 100.00 % + +Key is (please highlight to see): ff08101f061aa670158601bf5be5efa6 + +Finished in 1m 25s +``` + ## Test Vectors In order to verify the validity of the Scrypt calculation, you can pass the `-t/--test` flag. @@ -187,10 +222,10 @@ Test vectors: Results should be: ```sh -Test vector parameters: Scrypt (log_n: 14, r: 8, p: 1, iterations: 1, len: 64), salt: "", secret: "" +Test vector parameters: Scrypt (log_n: 14, r: 8, p: 1, iterations: 1, length: 64), salt: "", secret: "" Derived key: d72c87d0f077c7766f2985dfab30e8955c373a13a1e93d315203939f542ff86e73ee37c31f4c4b571f4719fa8e3589f12db8dcb57ea9f56764bb7d58f64cf705 -Test vector parameters: Scrypt (log_n: 14, r: 8, p: 1, iterations: 3, len: 64), salt: "", secret: "Hello World" +Test vector parameters: Scrypt (log_n: 14, r: 8, p: 1, iterations: 3, length: 64), salt: "", secret: "Hello World" Derived key: 1487e1ac9c7a63e785b1f3e9560ea749913d50c9797dc6ca8d0db953fe03df1c66af878bd6dcce79884e8b7e3e29f39cb709cd63b7e7f4099d82ab199664eab3 ``` diff --git a/src/main.rs b/src/main.rs index 866892c..a12312a 100755 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,9 @@ extern crate hex; extern crate pbr; +#[macro_use] +extern crate lazy_static; + use mimalloc::MiMalloc; #[global_allocator] @@ -22,6 +25,7 @@ use std::{ env, io::{self, Write}, process::exit, + sync::{Arc, Mutex}, time::{Duration, Instant}, }; @@ -50,8 +54,18 @@ enum Commands { #[arg(short, default_value = DEFAULT_SCRYPT_KDF_OPTIONS.p.to_string(), help = format!("Parallelization parameter (must be greater than 0 and less than {})", u32::MAX))] p: u32, - #[arg(short, long, default_value = DEFAULT_SCRYPT_KDF_OPTIONS.len.to_string(), help = format!("Length of the derived result (must be greater than {} and less than or equal to {})", MIN_KDF_LEN - 1, MAX_KDF_LEN))] + #[arg(short, long, default_value = DEFAULT_SCRYPT_KDF_OPTIONS.length.to_string(), help = format!("Length of the derived result (must be greater than {} and less than or equal to {})", MIN_KDF_LEN - 1, MAX_KDF_LEN))] length: u8, + + #[arg( + long, + default_value = "0", + help = "Start the derivation from this index. In order to use it, you also have to specify the intermediary offset data in hex format" + )] + offset: u32, + + #[arg(long, help = "Start the derivation with this intermediary data in hex format")] + offset_data: Option, }, #[command(about = "Print test vectors")] @@ -75,33 +89,34 @@ fn read_line() -> Result { Ok(line) } -fn get_salt() -> String { +fn get_salt() -> Vec { print!("Enter your salt: "); io::stdout().flush().unwrap(); - read_line().unwrap() + read_line().unwrap().as_bytes().to_vec() } -fn get_secret() -> String { +fn get_secret() -> Vec { let pass = rpassword::prompt_password("Enter your secret: ").unwrap(); let pass2 = rpassword::prompt_password("Enter your secret again: ").unwrap(); - println!(); - if pass != pass2 { + println!(); println!("Secrets don't match!"); + exit(-1); } - pass + pass.as_bytes().to_vec() } fn main() { better_panic::install(); color_backtrace::install(); - println!("Scrypt KDF v{VERSION}\n"); + println!("Scrypt KDF v{VERSION}"); + println!(); let cli = Cli::parse(); @@ -112,45 +127,97 @@ fn main() { r, p, length, + offset, + offset_data, }) => { println!( - "Parameters: {} (log_n: {}, r: {}, p: {}, len: {})\n", + "Parameters: {} (log_n: {}, r: {}, p: {}, length: {})", "Scrypt".yellow(), log_n.to_string().cyan(), r.to_string().cyan(), p.to_string().cyan(), length.to_string().cyan(), ); + println!(); + + // Register a termination handler to output intermediary results + let last_iteration_ref = Arc::new(Mutex::new(0)); + let last_result_ref = Arc::new(Mutex::new(String::new())); + + let last_iteration = last_iteration_ref.clone(); + let last_result = last_result_ref.clone(); + + ctrlc::set_handler(move || { + println!(); + println!(); + println!( + "Terminated. To resume, please specify --offset {} and --offset-data (please highlight to see) {}", + *last_iteration.lock().unwrap() + 1, + last_result.lock().unwrap().clone().black().on_black() + ); + + exit(-1); + }) + .expect("Error setting termination handler"); let salt = get_salt(); - let secret = get_secret(); - let mut pb = ProgressBar::new(u64::from(*iterations)); + let data: Vec; + if *offset != 0 { + data = match offset_data { + Some(data) => { + println!(); + println!("Resuming from iteration {offset} with intermediary offset data {data}. Secret input isn't be required"); + println!(); + + hex::decode(data).unwrap() + }, + + None => { + panic!("Missing intermediary offset data"); + }, + } + } else { + data = get_secret(); + + println!(); + } + + let mut pb = ProgressBar::new(u64::from(*iterations - *offset)); pb.show_speed = false; pb.message("Processing: "); pb.tick(); - let start = Instant::now(); + let start_time = Instant::now(); let opts = ScryptKDFOptions { log_n: *log_n, r: *r, p: *p, - len: *length, + length: *length, iterations: *iterations, }; let kdf = ScryptKDF::new(&opts); - let res = kdf.derive_key_with_callback(&salt, &secret, || { + let last_iteration2 = last_iteration_ref; + let last_result2 = last_result_ref; + let res = kdf.derive_key_with_callback(&salt, &data, *offset, |i, res| { + *last_iteration2.lock().unwrap() = i; + *last_result2.lock().unwrap() = hex::encode(res); + pb.inc(); }); - println!("Key is (please highlight to see): "); - println!("{}", hex::encode(&res as &[u8]).black().on_black()); + println!(); + println!(); + println!( + "Key is (please highlight to see): {}", + hex::encode(res).black().on_black() + ); pb.finish_println(&format!( "Finished in {}\n", - format_duration(Duration::new(start.elapsed().as_secs(), 0)) + format_duration(Duration::new(start_time.elapsed().as_secs(), 0)) .to_string() .cyan() )); @@ -159,19 +226,19 @@ fn main() { Some(Commands::Test {}) => { for test_vector in TEST_VECTORS.iter() { println!( - "Test vector parameters: {} (log_n: {}, r: {}, p: {}, iterations: {}, len: {}), salt: \"{}\", secret: \"{}\"", + "Test vector parameters: {} (log_n: {}, r: {}, p: {}, iterations: {}, length: {}), salt: \"{}\", secret: \"{}\"", "Scrypt".yellow(), test_vector.opts.log_n.to_string().cyan(), test_vector.opts.r.to_string().cyan(), test_vector.opts.p.to_string().cyan(), test_vector.opts.iterations.to_string().cyan(), - test_vector.opts.len.to_string().cyan(), - test_vector.salt.to_string().cyan(), - test_vector.secret.to_string().cyan(), + test_vector.opts.length.to_string().cyan(), + hex::encode(&test_vector.salt).cyan(), + hex::encode(&test_vector.secret).cyan(), ); let kdf = ScryptKDF::new(&test_vector.opts); - let key = kdf.derive_key(test_vector.salt, test_vector.secret); + let key = kdf.derive_key(&test_vector.salt, &test_vector.secret, 0); println!("Derived key: {}", hex::encode(&key).cyan()); diff --git a/src/scrypt_kdf.rs b/src/scrypt_kdf.rs index 981f158..af795fc 100755 --- a/src/scrypt_kdf.rs +++ b/src/scrypt_kdf.rs @@ -6,14 +6,15 @@ pub struct ScryptKDFOptions { pub r: u32, pub p: u32, pub iterations: u32, - pub len: u8, + pub length: u8, } #[derive(PartialEq, Debug)] pub struct TestScryptKDFOptions { pub opts: ScryptKDFOptions, - pub salt: &'static str, - pub secret: &'static str, + pub salt: Vec, + pub secret: Vec, + pub offset: u32, } pub const DEFAULT_SCRYPT_KDF_OPTIONS: ScryptKDFOptions = ScryptKDFOptions { @@ -21,33 +22,37 @@ pub const DEFAULT_SCRYPT_KDF_OPTIONS: ScryptKDFOptions = ScryptKDFOptions { r: 8, p: 1, iterations: 100, - len: 16, + length: 16, }; -pub const TEST_VECTORS: &[&TestScryptKDFOptions] = &[ - &TestScryptKDFOptions { - opts: ScryptKDFOptions { - log_n: 14, - r: 8, - p: 1, - iterations: 1, - len: 64, +lazy_static! { + pub static ref TEST_VECTORS: Vec = vec![ + TestScryptKDFOptions { + opts: ScryptKDFOptions { + log_n: 14, + r: 8, + p: 1, + iterations: 1, + length: 64, + }, + salt: Vec::new(), + secret: Vec::new(), + offset: 0, }, - salt: "", - secret: "", - }, - &TestScryptKDFOptions { - opts: ScryptKDFOptions { - log_n: 14, - r: 8, - p: 1, - iterations: 3, - len: 64, + TestScryptKDFOptions { + opts: ScryptKDFOptions { + log_n: 14, + r: 8, + p: 1, + iterations: 3, + length: 64, + }, + salt: Vec::new(), + secret: "Hello World".as_bytes().to_vec(), + offset: 0, }, - salt: "", - secret: "Hello World", - }, -]; + ]; +} pub const MIN_KDF_LEN: u8 = 10; pub const MAX_KDF_LEN: u8 = 64; @@ -58,19 +63,19 @@ pub struct ScryptKDF<'a> { impl<'a> ScryptKDF<'a> { pub fn new(opts: &'a ScryptKDFOptions) -> Self { - if opts.len < MIN_KDF_LEN { - panic!("length {} is lower than the min length of {MIN_KDF_LEN}", opts.len); + if opts.length < MIN_KDF_LEN { + panic!("length {} is lower than the min length of {MIN_KDF_LEN}", opts.length); } - if opts.len > MAX_KDF_LEN { - panic!("length {} is greater than the max length of {MAX_KDF_LEN}", opts.len); + if opts.length > MAX_KDF_LEN { + panic!("length {} is greater than the max length of {MAX_KDF_LEN}", opts.length); } ScryptKDF { opts } } fn derive(&self, salt: &[u8], secret: &[u8]) -> Vec { - let mut dk = vec![0; self.opts.len as usize]; + let mut dk = vec![0; self.opts.length as usize]; scrypt( secret, @@ -83,19 +88,21 @@ impl<'a> ScryptKDF<'a> { dk.to_vec() } - pub fn derive_key_with_callback(&self, salt: &str, secret: &str, mut callback: F) -> Vec { - let mut res: Vec = secret.as_bytes().to_vec(); - let salt_bytes = salt.as_bytes(); - for _ in 0..self.opts.iterations { - res = self.derive(salt_bytes, &res); - callback(); + pub fn derive_key_with_callback)>( + &self, salt: &[u8], data: &[u8], offset: u32, mut callback: F, + ) -> Vec { + let mut res: Vec = data.to_vec(); + + for i in 0..(self.opts.iterations - offset) { + res = self.derive(salt, &res); + callback(i, &res); } res } - pub fn derive_key(&self, salt: &str, secret: &str) -> Vec { - self.derive_key_with_callback(salt, secret, || {}) + pub fn derive_key(&self, salt: &[u8], data: &[u8], start: u32) -> Vec { + self.derive_key_with_callback(salt, data, start, |_, _| {}) } } @@ -105,85 +112,103 @@ mod tests { use rstest::rstest; #[rstest] - #[case(&TEST_VECTORS[0].opts, TEST_VECTORS[0].salt, TEST_VECTORS[0].secret, "d72c87d0f077c7766f2985dfab30e8955c373a13a1e93d315203939f542ff86e73ee37c31f4c4b571f4719fa8e3589f12db8dcb57ea9f56764bb7d58f64cf705")] - #[case(&TEST_VECTORS[1].opts, TEST_VECTORS[1].salt, TEST_VECTORS[1].secret, "1487e1ac9c7a63e785b1f3e9560ea749913d50c9797dc6ca8d0db953fe03df1c66af878bd6dcce79884e8b7e3e29f39cb709cd63b7e7f4099d82ab199664eab3")] + #[case(&TEST_VECTORS[0].opts, &TEST_VECTORS[0].salt, &TEST_VECTORS[0].secret, TEST_VECTORS[0].offset, "d72c87d0f077c7766f2985dfab30e8955c373a13a1e93d315203939f542ff86e73ee37c31f4c4b571f4719fa8e3589f12db8dcb57ea9f56764bb7d58f64cf705")] + #[case(&TEST_VECTORS[1].opts, &TEST_VECTORS[1].salt, &TEST_VECTORS[1].secret, TEST_VECTORS[1].offset, "1487e1ac9c7a63e785b1f3e9560ea749913d50c9797dc6ca8d0db953fe03df1c66af878bd6dcce79884e8b7e3e29f39cb709cd63b7e7f4099d82ab199664eab3")] #[case(& ScryptKDFOptions { log_n: 14, r: 8, p: 1, iterations: 1, - len: 64 - }, "salt", "test", + length: 64 + }, &"salt".as_bytes(), &"test".as_bytes(), 0, "72f47a5f6bcb1b96a9d77b2c2f1463395d4a3a325fada6290fc0fef7bcddb58eb46e36a0d944613790c2e7bc9ea0e8447b9c4b493734c43526a14963e4a56bdc")] #[case(& ScryptKDFOptions { log_n: 12, r: 8, p: 1, iterations: 10, - len: 32 - }, "salt", "test", + length: 32 + }, &"salt".as_bytes(), &"test".as_bytes(), 0, "e419dac917d02f544469a5164c797ed0066cea15568958f6acc58411df5ac17e")] #[case(& ScryptKDFOptions { log_n: 20, r: 8, p: 1, iterations: 4, - len: 64 - }, "salt", "test", + length: 64 + }, &"salt".as_bytes(), &"test".as_bytes(), 0, "bd13f3cba884d87aeb68ca53efcd65175af1ee9d60907cf71d91e6bbddfa95ee7fb4d48442e54c8a28ac1d02298cdd793618827755ca69704b6cb9ec2b1e2f8e")] #[case(& ScryptKDFOptions { log_n: 15, r: 8, p: 1, iterations: 4, - len: 64 - }, "", "test", + length: 64 + }, &Vec::new(), &"test".as_bytes(), 0, "8c18f4925f57caa69143d178e48d9a559963b045e413dc30ff02fd1c3c9ba1c5a5bf684aaf2aceb4fbc2eef11f4f9ac71b837b68797dc9c19062653b3e96664a")] #[case(& ScryptKDFOptions { log_n: 15, r: 8, p: 1, iterations: 4, - len: 64 - }, "", "", + length: 64 + }, &Vec::new(), &Vec::new(), 0, "7cb7f9c94b25bbf9afa023d20340bff9164658ccce3f09b164b5ce7130aaf84ec8fccbfc9d9de76a133218b7220da069430f40c58ef4bc53c639d5ea72b4437a")] #[case(& ScryptKDFOptions { log_n: 15, r: 8, p: 1, iterations: 4, - len: 64 - }, "salt", "", + length: 64 + }, &"salt".as_bytes(), &"".as_bytes(), 0, "9843308b393a354dd7166eab6a3da12cf324c88417899e195bc9231004acacab26c75bd0ac6b1e6d48f6f12ffd0869e485a67f4d98dd54d1d36384e94abfc11f")] #[case(& ScryptKDFOptions { log_n: 15, r: 8, p: 1, iterations: 10, - len: 64 - }, "salt", "test", + length: 64 + }, &"salt".as_bytes(), &"test".as_bytes(), 0, "e409d625547cb5702ade6e74460e3b90768164e0771975f3548dda809bfadcb1ae4484ca0c7c659bc9e6d9753c28dc7d1ddb9ebfadde8375045dd3cbbaa2eac7")] #[case(& ScryptKDFOptions { log_n: 15, r: 8, p: 1, iterations: 10, - len: 64 - }, "salt2", "test", + length: 64 + }, &"salt2".as_bytes(), &"test".as_bytes(), 0, "d885f5c4c1196fc99eb97f5a08ae318d7a525dbbfdac2d5e8c8c210eb0ef2c58994cdef063463ba37caf47b6fc94693cced3ab03fefc9baf2cb05707d75767d2")] #[case(& ScryptKDFOptions { log_n: 15, r: 8, p: 1, iterations: 10, - len: 64 - }, "salt", "test2", + length: 64 + }, &"salt".as_bytes(), &"test2".as_bytes(), 0, "ff71c6680cd2e221a6a0d13d4527cddea71da1649d721a8392d969cc5f3bf7bc41d58cc2001296b9d985ea319473aa24813065bbaa675cb135372b1133f71d5c")] + #[case(& ScryptKDFOptions { + log_n: 12, + r: 8, + p: 1, + iterations: 10, + length: 32 + }, &"salt".as_bytes(), &hex::decode("881958a1b9fd93fc81c7bdc92a384199a558426c06b9c1374e3d9e155d43a436").unwrap(), 1, + "e419dac917d02f544469a5164c797ed0066cea15568958f6acc58411df5ac17e")] + #[case(& ScryptKDFOptions { + log_n: 15, + r: 8, + p: 1, + iterations: 10, + length: 64 + }, &"salt".as_bytes(), &hex::decode("cf327a4f6f7809a453bab78aaa645bcd79a505728191df2f8c9149dd6c92ee0ae4d63400cb6f20ee8a9c42ef1a2c5c596e71f04b18c0f9bf0df75ab060e75436").unwrap(), 5, + "e409d625547cb5702ade6e74460e3b90768164e0771975f3548dda809bfadcb1ae4484ca0c7c659bc9e6d9753c28dc7d1ddb9ebfadde8375045dd3cbbaa2eac7")] + fn derive_test( - #[case] options: &ScryptKDFOptions, #[case] salt: &str, #[case] secret: &str, #[case] expected: &str, + #[case] options: &ScryptKDFOptions, #[case] salt: &[u8], #[case] data: &[u8], #[case] offset: u32, + #[case] expected: &str, ) { let kdf = ScryptKDF::new(options); - let key = kdf.derive_key(salt, secret); - assert_eq!(key, hex::decode(expected).unwrap()); + let key = kdf.derive_key(salt, data, offset); + assert_eq!(hex::encode(key), expected); } }