]> git.saurik.com Git - apple/security.git/blobdiff - Security/libsecurity_cryptkit/lib/feeDES.c
Security-57031.1.35.tar.gz
[apple/security.git] / 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 (file)
index 0000000..57cc150
--- /dev/null
@@ -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 <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 */