diff --git a/Cargo.toml b/Cargo.toml index a8f300d..9a08972 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,7 @@ image = "0.23" base64 = "0.13" hex = "0.4" sha2 = "0.10" +argon2 = "0.3" blake3 = "1.2" bincode = "1.3" aes-gcm = "0.9" @@ -45,6 +46,7 @@ group_types = { git = "https://github.com/cympletech/esse_types", branch="main" cloud_types = { git = "https://github.com/cympletech/esse_types", branch="main" } domain_types = { git = "https://github.com/cympletech/esse_types", branch="main" } dao_types = { git = "https://github.com/cympletech/esse_types", branch="main" } +data = { git = "https://github.com/cympletech/esse_types", branch="main" } #chat_types = { path = "../esse_types/chat" } #group_types = { path = "../esse_types/group" } #dao_types = { path = "../esse_types/dao" } diff --git a/src/account.rs b/src/account.rs index 049e8c4..1799211 100644 --- a/src/account.rs +++ b/src/account.rs @@ -52,7 +52,7 @@ pub(crate) struct Account { pub pass: String, pub name: String, pub avatar: Vec, - pub lock: Vec, // hashed-lock. + pub lock: String, // hashed-lock. pub secret: Vec, // encrypted value. pub encrypt: Vec, // encrypted encrypt key. pub wallet: String, // main wallet info. @@ -69,7 +69,7 @@ impl Account { lang: i64, pass: String, name: String, - lock: Vec, + lock: String, avatar: Vec, mnemonic: Vec, secret: Vec, @@ -138,7 +138,7 @@ impl Account { lang, pass.to_string(), name.to_string(), - hash_pin(salt, lock, index), + hash_pin(lock)?, avatar, mnemonic, secret, @@ -148,8 +148,8 @@ impl Account { )) } - pub fn check_lock(&self, salt: &[u8], lock: &str) -> Result<()> { - if check_pin(salt, lock, self.index, &self.lock) { + pub fn check_lock(&self, lock: &str) -> Result<()> { + if check_pin(lock, &self.lock)? { Ok(()) } else { Err(anyhow!("lock is invalid!")) @@ -157,8 +157,8 @@ impl Account { } pub fn pin(&mut self, salt: &[u8], old: &str, new: &str) -> Result<()> { - self.check_lock(salt, old)?; - self.lock = hash_pin(salt, new, self.index); + self.check_lock(old)?; + self.lock = hash_pin(new)?; let key = decrypt_key(salt, old, &self.encrypt)?; self.encrypt = encrypt_key(salt, new, &key)?; @@ -166,13 +166,13 @@ impl Account { } pub fn mnemonic(&self, salt: &[u8], lock: &str) -> Result { - self.check_lock(salt, lock)?; + self.check_lock(lock)?; let pbytes = decrypt(salt, lock, &self.encrypt, &self.mnemonic)?; String::from_utf8(pbytes).or(Err(anyhow!("mnemonic unlock invalid."))) } pub fn secret(&self, salt: &[u8], lock: &str) -> Result { - self.check_lock(salt, lock)?; + self.check_lock(lock)?; let pbytes = decrypt(salt, lock, &self.encrypt, &self.secret)?; Keypair::from_bytes(&pbytes).or(Err(anyhow!("secret unlock invalid."))) } @@ -189,7 +189,7 @@ impl Account { encrypt: base64::decode(v.pop().unwrap().as_str()).unwrap_or(vec![]), secret: base64::decode(v.pop().unwrap().as_str()).unwrap_or(vec![]), mnemonic: base64::decode(v.pop().unwrap().as_str()).unwrap_or(vec![]), - lock: base64::decode(v.pop().unwrap().as_string()).unwrap_or(vec![]), + lock: v.pop().unwrap().as_string(), name: v.pop().unwrap().as_string(), pass: v.pop().unwrap().as_string(), lang: v.pop().unwrap().as_i64(), @@ -240,7 +240,7 @@ impl Account { self.lang, self.pass, self.name, - base64::encode(&self.lock), + self.lock, base64::encode(&self.mnemonic), base64::encode(&self.secret), base64::encode(&self.encrypt), @@ -260,7 +260,7 @@ impl Account { pub fn update(&self, db: &DStorage) -> Result { let sql = format!("UPDATE accounts SET name='{}', lock='{}', encrypt='{}', avatar='{}', wallet='{}', pub_height={}, own_height={}, event='{}', datetime={} WHERE id = {}", self.name, - base64::encode(&self.lock), + self.lock, base64::encode(&self.encrypt), base64::encode(&self.avatar), self.wallet, diff --git a/src/group.rs b/src/group.rs index 681b6df..8a2d211 100644 --- a/src/group.rs +++ b/src/group.rs @@ -278,7 +278,7 @@ impl Group { pub fn check_lock(&self, gid: &GroupId, lock: &str) -> bool { if let Some(account) = self.accounts.get(gid) { - account.check_lock(&self.secret, lock).is_ok() + account.check_lock(lock).is_ok() } else { false } diff --git a/src/utils/crypto.rs b/src/utils/crypto.rs index 55d5a50..7111649 100644 --- a/src/utils/crypto.rs +++ b/src/utils/crypto.rs @@ -2,6 +2,10 @@ use aes_gcm::{ aead::{generic_array::GenericArray, Aead, NewAead}, Aes256Gcm, }; +use argon2::{ + password_hash::{rand_core::OsRng, PasswordHash, PasswordHasher, PasswordVerifier, SaltString}, + Argon2, +}; use sha2::{Digest, Sha256}; const FIX_PADDING: [u8; 19] = [ @@ -9,22 +13,21 @@ const FIX_PADDING: [u8; 19] = [ ]; /// Hash the given pin. -pub fn hash_pin(salt: &[u8], pin: &str, index: i64) -> Vec { - let mut hasher = Sha256::new(); - hasher.update(salt); // for avoid same hash when no-pin in other derives. - hasher.update(pin.as_bytes()); - hasher.update(index.to_le_bytes()); // for avoid same hash when no-pin in one device. - hasher.finalize().to_vec() +pub fn hash_pin(pin: &str) -> anyhow::Result { + let salt = SaltString::generate(&mut OsRng); + let argon2 = Argon2::default(); + Ok(argon2 + .hash_password(pin.as_bytes(), &salt) + .map_err(|_| anyhow!("hash pin failure!"))? + .to_string()) } /// check the pin is the given hash pre-image. -pub fn check_pin(salt: &[u8], pin: &str, index: i64, hash: &[u8]) -> bool { - let mut hasher = Sha256::new(); - hasher.update(salt); - hasher.update(pin.as_bytes()); - hasher.update(index.to_le_bytes()); - let hash_key = hasher.finalize(); - &hash_key[..] == hash +pub fn check_pin(pin: &str, hash: &str) -> anyhow::Result { + let parsed_hash = PasswordHash::new(hash).map_err(|_| anyhow!("hash pin failure!"))?; + Ok(Argon2::default() + .verify_password(pin.as_bytes(), &parsed_hash) + .is_ok()) } fn build_cipher(salt: &[u8], pin: &str) -> Aes256Gcm {