diff --git a/core/src/crypto.rs b/core/src/crypto.rs index 63cb1e5..7ee4c0e 100644 --- a/core/src/crypto.rs +++ b/core/src/crypto.rs @@ -1,10 +1,9 @@ -use futures::io::{AsyncReadExt, AsyncWriteExt}; use argon2::{ Argon2, PasswordHasher as ArgonPasswordHasher, PasswordVerifier as ArgonPasswordVerifier, }; +use futures::io::{AsyncReadExt, AsyncWriteExt}; use rand::Rng; - /// Foolproof random 8 char string /// only uppercase letters (except for 0 and O) and numbers /// TODO tests @@ -12,14 +11,11 @@ pub fn random_8_char_string() -> String { let iterator = rand::thread_rng() .sample_iter(&rand::distributions::Alphanumeric) .map(char::from); - let mut s = String::new(); - for c in iterator { // add all characters except for: lowercase chars, 0 and O - if ('1'..='9').contains(&c) || - ('A'..='N').contains(&c) || - ('P'..'Z').contains(&c) - { + for c in iterator { + // add all characters except for: lowercase chars, 0 and O + if ('1'..='9').contains(&c) || ('A'..='N').contains(&c) || ('P'..'Z').contains(&c) { s.push(c); if s.len() == 8 { break; @@ -29,34 +25,67 @@ pub fn random_8_char_string() -> String { s } -pub async fn hash_password(password_plaint_text: String) -> Result { +// TODO: No unwrap for spawn_blocking +pub async fn hash_password( + password_plaint_text: String, +) -> Result { let argon_config = Argon2::default(); let hash = tokio::task::spawn_blocking(move || { let password = password_plaint_text.as_bytes(); let salt = "c2VjcmV0bHl0ZXN0aW5nZXZlcnl0aGluZw"; - + let encrypted = argon_config.hash_password(password, salt); encrypted - }).await; + }) + .await.unwrap(); - let result = hash.unwrap()?; + let result = hash?; return Ok(result.to_string()); } -pub async fn encrypt_password(password_plaint_text: &str, key: &str) -> Result { +// TODO: No unwrap for spawn_blocking +pub async fn verify_password<'a>( + password_plaint_text: String, + hash: String, +) -> Result { + let argon_config = Argon2::default(); + + let result: Result = tokio::task::spawn_blocking(move || { + let parsed_hash = argon2::PasswordHash::new(&hash); + match parsed_hash { + Ok(parsed) => { + return Ok(argon_config + .verify_password(password_plaint_text.as_bytes(), &parsed) + .is_ok()) + } + Err(error) => return Err(error), + } + }) + .await + .unwrap(); + + result +} + +pub async fn encrypt_password( + password_plaint_text: &str, + key: &str, +) -> Result { let encryptor = age::Encryptor::with_user_passphrase(age::secrecy::Secret::new(key.to_owned())); let mut encrypt_buffer = Vec::new(); let mut encrypt_writer = encryptor.wrap_async_output(&mut encrypt_buffer).await?; - encrypt_writer.write_all(password_plaint_text.as_bytes()).await?; + encrypt_writer + .write_all(password_plaint_text.as_bytes()) + .await?; encrypt_writer.flush().await?; encrypt_writer.close().await?; - + Ok(base64::encode(encrypt_buffer)) } @@ -72,22 +101,10 @@ pub async fn decrypt_password( }; let mut decrypt_buffer = Vec::new(); - let mut decrypt_writer = decryptor.decrypt_async(&age::secrecy::Secret::new(key.to_owned()), None)?; + let mut decrypt_writer = + decryptor.decrypt_async(&age::secrecy::Secret::new(key.to_owned()), None)?; decrypt_writer.read_to_end(&mut decrypt_buffer).await?; Ok(String::from_utf8(decrypt_buffer)?) } - -pub fn verify_password( - password_plaint_text: &str, - hash: &str, -) -> Result { - let argon_config = Argon2::default(); - - let parsed_hash = argon2::PasswordHash::new(&hash)?; - - return Ok(argon_config - .verify_password(password_plaint_text.as_bytes(), &parsed_hash) - .is_ok()); -}