X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/Security/libsecurity_cryptkit/lib/feeDES.c diff --git a/Security/libsecurity_cryptkit/lib/feeDES.c b/Security/libsecurity_cryptkit/lib/feeDES.c new file mode 100644 index 00000000..57cc150a --- /dev/null +++ b/Security/libsecurity_cryptkit/lib/feeDES.c @@ -0,0 +1,529 @@ +/* Copyright (c) 1998,2011,2014 Apple Inc. All Rights Reserved. + * + * NOTICE: USE OF THE MATERIALS ACCOMPANYING THIS NOTICE IS SUBJECT + * TO THE TERMS OF THE SIGNED "FAST ELLIPTIC ENCRYPTION (FEE) REFERENCE + * SOURCE CODE EVALUATION AGREEMENT" BETWEEN APPLE, INC. AND THE + * ORIGINAL LICENSEE THAT OBTAINED THESE MATERIALS FROM APPLE, + * INC. ANY USE OF THESE MATERIALS NOT PERMITTED BY SUCH AGREEMENT WILL + * EXPOSE YOU TO LIABILITY. + *************************************************************************** + * + * FeeDES.c - generic, portable DES encryption object + * + * Revision History + * ---------------- + * 10/06/98 ap + * Changed to compile with C++. + * 05 Jan 98 at Apple + * Avoid a bcopy() on encrypt/decrypt of each block + * 31 Mar 97 at Apple + * New per-instance API for DES.c + * 26 Aug 96 at NeXT + * Created. + */ + +#include "ckconfig.h" + +#if CRYPTKIT_SYMMETRIC_ENABLE + +#include "feeDES.h" +#include "feeTypes.h" +#include "ckDES.h" +#include "falloc.h" +#include "feeDebug.h" +#include "feeFunctions.h" +#include "platform.h" +#include + +#ifndef NULL +#define NULL ((void *)0) +#endif /* NULL */ + +typedef struct { + int blockMode; /* default = 0 */ + unsigned char lastBlock[DES_BLOCK_SIZE_BYTES]; /* for CBC */ + struct _desInst dinst; +} fdesInst; + +static void feeDESInit(desInst dinst) +{ + desinit(dinst, DES_MODE_STD); // detects redundant calls +} + +/* + * Alloc and init a feeDES object with specified initial state. + * State must be at least 8 bytes; only 8 bytes are used, ignoring + * MSB of each bytes. + */ +feeDES feeDESNewWithState(const unsigned char *state, + unsigned stateLen) +{ + fdesInst *fdinst; + + if(stateLen < FEE_DES_MIN_STATE_SIZE) { + return NULL; + } + fdinst = (fdesInst*) fmalloc(sizeof(fdesInst)); + bzero(fdinst, sizeof(fdesInst)); + feeDESInit(&fdinst->dinst); + feeDESSetState((feeDES)fdinst, state, stateLen); + return fdinst; +} + +void feeDESFree(feeDES des) +{ + memset(des, 0, sizeof(fdesInst)); + ffree(des); +} + +/* + * Set new initial state. + */ +feeReturn feeDESSetState(feeDES des, + const unsigned char *state, + unsigned stateLen) +{ + fdesInst *fdinst = (fdesInst*) des; + char Key[DES_KEY_SIZE_BYTES_EXTERNAL]; + // 'key' causes problems with + // some weird Unix header + unsigned byte; + + if(stateLen < (DES_KEY_SIZE_BYTES_EXTERNAL)) { + return FR_IllegalArg; + } + bzero(fdinst->lastBlock, DES_BLOCK_SIZE_BYTES); + bcopy(state, Key, DES_KEY_SIZE_BYTES_EXTERNAL); + + /* + * Set up parity bits + */ + for(byte=0; bytedinst, Key); + return FR_Success; +} + +void feeDESSetBlockMode(feeDES des) +{ + fdesInst *fdinst = (fdesInst*) des; + + fdinst->blockMode = 1; +} + +void feeDESSetChainMode(feeDES des) +{ + fdesInst *fdinst = (fdesInst*) des; + + fdinst->blockMode = 0; +} + +unsigned feeDESPlainBlockSize(feeDES des) +{ + return DES_BLOCK_SIZE_BYTES; +} + +unsigned feeDESCipherBlockSize(feeDES des) +{ + return DES_BLOCK_SIZE_BYTES; +} + +unsigned feeDESCipherBufSize(feeDES des) +{ + /* + * Normally DES_BLOCK_SIZE, two blocks for finalBlock + */ + return 2 * DES_BLOCK_SIZE_BYTES; +} + +/* + + * Return the size of ciphertext to hold specified size of plaintext. + + */ + +unsigned feeDESCipherTextSize(feeDES des, unsigned plainTextSize) + +{ + + unsigned blocks = (plainTextSize + DES_BLOCK_SIZE_BYTES - 1) / + DES_BLOCK_SIZE_BYTES; + + if((plainTextSize % DES_BLOCK_SIZE_BYTES) == 0) { + /* + * One more block for resid count + */ + blocks++; + } + + return blocks * DES_BLOCK_SIZE_BYTES; + +} + + +/* + * Key size in bits. + */ +unsigned feeDESKeySize(feeDES des) +{ + return DES_KEY_SIZE_BITS; +} + +/* + * Encrypt a block or less of data. Caller malloc's cipherText. + */ +feeReturn feeDESEncryptBlock(feeDES des, + const unsigned char *plainText, + unsigned plainTextLen, + unsigned char *cipherText, + unsigned *cipherTextLen, // RETURNED + int finalBlock) +{ + fdesInst *fdinst = (fdesInst*) des; + feeReturn frtn = FR_Success; + unsigned cipherLen; + + if(plainTextLen > DES_BLOCK_SIZE_BYTES) { + return FR_IllegalArg; + } + if(plainTextLen) { + /* + * We're called with plainTextLen = 0 and finalBlock + * recursively to clean up last block. + */ + bcopy(plainText, cipherText, plainTextLen); + } + if(plainTextLen < DES_BLOCK_SIZE_BYTES) { + if(!finalBlock) { + /* + * odd-size block only legal last time thru + */ + return FR_IllegalArg; + } + + /* + * Last block, final byte = residual length. + */ + cipherText[DES_BLOCK_SIZE_BYTES - 1] = plainTextLen; + } + + if(!fdinst->blockMode) { + /* + * CBC mode; chain in last cipher word + */ + unsigned char *cp = cipherText; + unsigned char *cp1 = fdinst->lastBlock; + int i; + + for(i=0; idinst, (char *)cipherText); /* Encrypt block */ + if(!fdinst->blockMode){ + /* + * Save outgoing ciphertext for chain + */ + bcopy(cipherText, fdinst->lastBlock, DES_BLOCK_SIZE_BYTES); + } + cipherLen = DES_BLOCK_SIZE_BYTES; + + if(finalBlock) { + if(plainTextLen == DES_BLOCK_SIZE_BYTES) { + /* + * Special case: finalBlock true, plainTextLen == blockSize. + * In this case we generate one more block of ciphertext, + * with a resid length of zero. + */ + unsigned moreCipher; // additional cipherLen + + frtn = feeDESEncryptBlock(des, + NULL, // plainText not used + 0, // resid + cipherText + DES_BLOCK_SIZE_BYTES, // append... + &moreCipher, + 1); + if(frtn == FR_Success) { + cipherLen += moreCipher; + } + + } + if(plainTextLen != 0) { + /* + * Reset internal state in prep for next encrypt/decrypt. + * Note we avoid this in the recursive call (plainTextLen = 0). + */ + bzero(fdinst->lastBlock, DES_BLOCK_SIZE_BYTES); + } + } + + if(frtn == FR_Success) { + *cipherTextLen = cipherLen; + } + return frtn; +} + +/* + * Decrypt a block of data. Caller malloc's plainText. Always + * generates DES_BLOCK_SIZE_BYTES bytes or less of plainText. + */ +feeReturn feeDESDecryptBlock(feeDES des, + const unsigned char *cipherText, + unsigned cipherTextLen, + unsigned char *plainText, + unsigned *plainTextLen, // RETURNED + int finalBlock) +{ + fdesInst *fdinst = (fdesInst*) des; + unsigned char work[DES_BLOCK_SIZE_BYTES]; + unsigned char ivtmp[DES_BLOCK_SIZE_BYTES]; + + if(cipherTextLen != DES_BLOCK_SIZE_BYTES) { + /* + * We always generate ciphertext in multiples of block size. + */ + return FR_IllegalArg; + } + + bcopy(cipherText, work, DES_BLOCK_SIZE_BYTES); + if(!fdinst->blockMode && !finalBlock) { + /* + * Save incoming ciphertext for chain + */ + bcopy(cipherText, ivtmp, DES_BLOCK_SIZE_BYTES); + } + dedes(&fdinst->dinst, (char *)work); + if(!fdinst->blockMode){ + /* + * Unchain block using previous block's ciphertext; + * save current ciphertext for next + */ + char *cp = (char *)work; + char *cp1 = (char*)fdinst->lastBlock; + int i; + + for(i=0; ilastBlock, DES_BLOCK_SIZE_BYTES); + } + } + if(finalBlock) { + /* + * deal with residual block; its size is in last byte of + * work[] + */ + unsigned resid = work[DES_BLOCK_SIZE_BYTES-1]; + + if(resid > (DES_BLOCK_SIZE_BYTES-1)) { + return FR_BadCipherText; + } + if(resid > 0) { + bcopy(work, plainText, resid); + } + *plainTextLen = resid; + + /* + * Reset internal state in prep for next encrypt/decrypt. + */ + bzero(fdinst->lastBlock, DES_BLOCK_SIZE_BYTES); + } + else { + bcopy(work, plainText, DES_BLOCK_SIZE_BYTES); + *plainTextLen = DES_BLOCK_SIZE_BYTES; + } + return FR_Success; +} + +/* + * Convenience routines to encrypt & decrypt multi-block data. + */ +feeReturn feeDESEncrypt(feeDES des, + const unsigned char *plainText, + unsigned plainTextLen, + unsigned char **cipherText, // malloc'd and RETURNED + unsigned *cipherTextLen) // RETURNED +{ + const unsigned char *ptext; // per block + unsigned ptextLen; // total to go + unsigned thisPtextLen; // per block + unsigned ctextLen; // per block + unsigned char *ctextResult; // to return + unsigned char *ctextPtr; + unsigned ctextLenTotal; // running total + feeReturn frtn; + int finalBlock; + unsigned ctextMallocd; + + if(plainTextLen == 0) { + dbgLog(("feeDESDecrypt: NULL plainText\n")); + return FR_IllegalArg; + } + + ptext = plainText; + ptextLen = plainTextLen; + ctextMallocd = feeDESCipherTextSize(des, plainTextLen); + ctextResult = (unsigned char*) fmalloc(ctextMallocd); + ctextPtr = ctextResult; + ctextLenTotal = 0; + + while(1) { + if(ptextLen <= DES_BLOCK_SIZE_BYTES) { + finalBlock = 1; + thisPtextLen = ptextLen; + } + else { + finalBlock = 0; + thisPtextLen = DES_BLOCK_SIZE_BYTES; + } + frtn = feeDESEncryptBlock(des, + ptext, + thisPtextLen, + ctextPtr, + &ctextLen, + finalBlock); + if(frtn) { + dbgLog(("feeDESEncrypt: encrypt error: %s\n", + feeReturnString(frtn))); + break; + } + if(ctextLen == 0) { + dbgLog(("feeDESEncrypt: null ciphertext\n")); + frtn = FR_Internal; + break; + } + ctextLenTotal += ctextLen; + if(ctextLenTotal > (plainTextLen + DES_BLOCK_SIZE_BYTES)) { + dbgLog(("feeDESEncrypt: ciphertext overflow\n")); + frtn = FR_Internal; + break; + } + if(finalBlock) { + break; + } + ctextPtr += ctextLen; + ptext += thisPtextLen; + ptextLen -= thisPtextLen; + } + if(frtn) { + ffree(ctextResult); + *cipherText = NULL; + *cipherTextLen = 0; + } + else { + #if FEE_DEBUG + if(ctextLenTotal != ctextMallocd) { + dbgLog(("feeDESEncrypt: ctextLen error\n")); + } + #endif /* FEE_DEBUG */ + *cipherText = ctextResult; + *cipherTextLen = ctextLenTotal; + } + return frtn; + +} + +feeReturn feeDESDecrypt(feeDES des, + const unsigned char *cipherText, + unsigned cipherTextLen, + unsigned char **plainText, // malloc'd and RETURNED + unsigned *plainTextLen) // RETURNED +{ + const unsigned char *ctext; + unsigned ctextLen; // total to go + unsigned ptextLen; // per block + unsigned char *ptextResult; // to return + unsigned char *ptextPtr; + unsigned ptextLenTotal; // running total + feeReturn frtn = FR_Success; + int finalBlock; + + if(cipherTextLen % DES_BLOCK_SIZE_BYTES) { + dbgLog(("feeDESDecrypt: unaligned cipherText\n")); + return FR_BadCipherText; + } + if(cipherTextLen == 0) { + dbgLog(("feeDESDecrypt: NULL cipherText\n")); + return FR_BadCipherText; + } + + ctext = cipherText; + ctextLen = cipherTextLen; + + /* + * Plaintext length always <= cipherTextLen + */ + ptextResult = (unsigned char*) fmalloc(cipherTextLen); + ptextPtr = ptextResult; + ptextLenTotal = 0; + + while(ctextLen) { + if(ctextLen == DES_BLOCK_SIZE_BYTES) { + finalBlock = 1; + } + else { + finalBlock = 0; + } + frtn = feeDESDecryptBlock(des, + ctext, + DES_BLOCK_SIZE_BYTES, + ptextPtr, + &ptextLen, + finalBlock); + if(frtn) { + dbgLog(("feeDESDecrypt decrypt: %s\n", + feeReturnString(frtn))); + break; + } + if(ptextLen == 0) { + /* + * Normal termination case for + * plainTextLen % DES_BLOCK_SIZE_BYTES == 0 + */ + if(!finalBlock) { + dbgLog(("feeDESDecrypt: decrypt sync" + " error!\n")); + frtn = FR_BadCipherText; + break; + } + else { + break; + } + } + else { + ptextPtr += ptextLen; + ptextLenTotal += ptextLen; + } + ctext += DES_BLOCK_SIZE_BYTES; + ctextLen -= DES_BLOCK_SIZE_BYTES; + } + + if(frtn) { + ffree(ptextResult); + *plainText = NULL; + *plainTextLen = 0; + } + else { + *plainText = ptextResult; + *plainTextLen = ptextLenTotal; + } + return frtn; +} + +#endif /* CRYPTKIT_SYMMETRIC_ENABLE */