use super::md5::md5_hex;
pub const KEY_LENGTH: usize = 32;
pub fn prepare_key(password: &str, hash: Option<&str>, re_encryption_count: u32) -> [u8; KEY_LENGTH] {
let key_string = if let Some(h) = hash {
if !h.is_empty() && re_encryption_count > 0 {
h.to_string()
} else {
derive_key_from_password(password, re_encryption_count)
}
} else {
derive_key_from_password(password, re_encryption_count)
};
let key_bytes = key_string.as_bytes();
let mut key = [0u8; KEY_LENGTH];
let copy_len = std::cmp::min(key_bytes.len(), KEY_LENGTH);
key[..copy_len].copy_from_slice(&key_bytes[..copy_len]);
key
}
fn derive_key_from_password(password: &str, re_encryption_count: u32) -> String {
let mut padded = password.to_string();
while padded.chars().count() < KEY_LENGTH {
padded.push_str(password);
}
let truncated: String = padded.chars().take(KEY_LENGTH).collect();
if re_encryption_count > 0 {
apply_md5_iterations(&truncated, re_encryption_count)
} else {
truncated
}
}
fn apply_md5_iterations(input: &str, count: u32) -> String {
let mut result = input.to_string();
for _ in 0..count {
result = md5_hex(&result);
}
result
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_key_short_password() {
let key = prepare_key("Sun001!", None, 0);
let expected = b"Sun001!Sun001!Sun001!Sun001!Sun0";
assert_eq!(&key[..], &expected[..]);
}
#[test]
fn test_key_exact_32_chars() {
let password = "12345678901234567890123456789012"; let key = prepare_key(password, None, 0);
assert_eq!(&key[..], password.as_bytes());
}
#[test]
fn test_key_longer_than_32() {
let password = "1234567890123456789012345678901234567890"; let key = prepare_key(password, None, 0);
let expected = b"12345678901234567890123456789012";
assert_eq!(&key[..], &expected[..]);
}
#[test]
fn test_key_with_hash() {
let hash = "12345678901234567890123456789012";
let key = prepare_key("ignored", Some(hash), 1);
assert_eq!(&key[..], hash.as_bytes());
}
#[test]
fn test_key_with_empty_hash() {
let key = prepare_key("Sun001!", Some(""), 0);
let expected = b"Sun001!Sun001!Sun001!Sun001!Sun0";
assert_eq!(&key[..], &expected[..]);
}
#[test]
fn test_key_with_reencryption() {
let key = prepare_key("test", None, 1);
let padded: String = "test".repeat(8);
let expected_hash = super::md5_hex(&padded);
assert_eq!(&key[..], expected_hash.as_bytes());
}
}