use crate::archive::ArchiveReader;
use crate::crypto::encryption::decrypt_aes256gcm;
use crate::crypto::keys::KeyManager;
use crate::error::{Lib3mfError, Result};
use crate::model::secure_content::*;
use uuid::Uuid;
use rsa::RsaPrivateKey;
use std::collections::HashMap;
pub struct SecureContext {
keystore: KeyStore,
private_key: RsaPrivateKey,
cek_cache: HashMap<String, Vec<u8>>,
resource_key_map: HashMap<String, Uuid>,
consumer_id: String,
}
impl SecureContext {
pub fn new(
keystore: KeyStore,
private_key: RsaPrivateKey,
resource_key_map: HashMap<String, Uuid>,
consumer_id: String,
) -> Self {
Self {
keystore,
private_key,
cek_cache: HashMap::new(),
resource_key_map,
consumer_id,
}
}
pub fn decrypt_entry(
&mut self,
archiver: &mut impl ArchiveReader,
path: &str,
) -> Result<Option<Vec<u8>>> {
let key_uuid = match self.resource_key_map.get(path) {
Some(u) => u,
None => return Ok(None), };
let group = self
.keystore
.resource_data_groups
.iter()
.find(|g| g.key_uuid == *key_uuid)
.ok_or_else(|| {
Lib3mfError::Validation(format!("KeyUUID {} not found in KeyStore", key_uuid))
})?;
let cek = if let Some(cached) = self.cek_cache.get(&key_uuid.to_string()) {
cached.clone()
} else {
let right = group
.access_rights
.iter()
.find(|ar| ar.consumer_id == self.consumer_id)
.ok_or_else(|| {
Lib3mfError::Validation(format!(
"No access right for consumer {} in group {}",
self.consumer_id, key_uuid
))
})?;
let cek = KeyManager::unwrap_key(&self.private_key, &right.wrapped_key)?;
self.cek_cache.insert(key_uuid.to_string(), cek.clone());
cek
};
let encrypted_data = archiver.read_entry(path)?;
if encrypted_data.len() < 12 + 16 {
return Err(Lib3mfError::Validation(
"Encrypted file too short".to_string(),
));
}
let (nonce, ciphertext) = encrypted_data.split_at(12);
let plaintext = decrypt_aes256gcm(&cek, nonce, ciphertext)?;
Ok(Some(plaintext))
}
}