1use crate::ct::{ct_lookup_u32, zeroize_slice};
14use crate::BlockCipher;
15
16include!("cast128_tables.rs");
17
18#[inline]
19fn sbox(table: &[u32; 256], idx: u8, use_ct: bool) -> u32 {
20 if use_ct {
21 ct_lookup_u32(table, idx)
22 } else {
23 table[idx as usize]
24 }
25}
26
27#[inline]
28fn pack(bytes: &[u8; 16], a: usize, b: usize, c: usize, d: usize) -> u32 {
29 u32::from_be_bytes([bytes[a], bytes[b], bytes[c], bytes[d]])
30}
31
32#[inline]
33fn unpack(bytes: &mut [u8; 16], start: usize, value: u32) {
34 bytes[start..start + 4].copy_from_slice(&value.to_be_bytes());
35}
36
37fn x_to_z(x: &[u8; 16], use_ct: bool) -> [u8; 16] {
41 let mut z = [0u8; 16];
42 let w0 = pack(x, 0, 1, 2, 3)
43 ^ sbox(&S5, x[13], use_ct)
44 ^ sbox(&S6, x[15], use_ct)
45 ^ sbox(&S7, x[12], use_ct)
46 ^ sbox(&S8, x[14], use_ct)
47 ^ sbox(&S7, x[8], use_ct);
48 unpack(&mut z, 0, w0);
49
50 let w1 = pack(x, 8, 9, 10, 11)
51 ^ sbox(&S5, z[0], use_ct)
52 ^ sbox(&S6, z[2], use_ct)
53 ^ sbox(&S7, z[1], use_ct)
54 ^ sbox(&S8, z[3], use_ct)
55 ^ sbox(&S8, x[10], use_ct);
56 unpack(&mut z, 4, w1);
57
58 let w2 = pack(x, 12, 13, 14, 15)
59 ^ sbox(&S5, z[7], use_ct)
60 ^ sbox(&S6, z[6], use_ct)
61 ^ sbox(&S7, z[5], use_ct)
62 ^ sbox(&S8, z[4], use_ct)
63 ^ sbox(&S5, x[9], use_ct);
64 unpack(&mut z, 8, w2);
65
66 let w3 = pack(x, 4, 5, 6, 7)
67 ^ sbox(&S5, z[10], use_ct)
68 ^ sbox(&S6, z[9], use_ct)
69 ^ sbox(&S7, z[11], use_ct)
70 ^ sbox(&S8, z[8], use_ct)
71 ^ sbox(&S6, x[11], use_ct);
72 unpack(&mut z, 12, w3);
73
74 z
75}
76
77fn z_to_x(z: &[u8; 16], use_ct: bool) -> [u8; 16] {
78 let mut x = [0u8; 16];
79 let w0 = pack(z, 8, 9, 10, 11)
80 ^ sbox(&S5, z[5], use_ct)
81 ^ sbox(&S6, z[7], use_ct)
82 ^ sbox(&S7, z[4], use_ct)
83 ^ sbox(&S8, z[6], use_ct)
84 ^ sbox(&S7, z[0], use_ct);
85 unpack(&mut x, 0, w0);
86
87 let w1 = pack(z, 0, 1, 2, 3)
88 ^ sbox(&S5, x[0], use_ct)
89 ^ sbox(&S6, x[2], use_ct)
90 ^ sbox(&S7, x[1], use_ct)
91 ^ sbox(&S8, x[3], use_ct)
92 ^ sbox(&S8, z[2], use_ct);
93 unpack(&mut x, 4, w1);
94
95 let w2 = pack(z, 4, 5, 6, 7)
96 ^ sbox(&S5, x[7], use_ct)
97 ^ sbox(&S6, x[6], use_ct)
98 ^ sbox(&S7, x[5], use_ct)
99 ^ sbox(&S8, x[4], use_ct)
100 ^ sbox(&S5, z[1], use_ct);
101 unpack(&mut x, 8, w2);
102
103 let w3 = pack(z, 12, 13, 14, 15)
104 ^ sbox(&S5, x[10], use_ct)
105 ^ sbox(&S6, x[9], use_ct)
106 ^ sbox(&S7, x[11], use_ct)
107 ^ sbox(&S8, x[8], use_ct)
108 ^ sbox(&S6, z[3], use_ct);
109 unpack(&mut x, 12, w3);
110
111 x
112}
113
114fn extract_z_a(z: &[u8; 16], use_ct: bool) -> [u32; 4] {
115 [
116 sbox(&S5, z[8], use_ct)
117 ^ sbox(&S6, z[9], use_ct)
118 ^ sbox(&S7, z[7], use_ct)
119 ^ sbox(&S8, z[6], use_ct)
120 ^ sbox(&S5, z[2], use_ct),
121 sbox(&S5, z[10], use_ct)
122 ^ sbox(&S6, z[11], use_ct)
123 ^ sbox(&S7, z[5], use_ct)
124 ^ sbox(&S8, z[4], use_ct)
125 ^ sbox(&S6, z[6], use_ct),
126 sbox(&S5, z[12], use_ct)
127 ^ sbox(&S6, z[13], use_ct)
128 ^ sbox(&S7, z[3], use_ct)
129 ^ sbox(&S8, z[2], use_ct)
130 ^ sbox(&S7, z[9], use_ct),
131 sbox(&S5, z[14], use_ct)
132 ^ sbox(&S6, z[15], use_ct)
133 ^ sbox(&S7, z[1], use_ct)
134 ^ sbox(&S8, z[0], use_ct)
135 ^ sbox(&S8, z[12], use_ct),
136 ]
137}
138
139fn extract_x_a(x: &[u8; 16], use_ct: bool) -> [u32; 4] {
140 [
141 sbox(&S5, x[3], use_ct)
142 ^ sbox(&S6, x[2], use_ct)
143 ^ sbox(&S7, x[12], use_ct)
144 ^ sbox(&S8, x[13], use_ct)
145 ^ sbox(&S5, x[8], use_ct),
146 sbox(&S5, x[1], use_ct)
147 ^ sbox(&S6, x[0], use_ct)
148 ^ sbox(&S7, x[14], use_ct)
149 ^ sbox(&S8, x[15], use_ct)
150 ^ sbox(&S6, x[13], use_ct),
151 sbox(&S5, x[7], use_ct)
152 ^ sbox(&S6, x[6], use_ct)
153 ^ sbox(&S7, x[8], use_ct)
154 ^ sbox(&S8, x[9], use_ct)
155 ^ sbox(&S7, x[3], use_ct),
156 sbox(&S5, x[5], use_ct)
157 ^ sbox(&S6, x[4], use_ct)
158 ^ sbox(&S7, x[10], use_ct)
159 ^ sbox(&S8, x[11], use_ct)
160 ^ sbox(&S8, x[7], use_ct),
161 ]
162}
163
164fn extract_z_b(z: &[u8; 16], use_ct: bool) -> [u32; 4] {
165 [
166 sbox(&S5, z[3], use_ct)
167 ^ sbox(&S6, z[2], use_ct)
168 ^ sbox(&S7, z[12], use_ct)
169 ^ sbox(&S8, z[13], use_ct)
170 ^ sbox(&S5, z[9], use_ct),
171 sbox(&S5, z[1], use_ct)
172 ^ sbox(&S6, z[0], use_ct)
173 ^ sbox(&S7, z[14], use_ct)
174 ^ sbox(&S8, z[15], use_ct)
175 ^ sbox(&S6, z[12], use_ct),
176 sbox(&S5, z[7], use_ct)
177 ^ sbox(&S6, z[6], use_ct)
178 ^ sbox(&S7, z[8], use_ct)
179 ^ sbox(&S8, z[9], use_ct)
180 ^ sbox(&S7, z[2], use_ct),
181 sbox(&S5, z[5], use_ct)
182 ^ sbox(&S6, z[4], use_ct)
183 ^ sbox(&S7, z[10], use_ct)
184 ^ sbox(&S8, z[11], use_ct)
185 ^ sbox(&S8, z[6], use_ct),
186 ]
187}
188
189fn extract_x_b(x: &[u8; 16], use_ct: bool) -> [u32; 4] {
190 [
191 sbox(&S5, x[8], use_ct)
192 ^ sbox(&S6, x[9], use_ct)
193 ^ sbox(&S7, x[7], use_ct)
194 ^ sbox(&S8, x[6], use_ct)
195 ^ sbox(&S5, x[3], use_ct),
196 sbox(&S5, x[10], use_ct)
197 ^ sbox(&S6, x[11], use_ct)
198 ^ sbox(&S7, x[5], use_ct)
199 ^ sbox(&S8, x[4], use_ct)
200 ^ sbox(&S6, x[7], use_ct),
201 sbox(&S5, x[12], use_ct)
202 ^ sbox(&S6, x[13], use_ct)
203 ^ sbox(&S7, x[3], use_ct)
204 ^ sbox(&S8, x[2], use_ct)
205 ^ sbox(&S7, x[8], use_ct),
206 sbox(&S5, x[14], use_ct)
207 ^ sbox(&S6, x[15], use_ct)
208 ^ sbox(&S7, x[1], use_ct)
209 ^ sbox(&S8, x[0], use_ct)
210 ^ sbox(&S8, x[13], use_ct),
211 ]
212}
213
214fn round_f(data: u32, km: u32, kr: u8, round: usize, use_ct: bool) -> u32 {
215 let i = match round % 3 {
218 0 => km.wrapping_add(data).rotate_left(u32::from(kr)),
219 1 => (km ^ data).rotate_left(u32::from(kr)),
220 _ => km.wrapping_sub(data).rotate_left(u32::from(kr)),
221 };
222 let [ia, ib, ic, id] = i.to_be_bytes();
223 match round % 3 {
224 0 => (sbox(&S1, ia, use_ct) ^ sbox(&S2, ib, use_ct))
225 .wrapping_sub(sbox(&S3, ic, use_ct))
226 .wrapping_add(sbox(&S4, id, use_ct)),
227 1 => {
228 (sbox(&S1, ia, use_ct).wrapping_sub(sbox(&S2, ib, use_ct)))
229 .wrapping_add(sbox(&S3, ic, use_ct))
230 ^ sbox(&S4, id, use_ct)
231 }
232 _ => ((sbox(&S1, ia, use_ct).wrapping_add(sbox(&S2, ib, use_ct))) ^ sbox(&S3, ic, use_ct))
233 .wrapping_sub(sbox(&S4, id, use_ct)),
234 }
235}
236
237#[derive(Clone, Copy)]
238struct Subkeys {
239 km: [u32; 16],
240 kr: [u8; 16],
241 rounds: usize,
242}
243
244fn expand_subkeys(key: &[u8], use_ct: bool) -> Subkeys {
245 assert!(
246 (5..=16).contains(&key.len()),
247 "CAST-128 key length must be 5..=16 bytes, got {}",
248 key.len()
249 );
250
251 let mut x = [0u8; 16];
252 x[..key.len()].copy_from_slice(key);
253 let rounds = if key.len() * 8 <= 80 { 12 } else { 16 };
256
257 let mut k = [0u32; 32];
258 let mut offset = 0usize;
259
260 for _ in 0..2 {
261 let z = x_to_z(&x, use_ct);
264 k[offset..offset + 4].copy_from_slice(&extract_z_a(&z, use_ct));
265 x = z_to_x(&z, use_ct);
266 k[offset + 4..offset + 8].copy_from_slice(&extract_x_a(&x, use_ct));
267 let z = x_to_z(&x, use_ct);
268 k[offset + 8..offset + 12].copy_from_slice(&extract_z_b(&z, use_ct));
269 x = z_to_x(&z, use_ct);
270 k[offset + 12..offset + 16].copy_from_slice(&extract_x_b(&x, use_ct));
271 offset += 16;
272 }
273
274 let mut km = [0u32; 16];
275 let mut kr = [0u8; 16];
276 let mut i = 0usize;
277 while i < 16 {
278 km[i] = k[i];
279 kr[i] = (k[16 + i] & 0x1f) as u8;
280 i += 1;
281 }
282
283 Subkeys { km, kr, rounds }
284}
285
286fn cast_encrypt(block: [u8; 8], subkeys: &Subkeys, use_ct: bool) -> [u8; 8] {
287 let mut l = u32::from_be_bytes(block[0..4].try_into().unwrap());
288 let mut r = u32::from_be_bytes(block[4..8].try_into().unwrap());
289
290 let mut i = 0usize;
291 while i < subkeys.rounds {
292 let new_l = r;
295 let new_r = l ^ round_f(r, subkeys.km[i], subkeys.kr[i], i, use_ct);
296 l = new_l;
297 r = new_r;
298 i += 1;
299 }
300
301 let mut out = [0u8; 8];
302 out[0..4].copy_from_slice(&r.to_be_bytes());
303 out[4..8].copy_from_slice(&l.to_be_bytes());
304 out
305}
306
307fn cast_decrypt(block: [u8; 8], subkeys: &Subkeys, use_ct: bool) -> [u8; 8] {
308 let mut l = u32::from_be_bytes(block[0..4].try_into().unwrap());
309 let mut r = u32::from_be_bytes(block[4..8].try_into().unwrap());
310
311 let mut idx = subkeys.rounds;
312 while idx > 0 {
313 idx -= 1;
314 let new_l = r;
317 let new_r = l ^ round_f(r, subkeys.km[idx], subkeys.kr[idx], idx, use_ct);
318 l = new_l;
319 r = new_r;
320 }
321
322 let mut out = [0u8; 8];
323 out[0..4].copy_from_slice(&r.to_be_bytes());
324 out[4..8].copy_from_slice(&l.to_be_bytes());
325 out
326}
327
328pub struct Cast128 {
329 subkeys: Subkeys,
330}
331
332impl Cast128 {
333 #[must_use]
334 pub fn new(key: &[u8; 16]) -> Self {
335 Self {
336 subkeys: expand_subkeys(key, false),
337 }
338 }
339
340 #[must_use]
341 pub fn with_key_bytes(key: &[u8]) -> Self {
342 Self {
343 subkeys: expand_subkeys(key, false),
344 }
345 }
346
347 pub fn with_key_bytes_wiping(key: &mut [u8]) -> Self {
348 let out = Self::with_key_bytes(key);
349 zeroize_slice(key);
350 out
351 }
352
353 pub fn new_wiping(key: &mut [u8; 16]) -> Self {
354 let out = Self::new(key);
355 zeroize_slice(key);
356 out
357 }
358
359 #[must_use]
360 pub fn encrypt_block(&self, block: &[u8; 8]) -> [u8; 8] {
361 cast_encrypt(*block, &self.subkeys, false)
362 }
363
364 #[must_use]
365 pub fn decrypt_block(&self, block: &[u8; 8]) -> [u8; 8] {
366 cast_decrypt(*block, &self.subkeys, false)
367 }
368}
369
370impl BlockCipher for Cast128 {
371 const BLOCK_LEN: usize = 8;
372
373 fn encrypt(&self, block: &mut [u8]) {
374 let arr: &[u8; 8] = (&*block).try_into().expect("wrong block length");
375 let ct = self.encrypt_block(arr);
376 block.copy_from_slice(&ct);
377 }
378
379 fn decrypt(&self, block: &mut [u8]) {
380 let arr: &[u8; 8] = (&*block).try_into().expect("wrong block length");
381 let pt = self.decrypt_block(arr);
382 block.copy_from_slice(&pt);
383 }
384}
385
386impl Drop for Cast128 {
387 fn drop(&mut self) {
388 zeroize_slice(&mut self.subkeys.km);
389 zeroize_slice(&mut self.subkeys.kr);
390 }
391}
392
393pub struct Cast128Ct {
394 subkeys: Subkeys,
395}
396
397impl Cast128Ct {
398 #[must_use]
399 pub fn new(key: &[u8; 16]) -> Self {
400 Self {
401 subkeys: expand_subkeys(key, true),
402 }
403 }
404
405 #[must_use]
406 pub fn with_key_bytes(key: &[u8]) -> Self {
407 Self {
408 subkeys: expand_subkeys(key, true),
409 }
410 }
411
412 pub fn with_key_bytes_wiping(key: &mut [u8]) -> Self {
413 let out = Self::with_key_bytes(key);
414 zeroize_slice(key);
415 out
416 }
417
418 pub fn new_wiping(key: &mut [u8; 16]) -> Self {
419 let out = Self::new(key);
420 zeroize_slice(key);
421 out
422 }
423
424 #[must_use]
425 pub fn encrypt_block(&self, block: &[u8; 8]) -> [u8; 8] {
426 cast_encrypt(*block, &self.subkeys, true)
427 }
428
429 #[must_use]
430 pub fn decrypt_block(&self, block: &[u8; 8]) -> [u8; 8] {
431 cast_decrypt(*block, &self.subkeys, true)
432 }
433}
434
435impl BlockCipher for Cast128Ct {
436 const BLOCK_LEN: usize = 8;
437
438 fn encrypt(&self, block: &mut [u8]) {
439 let arr: &[u8; 8] = (&*block).try_into().expect("wrong block length");
440 let ct = self.encrypt_block(arr);
441 block.copy_from_slice(&ct);
442 }
443
444 fn decrypt(&self, block: &mut [u8]) {
445 let arr: &[u8; 8] = (&*block).try_into().expect("wrong block length");
446 let pt = self.decrypt_block(arr);
447 block.copy_from_slice(&pt);
448 }
449}
450
451impl Drop for Cast128Ct {
452 fn drop(&mut self) {
453 zeroize_slice(&mut self.subkeys.km);
454 zeroize_slice(&mut self.subkeys.kr);
455 }
456}
457
458pub type Cast5 = Cast128;
459pub type Cast5Ct = Cast128Ct;
460
461#[cfg(test)]
462mod tests {
463 use super::*;
464
465 fn decode_hex(s: &str) -> Vec<u8> {
466 assert_eq!(s.len() % 2, 0);
467 let mut out = Vec::with_capacity(s.len() / 2);
468 let bytes = s.as_bytes();
469 let mut i = 0usize;
470 while i < bytes.len() {
471 let hi = (bytes[i] as char).to_digit(16).unwrap();
472 let lo = (bytes[i + 1] as char).to_digit(16).unwrap();
473 out.push(u8::try_from((hi << 4) | lo).expect("decoded hex byte fits in u8"));
474 i += 2;
475 }
476 out
477 }
478
479 #[test]
480 fn cast128_128bit_kat() {
481 let key: [u8; 16] = decode_hex("0123456712345678234567893456789A")
482 .try_into()
483 .unwrap();
484 let pt: [u8; 8] = decode_hex("0123456789ABCDEF").try_into().unwrap();
485 let ct: [u8; 8] = decode_hex("238B4FE5847E44B2").try_into().unwrap();
486 let cipher = Cast128::new(&key);
487 assert_eq!(cipher.encrypt_block(&pt), ct);
488 assert_eq!(cipher.decrypt_block(&ct), pt);
489 let cipher_ct = Cast128Ct::new(&key);
490 assert_eq!(cipher_ct.encrypt_block(&pt), ct);
491 assert_eq!(cipher_ct.decrypt_block(&ct), pt);
492 }
493
494 #[test]
495 fn cast128_80bit_kat() {
496 let key = decode_hex("01234567123456782345");
497 let pt: [u8; 8] = decode_hex("0123456789ABCDEF").try_into().unwrap();
498 let ct: [u8; 8] = decode_hex("EB6A711A2C02271B").try_into().unwrap();
499 let cipher = Cast128::with_key_bytes(&key);
500 assert_eq!(cipher.encrypt_block(&pt), ct);
501 assert_eq!(cipher.decrypt_block(&ct), pt);
502 let cipher_ct = Cast128Ct::with_key_bytes(&key);
503 assert_eq!(cipher_ct.encrypt_block(&pt), ct);
504 assert_eq!(cipher_ct.decrypt_block(&ct), pt);
505 }
506
507 #[test]
508 fn cast128_40bit_kat() {
509 let key = decode_hex("0123456712");
510 let pt: [u8; 8] = decode_hex("0123456789ABCDEF").try_into().unwrap();
511 let ct: [u8; 8] = decode_hex("7AC816D16E9B302E").try_into().unwrap();
512 let cipher = Cast128::with_key_bytes(&key);
513 assert_eq!(cipher.encrypt_block(&pt), ct);
514 assert_eq!(cipher.decrypt_block(&ct), pt);
515 let cipher_ct = Cast128Ct::with_key_bytes(&key);
516 assert_eq!(cipher_ct.encrypt_block(&pt), ct);
517 assert_eq!(cipher_ct.decrypt_block(&ct), pt);
518 }
519
520 #[test]
521 fn cast128_matches_openssl_ecb() {
522 let key_hex = "0123456712345678234567893456789a";
523 let pt_hex = "0123456789abcdef";
524 let pt: [u8; 8] = decode_hex(pt_hex).try_into().unwrap();
525 let Some(expected) = crate::test_utils::run_openssl_enc("-cast5-ecb", key_hex, None, &pt) else {
526 return;
527 };
528
529 let key: [u8; 16] = decode_hex(key_hex).try_into().unwrap();
530 let cipher = Cast128::new(&key);
531 assert_eq!(cipher.encrypt_block(&pt).as_slice(), expected.as_slice());
532 }
533}