use super::key::SecureKey;
use super::page_encryptor::PageEncryptor;
use crate::crypto::uuid::Uuid;
pub use reddb_file::{
PAGED_ENCRYPTION_KEY_CHECK_PLAINTEXT_SIZE as KEY_CHECK_LEN,
PAGED_ENCRYPTION_SALT_SIZE as SALT_SIZE,
};
#[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> {
reddb_file::encode_paged_encryption_header(&reddb_file::PagedEncryptionHeader {
salt: self.salt,
key_check: self.key_check.clone(),
})
}
pub fn from_bytes(data: &[u8]) -> Result<Self, String> {
let raw = reddb_file::decode_paged_encryption_header(data)
.map_err(|err| format!("Data too short for EncryptionHeader: {err}"))?;
Ok(Self {
salt: raw.salt,
key_check: raw.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));
}
}