use super::aes::aes128_ecb_encrypt_block;
fn password_to_a32_bytes(password: &str) -> (Vec<u8>, usize) {
let code_units: Vec<u16> = password.encode_utf16().collect();
let len_units = code_units.len();
let mut bytes = Vec::with_capacity(len_units * 2);
for cu in &code_units {
if *cu <= 0x00FF {
bytes.push(*cu as u8);
} else {
let be = cu.to_be_bytes();
bytes.extend_from_slice(&be);
}
}
while bytes.len() % 4 != 0 {
bytes.push(0);
}
(bytes, len_units)
}
pub fn make_password_key(password: &str) -> [u8; 16] {
let (password_bytes, len_units) = password_to_a32_bytes(password);
let mut pkey: [u8; 16] = [
0x93, 0xC4, 0x67, 0xE3, 0x7D, 0xB0, 0xC7, 0xA4, 0xD1, 0xBE, 0x3F, 0x81, 0x01, 0x52, 0xCB,
0x56,
];
if len_units == 0 {
return pkey;
}
let total_len = password_bytes.len();
for _ in 0..65536 {
let mut i = 0;
while i < total_len {
let mut key = [0u8; 16];
let chunk_len = std::cmp::min(16, total_len - i);
key[..chunk_len].copy_from_slice(&password_bytes[i..i + chunk_len]);
pkey = aes128_ecb_encrypt_block(&pkey, &key);
i += 16;
}
}
pkey
}
pub fn make_username_hash(username: &str, key: &[u8; 16]) -> [u8; 8] {
let username_bytes = username.as_bytes();
let mut hash = [0u8; 16];
for (i, &byte) in username_bytes.iter().enumerate() {
hash[i % 16] ^= byte;
}
for _ in 0..16384 {
hash = aes128_ecb_encrypt_block(&hash, key);
}
let mut result = [0u8; 8];
result[..4].copy_from_slice(&hash[..4]);
result[4..].copy_from_slice(&hash[8..12]);
result
}
pub fn pack_node_key(file_key: &[u8; 16], nonce: &[u8; 8], meta_mac: &[u8; 16]) -> [u8; 32] {
let mut node_key = [0u8; 32];
for i in 0..4 {
node_key[i] = file_key[i] ^ nonce[i];
node_key[4 + i] = file_key[4 + i] ^ nonce[4 + i];
node_key[8 + i] = file_key[8 + i] ^ meta_mac[i] ^ meta_mac[4 + i];
node_key[12 + i] = file_key[12 + i] ^ meta_mac[8 + i] ^ meta_mac[12 + i];
node_key[16 + i] = nonce[i];
node_key[20 + i] = nonce[4 + i];
node_key[24 + i] = meta_mac[i] ^ meta_mac[4 + i];
node_key[28 + i] = meta_mac[8 + i] ^ meta_mac[12 + i];
}
node_key
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_password_key_deterministic() {
let key1 = make_password_key("testpassword");
let key2 = make_password_key("testpassword");
assert_eq!(key1, key2);
}
#[test]
fn test_password_key_different_passwords() {
let key1 = make_password_key("password1");
let key2 = make_password_key("password2");
assert_ne!(key1, key2);
}
#[test]
fn test_password_to_a32_ascii() {
let (bytes, len_units) = password_to_a32_bytes("test");
assert_eq!(len_units, 4);
assert_eq!(bytes, vec![0x74, 0x65, 0x73, 0x74]);
}
#[test]
fn test_password_to_a32_surrogate_pair() {
let (bytes, len_units) = password_to_a32_bytes("😀");
assert_eq!(len_units, 2);
assert_eq!(bytes, vec![0xD8, 0x3D, 0xDE, 0x00]);
}
#[test]
fn test_username_hash_deterministic() {
let password_key = make_password_key("testpassword");
let hash1 = make_username_hash("test@example.com", &password_key);
let hash2 = make_username_hash("test@example.com", &password_key);
assert_eq!(hash1, hash2);
}
#[test]
fn test_username_hash_different_usernames() {
let password_key = make_password_key("testpassword");
let hash1 = make_username_hash("user1@example.com", &password_key);
let hash2 = make_username_hash("user2@example.com", &password_key);
assert_ne!(hash1, hash2);
}
#[test]
fn test_empty_password() {
let key = make_password_key("");
let expected: [u8; 16] = [
0x93, 0xC4, 0x67, 0xE3, 0x7D, 0xB0, 0xC7, 0xA4, 0xD1, 0xBE, 0x3F, 0x81, 0x01, 0x52,
0xCB, 0x56,
];
assert_eq!(key, expected);
}
}