sysfunc_blockcipher_xtea/
lib.rs

1//! Simple [`XTEA`] implementation in Rust.
2//!
3//! Minimal protection is afforded by the use of `wrapping_add`
4//! and `wrapping_sub` functions of Rust's core.  Generally
5//! speaking the code should not have any troubles (and this
6//! code has been moderately used in production).
7//!
8//! [`XTEA`]: https://en.wikipedia.org/wiki/XTEA
9
10#![no_std]
11
12/// Enciphers the blocks of data using the given key.
13///
14/// Blocks must be greater than two or no action is performed.
15/// Blocks should be divisible by two, where this is not the case
16/// any remaining blocks will not be processed (i.e. the last block
17/// will be ignored.)
18///
19/// The key data should be a set of four values (128 bits total).
20pub fn encipher(blocks: &mut [u32], key: &[u32], delta: u32, rounds: usize) {
21
22    // Can't process less than two blocks because
23    // that's not how block ciphers work.
24    let n = blocks.len();
25    if n < 2 {
26        return;
27    }
28
29    // Value of 'a' block
30    let mut a: u32;
31
32    // Value of 'b' block
33    let mut b: u32;
34
35    // Running/internal sum value
36    let mut s: u32;
37
38    // Step the blocks in pairs.
39    for i in 0..(n / 2) {
40        // Get 'a'
41        a = blocks[i * 2];
42
43        // Get 'b'
44        b = blocks[(i * 2) + 1];
45
46        // Reset running sum.
47        s = 0;
48
49        // Step the number of rounds;
50        // the iterator index isn't relevant to us.
51        for _ in 0..rounds {
52
53            // Modify 'a'
54            a = a.wrapping_add((((b << 4) ^ (b >> 5)).wrapping_add(b)) ^
55                               s.wrapping_add(key[(s & 3) as usize]));
56
57            // Update running sum using delta
58            s = s.wrapping_add(delta);
59
60            // modify 'b'
61            b = b.wrapping_add((((a << 4) ^ (a >> 5)).wrapping_add(a)) ^
62                               s.wrapping_add(key[((s >> 11) & 3) as usize]));
63        }
64
65        // Store a
66        blocks[i * 2] = a;
67
68        // Store b
69        blocks[(i * 2) + 1] = b;
70    }
71}
72
73/// Enciphers a single pair pair (a single 64-bit block) in place.
74///
75/// The key data should be a set of four values (128 bits total).
76pub fn encipher_pair(aa: &mut u32, bb: &mut u32, key: &[u32], delta: u32, rounds: usize) {
77    // Set the value of a
78    let mut a: u32 = *aa;
79
80    // Set the value of b
81    let mut b: u32 = *bb;
82
83    // Reset running sum.
84    let mut s: u32 = 0;
85
86    // Step the number of rounds;
87    // the iterator index isn't relevant to us.
88    for _ in 0..rounds {
89
90        // Modify 'a'
91        a = a.wrapping_add((((b << 4) ^ (b >> 5)).wrapping_add(b)) ^
92                           s.wrapping_add(key[(s & 3) as usize]));
93
94        // Update running sum using delta
95        s = s.wrapping_add(delta);
96
97        // modify 'b'
98        b = b.wrapping_add((((a << 4) ^ (a >> 5)).wrapping_add(a)) ^
99                           s.wrapping_add(key[((s >> 11) & 3) as usize]));
100    }
101
102    *aa = a;
103    *bb = b;
104}
105
106/// Deciphers the blocks of data using the given key.
107///
108/// Blocks must be greater than two or no action is performed.
109/// Blocks should be divisible by two, where this is not the case
110/// any remaining blocks will not be processed (i.e. the last block
111/// will be ignored.)
112///
113/// The key data should be a set of four values (128 bits total).
114pub fn decipher(blocks: &mut [u32], key: &[u32], delta: u32, rounds: usize) {
115
116    // Can't process less than two blocks because
117    // that's not how block ciphers work.
118    let n = blocks.len();
119    if n < 2 {
120        return;
121    }
122
123    // Value of 'a' block
124    let mut a: u32;
125
126    // Value of 'b' block
127    let mut b: u32;
128
129    // Running/internal sum value
130    let mut s: u32;
131
132    // Pre-calculate the initial sum
133    // so it can be re-used.
134    let sum: u32 = delta.wrapping_mul(rounds as u32);
135
136    // Step the blocks in pairs.
137    for i in 0..(n / 2) {
138
139        // Get 'a'
140        a = blocks[i * 2];
141
142        // Get 'b'
143        b = blocks[(i * 2) + 1];
144
145        // Reset running sum.
146        s = sum;
147
148        // Step the number of rounds;
149        // the iterator index isn't relevant to us.
150        for _ in 0..rounds {
151            // modify b
152            b = b.wrapping_sub((((a << 4) ^ (a >> 5)).wrapping_add(a)) ^
153                               s.wrapping_add(key[((s >> 11) & 3) as usize]));
154
155            // Update running sum using delta
156            s = s.wrapping_sub(delta);
157
158            // modify a
159            a = a.wrapping_sub((((b << 4) ^ (b >> 5)).wrapping_add(b)) ^
160                               s.wrapping_add(key[(s & 3) as usize]));
161        }
162
163        // Store a
164        blocks[i * 2] = a;
165
166        // Store b
167        blocks[(i * 2) + 1] = b;
168    }
169}
170
171/// Deciphers a single pair pair (a single 64-bit block) in place.
172///
173/// The key data should be a set of four values (128 bits total).
174pub fn decipher_pair(aa: &mut u32, bb: &mut u32, key: &[u32], delta: u32, rounds: usize) {
175    // Set the value of a
176    let mut a: u32 = *aa;
177
178    // Set the value of b
179    let mut b: u32 = *bb;
180
181    // Reset running sum.
182    let mut s: u32 = delta.wrapping_mul(rounds as u32);
183
184    // Step the number of rounds;
185    // the iterator index isn't relevant to us.
186    for _ in 0..rounds {
187        // modify b
188        b = b.wrapping_sub((((a << 4) ^ (a >> 5)).wrapping_add(a)) ^
189                           s.wrapping_add(key[((s >> 11) & 3) as usize]));
190
191        // Update running sum using delta
192        s = s.wrapping_sub(delta);
193
194        // modify a
195        a = a.wrapping_sub((((b << 4) ^ (b >> 5)).wrapping_add(b)) ^
196                           s.wrapping_add(key[(s & 3) as usize]));
197    }
198
199    *aa = a;
200    *bb = b;
201}
202
203#[cfg(test)]
204mod test {
205    #[test]
206    fn simple_test() {
207        use super::{encipher, decipher};
208
209        const DELTA: u32 = 0x9E3779B9;
210        const ROUNDS: usize = 32;
211        const KEY: [u32; 4] = [0xDEADBEEF, 0xAAAAAAAA, 0x0CD0CDAA, 0x12345678];
212
213        // Decoded
214        let data_d: [u32; 32] =
215            [0x90b61054, 0x4f117340, 0x2a192f72, 0xc6d20912, 0xd4a00486, 0x343b1fa9, 0xe7806b43,
216             0xd80e41e0, 0x81462e8a, 0x5e59805e, 0x7310266c, 0xb5c3f09d, 0xc830c818, 0xff5425ad,
217             0x5a4f3477, 0xb63eb737, 0x3df4acab, 0x679b76e1, 0x52befb4a, 0x54a6d777, 0xcfb5eb73,
218             0x83e661e2, 0xcddc1290, 0xe1d3972b, 0x9e9fe877, 0xe021d4c5, 0x69ac7f72, 0x3c3476cd,
219             0x7bf3ba34, 0x4183fa09, 0xbd82c98a, 0xdc181a43];
220
221        // Encoded
222        let data_e: [u32; 32] =
223            [0xecaf9488, 0xd768bb69, 0xa6b2a074, 0x6b43c81c, 0x2fefb898, 0xa385f8cc, 0x3a9d7e7a,
224             0x2461333d, 0x5faffa3e, 0x043fa28b, 0x22e91e81, 0x11b5e618, 0x10d741fe, 0x661f1de6,
225             0x19b91f26, 0xa3f94e5d, 0xe822918e, 0x62afd15b, 0x14aa9fb4, 0x23237adb, 0xdc64bf3a,
226             0x6e93102d, 0x2b1b7c24, 0x246e6058, 0x590e37a8, 0x60b51b69, 0x35970d7c, 0x2f247f1d,
227             0x361bded3, 0x40c6ff4b, 0xb7d1370d, 0x471ebe43];
228
229        // Start state (pulled from decoded);
230        // Do an explicit clone here so if the data changes above it doesn't break.
231        let mut data: [u32; 32] = data_d.clone();
232
233        encipher(&mut data, &KEY, DELTA, ROUNDS);
234
235        for i in 0..32 {
236            assert_eq!(data_e[i], data[i]);
237        }
238
239        decipher(&mut data, &KEY, DELTA, ROUNDS);
240
241        for i in 0..32 {
242            assert_eq!(data_d[i], data[i]);
243        }
244    }
245
246    #[test]
247    fn simple_test_pairs() {
248        use super::{encipher, decipher};
249
250        const DELTA: u32 = 0x9E3779B9;
251        const ROUNDS: usize = 32;
252        const KEY: [u32; 4] = [0xDEADBEEF, 0xAAAAAAAA, 0x0CD0CDAA, 0x12345678];
253
254        // Decoded
255        let data_d: [u32; 32] =
256            [0x90b61054, 0x4f117340, 0x2a192f72, 0xc6d20912, 0xd4a00486, 0x343b1fa9, 0xe7806b43,
257             0xd80e41e0, 0x81462e8a, 0x5e59805e, 0x7310266c, 0xb5c3f09d, 0xc830c818, 0xff5425ad,
258             0x5a4f3477, 0xb63eb737, 0x3df4acab, 0x679b76e1, 0x52befb4a, 0x54a6d777, 0xcfb5eb73,
259             0x83e661e2, 0xcddc1290, 0xe1d3972b, 0x9e9fe877, 0xe021d4c5, 0x69ac7f72, 0x3c3476cd,
260             0x7bf3ba34, 0x4183fa09, 0xbd82c98a, 0xdc181a43];
261
262        // Encoded
263        let data_e: [u32; 32] =
264            [0xecaf9488, 0xd768bb69, 0xa6b2a074, 0x6b43c81c, 0x2fefb898, 0xa385f8cc, 0x3a9d7e7a,
265             0x2461333d, 0x5faffa3e, 0x043fa28b, 0x22e91e81, 0x11b5e618, 0x10d741fe, 0x661f1de6,
266             0x19b91f26, 0xa3f94e5d, 0xe822918e, 0x62afd15b, 0x14aa9fb4, 0x23237adb, 0xdc64bf3a,
267             0x6e93102d, 0x2b1b7c24, 0x246e6058, 0x590e37a8, 0x60b51b69, 0x35970d7c, 0x2f247f1d,
268             0x361bded3, 0x40c6ff4b, 0xb7d1370d, 0x471ebe43];
269
270        for j in 0..16 {
271            let a = j * 2;
272            let b = a + 1;
273
274            let mut data: [u32; 2] = [data_d[a], data_d[b]];
275
276            encipher(&mut data, &KEY, DELTA, ROUNDS);
277
278            assert_eq!(data_e[a], data[0]);
279            assert_eq!(data_e[b], data[1]);
280
281            decipher(&mut data, &KEY, DELTA, ROUNDS);
282
283            assert_eq!(data_d[a], data[0]);
284            assert_eq!(data_d[b], data[1]);
285        }
286    }
287}