diff --git a/Cargo.lock b/Cargo.lock index 8b689dd..c455e41 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -43,6 +43,17 @@ version = "1.0.65" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "98161a4e3e2184da77bb14f02184cdd111e83bbbcc9979dfee3c44b9a85f5602" +[[package]] +name = "argon2" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95c2fcf79ad1932ac6269a738109997a83c227c09b75842ae564dc8ede6a861c" +dependencies = [ + "base64ct", + "blake2", + "password-hash", +] + [[package]] name = "arrayref" version = "0.3.6" @@ -73,6 +84,12 @@ version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + [[package]] name = "bitcoin_hashes" version = "0.11.0" @@ -97,6 +114,15 @@ dependencies = [ "wyz", ] +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest 0.10.6", +] + [[package]] name = "block-buffer" version = "0.9.0" @@ -544,6 +570,27 @@ dependencies = [ "syn", ] +[[package]] +name = "password-hash" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" +dependencies = [ + "base64ct", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "pbkdf2" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0ca0b5a68607598bf3bad68f32227a8164f6254833f84eafaac409cd6746c31" +dependencies = [ + "digest 0.10.6", + "hmac 0.12.1", +] + [[package]] name = "polyval" version = "0.6.0" @@ -676,11 +723,13 @@ name = "rustwallet" version = "0.1.0" dependencies = [ "anyhow", + "argon2", "base64 0.21.0", "bitcoin_hashes", "ecies", "hex", "primitive-types", + "scrypt", "secp256k1", "serde", "serde_json", @@ -694,6 +743,27 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" +[[package]] +name = "salsa20" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" +dependencies = [ + "cipher", +] + +[[package]] +name = "scrypt" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0516a385866c09368f0b5bcd1caff3366aace790fcd46e2bb032697bb172fd1f" +dependencies = [ + "password-hash", + "pbkdf2", + "salsa20", + "sha2 0.10.6", +] + [[package]] name = "secp256k1" version = "0.25.0" diff --git a/Cargo.toml b/Cargo.toml index ef7fbd7..f5b7f5a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,3 +25,5 @@ tiny-keccak = "1.5" primitive-types = "0.12.1" ecies = {version = "0.2", default-features = false, features = ["pure"]} base64 = "0.21.0" +scrypt = { version = "0.11.0", default-features = false, features = ["simple"] } +argon2 = { version = "0.5.0" } diff --git a/examples/argon2.rs b/examples/argon2.rs new file mode 100644 index 0000000..e15a4f3 --- /dev/null +++ b/examples/argon2.rs @@ -0,0 +1,28 @@ +use argon2::{ + password_hash::{rand_core::OsRng, PasswordHash, PasswordHasher, PasswordVerifier, SaltString}, + Argon2, +}; +use std::time::SystemTime; + +fn main() { + let password = b"hunter42"; // Bad password; don't actually use! + let start = SystemTime::now(); + let salt: SaltString = SaltString::generate(&mut OsRng); + println!("salt: {}", salt); + // Argon2 with default params (Argon2id v19) + let argon2 = Argon2::default(); + + // Hash password to PHC string ($argon2id$v=19$...) + let password_hash = argon2.hash_password(password, &salt).unwrap().to_string(); + println!("password_hash: {}", password_hash); + println!("Elapsed time: {:?}", start.elapsed()); + // Verify password against PHC string. + // + // NOTE: hash params from `parsed_hash` are used instead of what is configured in the + // `Argon2` instance. + let parsed_hash = PasswordHash::new(&password_hash).unwrap(); + assert!(Argon2::default() + .verify_password(password, &parsed_hash) + .is_ok()); + println!("Elapsed time: {:?}", start.elapsed()); +} diff --git a/examples/scrypt.rs b/examples/scrypt.rs new file mode 100644 index 0000000..19730fb --- /dev/null +++ b/examples/scrypt.rs @@ -0,0 +1,34 @@ +use scrypt::{ + password_hash::{rand_core::OsRng, PasswordHash, PasswordHasher, PasswordVerifier, SaltString}, + Params, Scrypt, +}; + +use std::time::SystemTime; + +fn main() { + let password = b"hunter42"; // Bad password; don't actually use! + let start = SystemTime::now(); + + let salt = SaltString::generate(&mut OsRng); + println!("salt: {}", salt); + + // Hash password to PHC string ($scrypt$...) + let param = Params::new(13, 8, 1, 32).unwrap(); + let password_hash = Scrypt + .hash_password_customized(password, None, None, param, &salt) + .unwrap() + .to_string(); + print!("password_hash: {}", password_hash); + println!( + "Elapsed time: {:?}", + SystemTime::now().duration_since(start) + ); + // Verify password against PHC string + + let parsed_hash = PasswordHash::new(&password_hash).unwrap(); + assert!(Scrypt.verify_password(password, &parsed_hash).is_ok()); + println!( + "Elapsed time: {:?}", + SystemTime::now().duration_since(start) + ); +}