1/* Copyright (c) 1998,2011,2014 Apple Inc. All Rights Reserved. 2 * 3 * NOTICE: USE OF THE MATERIALS ACCOMPANYING THIS NOTICE IS SUBJECT 4 * TO THE TERMS OF THE SIGNED "FAST ELLIPTIC ENCRYPTION (FEE) REFERENCE 5 * SOURCE CODE EVALUATION AGREEMENT" BETWEEN APPLE, INC. AND THE 6 * ORIGINAL LICENSEE THAT OBTAINED THESE MATERIALS FROM APPLE, 7 * INC. ANY USE OF THESE MATERIALS NOT PERMITTED BY SUCH AGREEMENT WILL 8 * EXPOSE YOU TO LIABILITY. 9 *************************************************************************** 10 * 11 * FeeDES.c - generic, portable DES encryption object 12 * 13 * Revision History 14 * ---------------- 15 * 10/06/98 ap 16 * Changed to compile with C++. 17 * 05 Jan 98 at Apple 18 * Avoid a bcopy() on encrypt/decrypt of each block 19 * 31 Mar 97 at Apple 20 * New per-instance API for DES.c 21 * 26 Aug 96 at NeXT 22 * Created. 23 */ 24 25#include "ckconfig.h" 26 27#if CRYPTKIT_SYMMETRIC_ENABLE 28 29#include "feeDES.h" 30#include "feeTypes.h" 31#include "ckDES.h" 32#include "falloc.h" 33#include "feeDebug.h" 34#include "feeFunctions.h" 35#include "platform.h" 36#include <stdlib.h> 37 38#ifndef NULL 39#define NULL ((void *)0) 40#endif /* NULL */ 41 42typedef struct { 43 int blockMode; /* default = 0 */ 44 unsigned char lastBlock[DES_BLOCK_SIZE_BYTES]; /* for CBC */ 45 struct _desInst dinst; 46} fdesInst; 47 48static void feeDESInit(desInst dinst) 49{ 50 desinit(dinst, DES_MODE_STD); // detects redundant calls 51} 52 53/* 54 * Alloc and init a feeDES object with specified initial state. 55 * State must be at least 8 bytes; only 8 bytes are used, ignoring 56 * MSB of each bytes. 57 */ 58feeDES feeDESNewWithState(const unsigned char *state, 59 unsigned stateLen) 60{ 61 fdesInst *fdinst; 62 63 if(stateLen < FEE_DES_MIN_STATE_SIZE) { 64 return NULL; 65 } 66 fdinst = (fdesInst*) fmalloc(sizeof(fdesInst)); 67 bzero(fdinst, sizeof(fdesInst)); 68 feeDESInit(&fdinst->dinst); 69 feeDESSetState((feeDES)fdinst, state, stateLen); 70 return fdinst; 71} 72 73void feeDESFree(feeDES des) 74{ 75 memset(des, 0, sizeof(fdesInst)); 76 ffree(des); 77} 78 79/* 80 * Set new initial state. 81 */ 82feeReturn feeDESSetState(feeDES des, 83 const unsigned char *state, 84 unsigned stateLen) 85{ 86 fdesInst *fdinst = (fdesInst*) des; 87 char Key[DES_KEY_SIZE_BYTES_EXTERNAL]; 88 // 'key' causes problems with 89 // some weird Unix header 90 unsigned byte; 91 92 if(stateLen < (DES_KEY_SIZE_BYTES_EXTERNAL)) { 93 return FR_IllegalArg; 94 } 95 bzero(fdinst->lastBlock, DES_BLOCK_SIZE_BYTES); 96 bcopy(state, Key, DES_KEY_SIZE_BYTES_EXTERNAL); 97 98 /* 99 * Set up parity bits 100 */ 101 for(byte=0; byte<DES_KEY_SIZE_BYTES_EXTERNAL; byte++){ 102 int i; 103 unsigned p; 104 105 p = 0; 106 for(i=0;i<7;i++) { 107 if(Key[byte] & (1 << i)) { 108 p++; 109 } 110 } 111 if((p & 1) == 0) { 112 Key[byte] |= 0x80; 113 } 114 else { 115 Key[byte] &= ~0x80; 116 } 117 } 118 dessetkey(&fdinst->dinst, Key); 119 return FR_Success; 120} 121 122void feeDESSetBlockMode(feeDES des) 123{ 124 fdesInst *fdinst = (fdesInst*) des; 125 126 fdinst->blockMode = 1; 127} 128 129void feeDESSetChainMode(feeDES des) 130{ 131 fdesInst *fdinst = (fdesInst*) des; 132 133 fdinst->blockMode = 0; 134} 135 136unsigned feeDESPlainBlockSize(feeDES des) 137{ 138 return DES_BLOCK_SIZE_BYTES; 139} 140 141unsigned feeDESCipherBlockSize(feeDES des) 142{ 143 return DES_BLOCK_SIZE_BYTES; 144} 145 146unsigned feeDESCipherBufSize(feeDES des) 147{ 148 /* 149 * Normally DES_BLOCK_SIZE, two blocks for finalBlock 150 */ 151 return 2 * DES_BLOCK_SIZE_BYTES; 152} 153 154/* 155 156 * Return the size of ciphertext to hold specified size of plaintext. 157 158 */ 159 160unsigned feeDESCipherTextSize(feeDES des, unsigned plainTextSize) 161 162{ 163 164 unsigned blocks = (plainTextSize + DES_BLOCK_SIZE_BYTES - 1) / 165 DES_BLOCK_SIZE_BYTES; 166 167 if((plainTextSize % DES_BLOCK_SIZE_BYTES) == 0) { 168 /* 169 * One more block for resid count 170 */ 171 blocks++; 172 } 173 174 return blocks * DES_BLOCK_SIZE_BYTES; 175 176} 177 178 179/* 180 * Key size in bits. 181 */ 182unsigned feeDESKeySize(feeDES des) 183{ 184 return DES_KEY_SIZE_BITS; 185} 186 187/* 188 * Encrypt a block or less of data. Caller malloc's cipherText. 189 */ 190feeReturn feeDESEncryptBlock(feeDES des, 191 const unsigned char *plainText, 192 unsigned plainTextLen, 193 unsigned char *cipherText, 194 unsigned *cipherTextLen, // RETURNED 195 int finalBlock) 196{ 197 fdesInst *fdinst = (fdesInst*) des; 198 feeReturn frtn = FR_Success; 199 unsigned cipherLen; 200 201 if(plainTextLen > DES_BLOCK_SIZE_BYTES) { 202 return FR_IllegalArg; 203 } 204 if(plainTextLen) { 205 /* 206 * We're called with plainTextLen = 0 and finalBlock 207 * recursively to clean up last block. 208 */ 209 bcopy(plainText, cipherText, plainTextLen); 210 } 211 if(plainTextLen < DES_BLOCK_SIZE_BYTES) { 212 if(!finalBlock) { 213 /* 214 * odd-size block only legal last time thru 215 */ 216 return FR_IllegalArg; 217 } 218 219 /* 220 * Last block, final byte = residual length. 221 */ 222 cipherText[DES_BLOCK_SIZE_BYTES - 1] = plainTextLen; 223 } 224 225 if(!fdinst->blockMode) { 226 /* 227 * CBC mode; chain in last cipher word 228 */ 229 unsigned char *cp = cipherText; 230 unsigned char *cp1 = fdinst->lastBlock; 231 int i; 232 233 for(i=0; i<DES_BLOCK_SIZE_BYTES; i++) { 234 *cp++ ^= *cp1++; 235 } 236 } 237 endes(&fdinst->dinst, (char *)cipherText); /* Encrypt block */ 238 if(!fdinst->blockMode){ 239 /* 240 * Save outgoing ciphertext for chain 241 */ 242 bcopy(cipherText, fdinst->lastBlock, DES_BLOCK_SIZE_BYTES); 243 } 244 cipherLen = DES_BLOCK_SIZE_BYTES; 245 246 if(finalBlock) { 247 if(plainTextLen == DES_BLOCK_SIZE_BYTES) { 248 /* 249 * Special case: finalBlock true, plainTextLen == blockSize. 250 * In this case we generate one more block of ciphertext, 251 * with a resid length of zero. 252 */ 253 unsigned moreCipher; // additional cipherLen 254 255 frtn = feeDESEncryptBlock(des, 256 NULL, // plainText not used 257 0, // resid 258 cipherText + DES_BLOCK_SIZE_BYTES, // append... 259 &moreCipher, 260 1); 261 if(frtn == FR_Success) { 262 cipherLen += moreCipher; 263 } 264 265 } 266 if(plainTextLen != 0) { 267 /* 268 * Reset internal state in prep for next encrypt/decrypt. 269 * Note we avoid this in the recursive call (plainTextLen = 0). 270 */ 271 bzero(fdinst->lastBlock, DES_BLOCK_SIZE_BYTES); 272 } 273 } 274 275 if(frtn == FR_Success) { 276 *cipherTextLen = cipherLen; 277 } 278 return frtn; 279} 280 281/* 282 * Decrypt a block of data. Caller malloc's plainText. Always 283 * generates DES_BLOCK_SIZE_BYTES bytes or less of plainText. 284 */ 285feeReturn feeDESDecryptBlock(feeDES des, 286 const unsigned char *cipherText, 287 unsigned cipherTextLen, 288 unsigned char *plainText, 289 unsigned *plainTextLen, // RETURNED 290 int finalBlock) 291{ 292 fdesInst *fdinst = (fdesInst*) des; 293 unsigned char work[DES_BLOCK_SIZE_BYTES]; 294 unsigned char ivtmp[DES_BLOCK_SIZE_BYTES]; 295 296 if(cipherTextLen != DES_BLOCK_SIZE_BYTES) { 297 /* 298 * We always generate ciphertext in multiples of block size. 299 */ 300 return FR_IllegalArg; 301 } 302 303 bcopy(cipherText, work, DES_BLOCK_SIZE_BYTES); 304 if(!fdinst->blockMode && !finalBlock) { 305 /* 306 * Save incoming ciphertext for chain 307 */ 308 bcopy(cipherText, ivtmp, DES_BLOCK_SIZE_BYTES); 309 } 310 dedes(&fdinst->dinst, (char *)work); 311 if(!fdinst->blockMode){ 312 /* 313 * Unchain block using previous block's ciphertext; 314 * save current ciphertext for next 315 */ 316 char *cp = (char *)work; 317 char *cp1 = (char*)fdinst->lastBlock; 318 int i; 319 320 for(i=0; i<DES_BLOCK_SIZE_BYTES; i++) { 321 *cp++ ^= *cp1++; 322 } 323 if(!finalBlock) { 324 bcopy(ivtmp, fdinst->lastBlock, DES_BLOCK_SIZE_BYTES); 325 } 326 } 327 if(finalBlock) { 328 /* 329 * deal with residual block; its size is in last byte of 330 * work[] 331 */ 332 unsigned resid = work[DES_BLOCK_SIZE_BYTES-1]; 333 334 if(resid > (DES_BLOCK_SIZE_BYTES-1)) { 335 return FR_BadCipherText; 336 } 337 if(resid > 0) { 338 bcopy(work, plainText, resid); 339 } 340 *plainTextLen = resid; 341 342 /* 343 * Reset internal state in prep for next encrypt/decrypt. 344 */ 345 bzero(fdinst->lastBlock, DES_BLOCK_SIZE_BYTES); 346 } 347 else { 348 bcopy(work, plainText, DES_BLOCK_SIZE_BYTES); 349 *plainTextLen = DES_BLOCK_SIZE_BYTES; 350 } 351 return FR_Success; 352} 353 354/* 355 * Convenience routines to encrypt & decrypt multi-block data. 356 */ 357feeReturn feeDESEncrypt(feeDES des, 358 const unsigned char *plainText, 359 unsigned plainTextLen, 360 unsigned char **cipherText, // malloc'd and RETURNED 361 unsigned *cipherTextLen) // RETURNED 362{ 363 const unsigned char *ptext; // per block 364 unsigned ptextLen; // total to go 365 unsigned thisPtextLen; // per block 366 unsigned ctextLen; // per block 367 unsigned char *ctextResult; // to return 368 unsigned char *ctextPtr; 369 unsigned ctextLenTotal; // running total 370 feeReturn frtn; 371 int finalBlock; 372 unsigned ctextMallocd; 373 374 if(plainTextLen == 0) { 375 dbgLog(("feeDESDecrypt: NULL plainText\n")); 376 return FR_IllegalArg; 377 } 378 379 ptext = plainText; 380 ptextLen = plainTextLen; 381 ctextMallocd = feeDESCipherTextSize(des, plainTextLen); 382 ctextResult = (unsigned char*) fmalloc(ctextMallocd); 383 ctextPtr = ctextResult; 384 ctextLenTotal = 0; 385 386 while(1) { 387 if(ptextLen <= DES_BLOCK_SIZE_BYTES) { 388 finalBlock = 1; 389 thisPtextLen = ptextLen; 390 } 391 else { 392 finalBlock = 0; 393 thisPtextLen = DES_BLOCK_SIZE_BYTES; 394 } 395 frtn = feeDESEncryptBlock(des, 396 ptext, 397 thisPtextLen, 398 ctextPtr, 399 &ctextLen, 400 finalBlock); 401 if(frtn) { 402 dbgLog(("feeDESEncrypt: encrypt error: %s\n", 403 feeReturnString(frtn))); 404 break; 405 } 406 if(ctextLen == 0) { 407 dbgLog(("feeDESEncrypt: null ciphertext\n")); 408 frtn = FR_Internal; 409 break; 410 } 411 ctextLenTotal += ctextLen; 412 if(ctextLenTotal > (plainTextLen + DES_BLOCK_SIZE_BYTES)) { 413 dbgLog(("feeDESEncrypt: ciphertext overflow\n")); 414 frtn = FR_Internal; 415 break; 416 } 417 if(finalBlock) { 418 break; 419 } 420 ctextPtr += ctextLen; 421 ptext += thisPtextLen; 422 ptextLen -= thisPtextLen; 423 } 424 if(frtn) { 425 ffree(ctextResult); 426 *cipherText = NULL; 427 *cipherTextLen = 0; 428 } 429 else { 430 #if FEE_DEBUG 431 if(ctextLenTotal != ctextMallocd) { 432 dbgLog(("feeDESEncrypt: ctextLen error\n")); 433 } 434 #endif /* FEE_DEBUG */ 435 *cipherText = ctextResult; 436 *cipherTextLen = ctextLenTotal; 437 } 438 return frtn; 439 440} 441 442feeReturn feeDESDecrypt(feeDES des, 443 const unsigned char *cipherText, 444 unsigned cipherTextLen, 445 unsigned char **plainText, // malloc'd and RETURNED 446 unsigned *plainTextLen) // RETURNED 447{ 448 const unsigned char *ctext; 449 unsigned ctextLen; // total to go 450 unsigned ptextLen; // per block 451 unsigned char *ptextResult; // to return 452 unsigned char *ptextPtr; 453 unsigned ptextLenTotal; // running total 454 feeReturn frtn = FR_Success; 455 int finalBlock; 456 457 if(cipherTextLen % DES_BLOCK_SIZE_BYTES) { 458 dbgLog(("feeDESDecrypt: unaligned cipherText\n")); 459 return FR_BadCipherText; 460 } 461 if(cipherTextLen == 0) { 462 dbgLog(("feeDESDecrypt: NULL cipherText\n")); 463 return FR_BadCipherText; 464 } 465 466 ctext = cipherText; 467 ctextLen = cipherTextLen; 468 469 /* 470 * Plaintext length always <= cipherTextLen 471 */ 472 ptextResult = (unsigned char*) fmalloc(cipherTextLen); 473 ptextPtr = ptextResult; 474 ptextLenTotal = 0; 475 476 while(ctextLen) { 477 if(ctextLen == DES_BLOCK_SIZE_BYTES) { 478 finalBlock = 1; 479 } 480 else { 481 finalBlock = 0; 482 } 483 frtn = feeDESDecryptBlock(des, 484 ctext, 485 DES_BLOCK_SIZE_BYTES, 486 ptextPtr, 487 &ptextLen, 488 finalBlock); 489 if(frtn) { 490 dbgLog(("feeDESDecrypt decrypt: %s\n", 491 feeReturnString(frtn))); 492 break; 493 } 494 if(ptextLen == 0) { 495 /* 496 * Normal termination case for 497 * plainTextLen % DES_BLOCK_SIZE_BYTES == 0 498 */ 499 if(!finalBlock) { 500 dbgLog(("feeDESDecrypt: decrypt sync" 501 " error!\n")); 502 frtn = FR_BadCipherText; 503 break; 504 } 505 else { 506 break; 507 } 508 } 509 else { 510 ptextPtr += ptextLen; 511 ptextLenTotal += ptextLen; 512 } 513 ctext += DES_BLOCK_SIZE_BYTES; 514 ctextLen -= DES_BLOCK_SIZE_BYTES; 515 } 516 517 if(frtn) { 518 ffree(ptextResult); 519 *plainText = NULL; 520 *plainTextLen = 0; 521 } 522 else { 523 *plainText = ptextResult; 524 *plainTextLen = ptextLenTotal; 525 } 526 return frtn; 527} 528 529#endif /* CRYPTKIT_SYMMETRIC_ENABLE */ 530