use argon2::{
Argon2,
password_hash::{self, PasswordHash, PasswordHasher, PasswordVerifier, SaltString},
};
use anyhow::Error;
use base64::{Engine as _, engine::general_purpose};
use hex::encode;
use rand::RngExt;
use tracing::warn;
pub struct Crypto;
impl Crypto {
pub fn md5_string(data: &str) -> String {
let digest = md5::compute(data);
format!("{:x}", digest)
}
pub fn hash_password(password: &str) -> Result<String, password_hash::Error> {
let mut salt_bytes = [0u8; 16];
let mut rng = rand::rng();
rng.fill(&mut salt_bytes);
let salt = SaltString::encode_b64(&salt_bytes)?;
let argon2 = Argon2::default();
let password_hash = argon2
.hash_password(password.as_bytes(), &salt)?
.to_string();
Ok(password_hash)
}
pub fn verify_password(password: &str, hash: &str) -> bool {
let parsed_hash = match PasswordHash::new(hash) {
Ok(hash) => hash,
Err(_) => return false, };
Argon2::default()
.verify_password(password.as_bytes(), &parsed_hash)
.is_ok()
}
pub fn generate_basic_auth_key(key: &str) -> String {
let first_encode = general_purpose::STANDARD.encode(key.as_bytes());
general_purpose::STANDARD.encode(first_encode.as_bytes())
}
pub fn decode_basic_auth_key(encoded_key: &str) -> Result<String, Error> {
warn!(
"...「decode_basic_auth_key」encoded_key: {} ...",
encoded_key
);
let first_decode = general_purpose::STANDARD.decode(encoded_key)?;
let second_decode = general_purpose::STANDARD.decode(&first_decode)?;
String::from_utf8(second_decode).map_err(Error::from)
}
pub fn zstd_compress(data: &[u8]) -> Result<Vec<u8>, Error> {
let compressed = zstd::stream::encode_all(data, 0)?;
Ok(compressed)
}
pub fn generate_aes_key() -> String {
let mut key = [0u8; 32];
rand::rng().fill(&mut key);
let hex_string = encode(&key);
let hex_string = if hex_string.len() >= 32 {
hex_string[..32].to_string()
} else {
hex_string
};
hex_string
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_generate_basic_auth_key() {
let key = "topedu::auth";
let encoded_key = Crypto::generate_basic_auth_key(key);
println!("{}", encoded_key);
}
#[test]
fn test_decode_basic_auth_key() {
let key = "topedu::auth";
let encoded_key = Crypto::generate_basic_auth_key(key);
let decoded_key =
Crypto::decode_basic_auth_key(&encoded_key).expect("Failed to decode key");
println!("encoded_key: {}", encoded_key);
println!("decoded_key: {}", decoded_key);
}
#[test]
fn test_new() {
assert!(Crypto::generate_basic_auth_key("test").len() > 0);
}
#[test]
fn test_ases_generate_aes_key() {
let key = Crypto::generate_aes_key();
println!("the aes_key :{}", key)
}
#[test]
fn test_md5_string() {
let data = "hello world";
let md5 = Crypto::md5_string(data);
println!("md5: {}", md5);
}
}