use super::aes;
use super::algorithms;
use super::rc4;
use super::Algorithm;
use md5::{Digest, Md5};
pub struct EncryptionWriteHandler {
encryption_key: Vec<u8>,
algorithm: Algorithm,
encrypt_metadata: bool,
}
impl EncryptionWriteHandler {
pub fn new(
user_password: &[u8],
owner_hash: &[u8],
permissions: i32,
file_id: &[u8],
algorithm: Algorithm,
encrypt_metadata: bool,
) -> Self {
let (_, revision) = Self::get_version_revision(algorithm);
let key_length = algorithm.key_length();
let encryption_key = algorithms::compute_encryption_key(
user_password,
owner_hash,
permissions,
file_id,
revision,
key_length,
encrypt_metadata,
);
Self {
encryption_key,
algorithm,
encrypt_metadata,
}
}
pub fn from_key(encryption_key: Vec<u8>, algorithm: Algorithm, encrypt_metadata: bool) -> Self {
Self {
encryption_key,
algorithm,
encrypt_metadata,
}
}
fn get_version_revision(algorithm: Algorithm) -> (u32, u32) {
match algorithm {
Algorithm::None => (0, 0),
Algorithm::RC4_40 => (1, 2),
Algorithm::Rc4_128 => (2, 3),
Algorithm::Aes128 => (4, 4),
Algorithm::Aes256 => (5, 6),
}
}
fn derive_object_key(&self, obj_num: u32, gen_num: u16) -> Vec<u8> {
let (_, revision) = Self::get_version_revision(self.algorithm);
if revision >= 5 {
return self.encryption_key.clone();
}
let mut hasher = Md5::new();
hasher.update(&self.encryption_key);
hasher.update(&obj_num.to_le_bytes()[..3]);
hasher.update(gen_num.to_le_bytes());
if self.algorithm.is_aes() {
hasher.update(b"sAlT");
}
let hash = hasher.finalize();
let key_length = (self.encryption_key.len() + 5).min(16);
hash[..key_length].to_vec()
}
pub fn encrypt_string(&self, data: &[u8], obj_num: u32, gen_num: u16) -> Vec<u8> {
if self.algorithm == Algorithm::None {
return data.to_vec();
}
let key = self.derive_object_key(obj_num, gen_num);
self.encrypt_with_key(&key, data)
}
pub fn encrypt_stream(&self, data: &[u8], obj_num: u32, gen_num: u16) -> Vec<u8> {
if self.algorithm == Algorithm::None {
return data.to_vec();
}
let key = self.derive_object_key(obj_num, gen_num);
self.encrypt_with_key(&key, data)
}
fn encrypt_with_key(&self, key: &[u8], data: &[u8]) -> Vec<u8> {
match self.algorithm {
Algorithm::None => data.to_vec(),
Algorithm::RC4_40 | Algorithm::Rc4_128 => rc4::rc4_crypt(key, data),
Algorithm::Aes128 => {
let iv = Self::generate_iv();
match aes::aes128_encrypt(key, &iv, data) {
Ok(ciphertext) => {
let mut result = iv.to_vec();
result.extend(ciphertext);
result
},
Err(_) => data.to_vec(), }
},
Algorithm::Aes256 => {
let iv = Self::generate_iv();
match aes::aes256_encrypt(key, &iv, data) {
Ok(ciphertext) => {
let mut result = iv.to_vec();
result.extend(ciphertext);
result
},
Err(_) => data.to_vec(), }
},
}
}
fn generate_iv() -> [u8; 16] {
use md5::{Digest, Md5};
let uuid = uuid::Uuid::new_v4();
let uuid_bytes = uuid.as_bytes();
let mut hasher = Md5::new();
hasher.update(uuid_bytes);
let now = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default();
hasher.update(now.as_nanos().to_le_bytes());
let hash = hasher.finalize();
let mut iv = [0u8; 16];
iv.copy_from_slice(&hash);
iv
}
pub fn algorithm(&self) -> Algorithm {
self.algorithm
}
pub fn encrypt_metadata(&self) -> bool {
self.encrypt_metadata
}
#[cfg(test)]
pub fn encryption_key(&self) -> &[u8] {
&self.encryption_key
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_object_key_derivation_rc4() {
let key = vec![0x01, 0x02, 0x03, 0x04, 0x05]; let handler = EncryptionWriteHandler::from_key(key, Algorithm::RC4_40, true);
let obj_key1 = handler.derive_object_key(1, 0);
let obj_key2 = handler.derive_object_key(2, 0);
let obj_key3 = handler.derive_object_key(1, 1);
assert_ne!(obj_key1, obj_key2);
assert_ne!(obj_key1, obj_key3);
assert_eq!(obj_key1.len(), 10); }
#[test]
fn test_object_key_derivation_aes128() {
let key = vec![0u8; 16]; let handler = EncryptionWriteHandler::from_key(key, Algorithm::Aes128, true);
let obj_key1 = handler.derive_object_key(1, 0);
let obj_key2 = handler.derive_object_key(2, 0);
assert_ne!(obj_key1, obj_key2);
assert_eq!(obj_key1.len(), 16);
}
#[test]
fn test_object_key_derivation_aes256() {
let key = vec![0u8; 32]; let handler = EncryptionWriteHandler::from_key(key.clone(), Algorithm::Aes256, true);
let obj_key = handler.derive_object_key(1, 0);
assert_eq!(obj_key, key);
}
#[test]
fn test_rc4_encryption_roundtrip() {
let key = vec![0x01, 0x02, 0x03, 0x04, 0x05];
let handler = EncryptionWriteHandler::from_key(key, Algorithm::RC4_40, true);
let plaintext = b"Hello, encrypted world!";
let ciphertext = handler.encrypt_string(plaintext, 1, 0);
let obj_key = handler.derive_object_key(1, 0);
let decrypted = rc4::rc4_crypt(&obj_key, &ciphertext);
assert_eq!(&decrypted, plaintext);
}
#[test]
fn test_aes_encryption() {
let key = vec![0u8; 16];
let handler = EncryptionWriteHandler::from_key(key, Algorithm::Aes128, true);
let plaintext = b"Hello, AES encrypted world!";
let ciphertext = handler.encrypt_stream(plaintext, 1, 0);
assert!(ciphertext.len() >= 16);
let iv = &ciphertext[..16];
let encrypted = &ciphertext[16..];
let obj_key = handler.derive_object_key(1, 0);
let decrypted = aes::aes128_decrypt(&obj_key, iv, encrypted).unwrap();
assert_eq!(&decrypted, plaintext);
}
}