use aes_gcm::{
aead::{Aead, KeyInit},
Aes256Gcm, Nonce,
};
use rand::Rng;
use crate::error::Error;
const APP_KEY: &[u8; 32] = b"smolder-wallet-encrypt-key-0032!";
const NONCE_SIZE: usize = 12;
pub fn encrypt_private_key(private_key: &str) -> Result<Vec<u8>, Error> {
let cipher = Aes256Gcm::new(APP_KEY.into());
let mut nonce_bytes = [0u8; NONCE_SIZE];
rand::thread_rng().fill(&mut nonce_bytes);
let nonce = Nonce::from(nonce_bytes);
let ciphertext = cipher
.encrypt(&nonce, private_key.as_bytes())
.map_err(|e| Error::Keyring(format!("Encryption failed: {}", e)))?;
let mut result = nonce_bytes.to_vec();
result.extend(ciphertext);
Ok(result)
}
pub fn decrypt_private_key(encrypted_data: &[u8]) -> Result<String, Error> {
if encrypted_data.len() < NONCE_SIZE {
return Err(Error::Keyring("Invalid encrypted data: too short".into()));
}
let cipher = Aes256Gcm::new(APP_KEY.into());
let (nonce_bytes, ciphertext) = encrypted_data.split_at(NONCE_SIZE);
let nonce_array: [u8; NONCE_SIZE] = nonce_bytes
.try_into()
.map_err(|_| Error::Keyring("Invalid nonce length".into()))?;
let nonce = Nonce::from(nonce_array);
let plaintext = cipher
.decrypt(&nonce, ciphertext)
.map_err(|e| Error::Keyring(format!("Decryption failed: {}", e)))?;
String::from_utf8(plaintext).map_err(|e| Error::Keyring(format!("Invalid UTF-8: {}", e)))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_encrypt_decrypt_roundtrip() {
let private_key = "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef";
let encrypted = encrypt_private_key(private_key).unwrap();
let decrypted = decrypt_private_key(&encrypted).unwrap();
assert_eq!(decrypted, private_key);
}
#[test]
fn test_different_nonces() {
let private_key = "0xabcdef";
let encrypted1 = encrypt_private_key(private_key).unwrap();
let encrypted2 = encrypt_private_key(private_key).unwrap();
assert_ne!(encrypted1, encrypted2);
assert_eq!(decrypt_private_key(&encrypted1).unwrap(), private_key);
assert_eq!(decrypt_private_key(&encrypted2).unwrap(), private_key);
}
#[test]
fn test_decrypt_invalid_data() {
assert!(decrypt_private_key(&[0u8; 5]).is_err());
assert!(decrypt_private_key(&[0u8; 20]).is_err());
}
}