use aes_gcm::{Aes256Gcm, Key, Nonce, KeyInit};
use aes_gcm::aead::Aead;
use base64::{Engine as _, engine::general_purpose};
use sha2::{Sha256, Digest};
use serde_json::Value;
use crate::error::{Result, SdkError};
pub fn encrypt_data(data: &Value, key: &str) -> Result<String> {
let data_bytes = serde_json::to_vec(data)?;
let mut hasher = Sha256::new();
hasher.update(key.as_bytes());
let key_hash = hasher.finalize();
let cipher_key = Key::<Aes256Gcm>::from_slice(&key_hash);
let cipher = Aes256Gcm::new(cipher_key);
let mut iv_hasher = Sha256::new();
iv_hasher.update(key.as_bytes());
let iv_hash = iv_hasher.finalize();
let nonce = Nonce::from_slice(&iv_hash[..12]);
let ciphertext = cipher.encrypt(nonce, data_bytes.as_ref())
.map_err(|e| SdkError::Crypto(format!("Encryption failed: {:?}", e)))?;
Ok(general_purpose::STANDARD.encode(ciphertext))
}
pub fn salt_key(key: &str, salt: i32) -> Result<String> {
let salt_str = salt.to_string();
let mut hasher = Sha256::new();
hasher.update(salt_str.as_bytes());
let salt_hash = hasher.finalize();
let cipher_key = Key::<Aes256Gcm>::from_slice(&salt_hash);
let cipher = Aes256Gcm::new(cipher_key);
let mut iv_hasher = Sha256::new();
iv_hasher.update(salt_str.as_bytes());
let iv_hash = iv_hasher.finalize();
let nonce = Nonce::from_slice(&iv_hash[..12]);
let key_bytes = key.as_bytes();
let ciphertext = cipher.encrypt(nonce, key_bytes)
.map_err(|e| SdkError::Crypto(format!("Key encryption failed: {:?}", e)))?;
Ok(general_purpose::STANDARD.encode(ciphertext))
}
pub fn decrypt_data(encrypted_data: &str, key: &str) -> Result<Value> {
let ciphertext = general_purpose::STANDARD.decode(encrypted_data)?;
let mut hasher = Sha256::new();
hasher.update(key.as_bytes());
let key_hash = hasher.finalize();
let cipher_key = Key::<Aes256Gcm>::from_slice(&key_hash);
let cipher = Aes256Gcm::new(cipher_key);
let mut iv_hasher = Sha256::new();
iv_hasher.update(key.as_bytes());
let iv_hash = iv_hasher.finalize();
let nonce = Nonce::from_slice(&iv_hash[..12]);
let plaintext = cipher.decrypt(nonce, ciphertext.as_ref())
.map_err(|e| SdkError::Crypto(format!("Decryption failed: {:?}", e)))?;
let value: Value = serde_json::from_slice(&plaintext)?;
Ok(value)
}
pub fn unsalt_key(salted_key: &str, salt: i32) -> Result<String> {
let ciphertext = general_purpose::STANDARD.decode(salted_key)?;
let salt_str = salt.to_string();
let mut hasher = Sha256::new();
hasher.update(salt_str.as_bytes());
let salt_hash = hasher.finalize();
let cipher_key = Key::<Aes256Gcm>::from_slice(&salt_hash);
let cipher = Aes256Gcm::new(cipher_key);
let mut iv_hasher = Sha256::new();
iv_hasher.update(salt_str.as_bytes());
let iv_hash = iv_hasher.finalize();
let nonce = Nonce::from_slice(&iv_hash[..12]);
let plaintext = cipher.decrypt(nonce, ciphertext.as_ref())
.map_err(|e| SdkError::Crypto(format!("Key decryption failed: {:?}", e)))?;
String::from_utf8(plaintext)
.map_err(|e| SdkError::Crypto(format!("Invalid UTF-8 in decrypted key: {}", e)))
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn test_encrypt_decrypt_data() {
let data = json!({
"message": "Hello, World!",
"number": 42
});
let key = "test-key-123";
let encrypted = encrypt_data(&data, key).unwrap();
let decrypted = decrypt_data(&encrypted, key).unwrap();
assert_eq!(data, decrypted);
}
#[test]
fn test_salt_unsalt_key() {
let key = "my-secret-key";
let salt = 123456;
let salted = salt_key(key, salt).unwrap();
let unsalted = unsalt_key(&salted, salt).unwrap();
assert_eq!(key, unsalted);
}
#[test]
fn test_deterministic_encryption() {
let data = json!({"test": "value"});
let key = "consistent-key";
let encrypted1 = encrypt_data(&data, key).unwrap();
let encrypted2 = encrypt_data(&data, key).unwrap();
assert_eq!(encrypted1, encrypted2);
}
}