rc5_cipher/
rc5.rs

1/*!
2 # RC5 block-cipher
3
4 Library implementation of the basic RC5 block cipher in Rust. RC5 is different
5 from the classical ciphers (like AES) in the sense that allows to parametrize
6 the algorithm and optimize both security and efficiency on different hardware.
7
8 These parameters are:
9
10 * `w`: word length in bytes
11 * `r`: number of rounds
12 * `b`: key length in bytes
13
14 The selection of each of them should be preferably done by choosing standards
15 from other use cases. For example the word length `w` could be any number of
16 bytes but the recommendation for performance and security is that should be a
17 power of 2, or even better, a power of 8. In that way one can use the hardware
18 registers more efficiently, e.g. 32-bits or 64-bits registers, with
19 vectorization possibilities (AVX on Intel or SVE on ARM).
20
21 This RC5 implementation is designed only for the standard values of `w` (powers
22 of 8) making use of the standard Rust types: u8, u16, u32, u64, u128.
23
24 ## Example: encryption
25
26 ```rust
27 use rc5_cipher::encrypt;
28
29 let rounds = 12;
30 let key = vec![
31     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
32     0x0E, 0x0F,
33 ];
34 let pt = [0x33221100u32, 0x77665544];
35
36 let ct = encrypt(pt, &key, rounds);
37
38 assert_eq!(ct, [0x9B14DC2Du32, 0x9E8B08CF]);
39 ```
40
41 ## Example: decryption
42
43 ```rust
44 use rc5_cipher::decrypt;
45
46 let rounds = 12;
47 let key = vec![
48     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
49     0x0E, 0x0F,
50 ];
51 let ct = [0x9B14DC2Du32, 0x9E8B08CF];
52
53 let pt = decrypt(ct, &key, rounds);
54
55 assert_eq!(pt, [0x33221100u32, 0x77665544]);
56 ```
57
58 ## Bibliography
59
60 - Rivest original paper: https://www.grc.com/r&d/rc5.pdf
61 - C implementation and tests: https://tools.ietf.org/id/draft-krovetz-rc6-rc5-vectors-00.html#rfc.section.4
62 - Haskell implementation: https://hackage.haskell.org/package/cipher-rc5-0.1.2.2/docs/src/Crypto-Cipher-RC5.html
63
64*/
65
66use crate::word::Word;
67
68pub fn rotl<W: Word>(x: W, y: W) -> W {
69    let w = W::BYTES * 8;
70    let a = y & W::from_usize(w - 1);
71    if a == W::ZERO {
72        x
73    } else {
74        (x << a) | (x >> (W::from_usize(w) - a))
75    }
76}
77
78pub fn rotr<W: Word>(x: W, y: W) -> W {
79    let w = W::BYTES * 8;
80    let a = y & W::from_usize(w - 1);
81    if a == W::ZERO {
82        x
83    } else {
84        (x >> a) | (x << (W::from_usize(w) - a))
85    }
86}
87
88///
89/// Encrypts a plaintext `pt` and returns a ciphertext `ct`.
90/// The `pt` is an array of two words `W` (u8, u16, u32, u64, u128)
91///
92/// Example:
93///
94/// ```rust
95/// use rc5_cipher::encrypt;
96///
97/// let rounds = 12;
98/// let key = vec![0x00, 0x01, 0x02, 0x03];
99/// let pt  = [0x00u8, 0x01];
100///
101/// let ct = encrypt(pt, &key, rounds);
102///     
103/// assert_eq!(ct, [0x21u8, 0x2A]);
104/// ```
105///
106pub fn encrypt<W: Word>(pt: [W; 2], key: &Vec<u8>, rounds: usize) -> [W; 2] {
107    let key_exp = expand_key::<W>(key, rounds);
108    let mut a = pt[0].wrapping_add(&key_exp[0]);
109    let mut b = pt[1].wrapping_add(&key_exp[1]);
110    for i in 1..=rounds {
111        a = rotl(a ^ b, b).wrapping_add(&key_exp[2 * i]);
112        b = rotl(b ^ a, a).wrapping_add(&key_exp[2 * i + 1]);
113    }
114    [a, b]
115}
116
117///
118/// Decrypts a ciphertext `ct` and returns a plaintext `pt`.
119/// The `ct` is an array of two words `W` (u8, u16, u32, u64, u128)
120///
121/// Example:
122///
123/// ```rust
124/// use rc5_cipher::decrypt;
125///
126/// let rounds = 12;
127/// let key = vec![0x00, 0x01, 0x02, 0x03];
128/// let ct  = [0x21u8, 0x2A];
129///
130/// let pt = decrypt(ct, &key, rounds);
131///
132/// assert_eq!(pt, [0x00u8, 0x01]);
133/// ```
134///
135#[allow(arithmetic_overflow)]
136pub fn decrypt<W: Word>(ct: [W; 2], key: &Vec<u8>, rounds: usize) -> [W; 2] {
137    let key_exp = expand_key::<W>(key, rounds);
138    let mut a = ct[0];
139    let mut b = ct[1];
140    for i in (1..=rounds).rev() {
141        b = rotr(b.wrapping_sub(&key_exp[2 * i + 1]), a) ^ a;
142        a = rotr(a.wrapping_sub(&key_exp[2 * i]), b) ^ b;
143    }
144    [a.wrapping_sub(&key_exp[0]), b.wrapping_sub(&key_exp[1])]
145}
146
147///
148/// Expands `key` into and array of length `T` of type `W`
149///
150/// `W`: is the data type. Currently supported: u8, u16, u32, u64, u128
151/// `T`: is the key expansion length `T = 2 * (r + 1)` being `r` number of
152/// rounds. `T` should be even.
153///
154/// Example:
155///
156/// ```rust
157/// use rc5_cipher::expand_key;
158///
159/// let rounds = 1;
160/// let key = vec![0x00, 0x01, 0x02, 0x03];
161/// let key_exp = expand_key::<u32>(&key, rounds);
162///
163/// assert_eq!(
164///     &key_exp[..],
165///     [0xbc13a1cf, 0xfeda18e9, 0x39252ff2, 0x57a51ad8]
166/// );
167/// ```
168///
169#[allow(arithmetic_overflow)]
170pub fn expand_key<W: Word>(key: &Vec<u8>, rounds: usize) -> Vec<W> {
171    let t = 2 * (rounds + 1);
172    let b = key.len();
173    let w = W::BYTES * 8;
174
175    // c = max(1, ceil(8*b/w))
176    let c = std::cmp::max(1, (8 * b + w - 1) / w);
177
178    // converting the secrey key from bytes to words
179    let mut key_l: Vec<W> = vec![W::ZERO; c];
180    let u = W::BYTES;
181    for i in (0..b).rev() {
182        let ix = i / u;
183        key_l[ix] = (key_l[ix].wrapping_shl(8u32)).wrapping_add(&W::from_u8(key[i]));
184    }
185
186    // initializing array S
187    let mut key_s = vec![W::ZERO; t];
188    key_s[0] = W::P;
189    for i in 1..t {
190        key_s[i] = key_s[i - 1].wrapping_add(&W::Q);
191    }
192
193    // Mixing in the secret key
194    let mut i = 0;
195    let mut j = 0;
196    let mut a = W::ZERO;
197    let mut b = W::ZERO;
198    for _k in 0..3 * std::cmp::max(c, t) {
199        key_s[i] = rotl(key_s[i].wrapping_add(&a.wrapping_add(&b)), W::from_usize(3));
200        a = key_s[i];
201        key_l[j] = rotl(
202            key_l[j].wrapping_add(&a.wrapping_add(&b)),
203            a.wrapping_add(&b),
204        );
205        b = key_l[j];
206        i = (i + 1) % t;
207        j = (j + 1) % c;
208    }
209    key_s
210}
211
212#[cfg(test)]
213mod tests {
214    use super::*;
215
216    #[test]
217    fn test_left_right_shift() {
218        let a = 0x77u8; // 0111 0111
219
220        assert_eq!(rotl(a, 1u8), 0xeeu8);
221        assert_eq!(rotl(a, 7u8), 0xbbu8); // 1011 1011 = 0xbb
222        assert_eq!(rotl(a, 8u8), a);
223        assert_eq!(rotl(a, 2 * 8u8), a);
224        assert_eq!(rotl(a, 5 * 8u8), a);
225        assert_eq!(rotl(a, 1u8), 0xeeu8); // 1110 1110 = 0xee
226        assert_eq!(rotl(a, 7u8), 0xbbu8); // 1011 1011 = 0xbb
227        assert_eq!(rotr(a, 8u8), a);
228
229        assert_eq!(rotr(a, 1u8), 0xbbu8); // 1011 1011 = 0xbb
230        assert_eq!(rotr(a, 2u8), 0xddu8); // 1101 1101 = 0xdd
231        assert_eq!(rotr(a, 7u8), 0xeeu8); // 1110 1110 = 0xee
232        assert_eq!(rotr(a, 8u8), a);
233        assert_eq!(rotr(a, 8u8 + 1u8), 0xbbu8);
234        assert_eq!(rotr(a, 8u8 + 2u8), 0xddu8);
235        assert_eq!(rotr(a, 8u8 + 7u8), 0xeeu8);
236        assert_eq!(rotr(a, 2 * 8u8), a);
237        assert_eq!(rotr(a, 5 * 8u8), a);
238    }
239
240    #[test]
241    fn test_rivest_1() {
242        let key = vec![
243            0x00u8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
244            0x00, 0x00,
245        ];
246        let pt = [0x00000000u32, 0x00000000];
247        let rounds = 12;
248
249        let ct = encrypt(pt, &key, rounds);
250        assert_eq!(ct, [0xEEDBA521u32, 0x6D8F4B15]);
251
252        let pt = decrypt(ct, &key, rounds);
253        assert_eq!(pt, [0x00000000u32, 0x00000000]);
254    }
255
256    #[test]
257    fn test_rivest_2() {
258        let key = vec![
259            0x91, 0x5F, 0x46, 0x19, 0xBE, 0x41, 0xB2, 0x51, 0x63, 0x55, 0xA5, 0x01, 0x10, 0xA9,
260            0xCE, 0x91,
261        ];
262        let pt = [0xEEDBA521u32, 0x6D8F4B15];
263        let rounds = 12;
264
265        let ct = encrypt(pt, &key, rounds);
266        assert_eq!(ct, [0xAC13C0F7u32, 0x52892B5B]);
267
268        let pt = decrypt(ct, &key, rounds);
269        assert_eq!(pt, [0xEEDBA521u32, 0x6D8F4B15]);
270    }
271
272    #[test]
273    fn test_rivest_3() {
274        let key = vec![
275            0x78, 0x33, 0x48, 0xE7, 0x5A, 0xEB, 0x0F, 0x2F, 0xD7, 0xB1, 0x69, 0xBB, 0x8D, 0xC1,
276            0x67, 0x87,
277        ];
278        let pt = [0xAC13C0F7u32, 0x52892B5B];
279        let rounds = 12;
280
281        let ct = encrypt(pt, &key, rounds);
282        assert_eq!(ct, [0xB7B3422Fu32, 0x92FC6903]);
283
284        let pt = decrypt(ct, &key, rounds);
285        assert_eq!(pt, [0xAC13C0F7u32, 0x52892B5B]);
286    }
287
288    #[test]
289    fn test_rivest_4() {
290        let key = vec![
291            0xDC, 0x49, 0xDB, 0x13, 0x75, 0xA5, 0x58, 0x4F, 0x64, 0x85, 0xB4, 0x13, 0xB5, 0xF1,
292            0x2B, 0xAF,
293        ];
294        let pt = [0xB7B3422Fu32, 0x92FC6903];
295        let rounds = 12;
296
297        let ct = encrypt(pt, &key, rounds);
298        assert_eq!(ct, [0xB278C165u32, 0xCC97D184]);
299
300        let pt = decrypt(ct, &key, rounds);
301        assert_eq!(pt, [0xB7B3422Fu32, 0x92FC6903]);
302    }
303
304    #[test]
305    fn test_rivest_5() {
306        let key = vec![
307            0x52, 0x69, 0xF1, 0x49, 0xD4, 0x1B, 0xA0, 0x15, 0x24, 0x97, 0x57, 0x4D, 0x7F, 0x15,
308            0x31, 0x25,
309        ];
310        let pt = [0xB278C165u32, 0xCC97D184];
311        let rounds = 12;
312
313        let ct = encrypt(pt, &key, rounds);
314        assert_eq!(ct, [0x15E444EBu32, 0x249831DA]);
315
316        let pt = decrypt(ct, &key, rounds);
317        assert_eq!(pt, [0xB278C165u32, 0xCC97D184]);
318    }
319
320    #[test]
321    fn encrypt_decrypt_a() {
322        let rounds = 12;
323        let key = vec![
324            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
325            0x0E, 0x0F,
326        ];
327        let pt = [0x33221100u32, 0x77665544];
328
329        let ct = encrypt(pt, &key, rounds);
330
331        assert_eq!(ct, [0x9B14DC2Du32, 0x9E8B08CF]);
332
333        let pt = decrypt(ct, &key, rounds);
334
335        assert_eq!(pt, [0x33221100u32, 0x77665544]);
336    }
337
338    #[test]
339    fn encrypt_decrypt_b() {
340        let rounds = 12;
341        let key = vec![
342            0x2B, 0xD6, 0x45, 0x9F, 0x82, 0xC5, 0xB3, 0x00, 0x95, 0x2C, 0x49, 0x10, 0x48, 0x81,
343            0xFF, 0x48,
344        ];
345        let pt = [0x144702EAu32, 0x844D5CAD];
346
347        let ct = encrypt(pt, &key, rounds);
348
349        assert_eq!(ct, [0x863BE411u32, 0x64EA31D2]);
350
351        let pt = decrypt(ct, &key, rounds);
352
353        assert_eq!(pt, [0x144702EAu32, 0x844D5CAD]);
354    }
355
356    // Test cases from https://tools.ietf.org/id/draft-krovetz-rc6-rc5-vectors-00.html#rfc.section.4
357
358    #[test]
359    fn encrypt_decrypt_8_12_4() {
360        let rounds = 12;
361        let key = vec![0x00, 0x01, 0x02, 0x03];
362
363        let pt = [0x00u8, 0x01];
364
365        let ct = encrypt(pt, &key, rounds);
366
367        assert_eq!(ct, [0x21u8, 0x2A]);
368
369        let pt = decrypt(ct, &key, rounds);
370
371        assert_eq!(pt, [0x00u8, 0x01]);
372    }
373
374    #[test]
375    fn encrypt_16_16_8() {
376        let rounds = 16;
377        let key = vec![0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07];
378
379        let pt = [0x0100u16, 0x0302];
380
381        let ct = encrypt(pt, &key, rounds);
382
383        assert_eq!(ct, [0xA823, 0x2ED7]);
384
385        let pt = decrypt(ct, &key, rounds);
386
387        assert_eq!(pt, [0x0100u16, 0x0302]);
388    }
389
390    #[test]
391    fn encrypt_decrypt_32_20_16() {
392        let rounds = 20;
393        let key = vec![
394            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
395            0x0E, 0x0F,
396        ];
397        let pt = [0x03020100u32, 0x07060504];
398
399        let ct = encrypt(pt, &key, rounds);
400
401        assert_eq!(ct, [0x0EDC0E2Au32, 0x73FF3194]);
402
403        let pt = decrypt(ct, &key, rounds);
404
405        assert_eq!(pt, [0x03020100u32, 0x07060504]);
406    }
407
408    #[test]
409    fn encrypt_64_24_24() {
410        let rounds = 24;
411        let key = vec![
412            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
413            0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
414        ];
415        let pt = [0x0706050403020100u64, 0x0F0E0D0C0B0A0908];
416
417        let ct = encrypt(pt, &key, rounds);
418
419        assert_eq!(ct, [0x02CEDB0E827267A4u64, 0xDA7871AE32EAAB35]);
420
421        let pt = decrypt(ct, &key, rounds);
422
423        assert_eq!(pt, [0x0706050403020100u64, 0x0F0E0D0C0B0A0908]);
424    }
425
426    #[test]
427    fn encrypt_kernel_128_28_32() {
428        let rounds = 28;
429        let key = vec![
430            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
431            0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B,
432            0x1C, 0x1D, 0x1E, 0x1F,
433        ];
434        let pt = [
435            0x0F0E0D0C0B0A09080706050403020100u128,
436            0x1F1E1D1C1B1A19181716151413121110,
437        ];
438
439        let ct = encrypt(pt, &key, rounds);
440
441        assert_eq!(
442            ct,
443            [
444                0xBAFCA120ADD77ADDCFF4A4210991A5ECu128,
445                0x40B480E17F4B91FE682D75CDA7C78E06
446            ]
447        );
448
449        let pt = decrypt(ct, &key, rounds);
450
451        assert_eq!(
452            pt,
453            [
454                0x0F0E0D0C0B0A09080706050403020100u128,
455                0x1F1E1D1C1B1A19181716151413121110,
456            ]
457        );
458    }
459}