diff --git a/Cargo.lock b/Cargo.lock index 3fe685b..d0735b7 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" @@ -522,6 +548,17 @@ 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 = "polyval" version = "0.6.0" @@ -661,6 +698,7 @@ name = "rustwallet" version = "0.1.0" dependencies = [ "anyhow", + "argon2", "base64 0.21.0", "bitcoin_hashes", "ecies", diff --git a/Cargo.toml b/Cargo.toml index fbfdcd4..9a19a1d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,7 @@ ecies = {version = "0.2", default-features = false, features = ["pure"]} wasm-bindgen = "0.2.83" qrcodegen = "1.8.0" base64 = "0.21.0" +argon2 = { version = "0.5.0" } [profile.release] lto = true diff --git a/examples/pass.rs b/examples/pass.rs new file mode 100644 index 0000000..da0f5d9 --- /dev/null +++ b/examples/pass.rs @@ -0,0 +1 @@ +pub fn main() {} diff --git a/src/lib.rs b/src/lib.rs index b5a6607..d438846 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,6 +7,7 @@ use qr::qr_code::QR; +use utils::pass_utils::{hash_password, verify_password}; use utils::str_utils::{base64_to_hex, hex_to_base64}; use wasm_bindgen::prelude::*; @@ -195,3 +196,13 @@ pub fn str_deflate(content: String) -> String { pub fn str_inflate(content: String) -> String { base64_to_hex(&content) } + +#[wasm_bindgen] +pub fn password_hash(pass: String) -> String { + hash_password(&pass) +} + +#[wasm_bindgen] +pub fn password_verify(pass: String, pass_hash: String) -> bool { + verify_password(&pass, &pass_hash) +} diff --git a/src/utils/mod.rs b/src/utils/mod.rs index d949670..25d5f55 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1 +1,2 @@ +pub mod pass_utils; pub mod str_utils; diff --git a/src/utils/pass_utils.rs b/src/utils/pass_utils.rs new file mode 100644 index 0000000..7738cab --- /dev/null +++ b/src/utils/pass_utils.rs @@ -0,0 +1,36 @@ +use argon2::{ + password_hash::{rand_core::OsRng, PasswordHash, PasswordHasher, PasswordVerifier, SaltString}, + Argon2, +}; +use base64::{engine::general_purpose, Engine as _}; +use std::str; + +pub fn hash_password(pass: &str) -> String { + let salt: SaltString = SaltString::generate(&mut OsRng); + let password = pass.as_bytes(); + let password_hash: String = match Argon2::default().hash_password(password, &salt) { + Ok(v) => v.to_string(), + Err(e) => panic!("error hash password: {}", e), + }; + general_purpose::STANDARD_NO_PAD.encode(&password_hash) +} + +pub fn verify_password(pass: &str, password_hash: &str) -> bool { + let str_tmp = match general_purpose::STANDARD_NO_PAD.decode(password_hash) { + Ok(v) => v, + Err(e) => panic!("error decode base64 str: {}", e), + }; + let s = match str::from_utf8(&str_tmp) { + Ok(v) => v, + Err(e) => panic!("Invalid UTF-8 sequence: {}", e), + }; + let parsed_hash = match PasswordHash::new(&s) { + Ok(v) => v, + Err(e) => panic!("error parse password hash: {}", e), + }; + + let password = pass.as_bytes(); + Argon2::default() + .verify_password(password, &parsed_hash) + .is_ok() +}