1use crate::BlockCipher;
24
25const IP: [u8; 64] = [
31 58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4, 62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48, 40, 32,
32 24, 16, 8, 57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3, 61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47,
33 39, 31, 23, 15, 7,
34];
35
36const FP: [u8; 64] = [
38 40, 8, 48, 16, 56, 24, 64, 32, 39, 7, 47, 15, 55, 23, 63, 31, 38, 6, 46, 14, 54, 22, 62, 30, 37, 5, 45, 13, 53, 21,
39 61, 29, 36, 4, 44, 12, 52, 20, 60, 28, 35, 3, 43, 11, 51, 19, 59, 27, 34, 2, 42, 10, 50, 18, 58, 26, 33, 1, 41, 9,
40 49, 17, 57, 25,
41];
42
43const E_PERM: [u8; 48] = [
45 32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9, 8, 9, 10, 11, 12, 13, 12, 13, 14, 15, 16, 17, 16, 17, 18, 19, 20, 21, 20, 21,
46 22, 23, 24, 25, 24, 25, 26, 27, 28, 29, 28, 29, 30, 31, 32, 1,
47];
48
49const P_PERM: [u8; 32] = [
51 16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10, 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4,
52 25,
53];
54
55const PC1: [u8; 56] = [
57 57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36, 63, 55,
58 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4,
59];
60
61const PC2: [u8; 48] = [
63 14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10, 23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2, 41, 52, 31, 37, 47, 55, 30,
64 40, 51, 45, 33, 48, 44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32,
65];
66
67const KEY_SHIFTS: [u8; 16] = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1];
69
70const SBOXES: [[u8; 64]; 8] = [
72 [
74 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7, 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8, 4,
75 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0, 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13,
76 ],
77 [
79 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10, 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5, 0,
80 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15, 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9,
81 ],
82 [
84 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8, 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1, 13,
85 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7, 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12,
86 ],
87 [
89 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15, 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9, 10,
90 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4, 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14,
91 ],
92 [
94 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9, 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6, 4,
95 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14, 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3,
96 ],
97 [
99 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11, 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8, 9,
100 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6, 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13,
101 ],
102 [
104 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1, 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6, 1,
105 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2, 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12,
106 ],
107 [
109 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7, 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 2, 0, 14, 9, 11, 7,
110 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8, 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11,
111 ],
112];
113
114#[inline]
120fn bytes_to_u64(b: &[u8]) -> u64 {
121 ((b[0] as u64) << 56)
122 | ((b[1] as u64) << 48)
123 | ((b[2] as u64) << 40)
124 | ((b[3] as u64) << 32)
125 | ((b[4] as u64) << 24)
126 | ((b[5] as u64) << 16)
127 | ((b[6] as u64) << 8)
128 | (b[7] as u64)
129}
130
131#[inline]
133fn u64_to_bytes(v: u64) -> [u8; 8] {
134 v.to_be_bytes()
135}
136
137#[inline]
139fn get_bit64(val: u64, pos: u8) -> u64 {
140 (val >> (64 - pos as u32)) & 1
141}
142
143fn permute64(input: u64, table: &[u8]) -> u64 {
148 let mut output: u64 = 0;
149 for (i, &pos) in table.iter().enumerate() {
150 let bit = get_bit64(input, pos);
151 output |= bit << (63 - i as u32);
152 }
153 output
154}
155
156pub struct Des {
162 subkeys: [u64; 16],
165}
166
167impl Des {
168 fn generate_subkeys(key: u64) -> [u64; 16] {
170 let pc1 = permute64(key, &PC1);
172
173 let mut c: u32 = (pc1 >> 36) as u32; let mut d: u32 = ((pc1 >> 8) as u32) & 0x0FFFFFFF; let mut subkeys = [0u64; 16];
178
179 for round in 0..16 {
180 let shift = KEY_SHIFTS[round] as u32;
181 c = ((c << shift) | (c >> (28 - shift))) & 0x0FFFFFFF;
183 d = ((d << shift) | (d >> (28 - shift))) & 0x0FFFFFFF;
184
185 let cd: u64 = ((c as u64) << 36) | ((d as u64) << 8);
187
188 subkeys[round] = permute64(cd, &PC2);
190 }
191
192 subkeys
193 }
194
195 fn feistel(r: u32, subkey: u64) -> u32 {
200 let r64 = (r as u64) << 32;
203 let expanded = permute64(r64, &E_PERM); let xored = expanded ^ subkey;
207
208 let mut sbox_result: u32 = 0;
210 for i in 0..8 {
211 let shift = 58 - (i * 6); let six_bits = ((xored >> shift) & 0x3F) as u8;
215
216 let row = ((six_bits & 0x20) >> 4) | (six_bits & 0x01); let col = (six_bits >> 1) & 0x0F;
219 let val = SBOXES[i as usize][(row as usize) * 16 + (col as usize)];
220
221 sbox_result |= (val as u32) << (28 - i * 4);
223 }
224
225 let sbox64 = (sbox_result as u64) << 32;
227 let p_out = permute64(sbox64, &P_PERM);
228 (p_out >> 32) as u32
229 }
230
231 fn des_cipher(&self, input: u64, decrypt: bool) -> u64 {
233 let permuted = permute64(input, &IP);
235
236 let mut l: u32 = (permuted >> 32) as u32;
237 let mut r: u32 = permuted as u32;
238
239 for round in 0..16 {
241 let subkey_idx = if decrypt { 15 - round } else { round };
242 let f_out = Self::feistel(r, self.subkeys[subkey_idx]);
243
244 let new_r = l ^ f_out;
245 l = r;
246 r = new_r;
247 }
248
249 let pre_fp: u64 = ((r as u64) << 32) | (l as u64);
251 permute64(pre_fp, &FP)
252 }
253}
254
255impl BlockCipher for Des {
256 const BLOCK_LEN: usize = 8;
257 const KEY_LENS: &'static [usize] = &[8]; fn new(key: &[u8]) -> Self {
260 assert_eq!(key.len(), 8, "DES requires an 8-byte key");
261 Des {
262 subkeys: Self::generate_subkeys(bytes_to_u64(key)),
263 }
264 }
265
266 fn encrypt_block(&self, block: &mut [u8]) {
267 assert!(block.len() >= 8, "DES: block must be at least 8 bytes");
268 let input = bytes_to_u64(&block[..8]);
269 let output = self.des_cipher(input, false);
270 block[..8].copy_from_slice(&u64_to_bytes(output));
271 }
272
273 fn decrypt_block(&self, block: &mut [u8]) {
274 assert!(block.len() >= 8, "DES: block must be at least 8 bytes");
275 let input = bytes_to_u64(&block[..8]);
276 let output = self.des_cipher(input, true);
277 block[..8].copy_from_slice(&u64_to_bytes(output));
278 }
279}
280
281pub struct TripleDes {
290 k1: Des,
291 k2: Des,
292 k3: Des,
293}
294
295impl BlockCipher for TripleDes {
296 const BLOCK_LEN: usize = 8;
297 const KEY_LENS: &'static [usize] = &[24]; fn new(key: &[u8]) -> Self {
300 assert_eq!(key.len(), 24, "3DES requires a 24-byte key (3 x 8)");
301 TripleDes {
302 k1: Des::new(&key[0..8]),
303 k2: Des::new(&key[8..16]),
304 k3: Des::new(&key[16..24]),
305 }
306 }
307
308 fn encrypt_block(&self, block: &mut [u8]) {
309 self.k1.encrypt_block(block);
310 self.k2.decrypt_block(block);
311 self.k3.encrypt_block(block);
312 }
313
314 fn decrypt_block(&self, block: &mut [u8]) {
315 self.k3.decrypt_block(block);
316 self.k2.encrypt_block(block);
317 self.k1.decrypt_block(block);
318 }
319}
320
321#[cfg(test)]
326mod tests {
327 use super::*;
328
329 fn hex_to_bytes(s: &str) -> Vec<u8> {
330 (0..s.len())
331 .step_by(2)
332 .map(|i| u8::from_str_radix(&s[i..i + 2], 16).unwrap())
333 .collect()
334 }
335
336 #[test]
338 fn des_known_answer_tests() {
339 let k1 = Des::new(&hex_to_bytes("133457799BBCDFF1"));
341 let mut b1 = hex_to_bytes("0123456789ABCDEF");
342 k1.encrypt_block(&mut b1);
343 assert_eq!(b1, hex_to_bytes("85E813540F0AB405").as_slice());
344 k1.decrypt_block(&mut b1);
345 assert_eq!(b1, hex_to_bytes("0123456789ABCDEF").as_slice());
346
347 let k2 = Des::new(&hex_to_bytes("FEDCBA9876543210"));
349 let mut b2 = hex_to_bytes("0123456789ABCDEF");
350 k2.encrypt_block(&mut b2);
351 assert_eq!(b2, hex_to_bytes("ED39D950FA74BCC4").as_slice());
352 k2.decrypt_block(&mut b2);
353 assert_eq!(b2, hex_to_bytes("0123456789ABCDEF").as_slice());
354
355 let k3 = Des::new(&hex_to_bytes("0123456789ABCDEF"));
357 let mut b3 = [0u8; 8];
358 k3.encrypt_block(&mut b3);
359 assert_eq!(b3.to_vec(), hex_to_bytes("D5D44FF720683D0D"));
360
361 let mut b4 = hex_to_bytes("0123456789ABCDEF");
363 k3.encrypt_block(&mut b4);
364 assert_eq!(b4, hex_to_bytes("56CC09E7CFDC4CEF").as_slice());
365 }
366
367 #[test]
369 fn des_round_trip() {
370 let cipher = Des::new(&hex_to_bytes("0123456789ABCDEF"));
371 for pt_hex in &[
372 "0000000000000000",
373 "FFFFFFFFFFFFFFFF",
374 "4E6F772069732074",
375 "0123456789ABCDEF",
376 ] {
377 let pt = hex_to_bytes(pt_hex);
378 let mut block = pt.clone();
379 cipher.encrypt_block(&mut block);
380 assert_ne!(block, pt.as_slice(), "CT should differ from PT for {}", pt_hex);
381 cipher.decrypt_block(&mut block);
382 assert_eq!(block, pt.as_slice(), "round-trip failed for PT={}", pt_hex);
383 }
384 }
385
386 #[test]
388 fn triple_des_round_trip() {
389 let key = hex_to_bytes("0123456789ABCDEF23456789ABCDEF01456789ABCDEF0123");
390 let plaintext = hex_to_bytes("4E6F772069732074");
391
392 let cipher = TripleDes::new(&key);
393
394 let mut block = plaintext.clone();
395 cipher.encrypt_block(&mut block);
396 assert_ne!(block, plaintext.as_slice());
397
398 cipher.decrypt_block(&mut block);
399 assert_eq!(block, plaintext.as_slice());
400 }
401
402 #[test]
404 fn triple_des_ede_consistency() {
405 let key = hex_to_bytes("0123456789ABCDEF23456789ABCDEF01456789ABCDEF0123");
406 let plaintext = hex_to_bytes("4E6F772069732074");
407 let cipher = TripleDes::new(&key);
408
409 let mut block = plaintext.clone();
410 cipher.encrypt_block(&mut block);
411
412 let k1 = Des::new(&hex_to_bytes("0123456789ABCDEF"));
414 let k2 = Des::new(&hex_to_bytes("23456789ABCDEF01"));
415 let k3 = Des::new(&hex_to_bytes("456789ABCDEF0123"));
416
417 let mut manual = plaintext.clone();
418 k1.encrypt_block(&mut manual);
419 k2.decrypt_block(&mut manual);
420 k3.encrypt_block(&mut manual);
421
422 assert_eq!(block, manual.as_slice(), "3DES EDE mismatch");
423 }
424}