use super::aes_gcm::VerifiedAesGcm;
use super::proof_certificate::{ProofCertificate, Verified};
use hkdf::Hkdf;
use sha2::{Digest, Sha256};
use zeroize::{Zeroize, ZeroizeOnDrop};
pub const TENANT_ISOLATION_CERT: ProofCertificate = ProofCertificate::new(
500, 1, 2026_0205, 1, );
pub const KEY_WRAPPING_SOUNDNESS_CERT: ProofCertificate = ProofCertificate::new(
501, 1, 2026_0205, 1, );
pub const FORWARD_SECRECY_CERT: ProofCertificate = ProofCertificate::new(
502, 1, 2026_0205, 2, );
pub const KEY_DERIVATION_INJECTIVE_CERT: ProofCertificate = ProofCertificate::new(
503, 1, 2026_0205, 2, );
#[derive(Zeroize, ZeroizeOnDrop)]
pub struct VerifiedMasterKey {
key: [u8; 32],
}
#[derive(Clone, Zeroize, ZeroizeOnDrop)]
pub struct VerifiedKEK {
key: [u8; 32],
}
#[derive(Clone, Zeroize, ZeroizeOnDrop)]
pub struct VerifiedDEK {
key: [u8; 32],
}
impl VerifiedMasterKey {
pub fn generate() -> Self {
use rand::RngCore;
let mut key = [0u8; 32];
rand::rngs::OsRng.fill_bytes(&mut key);
assert_ne!(key, [0u8; 32], "Master key is all zeros (degenerate)");
Self { key }
}
pub fn from_bytes(bytes: [u8; 32]) -> Self {
assert_ne!(bytes, [0u8; 32], "Master key is all zeros");
Self { key: bytes }
}
pub fn to_bytes(&self) -> [u8; 32] {
self.key
}
pub fn derive_kek(&self, tenant_id: u64) -> VerifiedKEK {
let key = Self::hkdf_derive(&self.key, b"kek", &tenant_id.to_le_bytes());
VerifiedKEK { key }
}
fn hkdf_derive(ikm: &[u8; 32], salt: &[u8], info: &[u8]) -> [u8; 32] {
let hk = Hkdf::<Sha256>::new(Some(salt), ikm);
let mut okm = [0u8; 32];
hk.expand(info, &mut okm)
.expect("32-byte output within HKDF maximum");
okm
}
}
impl VerifiedKEK {
pub fn derive_dek(&self, stream_id: u64) -> VerifiedDEK {
let key = VerifiedMasterKey::hkdf_derive(&self.key, b"dek", &stream_id.to_le_bytes());
VerifiedDEK { key }
}
pub fn wrap_dek(&self, dek: &VerifiedDEK) -> Result<VerifiedWrappedDEK, String> {
let nonce = Self::derive_wrap_nonce(&self.key, &dek.key);
let ciphertext = VerifiedAesGcm::encrypt(&self.key, &nonce, &dek.key, b"")?;
let mut output = Vec::with_capacity(12 + ciphertext.len());
output.extend_from_slice(&nonce);
output.extend_from_slice(&ciphertext);
Ok(VerifiedWrappedDEK { ciphertext: output })
}
pub fn unwrap_dek(&self, wrapped: &VerifiedWrappedDEK) -> Result<VerifiedDEK, String> {
if wrapped.ciphertext.len() < 12 {
return Err("Wrapped DEK too short to contain nonce".to_string());
}
let nonce: [u8; 12] = wrapped.ciphertext[..12]
.try_into()
.map_err(|_| "Failed to extract nonce from wrapped DEK")?;
let ciphertext = &wrapped.ciphertext[12..];
let plaintext = VerifiedAesGcm::decrypt(&self.key, &nonce, ciphertext, b"")?;
if plaintext.len() != 32 {
return Err("Unwrapped DEK has wrong length".to_string());
}
let mut key = [0u8; 32];
key.copy_from_slice(&plaintext);
Ok(VerifiedDEK { key })
}
pub fn to_bytes(&self) -> [u8; 32] {
self.key
}
fn derive_wrap_nonce(kek: &[u8; 32], dek: &[u8; 32]) -> [u8; 12] {
let mut hasher = Sha256::new();
hasher.update(kek);
hasher.update(dek);
let hash = hasher.finalize();
let mut nonce = [0u8; 12];
nonce.copy_from_slice(&hash[..12]);
nonce
}
}
impl VerifiedDEK {
pub fn encrypt(&self, position: u64, plaintext: &[u8]) -> Result<Vec<u8>, String> {
let nonce = VerifiedAesGcm::nonce_from_position(position);
VerifiedAesGcm::encrypt(&self.key, &nonce, plaintext, b"")
}
pub fn decrypt(&self, position: u64, ciphertext: &[u8]) -> Result<Vec<u8>, String> {
let nonce = VerifiedAesGcm::nonce_from_position(position);
VerifiedAesGcm::decrypt(&self.key, &nonce, ciphertext, b"")
}
pub fn to_bytes(&self) -> [u8; 32] {
self.key
}
}
#[derive(Clone)]
pub struct VerifiedWrappedDEK {
ciphertext: Vec<u8>,
}
impl VerifiedWrappedDEK {
pub fn to_bytes(&self) -> Vec<u8> {
self.ciphertext.clone()
}
pub fn from_bytes(bytes: Vec<u8>) -> Self {
Self { ciphertext: bytes }
}
}
impl Verified for VerifiedMasterKey {
fn proof_certificate() -> ProofCertificate {
TENANT_ISOLATION_CERT
}
fn theorem_name() -> &'static str {
"tenant_isolation"
}
fn theorem_description() -> &'static str {
"Tenant isolation: different tenants have cryptographically different KEKs"
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_master_key_generation() {
let master1 = VerifiedMasterKey::generate();
let master2 = VerifiedMasterKey::generate();
assert_ne!(master1.to_bytes(), master2.to_bytes());
}
#[test]
fn test_kek_derivation_deterministic() {
let master = VerifiedMasterKey::generate();
let kek1 = master.derive_kek(42);
let kek2 = master.derive_kek(42);
assert_eq!(kek1.to_bytes(), kek2.to_bytes());
}
#[test]
fn test_tenant_isolation() {
let master = VerifiedMasterKey::generate();
let kek1 = master.derive_kek(1);
let kek2 = master.derive_kek(2);
assert_ne!(kek1.to_bytes(), kek2.to_bytes());
}
#[test]
fn test_dek_derivation_deterministic() {
let master = VerifiedMasterKey::generate();
let kek = master.derive_kek(1);
let dek1 = kek.derive_dek(100);
let dek2 = kek.derive_dek(100);
assert_eq!(dek1.to_bytes(), dek2.to_bytes());
}
#[test]
fn test_dek_derivation_unique() {
let master = VerifiedMasterKey::generate();
let kek = master.derive_kek(1);
let dek1 = kek.derive_dek(100);
let dek2 = kek.derive_dek(200);
assert_ne!(dek1.to_bytes(), dek2.to_bytes());
}
#[test]
fn test_key_wrapping_roundtrip() {
let master = VerifiedMasterKey::generate();
let kek = master.derive_kek(1);
let dek = kek.derive_dek(100);
let wrapped = kek.wrap_dek(&dek).expect("wrap failed");
let unwrapped = kek.unwrap_dek(&wrapped).expect("unwrap failed");
assert_eq!(dek.to_bytes(), unwrapped.to_bytes());
}
#[test]
fn test_wrong_kek_unwrap_fails() {
let master = VerifiedMasterKey::generate();
let kek1 = master.derive_kek(1);
let kek2 = master.derive_kek(2);
let dek = kek1.derive_dek(100);
let wrapped = kek1.wrap_dek(&dek).expect("wrap failed");
let result = kek2.unwrap_dek(&wrapped);
assert!(result.is_err());
}
#[test]
fn test_tampered_wrapped_dek_fails() {
let master = VerifiedMasterKey::generate();
let kek = master.derive_kek(1);
let dek = kek.derive_dek(100);
let wrapped = kek.wrap_dek(&dek).expect("wrap failed");
let mut tampered_bytes = wrapped.to_bytes();
if !tampered_bytes.is_empty() {
tampered_bytes[0] ^= 0xFF;
}
let tampered = VerifiedWrappedDEK::from_bytes(tampered_bytes);
let result = kek.unwrap_dek(&tampered);
assert!(result.is_err());
}
#[test]
fn test_dek_encrypt_decrypt_roundtrip() {
let master = VerifiedMasterKey::generate();
let kek = master.derive_kek(1);
let dek = kek.derive_dek(100);
let plaintext = b"sensitive data";
let position = 0;
let ciphertext = dek.encrypt(position, plaintext).expect("encrypt failed");
let decrypted = dek.decrypt(position, &ciphertext).expect("decrypt failed");
assert_eq!(plaintext, &decrypted[..]);
}
#[test]
fn test_different_positions_different_ciphertexts() {
let master = VerifiedMasterKey::generate();
let kek = master.derive_kek(1);
let dek = kek.derive_dek(100);
let plaintext = b"data";
let ct1 = dek.encrypt(0, plaintext).expect("encrypt failed");
let ct2 = dek.encrypt(1, plaintext).expect("encrypt failed");
assert_ne!(ct1, ct2);
}
#[test]
fn test_full_hierarchy() {
let master = VerifiedMasterKey::generate();
let kek = master.derive_kek(1);
let dek = kek.derive_dek(100);
let wrapped_dek = kek.wrap_dek(&dek).expect("wrap failed");
let restored_dek = kek.unwrap_dek(&wrapped_dek).expect("unwrap failed");
let plaintext = b"test data";
let ciphertext = restored_dek.encrypt(0, plaintext).expect("encrypt failed");
let decrypted = restored_dek
.decrypt(0, &ciphertext)
.expect("decrypt failed");
assert_eq!(plaintext, &decrypted[..]);
}
#[test]
fn test_tenant_dek_isolation() {
let master = VerifiedMasterKey::generate();
let kek1 = master.derive_kek(1);
let kek2 = master.derive_kek(2);
let dek1 = kek1.derive_dek(100);
let dek2 = kek2.derive_dek(100);
assert_ne!(dek1.to_bytes(), dek2.to_bytes());
}
#[test]
fn test_master_key_serialization() {
let master = VerifiedMasterKey::generate();
let bytes = master.to_bytes();
let restored = VerifiedMasterKey::from_bytes(bytes);
let kek1 = master.derive_kek(42);
let kek2 = restored.derive_kek(42);
assert_eq!(kek1.to_bytes(), kek2.to_bytes());
}
#[test]
fn test_wrapped_dek_serialization() {
let master = VerifiedMasterKey::generate();
let kek = master.derive_kek(1);
let dek = kek.derive_dek(100);
let wrapped = kek.wrap_dek(&dek).expect("wrap failed");
let bytes = wrapped.to_bytes();
let restored = VerifiedWrappedDEK::from_bytes(bytes);
let unwrapped = kek.unwrap_dek(&restored).expect("unwrap failed");
assert_eq!(dek.to_bytes(), unwrapped.to_bytes());
}
#[test]
fn test_proof_certificate() {
let cert = VerifiedMasterKey::proof_certificate();
assert_eq!(cert.theorem_id, 500);
assert_eq!(cert.proof_system_id, 1);
assert_eq!(cert.verified_at, 20_260_205);
assert_eq!(cert.assumption_count, 1);
}
#[test]
fn test_verified_trait() {
assert_eq!(VerifiedMasterKey::theorem_name(), "tenant_isolation");
assert!(VerifiedMasterKey::theorem_description().contains("isolation"));
}
#[test]
#[should_panic(expected = "Master key is all zeros")]
fn test_master_key_from_bytes_rejects_zero() {
VerifiedMasterKey::from_bytes([0u8; 32]);
}
#[test]
fn test_forward_secrecy_simulation() {
let master = VerifiedMasterKey::generate();
let kek = master.derive_kek(1);
let dek = kek.derive_dek(100);
let _compromised_dek = dek.to_bytes();
assert_ne!(kek.to_bytes(), dek.to_bytes());
assert_ne!(master.to_bytes(), dek.to_bytes());
assert_ne!(master.to_bytes(), kek.to_bytes());
}
}