use crate::crypto::error::CryptoError;
use aes_gcm::{
aead::{Aead, AeadCore, KeyInit, OsRng},
Aes256Gcm, Nonce,
};
use argon2::{Algorithm, Argon2, Params, Version};
pub struct Aes256GcmCipher {
cipher: Aes256Gcm,
}
impl Aes256GcmCipher {
pub fn new(key: &[u8; 32]) -> Self {
let cipher = Aes256Gcm::new(key.into());
Self { cipher }
}
pub fn from_password(password: &str, salt: &[u8; 32]) -> Result<Self, CryptoError> {
let mut key = [0u8; 32];
let argon = Argon2::new(Algorithm::Argon2id, Version::V0x13, Params::default());
argon
.hash_password_into(password.as_bytes(), salt, &mut key)
.map_err(|e| CryptoError::KeyDerivationFailed(format!("Argon2 哈希失败: {}", e)))?;
Ok(Self::new(&key))
}
pub fn encrypt(&self, plaintext: &[u8]) -> Result<Vec<u8>, CryptoError> {
let nonce = Aes256Gcm::generate_nonce(&mut OsRng);
self.cipher
.encrypt(&nonce, plaintext)
.map(|mut encrypted| {
let mut result = nonce.to_vec();
result.append(&mut encrypted);
result
})
.map_err(|e| CryptoError::EncryptionFailed(e.to_string()))
}
pub fn decrypt(&self, ciphertext: &[u8]) -> Result<Vec<u8>, CryptoError> {
if ciphertext.len() < 12 {
return Err(CryptoError::DecryptionFailed("密文太短".to_string()));
}
let (nonce_bytes, encrypted) = ciphertext.split_at(12);
let nonce = Nonce::from_slice(nonce_bytes);
self.cipher
.decrypt(nonce, encrypted)
.map_err(|e| CryptoError::DecryptionFailed(e.to_string()))
}
}