use crate::crypto::aes_encryption::generate_wz_key;
pub struct WzKey {
iv: [u8; 4],
user_key: Option<[u8; 128]>,
keys: Vec<u8>,
}
impl WzKey {
pub fn new(iv: [u8; 4]) -> Self {
WzKey {
iv,
user_key: None,
keys: Vec::new(),
}
}
pub fn with_user_key(iv: [u8; 4], user_key: [u8; 128]) -> Self {
WzKey {
iv,
user_key: Some(user_key),
keys: Vec::new(),
}
}
pub fn ensure_size(&mut self, size: usize) {
if self.keys.len() < size {
self.keys = generate_wz_key(&self.iv, size, self.user_key.as_ref());
}
}
pub fn get(&mut self, index: usize) -> u8 {
self.ensure_size(index + 1);
self.keys[index]
}
pub fn get_slice(&mut self, start: usize, len: usize) -> &[u8] {
self.ensure_size(start + len);
&self.keys[start..start + len]
}
pub fn iv(&self) -> [u8; 4] {
self.iv
}
}
impl std::ops::Index<usize> for WzKey {
type Output = u8;
fn index(&self, index: usize) -> &Self::Output {
&self.keys[index]
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_ensure_size_generates_keys() {
let mut key = WzKey::new([0; 4]);
assert_eq!(key.keys.len(), 0);
key.ensure_size(256);
assert!(key.keys.len() >= 256);
}
#[test]
fn test_ensure_size_no_shrink() {
let mut key = WzKey::new([0; 4]);
key.ensure_size(512);
let len1 = key.keys.len();
key.ensure_size(100); assert_eq!(key.keys.len(), len1); }
#[test]
fn test_ensure_size_expands() {
let mut key = WzKey::new([0; 4]);
key.ensure_size(16);
let first = key.keys.clone();
key.ensure_size(1024);
assert!(key.keys.len() >= 1024);
assert_eq!(&key.keys[..16], &first[..16]);
}
#[test]
fn test_get_auto_expands() {
let mut key = WzKey::new([0; 4]);
let _byte = key.get(0);
assert!(!key.keys.is_empty());
}
#[test]
fn test_get_deterministic() {
let mut key1 = WzKey::new([0x4D, 0x23, 0xC7, 0x2B]);
let mut key2 = WzKey::new([0x4D, 0x23, 0xC7, 0x2B]);
for i in 0..32 {
assert_eq!(key1.get(i), key2.get(i), "mismatch at index {}", i);
}
}
#[test]
fn test_get_different_iv_different_keys() {
let mut gms = WzKey::new([0x4D, 0x23, 0xC7, 0x2B]);
let mut ems = WzKey::new([0xB9, 0x7D, 0x63, 0xE9]);
let differs = (0..32).any(|i| gms.get(i) != ems.get(i));
assert!(differs);
}
#[test]
fn test_get_slice_returns_correct_range() {
let mut key = WzKey::new([0x4D, 0x23, 0xC7, 0x2B]);
key.ensure_size(64);
let expected: Vec<u8> = key.keys[10..30].to_vec();
let slice = key.get_slice(10, 20);
assert_eq!(slice.len(), 20);
assert_eq!(slice, expected.as_slice());
}
#[test]
fn test_get_slice_auto_expands() {
let mut key = WzKey::new([0; 4]);
let slice = key.get_slice(0, 100);
assert_eq!(slice.len(), 100);
assert!(key.keys.len() >= 100);
}
#[test]
fn test_get_slice_at_offset() {
let mut key = WzKey::new([0x4D, 0x23, 0xC7, 0x2B]);
let snapshot: Vec<u8> = key.get_slice(50, 10).to_vec();
assert_eq!(snapshot.len(), 10);
for (i, &b) in snapshot.iter().enumerate() {
assert_eq!(b, key.get(50 + i));
}
}
#[test]
fn test_get_slice_empty() {
let mut key = WzKey::new([0; 4]);
let slice = key.get_slice(0, 0);
assert!(slice.is_empty());
}
#[test]
fn test_index_after_ensure_size() {
let mut key = WzKey::new([0x4D, 0x23, 0xC7, 0x2B]);
key.ensure_size(16);
let byte = key[0];
let byte15 = key[15];
assert_eq!(byte, key.get(0));
assert_eq!(byte15, key.get(15));
}
#[test]
#[should_panic]
fn test_index_panics_without_ensure() {
let key = WzKey::new([0; 4]);
let _ = key[0];
}
#[test]
fn test_zero_iv_produces_consistent_keys() {
let mut key1 = WzKey::new([0; 4]);
let mut key2 = WzKey::new([0; 4]);
let slice1 = key1.get_slice(0, 64);
let slice2 = key2.get_slice(0, 64);
assert_eq!(slice1, slice2);
}
}