rc5_rs/
cipher.rs

1use {
2  crate::{error::Error, word::Word},
3  num::integer::div_ceil,
4  std::{cmp::max, mem::size_of},
5};
6
7/// Block Encryption
8///
9/// We assume that the input block is given in two w-bit registers A and B. We
10/// also assume that key-expansion has already been performed, so that the array
11/// S[0...t−1] has been computed. Here is the encryption algorithm in
12/// pseudo-code:
13///
14/// A = A + S[0];
15/// B = B + S[1];
16/// for i = 1 to r do
17///   A = ((A ⊕ B) < B) + S[2 ∗ i];
18///   B = ((B ⊕ A) < A) + S[2 ∗ i + 1];
19/// end for
20///
21/// The output is in the registers A and B.
22pub fn encrypt_block<W: Word>(
23  expanded_key: &[W],
24  mut block: [W; 2], // A and B
25) -> Result<[W; 2], Error> {
26  let num_rounds = (expanded_key.len() / 2) - 1;
27  block[0] = block[0].wrapping_add(&expanded_key[0]);
28  block[1] = block[1].wrapping_add(&expanded_key[1]);
29
30  for i in 1..=num_rounds {
31    let rotation =
32      block[1].to_u128().ok_or(Error::InvalidWordSize)? % W::BITS as u128;
33    block[0] = (block[0].bitxor(block[1]))
34      .rotate_left(rotation as u32)
35      .wrapping_add(&expanded_key[2 * i]);
36
37    let rotation =
38      block[0].to_u128().ok_or(Error::InvalidWordSize)? % W::BITS as u128;
39    block[1] = (block[1].bitxor(block[0]))
40      .rotate_left(rotation as u32)
41      .wrapping_add(&expanded_key[2 * i + 1]);
42  }
43
44  Ok(block)
45}
46
47/// Block Decryption
48///
49/// The decryption routine is easily derived from the encryption routine.
50/// for i=r downto 1 do
51///   B = ((B − S[2 ∗ i + 1]) > A) ⊕ A;
52///   A = ((A − S[2 ∗ i]) > B) ⊕ B;
53///   
54/// B = B − S[1];
55/// A = A − S[0];
56pub fn decrypt_block<W: Word>(
57  expanded_key: &[W],
58  mut block: [W; 2],
59) -> Result<[W; 2], Error> {
60  let num_rounds = (expanded_key.len() / 2) - 1;
61
62  for i in (1..=num_rounds).rev() {
63    let rotation =
64      block[0].to_u128().ok_or(Error::InvalidWordSize)? % W::BITS as u128;
65
66    block[1] = (block[1].wrapping_sub(&expanded_key[2 * i + 1]))
67      .rotate_right(rotation as u32)
68      .bitxor(block[0]);
69
70    let rotation =
71      block[1].to_u128().ok_or(Error::InvalidWordSize)? % W::BITS as u128;
72    block[0] = (block[0].wrapping_sub(&expanded_key[2 * i]))
73      .rotate_right(rotation as u32)
74      .bitxor(block[1]);
75  }
76
77  block[1] = block[1].wrapping_sub(&expanded_key[1]);
78  block[0] = block[0].wrapping_sub(&expanded_key[0]);
79
80  Ok(block)
81}
82
83/// Key expansion algorithm
84pub fn expand_key<W: Word>(key: &[u8], rounds: usize) -> Result<Vec<W>, Error> {
85  // limit described in the paper.
86  const MAX_ROUNDS: usize = 256;
87  const MAX_KEY_SIZE: usize = 256;
88
89  if key.len() > MAX_KEY_SIZE {
90    return Err(Error::InvalidKeySize);
91  }
92
93  if rounds > MAX_ROUNDS {
94    return Err(Error::InvalidRoundsCount);
95  }
96
97  // 1. key bytes to words:
98  let mut words: Vec<W> = key_to_words(key);
99
100  // 2. Initialize the key-independent array S
101  // S[0] = Pw;
102  // for i = 1 to t − 1 do
103  //  S[i] = S[i − 1] + Qw;
104  let mut subkeys: Vec<W> = initialize_subkeys(rounds);
105
106  // the main key scheduling loop
107  // i = j = 0
108  // A = B = 0
109  // do 3 * max(t, c) times:
110  //    A = S[i] = (S[i] + A + B) <<< 3
111  //    B = L[j] = (L[j] + A + B) <<< (A + B)
112  //    i = (i + 1) mod t
113  //    j = (j + 1) mod c
114
115  let mut i = 0;
116  let mut j = 0;
117  let mut a = W::zero();
118  let mut b = W::zero();
119
120  // 3 * max(t, c)
121  let iters = max(subkeys.len(), words.len()) * 3;
122
123  for _ in 0..iters {
124    subkeys[i] = subkeys[i].wrapping_add(&a).wrapping_add(&b).rotate_left(3);
125    a = subkeys[i];
126
127    // this could be larger than the word size, so we need to mod it
128    let rotation =
129      a.wrapping_add(&b).to_u128().ok_or(Error::InvalidWordSize)?
130        % W::BITS as u128;
131
132    words[j] = words[j]
133      .wrapping_add(&a)
134      .wrapping_add(&b)
135      .rotate_left(rotation as u32);
136    b = words[j];
137
138    i = (i + 1) % subkeys.len();
139    j = (j + 1) % words.len();
140  }
141
142  Ok(subkeys)
143}
144
145/// Pseudocode:
146///
147/// c = [max(b, 1) / u]
148/// for i = b - 1 downto 0 do
149///   L[i/u] = (L[i/u] <<< 8) + K[i]
150fn key_to_words<W: Word>(key: &[u8]) -> Vec<W> {
151  let words_len = div_ceil(max(key.len(), 1), size_of::<W>());
152  let mut words = vec![W::zero(); words_len];
153  for i in (0..key.len()).rev() {
154    let word_index = i / size_of::<W>();
155    let word = W::from(key[i]).expect("minimum word size is 8");
156    words[word_index] = words[word_index].rotate_left(8).wrapping_add(&word);
157  }
158  words
159}
160
161/// Initialize the key-independent array S
162/// S[0] = Pw;
163/// for i = 1 to t − 1 do
164///  S[i] = S[i − 1] + Qw;
165fn initialize_subkeys<W: Word>(rounds: usize) -> Vec<W> {
166  let subkey_count = 2 * (rounds + 1); // t
167  let mut subkeys = vec![W::zero(); subkey_count];
168
169  subkeys[0] = W::P;
170  for i in 1..subkey_count {
171    subkeys[i] = subkeys[i - 1].wrapping_add(&W::Q);
172  }
173
174  subkeys
175}