1#![no_std]
33#![doc(
34 html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg",
35 html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg"
36)]
37#![deny(unsafe_code)]
38#![cfg_attr(docsrs, feature(doc_cfg))]
39#![warn(missing_docs, rust_2018_idioms)]
40
41pub use cipher;
42
43mod consts;
44mod schedule;
45
46use cipher::{
47 AlgorithmName, Block, BlockCipherDecBackend, BlockCipherDecClosure, BlockCipherDecrypt,
48 BlockCipherEncBackend, BlockCipherEncClosure, BlockCipherEncrypt, BlockSizeUser, InOut,
49 InvalidLength, Key, KeyInit, KeySizeUser, ParBlocksSizeUser,
50 consts::{U1, U8, U16},
51};
52use core::fmt;
53
54#[cfg(feature = "zeroize")]
55use cipher::zeroize::{Zeroize, ZeroizeOnDrop};
56
57use consts::{S1, S2, S3, S4};
58use schedule::key_schedule;
59
60#[derive(Clone)]
62pub struct Cast5 {
63 masking: [u32; 16],
64 rotate: [u8; 16],
65 small_key: bool,
68}
69
70impl Cast5 {
71 fn init_state(key_len: usize) -> Cast5 {
72 let small_key = key_len <= 10;
73
74 Cast5 {
75 masking: [0u32; 16],
76 rotate: [0u8; 16],
77 small_key,
78 }
79 }
80
81 fn key_schedule(&mut self, key: &[u8]) {
84 let mut x = [
85 u32::from_be_bytes(key[0..4].try_into().unwrap()),
86 u32::from_be_bytes(key[4..8].try_into().unwrap()),
87 u32::from_be_bytes(key[8..12].try_into().unwrap()),
88 u32::from_be_bytes(key[12..16].try_into().unwrap()),
89 ];
90
91 let mut z = [0u32; 4];
92 let mut k = [0u32; 16];
93
94 key_schedule(&mut x, &mut z, &mut k);
95 self.masking[..].clone_from_slice(&k[..]);
96
97 key_schedule(&mut x, &mut z, &mut k);
98
99 for (i, ki) in k.iter().enumerate() {
100 self.rotate[i] = (ki & 0x1f) as u8;
101 }
102 }
103}
104
105macro_rules! f1 {
106 ($D:expr, $m:expr, $r:expr) => {{
107 let i = ($m.wrapping_add($D)).rotate_left(u32::from($r));
108 (S1[(i >> 24) as usize] ^ S2[((i >> 16) & 0xff) as usize])
109 .wrapping_sub(S3[((i >> 8) & 0xff) as usize])
110 .wrapping_add(S4[(i & 0xff) as usize])
111 }};
112}
113
114macro_rules! f2 {
115 ($D:expr, $m:expr, $r:expr) => {{
116 let i = ($m ^ $D).rotate_left(u32::from($r));
117 S1[(i >> 24) as usize]
118 .wrapping_sub(S2[((i >> 16) & 0xff) as usize])
119 .wrapping_add(S3[((i >> 8) & 0xff) as usize])
120 ^ S4[(i & 0xff) as usize]
121 }};
122}
123
124macro_rules! f3 {
125 ($D:expr, $m:expr, $r:expr) => {{
126 let i = ($m.wrapping_sub($D)).rotate_left(u32::from($r));
127 (S1[(i >> 24) as usize].wrapping_add(S2[((i >> 16) & 0xff) as usize])
128 ^ S3[((i >> 8) & 0xff) as usize])
129 .wrapping_sub(S4[(i & 0xff) as usize])
130 }};
131}
132
133impl KeySizeUser for Cast5 {
134 type KeySize = U16;
135}
136
137impl KeyInit for Cast5 {
138 fn new(key: &Key<Self>) -> Self {
139 Self::new_from_slice(key).unwrap()
140 }
141
142 fn new_from_slice(key: &[u8]) -> Result<Self, InvalidLength> {
143 if key.len() < 5 || key.len() > 16 {
145 return Err(InvalidLength);
146 }
147 let mut cast5 = Cast5::init_state(key.len());
148
149 if key.len() < 16 {
150 let mut padded_key = [0u8; 16];
152 padded_key[..key.len()].copy_from_slice(key);
153 cast5.key_schedule(&padded_key[..]);
154 } else {
155 cast5.key_schedule(key);
156 }
157 Ok(cast5)
158 }
159}
160
161impl BlockSizeUser for Cast5 {
162 type BlockSize = U8;
163}
164
165impl ParBlocksSizeUser for Cast5 {
166 type ParBlocksSize = U1;
167}
168
169impl BlockCipherEncrypt for Cast5 {
170 #[inline]
171 fn encrypt_with_backend(&self, f: impl BlockCipherEncClosure<BlockSize = Self::BlockSize>) {
172 f.call(self)
173 }
174}
175
176impl BlockCipherEncBackend for Cast5 {
177 #[inline]
178 fn encrypt_block(&self, mut block: InOut<'_, '_, Block<Self>>) {
179 let masking = self.masking;
180 let rotate = self.rotate;
181
182 let b = block.get_in();
185 let l = u32::from_be_bytes(b[0..4].try_into().unwrap());
186 let r = u32::from_be_bytes(b[4..8].try_into().unwrap());
187 let (l, r) = (r, l ^ f1!(r, masking[0], rotate[0]));
197 let (l, r) = (r, l ^ f2!(r, masking[1], rotate[1]));
198 let (l, r) = (r, l ^ f3!(r, masking[2], rotate[2]));
199 let (l, r) = (r, l ^ f1!(r, masking[3], rotate[3]));
200 let (l, r) = (r, l ^ f2!(r, masking[4], rotate[4]));
201 let (l, r) = (r, l ^ f3!(r, masking[5], rotate[5]));
202 let (l, r) = (r, l ^ f1!(r, masking[6], rotate[6]));
203 let (l, r) = (r, l ^ f2!(r, masking[7], rotate[7]));
204 let (l, r) = (r, l ^ f3!(r, masking[8], rotate[8]));
205 let (l, r) = (r, l ^ f1!(r, masking[9], rotate[9]));
206 let (l, r) = (r, l ^ f2!(r, masking[10], rotate[10]));
207 let (l, r) = (r, l ^ f3!(r, masking[11], rotate[11]));
208
209 let (l, r) = if self.small_key {
210 (l, r)
211 } else {
212 let (l, r) = (r, l ^ f1!(r, masking[12], rotate[12]));
214 let (l, r) = (r, l ^ f2!(r, masking[13], rotate[13]));
215 let (l, r) = (r, l ^ f3!(r, masking[14], rotate[14]));
216 (r, l ^ f1!(r, masking[15], rotate[15]))
217 };
218
219 let block = block.get_out();
222 block[0..4].copy_from_slice(&r.to_be_bytes());
223 block[4..8].copy_from_slice(&l.to_be_bytes());
224 }
225}
226
227impl BlockCipherDecrypt for Cast5 {
228 #[inline]
229 fn decrypt_with_backend(&self, f: impl BlockCipherDecClosure<BlockSize = Self::BlockSize>) {
230 f.call(self)
231 }
232}
233
234impl BlockCipherDecBackend for Cast5 {
235 #[inline]
236 fn decrypt_block(&self, mut block: InOut<'_, '_, Block<Self>>) {
237 let masking = self.masking;
238 let rotate = self.rotate;
239
240 let b = block.get_in();
241 let l = u32::from_be_bytes(b[0..4].try_into().unwrap());
242 let r = u32::from_be_bytes(b[4..8].try_into().unwrap());
243
244 let (l, r) = if self.small_key {
245 (l, r)
246 } else {
247 let (l, r) = (r, l ^ f1!(r, masking[15], rotate[15]));
248 let (l, r) = (r, l ^ f3!(r, masking[14], rotate[14]));
249 let (l, r) = (r, l ^ f2!(r, masking[13], rotate[13]));
250 (r, l ^ f1!(r, masking[12], rotate[12]))
251 };
252
253 let (l, r) = (r, l ^ f3!(r, masking[11], rotate[11]));
254 let (l, r) = (r, l ^ f2!(r, masking[10], rotate[10]));
255 let (l, r) = (r, l ^ f1!(r, masking[9], rotate[9]));
256 let (l, r) = (r, l ^ f3!(r, masking[8], rotate[8]));
257 let (l, r) = (r, l ^ f2!(r, masking[7], rotate[7]));
258 let (l, r) = (r, l ^ f1!(r, masking[6], rotate[6]));
259 let (l, r) = (r, l ^ f3!(r, masking[5], rotate[5]));
260 let (l, r) = (r, l ^ f2!(r, masking[4], rotate[4]));
261 let (l, r) = (r, l ^ f1!(r, masking[3], rotate[3]));
262 let (l, r) = (r, l ^ f3!(r, masking[2], rotate[2]));
263 let (l, r) = (r, l ^ f2!(r, masking[1], rotate[1]));
264 let (l, r) = (r, l ^ f1!(r, masking[0], rotate[0]));
265
266 let block = block.get_out();
267 block[0..4].copy_from_slice(&r.to_be_bytes());
268 block[4..8].copy_from_slice(&l.to_be_bytes());
269 }
270}
271
272impl fmt::Debug for Cast5 {
273 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
274 f.write_str("Cast5 { ... }")
275 }
276}
277
278impl AlgorithmName for Cast5 {
279 fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
280 f.write_str("Cast5")
281 }
282}
283
284impl Drop for Cast5 {
285 fn drop(&mut self) {
286 #[cfg(feature = "zeroize")]
287 {
288 self.masking.zeroize();
289 self.rotate.zeroize();
290 self.small_key.zeroize();
291 }
292 }
293}
294
295#[cfg(feature = "zeroize")]
296impl ZeroizeOnDrop for Cast5 {}