use generic_array::typenum::U32;
use rc4::{KeyInit, Rc4, StreamCipher};
use tracing::{debug, trace};
use crate::{CryptoError, Result};
pub fn decrypt_arc4(data: &[u8], key: &[u8; 16], iv: &[u8], block_index: usize) -> Result<Vec<u8>> {
if iv.len() != 4 {
return Err(CryptoError::InvalidParameter(format!(
"IV must be 4 bytes, got {}",
iv.len()
)));
}
trace!(
"ARC4 decrypt: {} bytes, block_index={}",
data.len(),
block_index
);
let mut arc4_key = Vec::with_capacity(32);
arc4_key.extend_from_slice(key);
arc4_key.extend_from_slice(iv);
arc4_key.extend_from_slice(&(block_index as u32).to_le_bytes());
while arc4_key.len() < 32 {
arc4_key.push(0);
}
debug!(
"ARC4 key construction: base_key(16) + iv(4) + block_index(4) + padding({}) = {} bytes",
32 - 24,
arc4_key.len()
);
let mut cipher: Rc4<U32> = Rc4::new_from_slice(&arc4_key).map_err(|_| {
CryptoError::InitializationFailed("Failed to create RC4 cipher".to_string())
})?;
let mut decrypted = data.to_vec();
cipher.apply_keystream(&mut decrypted);
debug!(
"ARC4 decrypted {} bytes -> {} bytes",
data.len(),
decrypted.len()
);
Ok(decrypted)
}
pub fn encrypt_arc4(data: &[u8], key: &[u8; 16], iv: &[u8], block_index: usize) -> Result<Vec<u8>> {
decrypt_arc4(data, key, iv, block_index)
}
#[cfg(test)]
#[allow(deprecated)]
mod tests {
use super::*;
#[test]
#[allow(deprecated)]
fn test_arc4_roundtrip() {
let key = [0x01u8; 16];
let iv = [0x02, 0x03, 0x04, 0x05];
let block_index = 0;
let plaintext = b"Hello, BLTE ARC4 world!";
let encrypted = encrypt_arc4(plaintext, &key, &iv, block_index).unwrap();
assert_ne!(encrypted, plaintext);
let decrypted = decrypt_arc4(&encrypted, &key, &iv, block_index).unwrap();
assert_eq!(decrypted, plaintext);
}
#[test]
#[allow(deprecated)]
fn test_arc4_block_index_affects_output() {
let key = [0x01u8; 16];
let iv = [0x02, 0x03, 0x04, 0x05];
let plaintext = b"Test data for block index variation";
let encrypted_0 = encrypt_arc4(plaintext, &key, &iv, 0).unwrap();
let encrypted_1 = encrypt_arc4(plaintext, &key, &iv, 1).unwrap();
assert_ne!(encrypted_0, encrypted_1);
let decrypted_0 = decrypt_arc4(&encrypted_0, &key, &iv, 0).unwrap();
let decrypted_1 = decrypt_arc4(&encrypted_1, &key, &iv, 1).unwrap();
assert_eq!(decrypted_0, plaintext);
assert_eq!(decrypted_1, plaintext);
}
#[test]
#[allow(deprecated)]
fn test_arc4_different_keys_produce_different_output() {
let key1 = [0x01u8; 16];
let key2 = [0x02u8; 16];
let iv = [0x03, 0x04, 0x05, 0x06];
let block_index = 0;
let plaintext = b"Sensitive data";
let encrypted1 = encrypt_arc4(plaintext, &key1, &iv, block_index).unwrap();
let encrypted2 = encrypt_arc4(plaintext, &key2, &iv, block_index).unwrap();
assert_ne!(encrypted1, encrypted2);
}
#[test]
#[allow(deprecated)]
fn test_arc4_invalid_iv_size() {
let key = [0x01u8; 16];
let invalid_iv = [0x02, 0x03]; let block_index = 0;
let data = b"test";
let result = decrypt_arc4(data, &key, &invalid_iv, block_index);
assert!(result.is_err());
}
#[test]
#[allow(deprecated)]
fn test_arc4_key_construction() {
let key = [0xAAu8; 16];
let iv = [0xBB, 0xCC, 0xDD, 0xEE];
let block_index = 0x12345678;
let plaintext = b"test data";
let encrypted1 = encrypt_arc4(plaintext, &key, &iv, block_index).unwrap();
let encrypted2 = encrypt_arc4(plaintext, &key, &iv, block_index).unwrap();
assert_eq!(encrypted1, encrypted2);
let decrypted = decrypt_arc4(&encrypted1, &key, &iv, block_index).unwrap();
assert_eq!(decrypted, plaintext);
}
#[test]
#[allow(deprecated)]
fn test_arc4_empty_data() {
let key = [0x01u8; 16];
let iv = [0x02, 0x03, 0x04, 0x05];
let block_index = 0;
let empty_data = b"";
let encrypted = encrypt_arc4(empty_data, &key, &iv, block_index).unwrap();
assert_eq!(encrypted.len(), 0);
let decrypted = decrypt_arc4(&encrypted, &key, &iv, block_index).unwrap();
assert_eq!(decrypted, empty_data);
}
}