1use crate::{BlockCipher, Reason, Version, Word, bail};
2
3pub struct RC5ControlBlock<W: Word> {
12 version: Version,
14
15 key: RC5Key<W>,
18
19 rounds: usize,
22}
23
24impl<W: Word> RC5ControlBlock<W> {
25 pub fn new<K>(key: K, rounds: usize) -> Result<Self, Reason>
32 where
33 K: AsRef<[u8]>,
34 {
35 let key = RC5Key::from_raw(key, rounds)?;
36 Ok(Self {
37 rounds,
38 version: Version::from_parametric_vector(vec![
39 1,
40 (W::BYTES * 8) as u8,
41 rounds as u8,
42 key.raw_len() as u8,
43 ]),
44 key,
45 })
46 }
47
48 #[inline]
50 pub fn s_table(&self) -> &[W] {
51 &self.key.s_table
52 }
53
54 #[inline]
56 pub fn rounds(&self) -> usize {
57 self.rounds
58 }
59
60 #[inline]
63 pub fn parametric_version(&self) -> String {
64 self.version.version()
65 }
66}
67
68impl<W: Word> BlockCipher<W, 2> for RC5ControlBlock<W> {
69 fn encrypt(&self, pt: [W; 2]) -> [W; 2] {
70 let expanded_key = self.s_table();
71 let [mut word_a, mut word_b] = pt;
72
73 word_a = word_a.wrapping_add(expanded_key[0]);
74 word_b = word_b.wrapping_add(expanded_key[1]);
75
76 for r in 1..=self.rounds() {
77 word_a = ((word_a ^ word_b).rotate_left(word_b)).wrapping_add(expanded_key[2 * r]);
78 word_b = ((word_b ^ word_a).rotate_left(word_a)).wrapping_add(expanded_key[2 * r + 1]);
79 }
80
81 [word_a, word_b]
82 }
83
84 fn decrypt(&self, ct: [W; 2]) -> [W; 2] {
85 let expanded_key = self.s_table();
86 let [mut word_a, mut word_b] = ct;
87
88 for r in (1..=self.rounds()).rev() {
89 word_b = (word_b
90 .wrapping_sub(expanded_key[2 * r + 1])
91 .rotate_right(word_a))
92 ^ word_a;
93
94 word_a = (word_a
95 .wrapping_sub(expanded_key[2 * r])
96 .rotate_right(word_b))
97 ^ word_b;
98 }
99
100 word_b = word_b.wrapping_sub(expanded_key[1]);
101 word_a = word_a.wrapping_sub(expanded_key[0]);
102
103 [word_a, word_b]
104 }
105
106 fn generate_blocks(&self, pt: Vec<u8>) -> Vec<[W; 2]> {
107 let mut blocks = Vec::with_capacity(pt.len() / self.block_size());
108 for chunks in pt.chunks_exact(self.block_size()) {
109 blocks.push([
110 W::from_bytes_slice(&chunks[..W::BYTES]).unwrap(),
111 W::from_bytes_slice(&chunks[W::BYTES..]).unwrap(),
112 ]);
113 }
114
115 blocks
116 }
117
118 fn generate_bytes_stream(&self, blocks: Vec<[W; 2]>) -> Vec<u8> {
119 let mut stream = Vec::with_capacity(blocks.len() * self.block_size());
120 for blcok in blocks.iter() {
121 stream.extend_from_slice(&blcok[0].to_bytes_slice());
122 stream.extend_from_slice(&blcok[1].to_bytes_slice());
123 }
124 stream
125 }
126
127 fn control_block_version(&self) -> String {
128 self.parametric_version()
129 }
130
131 fn block_size(&self) -> usize {
132 W::BYTES * 2
133 }
134
135 fn word_size(&self) -> usize {
136 W::BYTES
137 }
138}
139
140const MAX_ROUNDS: usize = 255;
141const MAX_KEY_BYTES: usize = 255;
142
143pub struct RC5Key<W: Word> {
148 raw_key: Vec<u8>,
149 s_table: Vec<W>,
150}
151
152impl<W: Word> RC5Key<W> {
153 pub fn from_raw<K>(raw: K, rounds: usize) -> Result<Self, Reason>
156 where
157 K: AsRef<[u8]>,
158 {
159 let key_bytes = raw.as_ref();
160
161 bail!(
162 key_bytes.is_empty(),
163 Reason::InvalidKey,
164 key_bytes.len() > MAX_KEY_BYTES,
165 Reason::KeyTooLong {
166 current: key_bytes.len(),
167 supported: MAX_KEY_BYTES
168 },
169 rounds > MAX_ROUNDS,
170 Reason::InvalidRounds(rounds)
171 );
172
173 Ok(Self {
174 s_table: expand_key::<W>(key_bytes, rounds),
175 raw_key: key_bytes.to_vec(),
176 })
177 }
178
179 pub fn raw_len(&self) -> usize {
180 self.raw_key.len()
181 }
182}
183
184fn expand_key<W: Word>(key: &[u8], rounds: usize) -> Vec<W> {
199 let word_bytes = W::BYTES;
200 let key_length = key.len().max(1);
201
202 let expanded_length = key_length.div_ceil(word_bytes);
203 let mut key_words = vec![W::ZERO; expanded_length];
204
205 for index in (0..key_length).rev() {
208 let ix = index / word_bytes;
209 key_words[ix] = key_words[ix]
210 .rotate_left(W::from_u8(8))
211 .wrapping_add(W::from_u8(key[index]));
212 }
213
214 let table_size = 2 * (rounds + 1);
215 let mut s_table = vec![W::ZERO; table_size];
216
217 s_table[0] = W::P;
218
219 for i in 1..table_size {
221 s_table[i] = s_table[i - 1].wrapping_add(W::Q);
222 }
223
224 let (mut i, mut j) = (0, 0);
225 let (mut a, mut b) = (W::ZERO, W::ZERO);
226
227 for _ in 0..(3 * table_size.max(expanded_length)) {
230 a = s_table[i]
231 .wrapping_add(a)
232 .wrapping_add(b)
233 .rotate_left(W::from_u8(3));
234
235 b = key_words[j]
236 .wrapping_add(a)
237 .wrapping_add(b)
238 .rotate_left(a.wrapping_add(b));
239
240 s_table[i] = a;
241 key_words[j] = b;
242
243 i = (i + 1) % table_size;
244 j = (j + 1) % expanded_length;
245 }
246
247 s_table
248}