use std::collections::HashMap;
use std::fmt;
use std::sync::{Arc, RwLock};
use async_trait::async_trait;
use super::KeyManagementClient;
use crate::encryption::{AesGcmCipher, AesKeySize, SecureKey, SensitiveBytes};
use crate::error::lock_error;
use crate::{Error, ErrorKind, Result};
#[derive(Clone, Default)]
pub struct MemoryKeyManagementClient {
master_keys: Arc<RwLock<HashMap<String, SensitiveBytes>>>,
master_key_size: AesKeySize,
}
impl fmt::Debug for MemoryKeyManagementClient {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("MemoryKeyManagementClient")
.field("master_key_size", &self.master_key_size)
.field("key_count", &self.key_count())
.finish()
}
}
impl MemoryKeyManagementClient {
pub fn new() -> Self {
Self::default()
}
pub fn with_master_key_size(master_key_size: AesKeySize) -> Self {
Self {
master_keys: Arc::new(RwLock::new(HashMap::new())),
master_key_size,
}
}
pub fn add_master_key(&self, key_id: impl Into<String>) -> Result<()> {
let key = SecureKey::generate(self.master_key_size);
self.insert_key(key_id.into(), SensitiveBytes::new(key.as_bytes()))
}
pub fn add_master_key_bytes(
&self,
key_id: impl Into<String>,
key_bytes: SensitiveBytes,
) -> Result<()> {
Self::check_key_length(&key_bytes)?;
self.insert_key(key_id.into(), key_bytes)
}
fn check_key_length(key_bytes: &SensitiveBytes) -> Result<()> {
SecureKey::new(key_bytes.as_bytes())?;
Ok(())
}
fn insert_key(&self, key_id: String, key: SensitiveBytes) -> Result<()> {
let mut keys = self.master_keys.write().map_err(lock_error)?;
if keys.contains_key(&key_id) {
return Err(Error::new(
ErrorKind::DataInvalid,
format!("Master key already exists: {key_id}"),
));
}
keys.insert(key_id, key);
Ok(())
}
fn get_master_key(&self, key_id: &str) -> Result<SensitiveBytes> {
let keys = self.master_keys.read().map_err(lock_error)?;
keys.get(key_id).cloned().ok_or_else(|| {
Error::new(
ErrorKind::DataInvalid,
format!("Master key not found: {key_id}"),
)
})
}
pub fn key_count(&self) -> usize {
self.master_keys.read().map(|keys| keys.len()).unwrap_or(0)
}
pub fn has_key(&self, key_id: &str) -> bool {
self.master_keys
.read()
.map(|keys| keys.contains_key(key_id))
.unwrap_or(false)
}
}
#[async_trait]
impl KeyManagementClient for MemoryKeyManagementClient {
async fn wrap_key(&self, key: &[u8], wrapping_key_id: &str) -> Result<Vec<u8>> {
let master_key_bytes = self.get_master_key(wrapping_key_id)?;
let master_key = SecureKey::new(master_key_bytes.as_bytes())?;
let cipher = AesGcmCipher::new(master_key);
cipher.encrypt(key, None)
}
async fn unwrap_key(
&self,
wrapped_key: &[u8],
wrapping_key_id: &str,
) -> Result<SensitiveBytes> {
let master_key_bytes = self.get_master_key(wrapping_key_id)?;
let master_key = SecureKey::new(master_key_bytes.as_bytes())?;
let cipher = AesGcmCipher::new(master_key);
Ok(SensitiveBytes::new(cipher.decrypt(wrapped_key, None)?))
}
fn supports_key_generation(&self) -> bool {
false
}
async fn generate_key(&self, _wrapping_key_id: &str) -> Result<super::GeneratedKey> {
Err(Error::new(
ErrorKind::FeatureUnsupported,
"MemoryKeyManagementClient does not support server-side key generation",
))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_wrap_unwrap_roundtrip() {
let kms = MemoryKeyManagementClient::new();
kms.add_master_key("master-1").unwrap();
let dek = vec![0u8; 16];
let wrapped = kms.wrap_key(&dek, "master-1").await.unwrap();
let unwrapped = kms.unwrap_key(&wrapped, "master-1").await.unwrap();
assert_eq!(unwrapped.as_bytes(), dek.as_slice());
}
#[tokio::test]
async fn test_wrap_unknown_key_fails() {
let kms = MemoryKeyManagementClient::new();
let dek = vec![0u8; 16];
let result = kms.wrap_key(&dek, "nonexistent").await;
assert!(result.is_err());
}
#[tokio::test]
async fn test_wrong_master_key_fails_unwrap() {
let kms = MemoryKeyManagementClient::new();
kms.add_master_key("master-1").unwrap();
kms.add_master_key("master-2").unwrap();
let dek = vec![0u8; 16];
let wrapped = kms.wrap_key(&dek, "master-1").await.unwrap();
let result = kms.unwrap_key(&wrapped, "master-2").await;
assert!(result.is_err());
}
#[tokio::test]
async fn test_does_not_support_key_generation() {
let kms = MemoryKeyManagementClient::new();
assert!(!kms.supports_key_generation());
let result = kms.generate_key("master-1").await;
assert!(result.is_err());
}
#[tokio::test]
async fn test_multiple_master_keys() {
let kms = MemoryKeyManagementClient::new();
kms.add_master_key("master-1").unwrap();
kms.add_master_key("master-2").unwrap();
let dek1 = vec![1u8; 16];
let dek2 = vec![2u8; 16];
let wrapped1 = kms.wrap_key(&dek1, "master-1").await.unwrap();
let wrapped2 = kms.wrap_key(&dek2, "master-2").await.unwrap();
let unwrapped1 = kms.unwrap_key(&wrapped1, "master-1").await.unwrap();
let unwrapped2 = kms.unwrap_key(&wrapped2, "master-2").await.unwrap();
assert_eq!(unwrapped1.as_bytes(), dek1.as_slice());
assert_eq!(unwrapped2.as_bytes(), dek2.as_slice());
}
#[tokio::test]
async fn test_add_master_key() {
let kms = MemoryKeyManagementClient::new();
kms.add_master_key("my-key").unwrap();
assert!(kms.has_key("my-key"));
assert_eq!(kms.key_count(), 1);
let result = kms.add_master_key("my-key");
assert!(result.is_err());
}
#[tokio::test]
async fn test_add_master_key_bytes() {
let kms = MemoryKeyManagementClient::new();
let key_bytes = SensitiveBytes::new([42u8; 16]);
kms.add_master_key_bytes("my-key", key_bytes).unwrap();
assert!(kms.has_key("my-key"));
let dek = vec![7u8; 16];
let wrapped = kms.wrap_key(&dek, "my-key").await.unwrap();
let unwrapped = kms.unwrap_key(&wrapped, "my-key").await.unwrap();
assert_eq!(unwrapped.as_bytes(), dek.as_slice());
}
#[tokio::test]
async fn test_add_master_key_bytes_invalid_length() {
let kms = MemoryKeyManagementClient::new();
let result = kms.add_master_key_bytes("my-key", SensitiveBytes::new([0u8; 7]));
assert!(result.is_err());
}
#[tokio::test]
async fn test_with_master_key_size() {
let kms = MemoryKeyManagementClient::with_master_key_size(AesKeySize::Bits256);
kms.add_master_key("master-256").unwrap();
let dek = vec![0u8; 16];
let wrapped = kms.wrap_key(&dek, "master-256").await.unwrap();
let unwrapped = kms.unwrap_key(&wrapped, "master-256").await.unwrap();
assert_eq!(unwrapped.as_bytes(), dek.as_slice());
}
#[tokio::test]
async fn test_clone_shares_state() {
let kms1 = MemoryKeyManagementClient::new();
let kms2 = kms1.clone();
kms1.add_master_key("shared-key").unwrap();
assert!(kms2.has_key("shared-key"));
}
}