veza/veza-common/src/utils/crypto.rs
2025-12-12 21:34:34 -05:00

63 lines
2 KiB
Rust

use sha2::{Sha256, Digest};
use hmac::{Hmac, Mac};
use base64::{Engine as _, engine::general_purpose};
use crate::error::{CommonResult as Result, CommonError as Error};
/// Hash a string using SHA-256
pub fn hash_sha256(input: &str) -> String {
let mut hasher = Sha256::new();
hasher.update(input.as_bytes());
format!("{:x}", hasher.finalize())
}
/// Generate HMAC signature
pub fn generate_hmac_signature(data: &str, secret: &str) -> Result<String> {
let mut mac = Hmac::<Sha256>::new_from_slice(secret.as_bytes())
.map_err(|_| Error::InternalError("Invalid HMAC secret".to_string()))?;
mac.update(data.as_bytes());
let result = mac.finalize();
let signature = general_purpose::STANDARD.encode(result.into_bytes());
Ok(signature)
}
/// Verify HMAC signature
pub fn verify_hmac_signature(data: &str, signature: &str, secret: &str) -> Result<bool> {
let expected = generate_hmac_signature(data, secret)?;
Ok(signature == expected)
}
/// Encode data to base64
pub fn encode_base64(data: &[u8]) -> String {
general_purpose::STANDARD.encode(data)
}
/// Decode base64 data
pub fn decode_base64(data: &str) -> Result<Vec<u8>> {
general_purpose::STANDARD.decode(data)
.map_err(|e| Error::SerializationError(format!("Base64 decode error: {}", e)))
}
/// Convert bytes to hex string
pub fn bytes_to_hex(bytes: &[u8]) -> String {
bytes.iter().map(|b| format!("{:02x}", b)).collect()
}
/// Convert hex string to bytes
pub fn hex_to_bytes(hex: &str) -> Result<Vec<u8>> {
if hex.len() % 2 != 0 {
return Err(Error::ValidationError("Hex string must have even length".to_string()));
}
let mut bytes = Vec::new();
for chunk in hex.as_bytes().chunks(2) {
let byte_str = std::str::from_utf8(chunk)
.map_err(|_| Error::ValidationError("Invalid hex string".to_string()))?;
let byte = u8::from_str_radix(byte_str, 16)
.map_err(|_| Error::ValidationError("Invalid hex character".to_string()))?;
bytes.push(byte);
}
Ok(bytes)
}