use crate::error::{Error, Result};
use hmac::{Hmac, Mac};
use md5::Md5;
use sha2::{Sha256, Sha512, Digest};
pub struct Md5Util;
impl Md5Util {
pub fn digest(data: &[u8]) -> Vec<u8> {
let mut hasher = Md5::new();
hasher.update(data);
hasher.finalize().to_vec()
}
pub fn digest_hex(data: &[u8]) -> String {
let hash = Self::digest(data);
hex::encode(hash)
}
pub fn digest_str(data: &str) -> String {
Self::digest_hex(data.as_bytes())
}
}
pub struct ShaUtil;
impl ShaUtil {
pub fn sha256(data: &[u8]) -> Vec<u8> {
let mut hasher = Sha256::new();
hasher.update(data);
hasher.finalize().to_vec()
}
pub fn sha256_hex(data: &[u8]) -> String {
let hash = Self::sha256(data);
hex::encode(hash)
}
pub fn sha256_str(data: &str) -> String {
Self::sha256_hex(data.as_bytes())
}
pub fn sha512(data: &[u8]) -> Vec<u8> {
let mut hasher = Sha512::new();
hasher.update(data);
hasher.finalize().to_vec()
}
pub fn sha512_hex(data: &[u8]) -> String {
let hash = Self::sha512(data);
hex::encode(hash)
}
pub fn sha512_str(data: &str) -> String {
Self::sha512_hex(data.as_bytes())
}
}
pub struct HmacUtil;
impl HmacUtil {
pub fn hmac_sha256(key: &[u8], message: &[u8]) -> Result<Vec<u8>> {
type HmacSha256 = Hmac<Sha256>;
let mut mac = HmacSha256::new_from_slice(key)
.map_err(|e| Error::crypto(format!("Invalid key length: {}", e)))?;
mac.update(message);
let result = mac.finalize();
Ok(result.into_bytes().to_vec())
}
pub fn hmac_sha256_hex(key: &[u8], message: &[u8]) -> Result<String> {
let hmac = Self::hmac_sha256(key, message)?;
Ok(hex::encode(hmac))
}
pub fn hmac_sha256_str(key: &str, message: &str) -> Result<String> {
Self::hmac_sha256_hex(key.as_bytes(), message.as_bytes())
}
pub fn verify_hmac_sha256(key: &[u8], message: &[u8], expected_hmac: &[u8]) -> Result<bool> {
type HmacSha256 = Hmac<Sha256>;
let mut mac = HmacSha256::new_from_slice(key)
.map_err(|e| Error::crypto(format!("Invalid key length: {}", e)))?;
mac.update(message);
match mac.verify_slice(expected_hmac) {
Ok(()) => Ok(true),
Err(_) => Ok(false),
}
}
pub fn verify_hmac_sha256_hex(key: &[u8], message: &[u8], expected_hmac_hex: &str) -> Result<bool> {
let expected_hmac = hex::decode(expected_hmac_hex)
.map_err(|e| Error::crypto(format!("Invalid hex string: {}", e)))?;
Self::verify_hmac_sha256(key, message, &expected_hmac)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_md5_digest() {
let hash = Md5Util::digest(b"hello world");
assert_eq!(hash.len(), 16);
let hash_hex = Md5Util::digest_hex(b"hello world");
assert_eq!(hash_hex, "5eb63bbbe01eeed093cb22bb8f5acdc3");
}
#[test]
fn test_md5_string() {
let hash_hex = Md5Util::digest_str("hello world");
assert_eq!(hash_hex, "5eb63bbbe01eeed093cb22bb8f5acdc3");
}
#[test]
fn test_sha256_digest() {
let hash = ShaUtil::sha256(b"hello world");
assert_eq!(hash.len(), 32);
let hash_hex = ShaUtil::sha256_hex(b"hello world");
assert_eq!(hash_hex, "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9");
}
#[test]
fn test_sha256_string() {
let hash_hex = ShaUtil::sha256_str("hello world");
assert_eq!(hash_hex, "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9");
}
#[test]
fn test_sha512_digest() {
let hash = ShaUtil::sha512(b"hello world");
assert_eq!(hash.len(), 64);
let hash_hex = ShaUtil::sha512_hex(b"hello world");
assert_eq!(hash_hex.len(), 128);
}
#[test]
fn test_hmac_sha256() {
let key = b"my-secret-key";
let message = b"hello world";
let hmac = HmacUtil::hmac_sha256(key, message).unwrap();
assert_eq!(hmac.len(), 32);
let hmac_hex = HmacUtil::hmac_sha256_hex(key, message).unwrap();
assert_eq!(hmac_hex.len(), 64);
assert!(HmacUtil::verify_hmac_sha256(key, message, &hmac).unwrap());
assert!(HmacUtil::verify_hmac_sha256_hex(key, message, &hmac_hex).unwrap());
assert!(!HmacUtil::verify_hmac_sha256(key, b"wrong message", &hmac).unwrap());
}
#[test]
fn test_hmac_string() {
let hmac_hex = HmacUtil::hmac_sha256_str("my-secret-key", "hello world").unwrap();
assert_eq!(hmac_hex.len(), 64);
}
}