xtea_cipher/
lib.rs

1use bytes::Bytes;
2use std::io;
3
4pub mod bytes;
5
6/// A 128-bit key used by an [Xtea] instance when processing the block cipher.
7#[derive(Clone, Debug)]
8struct XteaKey(Vec<u32>);
9
10impl std::ops::Index<usize> for XteaKey {
11    type Output = u32;
12
13    fn index(&self, index: usize) -> &Self::Output {
14        &self.0[index]
15    }
16}
17
18/// An Xtea data structure equipped to perform the [eXtended TEA](https://en.wikipedia.org/wiki/XTEA) block cipher. Each XTEA
19/// instance takes a 128-bit key represented in the form of [XteaKey], applying a pseudorandom permutation on passed-in data 
20/// in 64-bit chunks, commonly referred to as "blocks".
21#[derive(Debug)]
22pub struct Xtea {
23    key: XteaKey,
24    rounds: u32,
25}
26
27impl Xtea {
28    /// The default suggested amount of rounds to apply.
29    const DEFAULT_ROUNDS: u32 = 32;
30
31    const DELTA: u32 = 0x9E3779B9;
32
33    /// Assigns a 128-bit key using the passed-in array of 32-bit integers.
34    pub fn using_key(key: [u32; 4]) -> Self {
35        assert!(key.len() == 4);
36        Self {
37            key: XteaKey(key.to_vec()),
38            rounds: Self::DEFAULT_ROUNDS,
39        }
40    }
41
42    /// Specifies the amount of rounds to be used when processing the block ciphers. This overrides the default amount of rounds
43    /// used of 32.
44    pub fn with_rounds(mut self, rounds: u32) -> Self {
45        self.rounds = rounds;
46        self
47    }
48
49    /// Encrypts the supplied `input` data and writes the processed results to the `output` array.
50    pub fn encipher(&self, mut input: &mut [u8], mut output: &mut [u8]) -> io::Result<()> {
51        self.do_block_cipher(&mut input, &mut output, false)
52    }
53
54    /// Decrypts the supplied encrypted `input` array and writes the processed results to the `output` array.
55    pub fn decipher(&self, input: &mut [u8], output: &mut [u8]) -> io::Result<()> {
56        self.do_block_cipher(input, output, true)
57    }
58
59    fn encipher_block(&self, input: &[u32; 2], output: &mut [u32; 2]) {
60        let mut v0 = input[0];
61        let mut v1 = input[1];
62        let mut sum = 0u32;
63
64        
65        for _ in 0..self.rounds {
66            v0 = v0.wrapping_add(((v1 << 4) ^ (v1 >> 5)).wrapping_add(v1))
67                ^ (sum.wrapping_add(self.key[(sum & 3) as usize]));
68            sum = sum.wrapping_add(Self::DELTA);
69            v1 = v1.wrapping_add(
70                (((v0 << 4) ^ (v0 >> 5)).wrapping_add(v0))
71                    ^ (sum.wrapping_add(self.key[((sum >> 11) & 3) as usize])),
72            );
73        }
74
75        output[0] = v0;
76        output[1] = v1;
77    }
78
79    fn decipher_block(&self, input: &[u32; 2], output: &mut [u32; 2]) {
80        let mut v0 = input[0];
81        let mut v1 = input[1];
82        let mut sum = Self::DELTA.wrapping_mul(self.rounds);
83
84        for _ in 0..self.rounds {
85            v1 = v1.wrapping_sub(
86                (((v0 << 4) ^ (v0 >> 5)).wrapping_add(v0))
87                    ^ (sum.wrapping_add(self.key[((sum >> 11) & 3) as usize])),
88            );
89            sum = sum.wrapping_sub(Self::DELTA);
90            v0 = v0.wrapping_sub(
91                (((v1 << 4) ^ (v1 >> 5)).wrapping_add(v1))
92                    ^ (sum.wrapping_add(self.key[(sum & 3) as usize])),
93            );
94        }
95
96        output[0] = v0;
97        output[1] = v1;
98    }
99
100    fn do_block_cipher(&self, input: &mut [u8], output: &mut [u8], decrypt: bool) -> io::Result<()> {
101        let mut input_buffer = Bytes::new(input.to_vec());
102        let mut output_buffer = Bytes::new(output.to_vec());
103        let mut input_slice = [0_u32; 2];
104        let mut output_slice = [0_u32; 2];
105        let iterations = input_buffer.readable() / 8;
106
107        for _ in 0..iterations {
108            input_slice[0] = input_buffer.get_u32()?;
109            input_slice[1] = input_buffer.get_u32()?;
110
111            if decrypt {
112                self.decipher_block(&input_slice, &mut output_slice);
113            } else {
114                self.encipher_block(&input_slice, &mut output_slice);
115            }
116
117            output_buffer.put_u32(output_slice[0]);
118            output_buffer.put_u32(output_slice[1]);
119        }
120        Ok(())
121    }
122}