1use zeroize::ZeroizeOnDrop;
2
3#[derive(ZeroizeOnDrop)]
4pub struct Rar13Cipher {
5 key: [u8; 3],
6}
7
8pub struct Rar13DecryptReader<R> {
9 inner: R,
10 cipher: Rar13Cipher,
11}
12
13impl Rar13Cipher {
14 pub fn new(password: &[u8]) -> Self {
15 let mut key = [0u8; 3];
16 for &byte in password {
17 key[0] = key[0].wrapping_add(byte);
18 key[1] ^= byte;
19 key[2] = key[2].wrapping_add(byte).rotate_left(1);
20 }
21 Self { key }
22 }
23
24 pub fn new_comment() -> Self {
25 Self { key: [0, 7, 77] }
26 }
27
28 pub fn encrypt_in_place(mut self, data: &mut [u8]) {
29 for byte in data {
30 *byte = self.encrypt_byte(*byte);
31 }
32 }
33
34 pub fn decrypt_in_place(mut self, data: &mut [u8]) {
35 for byte in data {
36 *byte = self.decrypt_byte(*byte);
37 }
38 }
39
40 pub fn encrypt_byte(&mut self, byte: u8) -> u8 {
41 self.advance();
42 byte.wrapping_add(self.key[0])
43 }
44
45 pub fn decrypt_byte(&mut self, byte: u8) -> u8 {
46 self.advance();
47 byte.wrapping_sub(self.key[0])
48 }
49
50 fn advance(&mut self) {
51 self.key[1] = self.key[1].wrapping_add(self.key[2]);
52 self.key[0] = self.key[0].wrapping_add(self.key[1]);
53 }
54}
55
56impl<R> Rar13DecryptReader<R> {
57 pub fn new(inner: R, cipher: Rar13Cipher) -> Self {
58 Self { inner, cipher }
59 }
60}
61
62impl<R: std::io::Read> std::io::Read for Rar13DecryptReader<R> {
63 fn read(&mut self, out: &mut [u8]) -> std::io::Result<usize> {
64 let read = self.inner.read(out)?;
65 for byte in &mut out[..read] {
66 *byte = self.cipher.decrypt_byte(*byte);
67 }
68 Ok(read)
69 }
70}
71
72#[cfg(test)]
73mod tests {
74 use super::Rar13Cipher;
75
76 #[test]
77 fn rar13_cipher_matches_pinned_stream_vector() {
78 let mut data = *b"hello world";
79 Rar13Cipher::new(b"password").encrypt_in_place(&mut data);
80 assert_eq!(
81 data,
82 [0x37, 0xcd, 0xaa, 0xbd, 0x10, 0x4e, 0x6f, 0x6e, 0xb5, 0x30, 0xe6]
83 );
84
85 Rar13Cipher::new(b"password").decrypt_in_place(&mut data);
86 assert_eq!(&data, b"hello world");
87 }
88}