upstream: https://github.com/mirage/mirage-crypto
at main 454 lines 16 kB view raw
1/* D3DES (V5.09) - 2 * 3 * A portable, public domain, version of the Data Encryption Standard. 4 * 5 * Written with Symantec's THINK (Lightspeed) C by Richard Outerbridge. 6 * Thanks to: Dan Hoey for his excellent Initial and Inverse permutation 7 * code; Jim Gillogly & Phil Karn for the DES key schedule code; Dennis 8 * Ferguson, Eric Young and Dana How for comparing notes; and Ray Lau, 9 * for humouring me on. 10 * 11 * THIS SOFTWARE PLACED IN THE PUBLIC DOMAIN BY THE AUTHOUR 12 * 920825 19:42 EDST 13 * 14 * Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge. 15 * (GEnie : OUTER; CIS : [71755,204]) Graven Imagery, 1992. 16 */ 17 18#include "crypto.h" 19 20#define EN0 0 /* MODE == encrypt */ 21#define DE1 1 /* MODE == decrypt */ 22 23static void scrunch(const unsigned char *, unsigned long *); 24static void unscrun(const unsigned long *, unsigned char *); 25static void desfunc(unsigned long *, const unsigned long *); 26static void cookey(const unsigned long *, unsigned long[32]); 27 28static const unsigned short bytebit[8] = { 29 0200, 0100, 040, 020, 010, 04, 02, 01 }; 30 31static const unsigned long bigbyte[24] = { 32 0x800000L, 0x400000L, 0x200000L, 0x100000L, 33 0x80000L, 0x40000L, 0x20000L, 0x10000L, 34 0x8000L, 0x4000L, 0x2000L, 0x1000L, 35 0x800L, 0x400L, 0x200L, 0x100L, 36 0x80L, 0x40L, 0x20L, 0x10L, 37 0x8L, 0x4L, 0x2L, 0x1L }; 38 39/* Use the key schedule specified in the Standard (ANSI X3.92-1981). */ 40 41static const unsigned char pc1[56] = { 42 56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17, 43 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35, 44 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21, 45 13, 5, 60, 52, 44, 36, 28, 20, 12, 4, 27, 19, 11, 3 }; 46 47static const unsigned char totrot[16] = { 48 1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28 }; 49 50static const unsigned char pc2[48] = { 51 13, 16, 10, 23, 0, 4, 2, 27, 14, 5, 20, 9, 52 22, 18, 11, 3, 25, 7, 15, 6, 26, 19, 12, 1, 53 40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47, 54 43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31 }; 55 56void mc_deskey(const unsigned char key[8], short edf, unsigned long into[32]) /* Thanks to James Gillogly & Phil Karn! */ 57{ 58 int i, j, l, m, n; 59 unsigned char pc1m[56], pcr[56]; 60 unsigned long kn[32]; 61 62 for ( j = 0; j < 56; j++ ) { 63 l = pc1[j]; 64 m = l & 07; 65 pc1m[j] = (key[l >> 3] & bytebit[m]) ? 1 : 0; 66 } 67 for( i = 0; i < 16; i++ ) { 68 if( edf == DE1 ) m = (15 - i) << 1; 69 else m = i << 1; 70 n = m + 1; 71 kn[m] = kn[n] = 0L; 72 for( j = 0; j < 28; j++ ) { 73 l = j + totrot[i]; 74 if( l < 28 ) pcr[j] = pc1m[l]; 75 else pcr[j] = pc1m[l - 28]; 76 } 77 for( j = 28; j < 56; j++ ) { 78 l = j + totrot[i]; 79 if( l < 56 ) pcr[j] = pc1m[l]; 80 else pcr[j] = pc1m[l - 28]; 81 } 82 for( j = 0; j < 24; j++ ) { 83 if( pcr[pc2[j]] ) kn[m] |= bigbyte[j]; 84 if( pcr[pc2[j+24]] ) kn[n] |= bigbyte[j]; 85 } 86 } 87 cookey(kn, into); 88 return; 89 } 90 91static void cookey(const unsigned long *raw1, unsigned long into[32]) 92{ 93 unsigned long *cook; 94 const unsigned long *raw0; 95 unsigned long dough[32]; 96 int i; 97 98 cook = dough; 99 for( i = 0; i < 16; i++, raw1++ ) { 100 raw0 = raw1++; 101 *cook = (*raw0 & 0x00fc0000L) << 6; 102 *cook |= (*raw0 & 0x00000fc0L) << 10; 103 *cook |= (*raw1 & 0x00fc0000L) >> 10; 104 *cook++ |= (*raw1 & 0x00000fc0L) >> 6; 105 *cook = (*raw0 & 0x0003f000L) << 12; 106 *cook |= (*raw0 & 0x0000003fL) << 16; 107 *cook |= (*raw1 & 0x0003f000L) >> 4; 108 *cook++ |= (*raw1 & 0x0000003fL); 109 } 110 for( i = 0; i < 32; i++) { 111 into[i] = dough[i]; 112 } 113 return; 114 } 115 116static void scrunch(const unsigned char *outof, unsigned long *into) 117{ 118 *into = (*outof++ & 0xffL) << 24; 119 *into |= (*outof++ & 0xffL) << 16; 120 *into |= (*outof++ & 0xffL) << 8; 121 *into++ |= (*outof++ & 0xffL); 122 *into = (*outof++ & 0xffL) << 24; 123 *into |= (*outof++ & 0xffL) << 16; 124 *into |= (*outof++ & 0xffL) << 8; 125 *into |= (*outof & 0xffL); 126 return; 127 } 128 129 130static void unscrun(const unsigned long *outof, unsigned char *into) 131{ 132 *into++ = (*outof >> 24) & 0xffL; 133 *into++ = (*outof >> 16) & 0xffL; 134 *into++ = (*outof >> 8) & 0xffL; 135 *into++ = *outof++ & 0xffL; 136 *into++ = (*outof >> 24) & 0xffL; 137 *into++ = (*outof >> 16) & 0xffL; 138 *into++ = (*outof >> 8) & 0xffL; 139 *into = *outof & 0xffL; 140 return; 141 } 142 143static const unsigned long SP1[64] = { 144 0x01010400L, 0x00000000L, 0x00010000L, 0x01010404L, 145 0x01010004L, 0x00010404L, 0x00000004L, 0x00010000L, 146 0x00000400L, 0x01010400L, 0x01010404L, 0x00000400L, 147 0x01000404L, 0x01010004L, 0x01000000L, 0x00000004L, 148 0x00000404L, 0x01000400L, 0x01000400L, 0x00010400L, 149 0x00010400L, 0x01010000L, 0x01010000L, 0x01000404L, 150 0x00010004L, 0x01000004L, 0x01000004L, 0x00010004L, 151 0x00000000L, 0x00000404L, 0x00010404L, 0x01000000L, 152 0x00010000L, 0x01010404L, 0x00000004L, 0x01010000L, 153 0x01010400L, 0x01000000L, 0x01000000L, 0x00000400L, 154 0x01010004L, 0x00010000L, 0x00010400L, 0x01000004L, 155 0x00000400L, 0x00000004L, 0x01000404L, 0x00010404L, 156 0x01010404L, 0x00010004L, 0x01010000L, 0x01000404L, 157 0x01000004L, 0x00000404L, 0x00010404L, 0x01010400L, 158 0x00000404L, 0x01000400L, 0x01000400L, 0x00000000L, 159 0x00010004L, 0x00010400L, 0x00000000L, 0x01010004L }; 160 161static const unsigned long SP2[64] = { 162 0x80108020L, 0x80008000L, 0x00008000L, 0x00108020L, 163 0x00100000L, 0x00000020L, 0x80100020L, 0x80008020L, 164 0x80000020L, 0x80108020L, 0x80108000L, 0x80000000L, 165 0x80008000L, 0x00100000L, 0x00000020L, 0x80100020L, 166 0x00108000L, 0x00100020L, 0x80008020L, 0x00000000L, 167 0x80000000L, 0x00008000L, 0x00108020L, 0x80100000L, 168 0x00100020L, 0x80000020L, 0x00000000L, 0x00108000L, 169 0x00008020L, 0x80108000L, 0x80100000L, 0x00008020L, 170 0x00000000L, 0x00108020L, 0x80100020L, 0x00100000L, 171 0x80008020L, 0x80100000L, 0x80108000L, 0x00008000L, 172 0x80100000L, 0x80008000L, 0x00000020L, 0x80108020L, 173 0x00108020L, 0x00000020L, 0x00008000L, 0x80000000L, 174 0x00008020L, 0x80108000L, 0x00100000L, 0x80000020L, 175 0x00100020L, 0x80008020L, 0x80000020L, 0x00100020L, 176 0x00108000L, 0x00000000L, 0x80008000L, 0x00008020L, 177 0x80000000L, 0x80100020L, 0x80108020L, 0x00108000L }; 178 179static const unsigned long SP3[64] = { 180 0x00000208L, 0x08020200L, 0x00000000L, 0x08020008L, 181 0x08000200L, 0x00000000L, 0x00020208L, 0x08000200L, 182 0x00020008L, 0x08000008L, 0x08000008L, 0x00020000L, 183 0x08020208L, 0x00020008L, 0x08020000L, 0x00000208L, 184 0x08000000L, 0x00000008L, 0x08020200L, 0x00000200L, 185 0x00020200L, 0x08020000L, 0x08020008L, 0x00020208L, 186 0x08000208L, 0x00020200L, 0x00020000L, 0x08000208L, 187 0x00000008L, 0x08020208L, 0x00000200L, 0x08000000L, 188 0x08020200L, 0x08000000L, 0x00020008L, 0x00000208L, 189 0x00020000L, 0x08020200L, 0x08000200L, 0x00000000L, 190 0x00000200L, 0x00020008L, 0x08020208L, 0x08000200L, 191 0x08000008L, 0x00000200L, 0x00000000L, 0x08020008L, 192 0x08000208L, 0x00020000L, 0x08000000L, 0x08020208L, 193 0x00000008L, 0x00020208L, 0x00020200L, 0x08000008L, 194 0x08020000L, 0x08000208L, 0x00000208L, 0x08020000L, 195 0x00020208L, 0x00000008L, 0x08020008L, 0x00020200L }; 196 197static const unsigned long SP4[64] = { 198 0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L, 199 0x00802080L, 0x00800081L, 0x00800001L, 0x00002001L, 200 0x00000000L, 0x00802000L, 0x00802000L, 0x00802081L, 201 0x00000081L, 0x00000000L, 0x00800080L, 0x00800001L, 202 0x00000001L, 0x00002000L, 0x00800000L, 0x00802001L, 203 0x00000080L, 0x00800000L, 0x00002001L, 0x00002080L, 204 0x00800081L, 0x00000001L, 0x00002080L, 0x00800080L, 205 0x00002000L, 0x00802080L, 0x00802081L, 0x00000081L, 206 0x00800080L, 0x00800001L, 0x00802000L, 0x00802081L, 207 0x00000081L, 0x00000000L, 0x00000000L, 0x00802000L, 208 0x00002080L, 0x00800080L, 0x00800081L, 0x00000001L, 209 0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L, 210 0x00802081L, 0x00000081L, 0x00000001L, 0x00002000L, 211 0x00800001L, 0x00002001L, 0x00802080L, 0x00800081L, 212 0x00002001L, 0x00002080L, 0x00800000L, 0x00802001L, 213 0x00000080L, 0x00800000L, 0x00002000L, 0x00802080L }; 214 215static const unsigned long SP5[64] = { 216 0x00000100L, 0x02080100L, 0x02080000L, 0x42000100L, 217 0x00080000L, 0x00000100L, 0x40000000L, 0x02080000L, 218 0x40080100L, 0x00080000L, 0x02000100L, 0x40080100L, 219 0x42000100L, 0x42080000L, 0x00080100L, 0x40000000L, 220 0x02000000L, 0x40080000L, 0x40080000L, 0x00000000L, 221 0x40000100L, 0x42080100L, 0x42080100L, 0x02000100L, 222 0x42080000L, 0x40000100L, 0x00000000L, 0x42000000L, 223 0x02080100L, 0x02000000L, 0x42000000L, 0x00080100L, 224 0x00080000L, 0x42000100L, 0x00000100L, 0x02000000L, 225 0x40000000L, 0x02080000L, 0x42000100L, 0x40080100L, 226 0x02000100L, 0x40000000L, 0x42080000L, 0x02080100L, 227 0x40080100L, 0x00000100L, 0x02000000L, 0x42080000L, 228 0x42080100L, 0x00080100L, 0x42000000L, 0x42080100L, 229 0x02080000L, 0x00000000L, 0x40080000L, 0x42000000L, 230 0x00080100L, 0x02000100L, 0x40000100L, 0x00080000L, 231 0x00000000L, 0x40080000L, 0x02080100L, 0x40000100L }; 232 233static const unsigned long SP6[64] = { 234 0x20000010L, 0x20400000L, 0x00004000L, 0x20404010L, 235 0x20400000L, 0x00000010L, 0x20404010L, 0x00400000L, 236 0x20004000L, 0x00404010L, 0x00400000L, 0x20000010L, 237 0x00400010L, 0x20004000L, 0x20000000L, 0x00004010L, 238 0x00000000L, 0x00400010L, 0x20004010L, 0x00004000L, 239 0x00404000L, 0x20004010L, 0x00000010L, 0x20400010L, 240 0x20400010L, 0x00000000L, 0x00404010L, 0x20404000L, 241 0x00004010L, 0x00404000L, 0x20404000L, 0x20000000L, 242 0x20004000L, 0x00000010L, 0x20400010L, 0x00404000L, 243 0x20404010L, 0x00400000L, 0x00004010L, 0x20000010L, 244 0x00400000L, 0x20004000L, 0x20000000L, 0x00004010L, 245 0x20000010L, 0x20404010L, 0x00404000L, 0x20400000L, 246 0x00404010L, 0x20404000L, 0x00000000L, 0x20400010L, 247 0x00000010L, 0x00004000L, 0x20400000L, 0x00404010L, 248 0x00004000L, 0x00400010L, 0x20004010L, 0x00000000L, 249 0x20404000L, 0x20000000L, 0x00400010L, 0x20004010L }; 250 251static const unsigned long SP7[64] = { 252 0x00200000L, 0x04200002L, 0x04000802L, 0x00000000L, 253 0x00000800L, 0x04000802L, 0x00200802L, 0x04200800L, 254 0x04200802L, 0x00200000L, 0x00000000L, 0x04000002L, 255 0x00000002L, 0x04000000L, 0x04200002L, 0x00000802L, 256 0x04000800L, 0x00200802L, 0x00200002L, 0x04000800L, 257 0x04000002L, 0x04200000L, 0x04200800L, 0x00200002L, 258 0x04200000L, 0x00000800L, 0x00000802L, 0x04200802L, 259 0x00200800L, 0x00000002L, 0x04000000L, 0x00200800L, 260 0x04000000L, 0x00200800L, 0x00200000L, 0x04000802L, 261 0x04000802L, 0x04200002L, 0x04200002L, 0x00000002L, 262 0x00200002L, 0x04000000L, 0x04000800L, 0x00200000L, 263 0x04200800L, 0x00000802L, 0x00200802L, 0x04200800L, 264 0x00000802L, 0x04000002L, 0x04200802L, 0x04200000L, 265 0x00200800L, 0x00000000L, 0x00000002L, 0x04200802L, 266 0x00000000L, 0x00200802L, 0x04200000L, 0x00000800L, 267 0x04000002L, 0x04000800L, 0x00000800L, 0x00200002L }; 268 269static const unsigned long SP8[64] = { 270 0x10001040L, 0x00001000L, 0x00040000L, 0x10041040L, 271 0x10000000L, 0x10001040L, 0x00000040L, 0x10000000L, 272 0x00040040L, 0x10040000L, 0x10041040L, 0x00041000L, 273 0x10041000L, 0x00041040L, 0x00001000L, 0x00000040L, 274 0x10040000L, 0x10000040L, 0x10001000L, 0x00001040L, 275 0x00041000L, 0x00040040L, 0x10040040L, 0x10041000L, 276 0x00001040L, 0x00000000L, 0x00000000L, 0x10040040L, 277 0x10000040L, 0x10001000L, 0x00041040L, 0x00040000L, 278 0x00041040L, 0x00040000L, 0x10041000L, 0x00001000L, 279 0x00000040L, 0x10040040L, 0x00001000L, 0x00041040L, 280 0x10001000L, 0x00000040L, 0x10000040L, 0x10040000L, 281 0x10040040L, 0x10000000L, 0x00040000L, 0x10001040L, 282 0x00000000L, 0x10041040L, 0x00040040L, 0x10000040L, 283 0x10040000L, 0x10001000L, 0x10001040L, 0x00000000L, 284 0x10041040L, 0x00041000L, 0x00041000L, 0x00001040L, 285 0x00001040L, 0x00040040L, 0x10000000L, 0x10041000L }; 286 287static void desfunc(unsigned long *block, const unsigned long *keys) 288{ 289 unsigned long fval, work, right, leftt; 290 int round; 291 292 leftt = block[0]; 293 right = block[1]; 294 work = ((leftt >> 4) ^ right) & 0x0f0f0f0fL; 295 right ^= work; 296 leftt ^= (work << 4); 297 work = ((leftt >> 16) ^ right) & 0x0000ffffL; 298 right ^= work; 299 leftt ^= (work << 16); 300 work = ((right >> 2) ^ leftt) & 0x33333333L; 301 leftt ^= work; 302 right ^= (work << 2); 303 work = ((right >> 8) ^ leftt) & 0x00ff00ffL; 304 leftt ^= work; 305 right ^= (work << 8); 306 right = ((right << 1) | ((right >> 31) & 1L)) & 0xffffffffL; 307 work = (leftt ^ right) & 0xaaaaaaaaL; 308 leftt ^= work; 309 right ^= work; 310 leftt = ((leftt << 1) | ((leftt >> 31) & 1L)) & 0xffffffffL; 311 312 for( round = 0; round < 8; round++ ) { 313 work = (right << 28) | (right >> 4); 314 work ^= *keys++; 315 fval = SP7[ work & 0x3fL]; 316 fval |= SP5[(work >> 8) & 0x3fL]; 317 fval |= SP3[(work >> 16) & 0x3fL]; 318 fval |= SP1[(work >> 24) & 0x3fL]; 319 work = right ^ *keys++; 320 fval |= SP8[ work & 0x3fL]; 321 fval |= SP6[(work >> 8) & 0x3fL]; 322 fval |= SP4[(work >> 16) & 0x3fL]; 323 fval |= SP2[(work >> 24) & 0x3fL]; 324 leftt ^= fval; 325 work = (leftt << 28) | (leftt >> 4); 326 work ^= *keys++; 327 fval = SP7[ work & 0x3fL]; 328 fval |= SP5[(work >> 8) & 0x3fL]; 329 fval |= SP3[(work >> 16) & 0x3fL]; 330 fval |= SP1[(work >> 24) & 0x3fL]; 331 work = leftt ^ *keys++; 332 fval |= SP8[ work & 0x3fL]; 333 fval |= SP6[(work >> 8) & 0x3fL]; 334 fval |= SP4[(work >> 16) & 0x3fL]; 335 fval |= SP2[(work >> 24) & 0x3fL]; 336 right ^= fval; 337 } 338 339 right = (right << 31) | (right >> 1); 340 work = (leftt ^ right) & 0xaaaaaaaaL; 341 leftt ^= work; 342 right ^= work; 343 leftt = (leftt << 31) | (leftt >> 1); 344 work = ((leftt >> 8) ^ right) & 0x00ff00ffL; 345 right ^= work; 346 leftt ^= (work << 8); 347 work = ((leftt >> 2) ^ right) & 0x33333333L; 348 right ^= work; 349 leftt ^= (work << 2); 350 work = ((right >> 16) ^ leftt) & 0x0000ffffL; 351 leftt ^= work; 352 right ^= (work << 16); 353 work = ((right >> 4) ^ leftt) & 0x0f0f0f0fL; 354 leftt ^= work; 355 right ^= (work << 4); 356 *block++ = right; 357 *block = leftt; 358 return; 359 } 360 361void mc_Ddes(const unsigned char from[8], unsigned char into[8], const unsigned long* key1, const unsigned long* key2, const unsigned long* key3) 362{ 363 unsigned long work[2]; 364 365 scrunch(from, work); 366 desfunc(work, key1); 367 desfunc(work, key2); 368 desfunc(work, key3); 369 unscrun(work, into); 370 return; 371 } 372 373void mc_des3key(const unsigned char hexkey[24], short mode, unsigned long into[96]) 374{ 375 const unsigned char *first, *third; 376 short revmod; 377 378 if( mode == EN0 ) { 379 revmod = DE1; 380 first = hexkey; 381 third = &hexkey[16]; 382 } 383 else { 384 revmod = EN0; 385 first = &hexkey[16]; 386 third = hexkey; 387 } 388 mc_deskey(&hexkey[8], revmod, &into[32]); 389 mc_deskey(third, mode, &into[64]); 390 mc_deskey(first, mode, into); 391 return; 392 } 393 394/* Validation sets: 395 * 396 * Single-length key, single-length plaintext - 397 * Key : 0123 4567 89ab cdef 398 * Plain : 0123 4567 89ab cde7 399 * Cipher : c957 4425 6a5e d31d 400 * 401 * Double-length key, single-length plaintext - 402 * Key : 0123 4567 89ab cdef fedc ba98 7654 3210 403 * Plain : 0123 4567 89ab cde7 404 * Cipher : 7f1d 0a77 826b 8aff 405 * 406 * Double-length key, double-length plaintext - 407 * Key : 0123 4567 89ab cdef fedc ba98 7654 3210 408 * Plain : 0123 4567 89ab cdef 0123 4567 89ab cdff 409 * Cipher : 27a0 8440 406a df60 278f 47cf 42d6 15d7 410 * 411 * Triple-length key, single-length plaintext - 412 * Key : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567 413 * Plain : 0123 4567 89ab cde7 414 * Cipher : de0b 7c06 ae5e 0ed5 415 * 416 * Triple-length key, double-length plaintext - 417 * Key : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567 418 * Plain : 0123 4567 89ab cdef 0123 4567 89ab cdff 419 * Cipher : ad0d 1b30 ac17 cf07 0ed1 1c63 81e4 4de5 420 * 421 * d3des V5.09 rwo 9208.04 20:31 Graven Imagery 422 **********************************************************************/ 423 424 425/* OCaml front-end */ 426 427static inline void _mc_ddes (const unsigned char *src, unsigned char *dst, unsigned int blocks, const unsigned long* key) { 428 const unsigned long* key1 = key; 429 const unsigned long* key2 = key + 32; 430 const unsigned long* key3 = key + 64; 431 while (blocks --) { 432 mc_Ddes (src, dst, key1, key2, key3); 433 src += 8 ; dst += 8; 434 } 435} 436 437CAMLprim value 438mc_des_key_size (__unit ()) { 439 return Val_int (sizeof (unsigned long) * 96); 440} 441 442CAMLprim value 443mc_des_des3key (value key, value direction, value dst) { 444 mc_des3key (_bp_uint8 (key), Int_val (direction), (unsigned long *) _bp_uint8 (dst)); 445 return Val_unit; 446} 447 448CAMLprim value 449mc_des_ddes (value src, value off1, value dst, value off2, value blocks, value key) { 450 _mc_ddes (_st_uint8_off (src, off1), _bp_uint8_off (dst, off2), Int_val (blocks), (unsigned long *) _st_uint8 (key)); 451 return Val_unit; 452} 453 454__define_bc_6(mc_des_ddes)