-/* 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 <stdlib.h>
-
-#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; byte<DES_KEY_SIZE_BYTES_EXTERNAL; byte++){
- int i;
- unsigned p;
-
- p = 0;
- for(i=0;i<7;i++) {
- if(Key[byte] & (1 << i)) {
- p++;
- }
- }
- if((p & 1) == 0) {
- Key[byte] |= 0x80;
- }
- else {
- Key[byte] &= ~0x80;
- }
- }
- dessetkey(&fdinst->dinst, 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; i<DES_BLOCK_SIZE_BYTES; i++) {
- *cp++ ^= *cp1++;
- }
- }
- endes(&fdinst->dinst, (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; i<DES_BLOCK_SIZE_BYTES; i++) {
- *cp++ ^= *cp1++;
- }
- if(!finalBlock) {
- bcopy(ivtmp, fdinst->lastBlock, 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 */