blob: b5bffa441daa25858ac43489ddf8f3dcc0850ab2 [file] [log] [blame]
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00001/*
2 * This is D3DES (V5.09) by Richard Outerbridge with the double and
3 * triple-length support removed for use in VNC. Also the bytebit[] array
4 * has been reversed so that the most significant bit in each byte of the
5 * key is ignored, not the least significant.
6 *
7 * These changes are:
8 * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
9 *
10 * This software is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 */
14
15/* D3DES (V5.09) -
16 *
17 * A portable, public domain, version of the Data Encryption Standard.
18 *
19 * Written with Symantec's THINK (Lightspeed) C by Richard Outerbridge.
20 * Thanks to: Dan Hoey for his excellent Initial and Inverse permutation
21 * code; Jim Gillogly & Phil Karn for the DES key schedule code; Dennis
22 * Ferguson, Eric Young and Dana How for comparing notes; and Ray Lau,
23 * for humouring me on.
24 *
25 * Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge.
26 * (GEnie : OUTER; CIS : [71755,204]) Graven Imagery, 1992.
27 */
28
29#include "d3des.h"
30
31static void scrunch(unsigned char *, unsigned long *);
32static void unscrun(unsigned long *, unsigned char *);
33static void desfunc(unsigned long *, unsigned long *);
34static void cookey(unsigned long *);
35
36static unsigned long KnL[32] = { 0L };
37
38static unsigned short bytebit[8] = {
39 01, 02, 04, 010, 020, 040, 0100, 0200 };
40
41static unsigned long bigbyte[24] = {
42 0x800000L, 0x400000L, 0x200000L, 0x100000L,
43 0x80000L, 0x40000L, 0x20000L, 0x10000L,
44 0x8000L, 0x4000L, 0x2000L, 0x1000L,
45 0x800L, 0x400L, 0x200L, 0x100L,
46 0x80L, 0x40L, 0x20L, 0x10L,
47 0x8L, 0x4L, 0x2L, 0x1L };
48
49/* Use the key schedule specified in the Standard (ANSI X3.92-1981). */
50
51static unsigned char pc1[56] = {
52 56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17,
53 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35,
54 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21,
55 13, 5, 60, 52, 44, 36, 28, 20, 12, 4, 27, 19, 11, 3 };
56
57static unsigned char totrot[16] = {
58 1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28 };
59
60static unsigned char pc2[48] = {
61 13, 16, 10, 23, 0, 4, 2, 27, 14, 5, 20, 9,
62 22, 18, 11, 3, 25, 7, 15, 6, 26, 19, 12, 1,
63 40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47,
64 43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31 };
65
Pierre Ossmanb3af44d2023-08-15 11:24:11 +020066void deskey(unsigned char *key, int edf) /* Thanks to James Gillogly & Phil Karn! */
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000067{
68 register int i, j, l, m, n;
69 unsigned char pc1m[56], pcr[56];
70 unsigned long kn[32];
71
72 for ( j = 0; j < 56; j++ ) {
73 l = pc1[j];
74 m = l & 07;
75 pc1m[j] = (key[l >> 3] & bytebit[m]) ? 1 : 0;
76 }
77 for( i = 0; i < 16; i++ ) {
78 if( edf == DE1 ) m = (15 - i) << 1;
79 else m = i << 1;
80 n = m + 1;
81 kn[m] = kn[n] = 0L;
82 for( j = 0; j < 28; j++ ) {
83 l = j + totrot[i];
84 if( l < 28 ) pcr[j] = pc1m[l];
85 else pcr[j] = pc1m[l - 28];
86 }
87 for( j = 28; j < 56; j++ ) {
88 l = j + totrot[i];
89 if( l < 56 ) pcr[j] = pc1m[l];
90 else pcr[j] = pc1m[l - 28];
91 }
92 for( j = 0; j < 24; j++ ) {
93 if( pcr[pc2[j]] ) kn[m] |= bigbyte[j];
94 if( pcr[pc2[j+24]] ) kn[n] |= bigbyte[j];
95 }
96 }
97 cookey(kn);
98 return;
99 }
100
Pierre Ossmanb3af44d2023-08-15 11:24:11 +0200101static void cookey(register unsigned long *raw1)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000102{
103 register unsigned long *cook, *raw0;
104 unsigned long dough[32];
105 register int i;
106
107 cook = dough;
108 for( i = 0; i < 16; i++, raw1++ ) {
109 raw0 = raw1++;
110 *cook = (*raw0 & 0x00fc0000L) << 6;
111 *cook |= (*raw0 & 0x00000fc0L) << 10;
112 *cook |= (*raw1 & 0x00fc0000L) >> 10;
113 *cook++ |= (*raw1 & 0x00000fc0L) >> 6;
114 *cook = (*raw0 & 0x0003f000L) << 12;
115 *cook |= (*raw0 & 0x0000003fL) << 16;
116 *cook |= (*raw1 & 0x0003f000L) >> 4;
117 *cook++ |= (*raw1 & 0x0000003fL);
118 }
119 usekey(dough);
120 return;
121 }
122
Pierre Ossmanb3af44d2023-08-15 11:24:11 +0200123void cpkey(register unsigned long *into)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000124{
125 register unsigned long *from, *endp;
126
127 from = KnL, endp = &KnL[32];
128 while( from < endp ) *into++ = *from++;
129 return;
130 }
131
Pierre Ossmanb3af44d2023-08-15 11:24:11 +0200132void usekey(register unsigned long *from)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000133{
134 register unsigned long *to, *endp;
135
136 to = KnL, endp = &KnL[32];
137 while( to < endp ) *to++ = *from++;
138 return;
139 }
140
Pierre Ossmanb3af44d2023-08-15 11:24:11 +0200141void des(unsigned char *inblock, unsigned char *outblock)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000142{
143 unsigned long work[2];
144
145 scrunch(inblock, work);
146 desfunc(work, KnL);
147 unscrun(work, outblock);
148 return;
149 }
150
Pierre Ossmanb3af44d2023-08-15 11:24:11 +0200151static void scrunch(register unsigned char *outof,
152 register unsigned long *into)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000153{
154 *into = (*outof++ & 0xffL) << 24;
155 *into |= (*outof++ & 0xffL) << 16;
156 *into |= (*outof++ & 0xffL) << 8;
157 *into++ |= (*outof++ & 0xffL);
158 *into = (*outof++ & 0xffL) << 24;
159 *into |= (*outof++ & 0xffL) << 16;
160 *into |= (*outof++ & 0xffL) << 8;
161 *into |= (*outof & 0xffL);
162 return;
163 }
164
Pierre Ossmanb3af44d2023-08-15 11:24:11 +0200165static void unscrun(register unsigned long *outof,
166 register unsigned char *into)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000167{
168 *into++ = (unsigned char)((*outof >> 24) & 0xffL);
169 *into++ = (unsigned char)((*outof >> 16) & 0xffL);
170 *into++ = (unsigned char)((*outof >> 8) & 0xffL);
171 *into++ = (unsigned char)(*outof++ & 0xffL);
172 *into++ = (unsigned char)((*outof >> 24) & 0xffL);
173 *into++ = (unsigned char)((*outof >> 16) & 0xffL);
174 *into++ = (unsigned char)((*outof >> 8) & 0xffL);
175 *into = (unsigned char)(*outof & 0xffL);
176 return;
177 }
178
179static unsigned long SP1[64] = {
180 0x01010400L, 0x00000000L, 0x00010000L, 0x01010404L,
181 0x01010004L, 0x00010404L, 0x00000004L, 0x00010000L,
182 0x00000400L, 0x01010400L, 0x01010404L, 0x00000400L,
183 0x01000404L, 0x01010004L, 0x01000000L, 0x00000004L,
184 0x00000404L, 0x01000400L, 0x01000400L, 0x00010400L,
185 0x00010400L, 0x01010000L, 0x01010000L, 0x01000404L,
186 0x00010004L, 0x01000004L, 0x01000004L, 0x00010004L,
187 0x00000000L, 0x00000404L, 0x00010404L, 0x01000000L,
188 0x00010000L, 0x01010404L, 0x00000004L, 0x01010000L,
189 0x01010400L, 0x01000000L, 0x01000000L, 0x00000400L,
190 0x01010004L, 0x00010000L, 0x00010400L, 0x01000004L,
191 0x00000400L, 0x00000004L, 0x01000404L, 0x00010404L,
192 0x01010404L, 0x00010004L, 0x01010000L, 0x01000404L,
193 0x01000004L, 0x00000404L, 0x00010404L, 0x01010400L,
194 0x00000404L, 0x01000400L, 0x01000400L, 0x00000000L,
195 0x00010004L, 0x00010400L, 0x00000000L, 0x01010004L };
196
197static unsigned long SP2[64] = {
198 0x80108020L, 0x80008000L, 0x00008000L, 0x00108020L,
199 0x00100000L, 0x00000020L, 0x80100020L, 0x80008020L,
200 0x80000020L, 0x80108020L, 0x80108000L, 0x80000000L,
201 0x80008000L, 0x00100000L, 0x00000020L, 0x80100020L,
202 0x00108000L, 0x00100020L, 0x80008020L, 0x00000000L,
203 0x80000000L, 0x00008000L, 0x00108020L, 0x80100000L,
204 0x00100020L, 0x80000020L, 0x00000000L, 0x00108000L,
205 0x00008020L, 0x80108000L, 0x80100000L, 0x00008020L,
206 0x00000000L, 0x00108020L, 0x80100020L, 0x00100000L,
207 0x80008020L, 0x80100000L, 0x80108000L, 0x00008000L,
208 0x80100000L, 0x80008000L, 0x00000020L, 0x80108020L,
209 0x00108020L, 0x00000020L, 0x00008000L, 0x80000000L,
210 0x00008020L, 0x80108000L, 0x00100000L, 0x80000020L,
211 0x00100020L, 0x80008020L, 0x80000020L, 0x00100020L,
212 0x00108000L, 0x00000000L, 0x80008000L, 0x00008020L,
213 0x80000000L, 0x80100020L, 0x80108020L, 0x00108000L };
214
215static unsigned long SP3[64] = {
216 0x00000208L, 0x08020200L, 0x00000000L, 0x08020008L,
217 0x08000200L, 0x00000000L, 0x00020208L, 0x08000200L,
218 0x00020008L, 0x08000008L, 0x08000008L, 0x00020000L,
219 0x08020208L, 0x00020008L, 0x08020000L, 0x00000208L,
220 0x08000000L, 0x00000008L, 0x08020200L, 0x00000200L,
221 0x00020200L, 0x08020000L, 0x08020008L, 0x00020208L,
222 0x08000208L, 0x00020200L, 0x00020000L, 0x08000208L,
223 0x00000008L, 0x08020208L, 0x00000200L, 0x08000000L,
224 0x08020200L, 0x08000000L, 0x00020008L, 0x00000208L,
225 0x00020000L, 0x08020200L, 0x08000200L, 0x00000000L,
226 0x00000200L, 0x00020008L, 0x08020208L, 0x08000200L,
227 0x08000008L, 0x00000200L, 0x00000000L, 0x08020008L,
228 0x08000208L, 0x00020000L, 0x08000000L, 0x08020208L,
229 0x00000008L, 0x00020208L, 0x00020200L, 0x08000008L,
230 0x08020000L, 0x08000208L, 0x00000208L, 0x08020000L,
231 0x00020208L, 0x00000008L, 0x08020008L, 0x00020200L };
232
233static unsigned long SP4[64] = {
234 0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L,
235 0x00802080L, 0x00800081L, 0x00800001L, 0x00002001L,
236 0x00000000L, 0x00802000L, 0x00802000L, 0x00802081L,
237 0x00000081L, 0x00000000L, 0x00800080L, 0x00800001L,
238 0x00000001L, 0x00002000L, 0x00800000L, 0x00802001L,
239 0x00000080L, 0x00800000L, 0x00002001L, 0x00002080L,
240 0x00800081L, 0x00000001L, 0x00002080L, 0x00800080L,
241 0x00002000L, 0x00802080L, 0x00802081L, 0x00000081L,
242 0x00800080L, 0x00800001L, 0x00802000L, 0x00802081L,
243 0x00000081L, 0x00000000L, 0x00000000L, 0x00802000L,
244 0x00002080L, 0x00800080L, 0x00800081L, 0x00000001L,
245 0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L,
246 0x00802081L, 0x00000081L, 0x00000001L, 0x00002000L,
247 0x00800001L, 0x00002001L, 0x00802080L, 0x00800081L,
248 0x00002001L, 0x00002080L, 0x00800000L, 0x00802001L,
249 0x00000080L, 0x00800000L, 0x00002000L, 0x00802080L };
250
251static unsigned long SP5[64] = {
252 0x00000100L, 0x02080100L, 0x02080000L, 0x42000100L,
253 0x00080000L, 0x00000100L, 0x40000000L, 0x02080000L,
254 0x40080100L, 0x00080000L, 0x02000100L, 0x40080100L,
255 0x42000100L, 0x42080000L, 0x00080100L, 0x40000000L,
256 0x02000000L, 0x40080000L, 0x40080000L, 0x00000000L,
257 0x40000100L, 0x42080100L, 0x42080100L, 0x02000100L,
258 0x42080000L, 0x40000100L, 0x00000000L, 0x42000000L,
259 0x02080100L, 0x02000000L, 0x42000000L, 0x00080100L,
260 0x00080000L, 0x42000100L, 0x00000100L, 0x02000000L,
261 0x40000000L, 0x02080000L, 0x42000100L, 0x40080100L,
262 0x02000100L, 0x40000000L, 0x42080000L, 0x02080100L,
263 0x40080100L, 0x00000100L, 0x02000000L, 0x42080000L,
264 0x42080100L, 0x00080100L, 0x42000000L, 0x42080100L,
265 0x02080000L, 0x00000000L, 0x40080000L, 0x42000000L,
266 0x00080100L, 0x02000100L, 0x40000100L, 0x00080000L,
267 0x00000000L, 0x40080000L, 0x02080100L, 0x40000100L };
268
269static unsigned long SP6[64] = {
270 0x20000010L, 0x20400000L, 0x00004000L, 0x20404010L,
271 0x20400000L, 0x00000010L, 0x20404010L, 0x00400000L,
272 0x20004000L, 0x00404010L, 0x00400000L, 0x20000010L,
273 0x00400010L, 0x20004000L, 0x20000000L, 0x00004010L,
274 0x00000000L, 0x00400010L, 0x20004010L, 0x00004000L,
275 0x00404000L, 0x20004010L, 0x00000010L, 0x20400010L,
276 0x20400010L, 0x00000000L, 0x00404010L, 0x20404000L,
277 0x00004010L, 0x00404000L, 0x20404000L, 0x20000000L,
278 0x20004000L, 0x00000010L, 0x20400010L, 0x00404000L,
279 0x20404010L, 0x00400000L, 0x00004010L, 0x20000010L,
280 0x00400000L, 0x20004000L, 0x20000000L, 0x00004010L,
281 0x20000010L, 0x20404010L, 0x00404000L, 0x20400000L,
282 0x00404010L, 0x20404000L, 0x00000000L, 0x20400010L,
283 0x00000010L, 0x00004000L, 0x20400000L, 0x00404010L,
284 0x00004000L, 0x00400010L, 0x20004010L, 0x00000000L,
285 0x20404000L, 0x20000000L, 0x00400010L, 0x20004010L };
286
287static unsigned long SP7[64] = {
288 0x00200000L, 0x04200002L, 0x04000802L, 0x00000000L,
289 0x00000800L, 0x04000802L, 0x00200802L, 0x04200800L,
290 0x04200802L, 0x00200000L, 0x00000000L, 0x04000002L,
291 0x00000002L, 0x04000000L, 0x04200002L, 0x00000802L,
292 0x04000800L, 0x00200802L, 0x00200002L, 0x04000800L,
293 0x04000002L, 0x04200000L, 0x04200800L, 0x00200002L,
294 0x04200000L, 0x00000800L, 0x00000802L, 0x04200802L,
295 0x00200800L, 0x00000002L, 0x04000000L, 0x00200800L,
296 0x04000000L, 0x00200800L, 0x00200000L, 0x04000802L,
297 0x04000802L, 0x04200002L, 0x04200002L, 0x00000002L,
298 0x00200002L, 0x04000000L, 0x04000800L, 0x00200000L,
299 0x04200800L, 0x00000802L, 0x00200802L, 0x04200800L,
300 0x00000802L, 0x04000002L, 0x04200802L, 0x04200000L,
301 0x00200800L, 0x00000000L, 0x00000002L, 0x04200802L,
302 0x00000000L, 0x00200802L, 0x04200000L, 0x00000800L,
303 0x04000002L, 0x04000800L, 0x00000800L, 0x00200002L };
304
305static unsigned long SP8[64] = {
306 0x10001040L, 0x00001000L, 0x00040000L, 0x10041040L,
307 0x10000000L, 0x10001040L, 0x00000040L, 0x10000000L,
308 0x00040040L, 0x10040000L, 0x10041040L, 0x00041000L,
309 0x10041000L, 0x00041040L, 0x00001000L, 0x00000040L,
310 0x10040000L, 0x10000040L, 0x10001000L, 0x00001040L,
311 0x00041000L, 0x00040040L, 0x10040040L, 0x10041000L,
312 0x00001040L, 0x00000000L, 0x00000000L, 0x10040040L,
313 0x10000040L, 0x10001000L, 0x00041040L, 0x00040000L,
314 0x00041040L, 0x00040000L, 0x10041000L, 0x00001000L,
315 0x00000040L, 0x10040040L, 0x00001000L, 0x00041040L,
316 0x10001000L, 0x00000040L, 0x10000040L, 0x10040000L,
317 0x10040040L, 0x10000000L, 0x00040000L, 0x10001040L,
318 0x00000000L, 0x10041040L, 0x00040040L, 0x10000040L,
319 0x10040000L, 0x10001000L, 0x10001040L, 0x00000000L,
320 0x10041040L, 0x00041000L, 0x00041000L, 0x00001040L,
321 0x00001040L, 0x00040040L, 0x10000000L, 0x10041000L };
322
Pierre Ossmanb3af44d2023-08-15 11:24:11 +0200323static void desfunc(register unsigned long *block,
324 register unsigned long *keys)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000325{
326 register unsigned long fval, work, right, leftt;
327 register int round;
328
329 leftt = block[0];
330 right = block[1];
331 work = ((leftt >> 4) ^ right) & 0x0f0f0f0fL;
332 right ^= work;
333 leftt ^= (work << 4);
334 work = ((leftt >> 16) ^ right) & 0x0000ffffL;
335 right ^= work;
336 leftt ^= (work << 16);
337 work = ((right >> 2) ^ leftt) & 0x33333333L;
338 leftt ^= work;
339 right ^= (work << 2);
340 work = ((right >> 8) ^ leftt) & 0x00ff00ffL;
341 leftt ^= work;
342 right ^= (work << 8);
343 right = ((right << 1) | ((right >> 31) & 1L)) & 0xffffffffL;
344 work = (leftt ^ right) & 0xaaaaaaaaL;
345 leftt ^= work;
346 right ^= work;
347 leftt = ((leftt << 1) | ((leftt >> 31) & 1L)) & 0xffffffffL;
348
349 for( round = 0; round < 8; round++ ) {
350 work = (right << 28) | (right >> 4);
351 work ^= *keys++;
352 fval = SP7[ work & 0x3fL];
353 fval |= SP5[(work >> 8) & 0x3fL];
354 fval |= SP3[(work >> 16) & 0x3fL];
355 fval |= SP1[(work >> 24) & 0x3fL];
356 work = right ^ *keys++;
357 fval |= SP8[ work & 0x3fL];
358 fval |= SP6[(work >> 8) & 0x3fL];
359 fval |= SP4[(work >> 16) & 0x3fL];
360 fval |= SP2[(work >> 24) & 0x3fL];
361 leftt ^= fval;
362 work = (leftt << 28) | (leftt >> 4);
363 work ^= *keys++;
364 fval = SP7[ work & 0x3fL];
365 fval |= SP5[(work >> 8) & 0x3fL];
366 fval |= SP3[(work >> 16) & 0x3fL];
367 fval |= SP1[(work >> 24) & 0x3fL];
368 work = leftt ^ *keys++;
369 fval |= SP8[ work & 0x3fL];
370 fval |= SP6[(work >> 8) & 0x3fL];
371 fval |= SP4[(work >> 16) & 0x3fL];
372 fval |= SP2[(work >> 24) & 0x3fL];
373 right ^= fval;
374 }
375
376 right = (right << 31) | (right >> 1);
377 work = (leftt ^ right) & 0xaaaaaaaaL;
378 leftt ^= work;
379 right ^= work;
380 leftt = (leftt << 31) | (leftt >> 1);
381 work = ((leftt >> 8) ^ right) & 0x00ff00ffL;
382 right ^= work;
383 leftt ^= (work << 8);
384 work = ((leftt >> 2) ^ right) & 0x33333333L;
385 right ^= work;
386 leftt ^= (work << 2);
387 work = ((right >> 16) ^ leftt) & 0x0000ffffL;
388 leftt ^= work;
389 right ^= (work << 16);
390 work = ((right >> 4) ^ leftt) & 0x0f0f0f0fL;
391 leftt ^= work;
392 right ^= (work << 4);
393 *block++ = right;
394 *block = leftt;
395 return;
396 }
397
398/* Validation sets:
399 *
400 * Single-length key, single-length plaintext -
401 * Key : 0123 4567 89ab cdef
402 * Plain : 0123 4567 89ab cde7
403 * Cipher : c957 4425 6a5e d31d
404 *
405 * Double-length key, single-length plaintext -
406 * Key : 0123 4567 89ab cdef fedc ba98 7654 3210
407 * Plain : 0123 4567 89ab cde7
408 * Cipher : 7f1d 0a77 826b 8aff
409 *
410 * Double-length key, double-length plaintext -
411 * Key : 0123 4567 89ab cdef fedc ba98 7654 3210
412 * Plain : 0123 4567 89ab cdef 0123 4567 89ab cdff
413 * Cipher : 27a0 8440 406a df60 278f 47cf 42d6 15d7
414 *
415 * Triple-length key, single-length plaintext -
416 * Key : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567
417 * Plain : 0123 4567 89ab cde7
418 * Cipher : de0b 7c06 ae5e 0ed5
419 *
420 * Triple-length key, double-length plaintext -
421 * Key : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567
422 * Plain : 0123 4567 89ab cdef 0123 4567 89ab cdff
423 * Cipher : ad0d 1b30 ac17 cf07 0ed1 1c63 81e4 4de5
424 *
425 * d3des V5.0a rwo 9208.07 18:44 Graven Imagery
426 **********************************************************************/