use super::key::SecureKey;
use super::page_encryptor::{PageEncryptor, NONCE_SIZE, TAG_SIZE};
use crate::crypto::uuid::Uuid;
pub const SALT_SIZE: usize = 32;
pub const KEY_CHECK_LEN: usize = 32;
#[derive(Debug, Clone)]
pub struct EncryptionHeader {
pub salt: [u8; SALT_SIZE],
pub key_check: Vec<u8>,
}
impl EncryptionHeader {
pub fn new(key: &SecureKey) -> Self {
let uuid = Uuid::new_v4();
let mut salt = [0u8; SALT_SIZE];
let b = uuid.as_bytes();
salt[0..16].copy_from_slice(b);
let uuid2 = Uuid::new_v4();
salt[16..32].copy_from_slice(uuid2.as_bytes());
let known_value = [0xAAu8; KEY_CHECK_LEN];
let encryptor = PageEncryptor::new(key.clone());
let check_blob = encryptor.encrypt(u32::MAX, &known_value);
Self {
salt,
key_check: check_blob,
}
}
pub fn validate(&self, key: &SecureKey) -> bool {
let encryptor = PageEncryptor::new(key.clone());
match encryptor.decrypt(u32::MAX, &self.key_check) {
Ok(plaintext) => {
let expected = [0xAAu8; KEY_CHECK_LEN];
plaintext == expected
}
Err(_) => false,
}
}
pub fn to_bytes(&self) -> Vec<u8> {
let mut buf = Vec::new();
buf.extend_from_slice(&self.salt);
buf.extend_from_slice(&self.key_check);
buf
}
pub fn from_bytes(data: &[u8]) -> Result<Self, String> {
let check_size = NONCE_SIZE + KEY_CHECK_LEN + TAG_SIZE;
let expected_len = SALT_SIZE + check_size;
if data.len() < expected_len {
return Err("Data too short for EncryptionHeader".to_string());
}
let mut salt = [0u8; SALT_SIZE];
salt.copy_from_slice(&data[0..SALT_SIZE]);
let key_check = data[SALT_SIZE..SALT_SIZE + check_size].to_vec();
Ok(Self { salt, key_check })
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_header_validation() {
let key = SecureKey::new(&[0x11u8; 32]);
let header = EncryptionHeader::new(&key);
assert!(header.validate(&key));
let wrong_key = SecureKey::new(&[0x22u8; 32]);
assert!(!header.validate(&wrong_key));
}
#[test]
fn test_header_serialization() {
let key = SecureKey::new(&[0x33u8; 32]);
let header = EncryptionHeader::new(&key);
let bytes = header.to_bytes();
let loaded = EncryptionHeader::from_bytes(&bytes).unwrap();
assert_eq!(header.salt, loaded.salt);
assert_eq!(header.key_check, loaded.key_check);
assert!(loaded.validate(&key));
}
}