Skip to main content

c/
des.rs

1// DES, used by crypt(3) with traditional salts and by encrypt(3)/setkey(3).
2// Straightforward table-driven implementation of FIPS 46-3.
3
4const IP: [u8; 64] = [
5    58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4,
6    62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8,
7    57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3,
8    61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7,
9];
10
11const FP: [u8; 64] = [
12    40, 8, 48, 16, 56, 24, 64, 32, 39, 7, 47, 15, 55, 23, 63, 31,
13    38, 6, 46, 14, 54, 22, 62, 30, 37, 5, 45, 13, 53, 21, 61, 29,
14    36, 4, 44, 12, 52, 20, 60, 28, 35, 3, 43, 11, 51, 19, 59, 27,
15    34, 2, 42, 10, 50, 18, 58, 26, 33, 1, 41, 9, 49, 17, 57, 25,
16];
17
18const E: [u8; 48] = [
19    32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9, 8, 9, 10, 11, 12, 13,
20    12, 13, 14, 15, 16, 17, 16, 17, 18, 19, 20, 21, 20, 21, 22, 23, 24, 25,
21    24, 25, 26, 27, 28, 29, 28, 29, 30, 31, 32, 1,
22];
23
24const P: [u8; 32] = [
25    16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10,
26    2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25,
27];
28
29const PC1: [u8; 56] = [
30    57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18,
31    10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36,
32    63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22,
33    14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4,
34];
35
36const PC2: [u8; 48] = [
37    14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10,
38    23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2,
39    41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48,
40    44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32,
41];
42
43const SHIFTS: [u8; 16] = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1];
44
45const SBOX: [[u8; 64]; 8] = [
46    [
47        14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7,
48        0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8,
49        4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0,
50        15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13,
51    ],
52    [
53        15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10,
54        3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5,
55        0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15,
56        13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9,
57    ],
58    [
59        10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8,
60        13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1,
61        13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7,
62        1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12,
63    ],
64    [
65        7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15,
66        13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9,
67        10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4,
68        3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14,
69    ],
70    [
71        2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9,
72        14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6,
73        4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14,
74        11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3,
75    ],
76    [
77        12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11,
78        10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8,
79        9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6,
80        4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13,
81    ],
82    [
83        4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1,
84        13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6,
85        1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2,
86        6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12,
87    ],
88    [
89        13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7,
90        1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2,
91        7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8,
92        2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11,
93    ],
94];
95
96#[derive(Copy, Clone)]
97pub struct DesKey {
98    subkeys: [u64; 16],
99}
100
101fn permute(input: u64, in_bits: u32, table: &[u8]) -> u64 {
102    let mut out = 0u64;
103    for (i, &p) in table.iter().enumerate() {
104        let bit = (input >> (in_bits - p as u32)) & 1;
105        out |= bit << (table.len() - 1 - i);
106    }
107    out
108}
109
110fn sbox_substitute(x: u64) -> u32 {
111    let mut out = 0u32;
112    for i in 0..8 {
113        let six = ((x >> (42 - 6 * i)) & 0x3f) as usize;
114        let row = ((six & 0x20) >> 4) | (six & 1);
115        let col = (six >> 1) & 0x0f;
116        out = (out << 4) | SBOX[i][row * 16 + col] as u32;
117    }
118    out
119}
120
121pub fn des_setkey(key: &[u8; 8]) -> DesKey {
122    let mut k = 0u64;
123    for &b in key.iter() { k = (k << 8) | b as u64; }
124    let pc1 = permute(k, 64, &PC1);
125    let mut c = ((pc1 >> 28) & 0x0fff_ffff) as u32;
126    let mut d = (pc1 & 0x0fff_ffff) as u32;
127    let mut subkeys = [0u64; 16];
128    for r in 0..16 {
129        let s = SHIFTS[r] as u32;
130        c = ((c << s) | (c >> (28 - s))) & 0x0fff_ffff;
131        d = ((d << s) | (d >> (28 - s))) & 0x0fff_ffff;
132        let cd = ((c as u64) << 28) | d as u64;
133        subkeys[r] = permute(cd, 56, &PC2);
134    }
135    DesKey { subkeys }
136}
137
138/// Raw DES on one block; `saltbits` implements the traditional crypt(3)
139/// bit swapping in the E expansion.
140pub fn des_do(l_in: u32, r_in: u32, count: u32, saltbits: u32, key: &DesKey) -> (u32, u32) {
141    let block = ((l_in as u64) << 32) | r_in as u64;
142    let ip = permute(block, 64, &IP);
143    let mut l = (ip >> 32) as u32;
144    let mut r = ip as u32;
145    for _ in 0..count {
146        for round in 0..16 {
147            let mut e = permute(r as u64, 32, &E);
148            if saltbits != 0 {
149                let hi = (e >> 24) as u32;
150                let lo = (e & 0x00ff_ffff) as u32;
151                let f = (hi ^ lo) & saltbits;
152                e = (((hi ^ f) as u64) << 24) | (lo ^ f) as u64;
153            }
154            let x = e ^ key.subkeys[round];
155            let s = sbox_substitute(x) as u64;
156            let p = permute(s, 32, &P) as u32;
157            let nl = r;
158            let nr = l ^ p;
159            l = nl;
160            r = nr;
161        }
162        // (L16, R16) -> (R16, L16) before the next encryption or the FP.
163        core::mem::swap(&mut l, &mut r);
164    }
165    let pre = ((l as u64) << 32) | r as u64;
166    let fp = permute(pre, 64, &FP);
167    ((fp >> 32) as u32, fp as u32)
168}
169
170pub fn des_cipher_block(key: &DesKey, input: &[u8; 8], count: u32, saltbits: u32) -> [u8; 8] {
171    let l = u32::from_be_bytes([input[0], input[1], input[2], input[3]]);
172    let r = u32::from_be_bytes([input[4], input[5], input[6], input[7]]);
173    let (lo, ro) = des_do(l, r, count, saltbits, key);
174    let mut out = [0u8; 8];
175    out[0..4].copy_from_slice(&lo.to_be_bytes());
176    out[4..8].copy_from_slice(&ro.to_be_bytes());
177    out
178}
179
180pub fn setup_salt(salt: u32) -> u32 {
181    let mut saltbits = 0u32;
182    let mut saltbit = 1u32;
183    let mut obit = 0x0080_0000u32;
184    for _ in 0..24 {
185        if salt & saltbit != 0 { saltbits |= obit; }
186        saltbit <<= 1;
187        obit >>= 1;
188    }
189    saltbits
190}
191
192fn ascii_to_bin(ch: u8) -> u32 {
193    let sch = ch as i8 as i32;
194    let mut retval = sch - '.' as i32;
195    if sch >= 'A' as i32 {
196        retval = sch - ('A' as i32 - 12);
197        if sch >= 'a' as i32 {
198            retval = sch - ('a' as i32 - 38);
199        }
200    }
201    (retval & 0x3f) as u32
202}
203
204const ASCII64: &[u8; 64] = b"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
205
206fn ascii_is_unsafe(ch: u8) -> bool {
207    ch == 0 || ch == b'\n' || ch == b':'
208}
209
210fn read_setting_char(s: *const u8, i: usize) -> u8 {
211    unsafe { *s.add(i) }
212}
213
214/// Traditional DES crypt. Returns the number of bytes written (excluding NUL)
215/// or 0 on failure.
216pub unsafe fn crypt_des(key: *const u8, setting: *const u8, output: *mut u8) -> usize {
217    if key.is_null() || setting.is_null() || output.is_null() { return 0; }
218    let mut keybuf = [0u8; 8];
219    let mut kp = key;
220    for i in 0..8 {
221        keybuf[i] = (*kp) << 1;
222        if *kp != 0 { kp = kp.add(1); }
223    }
224    let mut ekey = des_setkey(&keybuf);
225
226    let count: u32;
227    let salt: u32;
228    let mut outpos: usize;
229    if *setting == b'_' {
230        let mut c = 0u32;
231        for i in 1..5 {
232            let ch = read_setting_char(setting, i);
233            let v = ascii_to_bin(ch);
234            if ASCII64[v as usize] != ch { return 0; }
235            c |= v << ((i - 1) * 6);
236        }
237        if c == 0 { return 0; }
238        count = c;
239        let mut s = 0u32;
240        for i in 5..9 {
241            let ch = read_setting_char(setting, i);
242            let v = ascii_to_bin(ch);
243            if ASCII64[v as usize] != ch { return 0; }
244            s |= v << ((i - 5) * 6);
245        }
246        salt = s;
247        while *kp != 0 {
248            keybuf = des_cipher_block(&ekey, &keybuf, 1, 0);
249            for i in 0..8 {
250                if *kp == 0 { break; }
251                keybuf[i] ^= (*kp) << 1;
252                kp = kp.add(1);
253            }
254            ekey = des_setkey(&keybuf);
255        }
256        for i in 0..9 { *output.add(i) = *setting.add(i); }
257        *output.add(9) = 0;
258        outpos = 9;
259    } else {
260        count = 25;
261        let s0 = *setting;
262        let s1 = *setting.add(1);
263        if s1 == 0 || ascii_is_unsafe(s0) || ascii_is_unsafe(s1) { return 0; }
264        salt = (ascii_to_bin(s1) << 6) | ascii_to_bin(s0);
265        *output = s0;
266        *output.add(1) = s1;
267        outpos = 2;
268    }
269
270    let (r0, r1) = des_do(0, 0, count, setup_salt(salt), &ekey);
271
272    let mut l = r0 >> 8;
273    *output.add(outpos) = ASCII64[((l >> 18) & 0x3f) as usize]; outpos += 1;
274    *output.add(outpos) = ASCII64[((l >> 12) & 0x3f) as usize]; outpos += 1;
275    *output.add(outpos) = ASCII64[((l >> 6) & 0x3f) as usize]; outpos += 1;
276    *output.add(outpos) = ASCII64[(l & 0x3f) as usize]; outpos += 1;
277    l = (r0 << 16) | ((r1 >> 16) & 0xffff);
278    *output.add(outpos) = ASCII64[((l >> 18) & 0x3f) as usize]; outpos += 1;
279    *output.add(outpos) = ASCII64[((l >> 12) & 0x3f) as usize]; outpos += 1;
280    *output.add(outpos) = ASCII64[((l >> 6) & 0x3f) as usize]; outpos += 1;
281    *output.add(outpos) = ASCII64[(l & 0x3f) as usize]; outpos += 1;
282    l = r1 << 2;
283    *output.add(outpos) = ASCII64[((l >> 12) & 0x3f) as usize]; outpos += 1;
284    *output.add(outpos) = ASCII64[((l >> 6) & 0x3f) as usize]; outpos += 1;
285    *output.add(outpos) = ASCII64[(l & 0x3f) as usize]; outpos += 1;
286    *output.add(outpos) = 0;
287    outpos
288}
289
290static mut ENCRYPT_KEY: DesKey = DesKey { subkeys: [0; 16] };
291
292#[no_mangle]
293pub unsafe extern "C" fn setkey(key: *const c_char) {
294    if key.is_null() { return; }
295    let mut bkey = [0u8; 8];
296    let mut kp = key as *const u8;
297    for i in 0..8 {
298        let mut v = 0u8;
299        for j in (0..8).rev() {
300            v |= ((*kp as u8) & 1) << j;
301            kp = kp.add(1);
302        }
303        bkey[i] = v;
304    }
305    ENCRYPT_KEY = des_setkey(&bkey);
306}
307
308#[no_mangle]
309pub unsafe extern "C" fn encrypt(block: *mut c_char, edflag: c_int) {
310    if block.is_null() { return; }
311    let mut b = [0u32; 2];
312    let mut p = block as *const u8;
313    for i in 0..2 {
314        let mut v = 0u32;
315        for j in (0..32).rev() {
316            v |= ((*p & 1) as u32) << j;
317            p = p.add(1);
318        }
319        b[i] = v;
320    }
321    let mut key = ENCRYPT_KEY;
322    if edflag != 0 {
323        let mut rev = [0u64; 16];
324        for i in 0..16 { rev[i] = ENCRYPT_KEY.subkeys[15 - i]; }
325        key = DesKey { subkeys: rev };
326    }
327    let (lo, ro) = des_do(b[0], b[1], 1, 0, &key);
328    b[0] = lo;
329    b[1] = ro;
330    let mut q = block as *mut u8;
331    for i in 0..2 {
332        for j in (0..32).rev() {
333            *q = ((b[i] >> j) & 1) as u8;
334            q = q.add(1);
335        }
336    }
337}