]> git.saurik.com Git - apple/security.git/blobdiff - libsecurity_smime/lib/cmscipher.c
Security-57740.51.3.tar.gz
[apple/security.git] / libsecurity_smime / lib / cmscipher.c
index 60ee4501617f14a2f9cc6a5802527fdbea2b8a8d..5d869a6efdf05a27463675af451f98dec6f9e58e 100644 (file)
  * Encryption/decryption routines for CMS implementation, none of which are exported.
  *
  */
+#include <limits.h>
 
 #include "cmslocal.h"
 
 #include "secoid.h"
 #include <security_asn1/secerr.h>
 #include <security_asn1/secasn1.h>
+#include <security_asn1/secport.h>
+
 #include <Security/SecAsn1Templates.h>
-#include <Security/cssmapi.h>
-#include <Security/cssmapple.h>
-#include <Security/SecKeyPriv.h>
+#include <Security/SecRandom.h>
+#include <CommonCrypto/CommonCryptor.h>
 
 /*
  * -------------------------------------------------------------------
@@ -61,14 +63,14 @@ typedef OSStatus (*nss_cms_cipher_destroy) (void *, Boolean);
 
 struct SecCmsCipherContextStr {
 #if 1
-    CSSM_CC_HANDLE     cc;                     /* CSP CONTEXT */
+    void *              cc;                    /* CSP CONTEXT */
     Boolean            encrypt;                /* encrypt / decrypt switch */
+    int                        block_size;             /* block & pad sizes for cipher */
 #else
     void *             cx;                     /* PK11 cipher context */
     nss_cms_cipher_function doit;
     nss_cms_cipher_destroy destroy;
     Boolean            encrypt;                /* encrypt / decrypt switch */
-    int                        block_size;             /* block & pad sizes for cipher */
     int                        pad_size;
     int                        pending_count;          /* pending data (not yet en/decrypted */
     unsigned char      pending_buf[BLOCK_SIZE];/* because of blocking */
@@ -76,11 +78,11 @@ struct SecCmsCipherContextStr {
 };
 
 typedef struct sec_rc2cbcParameterStr {
-    SECItem rc2ParameterVersion;
-    SECItem iv;
+    SecAsn1Item rc2ParameterVersion;
+    SecAsn1Item iv;
 } sec_rc2cbcParameter;
 
-static const SecAsn1Template sec_rc2cbc_parameter_template[] = {
+__unused static const SecAsn1Template sec_rc2cbc_parameter_template[] = {
     { SEC_ASN1_SEQUENCE,
           0, NULL, sizeof(sec_rc2cbcParameter) },
     { SEC_ASN1_INTEGER | SEC_ASN1_SIGNED_INT,
@@ -90,65 +92,6 @@ static const SecAsn1Template sec_rc2cbc_parameter_template[] = {
     { 0 }
 };
 
-/*
-** Convert a der encoded *signed* integer into a machine integral value.
-** If an underflow/overflow occurs, sets error code and returns min/max.
-*/
-static long
-DER_GetInteger(SECItem *it)
-{
-    long ival = 0;
-    unsigned len = it->Length;
-    unsigned char *cp = it->Data;
-    unsigned long overflow = 0x1ffUL << (((sizeof(ival) - 1) * 8) - 1);
-    unsigned long ofloinit;
-
-    if (*cp & 0x80)
-        ival = -1L;
-    ofloinit = ival & overflow;
-
-    while (len) {
-        if ((ival & overflow) != ofloinit) {
-            PORT_SetError(SEC_ERROR_BAD_DER);
-            if (ival < 0) {
-                return LONG_MIN;
-            }
-            return LONG_MAX;
-        }
-        ival = ival << 8;
-        ival |= *cp++;
-        --len;
-    }
-    return ival;
-}
-
-/* S/MIME picked id values to represent differnt keysizes */      
-/* I do have a formula, but it ain't pretty, and it only works because you
- * can always match three points to a parabola:) */
-static unsigned char  rc2_map(SECItem *version)
-{
-    long x;
-
-    x = DER_GetInteger(version);
-
-    switch (x) {
-        case 58: return 128;
-        case 120: return 64;
-        case 160: return 40;
-    }
-    return 128;     
-}
-
-static unsigned long  rc2_unmap(unsigned long x)
-{
-    switch (x) {
-        case 128: return 58;
-        case 64: return 120;
-        case 40: return 160;
-    }
-    return 58;
-}
-
 /* default IV size in bytes */
 #define DEFAULT_IV_SIZE            8
 /* IV/block size for AES */
@@ -156,95 +99,62 @@ static unsigned long  rc2_unmap(unsigned long x)
 /* max IV size in bytes */
 #define MAX_IV_SIZE        AES_BLOCK_SIZE
 
+#ifndef kCCKeySizeMaxRC2
+#define kCCKeySizeMaxRC2 16
+#endif
+#ifndef kCCBlockSizeRC2
+#define kCCBlockSizeRC2 8
+#endif
+
 static SecCmsCipherContextRef
 SecCmsCipherContextStart(PRArenaPool *poolp, SecSymmetricKeyRef key, SECAlgorithmID *algid, Boolean encrypt)
 {
     SecCmsCipherContextRef cc;
-    CSSM_CC_HANDLE ciphercc = 0;
     SECOidData *oidData;
     SECOidTag algtag;
-    CSSM_ALGORITHMS algorithm;
-    CSSM_PADDING padding = CSSM_PADDING_PKCS7;
-    CSSM_ENCRYPT_MODE mode;
-    CSSM_CSP_HANDLE cspHandle;
-    const CSSM_KEY *cssmKey;
     OSStatus rv;
-    uint8 ivbuf[MAX_IV_SIZE];
-    CSSM_DATA initVector = { DEFAULT_IV_SIZE, ivbuf };
-    //CSSM_CONTEXT_ATTRIBUTE contextAttribute = { CSSM_ATTRIBUTE_ALG_PARAMS, sizeof(CSSM_DATA_PTR) };
-
-    rv = SecKeyGetCSPHandle(key, &cspHandle);
-    if (rv)
-       goto loser;
-    rv = SecKeyGetCSSMKey(key, &cssmKey);
-    if (rv)
-       goto loser;
-
+    uint8_t ivbuf[MAX_IV_SIZE];
+    SecAsn1Item initVector = { DEFAULT_IV_SIZE, ivbuf };
+    CCCryptorRef ciphercc = NULL;
+    CCOptions cipheroptions = kCCOptionPKCS7Padding;
+    int cipher_blocksize = 0;
     // @@@ Add support for PBE based stuff
 
     oidData = SECOID_FindOID(&algid->algorithm);
     if (!oidData)
        goto loser;
     algtag = oidData->offset;
-    algorithm = oidData->cssmAlgorithm;
-    if (!algorithm)
-       goto loser;
-
-    switch (algtag)
-    {
-    case SEC_OID_RC2_CBC:
-    case SEC_OID_RC4:
-    case SEC_OID_DES_EDE3_CBC:
-    case SEC_OID_DES_EDE:
-    case SEC_OID_DES_CBC:
-    case SEC_OID_RC5_CBC_PAD:
-    case SEC_OID_FORTEZZA_SKIPJACK:
-       mode = CSSM_ALGMODE_CBCPadIV8;
-       break;
-       
-    /* RFC 3565 says that these sizes refer to key size, NOT block size */
-    case SEC_OID_AES_128_CBC:
-    case SEC_OID_AES_192_CBC:
-    case SEC_OID_AES_256_CBC:
-       initVector.Length = AES_BLOCK_SIZE;
-       mode = CSSM_ALGMODE_CBCPadIV8;
-       break;
-
-    case SEC_OID_DES_ECB:
-    case SEC_OID_AES_128_ECB:
-    case SEC_OID_AES_192_ECB:
-    case SEC_OID_AES_256_ECB:
-       mode = CSSM_ALGMODE_ECBPad;
-       break;
-
-    case SEC_OID_DES_OFB:
-       mode = CSSM_ALGMODE_OFBPadIV8;
-       break;
 
-    case SEC_OID_DES_CFB:
-       mode = CSSM_ALGMODE_CFBPadIV8;
-       break;
-
-    default:
-       goto loser;
+    CCAlgorithm alg = -1;
+    switch (algtag) {
+        case SEC_OID_DES_CBC:
+            alg = kCCAlgorithmDES;
+            cipher_blocksize = kCCBlockSizeDES;
+            break;
+        case SEC_OID_DES_EDE3_CBC:
+            alg = kCCAlgorithm3DES;
+            cipher_blocksize = kCCBlockSize3DES;
+            break;
+        case SEC_OID_RC2_CBC:
+            alg = kCCAlgorithmRC2;
+            cipher_blocksize = kCCBlockSizeRC2;
+            break;
+        case SEC_OID_AES_128_CBC: 
+        case SEC_OID_AES_192_CBC:
+        case SEC_OID_AES_256_CBC:
+            alg = kCCAlgorithmAES128;
+            cipher_blocksize = kCCBlockSizeAES128;
+            initVector.Length = AES_BLOCK_SIZE;
+             break;
+        default: 
+            goto loser;
     }
 
     if (encrypt)
     {
-       CSSM_CC_HANDLE randomcc;
-       //SECItem *parameters;
-
-       // Generate random initVector
-       if (CSSM_CSP_CreateRandomGenContext(cspHandle,
-               CSSM_ALGID_APPLE_YARROW,
-               NULL, /* seed*/
-               initVector.Length,
-               &randomcc))
-           goto loser;
-
-       if (CSSM_GenerateRandom(randomcc, &initVector))
-           goto loser;
-       CSSM_DeleteContext(randomcc);
+        if (SecRandomCopyBytes(kSecRandomDefault, 
+            initVector.Length, initVector.Data))
+                goto loser;
 
        // Put IV into algid.parameters
        switch (algtag)
@@ -268,25 +178,7 @@ SecCmsCipherContextStart(PRArenaPool *poolp, SecSymmetricKeyRef key, SECAlgorith
                                    &initVector, kSecAsn1OctetStringTemplate))
                goto loser;
            break;
-    
        case SEC_OID_RC2_CBC:
-       {
-           sec_rc2cbcParameter rc2 = {};
-           unsigned long rc2version;
-           SECItem *newParams;
-
-           rc2.iv = initVector;
-           rc2version = rc2_unmap(cssmKey->KeyHeader.LogicalKeySizeInBits);
-           if (!SEC_ASN1EncodeUnsignedInteger (NULL, &(rc2.rc2ParameterVersion),
-                                              rc2version))
-               goto loser;
-           newParams = SEC_ASN1EncodeItem (poolp, &algid->parameters, &rc2,
-                               sec_rc2cbc_parameter_template);
-           PORT_Free(rc2.rc2ParameterVersion.Data);
-           if (newParams == NULL)
-               goto loser;
-           break;
-       }
        case SEC_OID_RC5_CBC_PAD:
        default:
            // @@@ Implement rc5 params stuff.
@@ -315,7 +207,7 @@ SecCmsCipherContextStart(PRArenaPool *poolp, SecSymmetricKeyRef key, SECAlgorith
        case SEC_OID_DES_OFB:
        case SEC_OID_DES_CFB:
        {
-           CSSM_DATA iv = {};
+           SecAsn1Item iv = {};
            /* Just decode the initVector from an octet string. */
            rv = SEC_ASN1DecodeItem(NULL, &iv, kSecAsn1OctetStringTemplate, &(algid->parameters));
            if (rv)
@@ -329,29 +221,6 @@ SecCmsCipherContextStart(PRArenaPool *poolp, SecSymmetricKeyRef key, SECAlgorith
            break;
        }
        case SEC_OID_RC2_CBC:
-       {
-           sec_rc2cbcParameter rc2 = {};
-           unsigned long ulEffectiveBits;
-
-           rv = SEC_ASN1DecodeItem(NULL, &rc2 ,sec_rc2cbc_parameter_template,
-                                                           &(algid->parameters));
-           if (rv)
-               goto loser;
-
-           if (initVector.Length != rc2.iv.Length) {
-               PORT_Free(rc2.iv.Data);
-               PORT_Free(rc2.rc2ParameterVersion.Data);
-               goto loser;
-           }
-           memcpy(initVector.Data, rc2.iv.Data, initVector.Length);
-           PORT_Free(rc2.iv.Data);
-
-           ulEffectiveBits = rc2_map(&rc2.rc2ParameterVersion);
-           PORT_Free(rc2.rc2ParameterVersion.Data);
-           if (ulEffectiveBits != cssmKey->KeyHeader.LogicalKeySizeInBits)
-               goto loser;
-           break;
-       }
        case SEC_OID_RC5_CBC_PAD:
        default:
            // @@@ Implement rc5 params stuff.
@@ -360,23 +229,10 @@ SecCmsCipherContextStart(PRArenaPool *poolp, SecSymmetricKeyRef key, SECAlgorith
        }
     }
 
-    if (CSSM_CSP_CreateSymmetricContext(cspHandle,
-           algorithm,
-           mode,
-           NULL, /* accessCred */
-           cssmKey,
-           &initVector,
-           padding,
-           NULL, /* reserved */
-           &ciphercc))
-       goto loser;
-
-    if (encrypt)
-       rv = CSSM_EncryptDataInit(ciphercc);
-    else
-       rv = CSSM_DecryptDataInit(ciphercc);
-    if (rv)
-       goto loser;
+        if (CCCryptorCreate(encrypt ? kCCEncrypt : kCCDecrypt, 
+            alg, cipheroptions, CFDataGetBytePtr(key), CFDataGetLength(key), 
+            initVector.Data, &ciphercc))
+                goto loser;
 
     cc = (SecCmsCipherContextRef)PORT_ZAlloc(sizeof(SecCmsCipherContext));
     if (cc == NULL)
@@ -384,11 +240,11 @@ SecCmsCipherContextStart(PRArenaPool *poolp, SecSymmetricKeyRef key, SECAlgorith
 
     cc->cc = ciphercc;
     cc->encrypt = encrypt;
-
+    cc->block_size =cipher_blocksize;
     return cc;
 loser:
     if (ciphercc)
-       CSSM_DeleteContext(ciphercc);
+        CCCryptorRelease(ciphercc);
 
     return NULL;
 }
@@ -405,88 +261,6 @@ SecCmsCipherContextRef
 SecCmsCipherContextStartDecrypt(SecSymmetricKeyRef key, SECAlgorithmID *algid)
 {
     return SecCmsCipherContextStart(NULL, key, algid, PR_FALSE);
-#if 0
-    SecCmsCipherContextRef cc;
-    void *ciphercx;
-    CK_MECHANISM_TYPE mechanism;
-    CSSM_DATA_PTR param;
-    PK11SlotInfo *slot;
-    SECOidTag algtag;
-
-    algtag = SECOID_GetAlgorithmTag(algid);
-
-    /* set param and mechanism */
-    if (SEC_PKCS5IsAlgorithmPBEAlg(algid)) {
-       CK_MECHANISM pbeMech, cryptoMech;
-       CSSM_DATA_PTR pbeParams;
-       SEC_PKCS5KeyAndPassword *keyPwd;
-
-       PORT_Memset(&pbeMech, 0, sizeof(CK_MECHANISM));
-       PORT_Memset(&cryptoMech, 0, sizeof(CK_MECHANISM));
-
-       /* HACK ALERT!
-        * in this case, key is not actually a SecSymmetricKeyRef, but a SEC_PKCS5KeyAndPassword *
-        */
-       keyPwd = (SEC_PKCS5KeyAndPassword *)key;
-       key = keyPwd->key;
-
-       /* find correct PK11 mechanism and parameters to initialize pbeMech */
-       pbeMech.mechanism = PK11_AlgtagToMechanism(algtag);
-       pbeParams = PK11_ParamFromAlgid(algid);
-       if (!pbeParams)
-           return NULL;
-       pbeMech.pParameter = pbeParams->Data;
-       pbeMech.ulParameterLen = pbeParams->Length;
-
-       /* now map pbeMech to cryptoMech */
-       if (PK11_MapPBEMechanismToCryptoMechanism(&pbeMech, &cryptoMech, keyPwd->pwitem,
-                                                 PR_FALSE) != CKR_OK) { 
-           SECITEM_ZfreeItem(pbeParams, PR_TRUE);
-           return NULL;
-       }
-       SECITEM_ZfreeItem(pbeParams, PR_TRUE);
-
-       /* and use it to initialize param & mechanism */
-       if ((param = (CSSM_DATA_PTR)PORT_ZAlloc(sizeof(CSSM_DATA))) == NULL)
-            return NULL;
-
-       param->Data = (unsigned char *)cryptoMech.pParameter;
-       param->Length = cryptoMech.ulParameterLen;
-       mechanism = cryptoMech.mechanism;
-    } else {
-       mechanism = PK11_AlgtagToMechanism(algtag);
-       if ((param = PK11_ParamFromAlgid(algid)) == NULL)
-           return NULL;
-    }
-
-    cc = (SecCmsCipherContextRef)PORT_ZAlloc(sizeof(SecCmsCipherContext));
-    if (cc == NULL) {
-       SECITEM_FreeItem(param,PR_TRUE);
-       return NULL;
-    }
-
-    /* figure out pad and block sizes */
-    cc->pad_size = PK11_GetBlockSize(mechanism, param);
-    slot = PK11_GetSlotFromKey(key);
-    cc->block_size = PK11_IsHW(slot) ? BLOCK_SIZE : cc->pad_size;
-    PK11_FreeSlot(slot);
-
-    /* create PK11 cipher context */
-    ciphercx = PK11_CreateContextBySymKey(mechanism, CKA_DECRYPT, key, param);
-    SECITEM_FreeItem(param, PR_TRUE);
-    if (ciphercx == NULL) {
-       PORT_Free (cc);
-       return NULL;
-    }
-
-    cc->cx = ciphercx;
-    cc->doit =  (nss_cms_cipher_function) PK11_CipherOp;
-    cc->destroy = (nss_cms_cipher_destroy) PK11_DestroyContext;
-    cc->encrypt = PR_FALSE;
-    cc->pending_count = 0;
-
-    return cc;
-#endif
 }
 
 /*
@@ -502,107 +276,6 @@ SecCmsCipherContextRef
 SecCmsCipherContextStartEncrypt(PRArenaPool *poolp, SecSymmetricKeyRef key, SECAlgorithmID *algid)
 {
     return SecCmsCipherContextStart(poolp, key, algid, PR_TRUE);
-#if 0
-    SecCmsCipherContextRef cc;
-    void *ciphercx;
-    CSSM_DATA_PTR param;
-    OSStatus rv;
-    CK_MECHANISM_TYPE mechanism;
-    PK11SlotInfo *slot;
-    Boolean needToEncodeAlgid = PR_FALSE;
-    SECOidTag algtag = SECOID_GetAlgorithmTag(algid);
-
-    /* set param and mechanism */
-    if (SEC_PKCS5IsAlgorithmPBEAlg(algid)) {
-       CK_MECHANISM pbeMech, cryptoMech;
-       CSSM_DATA_PTR pbeParams;
-       SEC_PKCS5KeyAndPassword *keyPwd;
-
-       PORT_Memset(&pbeMech, 0, sizeof(CK_MECHANISM));
-       PORT_Memset(&cryptoMech, 0, sizeof(CK_MECHANISM));
-
-       /* HACK ALERT!
-        * in this case, key is not actually a SecSymmetricKeyRef, but a SEC_PKCS5KeyAndPassword *
-        */
-       keyPwd = (SEC_PKCS5KeyAndPassword *)key;
-       key = keyPwd->key;
-
-       /* find correct PK11 mechanism and parameters to initialize pbeMech */
-       pbeMech.mechanism = PK11_AlgtagToMechanism(algtag);
-       pbeParams = PK11_ParamFromAlgid(algid);
-       if (!pbeParams)
-           return NULL;
-       pbeMech.pParameter = pbeParams->Data;
-       pbeMech.ulParameterLen = pbeParams->Length;
-
-       /* now map pbeMech to cryptoMech */
-       if (PK11_MapPBEMechanismToCryptoMechanism(&pbeMech, &cryptoMech, keyPwd->pwitem,
-                                                 PR_FALSE) != CKR_OK) { 
-           SECITEM_ZfreeItem(pbeParams, PR_TRUE);
-           return NULL;
-       }
-       SECITEM_ZfreeItem(pbeParams, PR_TRUE);
-
-       /* and use it to initialize param & mechanism */
-       if ((param = (CSSM_DATA_PTR)PORT_ZAlloc(sizeof(CSSM_DATA))) == NULL)
-           return NULL;
-
-       param->Data = (unsigned char *)cryptoMech.pParameter;
-       param->Length = cryptoMech.ulParameterLen;
-       mechanism = cryptoMech.mechanism;
-    } else {
-       mechanism = PK11_AlgtagToMechanism(algtag);
-       if ((param = PK11_GenerateNewParam(mechanism, key)) == NULL)
-           return NULL;
-       needToEncodeAlgid = PR_TRUE;
-    }
-
-    cc = (SecCmsCipherContextRef)PORT_ZAlloc(sizeof(SecCmsCipherContext));
-    if (cc == NULL)
-       return NULL;
-
-    /* now find pad and block sizes for our mechanism */
-    cc->pad_size = PK11_GetBlockSize(mechanism,param);
-    slot = PK11_GetSlotFromKey(key);
-    cc->block_size = PK11_IsHW(slot) ? BLOCK_SIZE : cc->pad_size;
-    PK11_FreeSlot(slot);
-
-    /* and here we go, creating a PK11 cipher context */
-    ciphercx = PK11_CreateContextBySymKey(mechanism, CKA_ENCRYPT, key, param);
-    if (ciphercx == NULL) {
-       PORT_Free(cc);
-       cc = NULL;
-       goto loser;
-    }
-
-    /*
-     * These are placed after the CreateContextBySymKey() because some
-     * mechanisms have to generate their IVs from their card (i.e. FORTEZZA).
-     * Don't move it from here.
-     * XXX is that right? the purpose of this is to get the correct algid
-     *     containing the IVs etc. for encoding. this means we need to set this up
-     *     BEFORE encoding the algid in the contentInfo, right?
-     */
-    if (needToEncodeAlgid) {
-       rv = PK11_ParamToAlgid(algtag, param, poolp, algid);
-       if(rv != SECSuccess) {
-           PORT_Free(cc);
-           cc = NULL;
-           goto loser;
-       }
-    }
-
-    cc->cx = ciphercx;
-    cc->doit = (nss_cms_cipher_function)PK11_CipherOp;
-    cc->destroy = (nss_cms_cipher_destroy)PK11_DestroyContext;
-    cc->encrypt = PR_TRUE;
-    cc->pending_count = 0;
-
-loser:
-    SECITEM_FreeItem(param, PR_TRUE);
-
-    return cc;
-#endif
 }
 
 void
@@ -611,23 +284,16 @@ SecCmsCipherContextDestroy(SecCmsCipherContextRef cc)
     PORT_Assert(cc != NULL);
     if (cc == NULL)
        return;
-    CSSM_DeleteContext(cc->cc);
+
+    CCCryptorRelease(cc->cc);
+
     PORT_Free(cc);
 }
 
-unsigned int
+static unsigned int
 SecCmsCipherContextLength(SecCmsCipherContextRef cc, unsigned int input_len, Boolean final, Boolean encrypt)
 {
-    CSSM_QUERY_SIZE_DATA dataBlockSize[2] = { { input_len, 0 }, { input_len, 0 } };
-    /* Hack CDSA treats the last block as the final one.  So unless we are being asked to report the final size we ask for 2 block and ignore the second (final) one. */
-    OSStatus rv = CSSM_QuerySize(cc->cc, cc->encrypt, final ? 1 : 2, dataBlockSize);
-    if (rv)
-    {
-       PORT_SetError(rv);
-       return 0;
-    }
-
-    return dataBlockSize[0].SizeOutputBlock;
+    return ((input_len + cc->block_size - 1) / cc->block_size * cc->block_size) + (final ? cc->block_size : 0);
 }
 
 /*
@@ -651,49 +317,10 @@ SecCmsCipherContextLength(SecCmsCipherContextRef cc, unsigned int input_len, Boo
  * passed in to the subsequent decrypt operation, as no output bytes
  * will be stored.
  */
-size_t
-SecCmsCipherContextDecryptLength(SecCmsCipherContextRef cc, size_t input_len, Boolean final)
+unsigned int
+SecCmsCipherContextDecryptLength(SecCmsCipherContextRef cc, unsigned int input_len, Boolean final)
 {
-#if 1
     return SecCmsCipherContextLength(cc, input_len, final, PR_FALSE);
-#else
-    int blocks, block_size;
-
-    PORT_Assert (! cc->encrypt);
-
-    block_size = cc->block_size;
-
-    /*
-     * If this is not a block cipher, then we always have the same
-     * number of output bytes as we had input bytes.
-     */
-    if (block_size == 0)
-       return input_len;
-
-    /*
-     * On the final call, we will always use up all of the pending
-     * bytes plus all of the input bytes, *but*, there will be padding
-     * at the end and we cannot predict how many bytes of padding we
-     * will end up removing.  The amount given here is actually known
-     * to be at least 1 byte too long (because we know we will have
-     * at least 1 byte of padding), but seemed clearer/better to me.
-     */
-    if (final)
-       return cc->pending_count + input_len;
-
-    /*
-     * Okay, this amount is exactly what we will output on the
-     * next cipher operation.  We will always hang onto the last
-     * 1 - block_size bytes for non-final operations.  That is,
-     * we will do as many complete blocks as we can *except* the
-     * last block (complete or partial).  (This is because until
-     * we know we are at the end, we cannot know when to interpret
-     * and removing the padding byte(s), which are guaranteed to
-     * be there.)
-     */
-    blocks = (cc->pending_count + input_len - 1) / block_size;
-    return blocks * block_size;
-#endif
 }
 
 /*
@@ -713,89 +340,38 @@ SecCmsCipherContextDecryptLength(SecCmsCipherContextRef cc, size_t input_len, Bo
  * passed in to the subsequent encrypt operation, as no output bytes
  * will be stored.
  */
-size_t
-SecCmsCipherContextEncryptLength(SecCmsCipherContextRef cc, size_t input_len, Boolean final)
+unsigned int
+SecCmsCipherContextEncryptLength(SecCmsCipherContextRef cc, unsigned int input_len, Boolean final)
 {
-#if 1
     return SecCmsCipherContextLength(cc, input_len, final, PR_TRUE);
-#else
-    int blocks, block_size;
-    int pad_size;
-
-    PORT_Assert (cc->encrypt);
-
-    block_size = cc->block_size;
-    pad_size = cc->pad_size;
-
-    /*
-     * If this is not a block cipher, then we always have the same
-     * number of output bytes as we had input bytes.
-     */
-    if (block_size == 0)
-       return input_len;
-
-    /*
-     * On the final call, we only send out what we need for
-     * remaining bytes plus the padding.  (There is always padding,
-     * so even if we have an exact number of blocks as input, we
-     * will add another full block that is just padding.)
-     */
-    if (final) {
-       if (pad_size == 0) {
-           return cc->pending_count + input_len;
-       } else {
-           blocks = (cc->pending_count + input_len) / pad_size;
-           blocks++;
-           return blocks*pad_size;
-       }
-    }
-
-    /*
-     * Now, count the number of complete blocks of data we have.
-     */
-    blocks = (cc->pending_count + input_len) / block_size;
-
-
-    return blocks * block_size;
-#endif
 }
 
 
-OSStatus
+static OSStatus
 SecCmsCipherContextCrypt(SecCmsCipherContextRef cc, unsigned char *output,
-                 size_t *output_len_p, size_t max_output_len,
-                 const unsigned char *input, size_t input_len,
+                 unsigned int *output_len_p, unsigned int max_output_len,
+                 const unsigned char *input, unsigned int input_len,
                  Boolean final, Boolean encrypt)
 {
-    CSSM_DATA outputBuf = { max_output_len, output };
-    CSSM_SIZE bytes_output = 0;
+    size_t bytes_output = 0;
     OSStatus rv = 0;
 
     if (input_len)
     {
-       CSSM_DATA inputBuf = { input_len, (uint8 *)input };
-
-       if (encrypt)
-           rv = CSSM_EncryptDataUpdate(cc->cc, &inputBuf, 1, &outputBuf, 1, &bytes_output);
-       else
-           rv = CSSM_DecryptDataUpdate(cc->cc, &inputBuf, 1, &outputBuf, 1, &bytes_output);
+        rv = CCCryptorUpdate(cc->cc, input, input_len, output, max_output_len, &bytes_output);
     }
 
     if (!rv && final)
     {
-       CSSM_DATA remainderBuf = { max_output_len - bytes_output, output + bytes_output };
-       if (encrypt)
-           rv = CSSM_EncryptDataFinal(cc->cc, &remainderBuf);
-       else
-           rv = CSSM_DecryptDataFinal(cc->cc, &remainderBuf);
-
-       bytes_output += remainderBuf.Length;
+        size_t bytes_output_final = 0;
+        rv = CCCryptorFinal(cc->cc, output+bytes_output, max_output_len-bytes_output, &bytes_output_final);
+        bytes_output += bytes_output_final;
     }
 
     if (rv)
        PORT_SetError(SEC_ERROR_BAD_DATA);
     else if (output_len_p)
-       *output_len_p = bytes_output;
+       *output_len_p = (unsigned int)bytes_output; /* This cast is safe since bytes_output can't be bigger than max_output_len */
 
     return rv;
 }
@@ -832,185 +408,14 @@ SecCmsCipherContextCrypt(SecCmsCipherContextRef cc, unsigned char *output,
  */ 
 OSStatus
 SecCmsCipherContextDecrypt(SecCmsCipherContextRef cc, unsigned char *output,
-                 size_t *output_len_p, size_t max_output_len,
-                 const unsigned char *input, size_t input_len,
+                 unsigned int *output_len_p, unsigned int max_output_len,
+                 const unsigned char *input, unsigned int input_len,
                  Boolean final)
 {
-#if 1
     return SecCmsCipherContextCrypt(cc, output,
                  output_len_p,  max_output_len,
                  input, input_len,
                  final, PR_FALSE);
-#else
-    int blocks, bsize, pcount, padsize;
-    unsigned int max_needed, ifraglen, ofraglen, output_len;
-    unsigned char *pbuf;
-    OSStatus rv;
-
-    PORT_Assert (! cc->encrypt);
-
-    /*
-     * Check that we have enough room for the output.  Our caller should
-     * already handle this; failure is really an internal error (i.e. bug).
-     */
-    max_needed = SecCmsCipherContextDecryptLength(cc, input_len, final);
-    PORT_Assert (max_output_len >= max_needed);
-    if (max_output_len < max_needed) {
-       /* PORT_SetError (XXX); */
-       return SECFailure;
-    }
-
-    /*
-     * hardware encryption does not like small decryption sizes here, so we
-     * allow both blocking and padding.
-     */
-    bsize = cc->block_size;
-    padsize = cc->pad_size;
-
-    /*
-     * When no blocking or padding work to do, we can simply call the
-     * cipher function and we are done.
-     */
-    if (bsize == 0) {
-       return (* cc->doit) (cc->cx, output, output_len_p, max_output_len,
-                             input, input_len);
-    }
-
-    pcount = cc->pending_count;
-    pbuf = cc->pending_buf;
-
-    output_len = 0;
-
-    if (pcount) {
-       /*
-        * Try to fill in an entire block, starting with the bytes
-        * we already have saved away.
-        */
-       while (input_len && pcount < bsize) {
-           pbuf[pcount++] = *input++;
-           input_len--;
-       }
-       /*
-        * If we have at most a whole block and this is not our last call,
-        * then we are done for now.  (We do not try to decrypt a lone
-        * single block because we cannot interpret the padding bytes
-        * until we know we are handling the very last block of all input.)
-        */
-       if (input_len == 0 && !final) {
-           cc->pending_count = pcount;
-           if (output_len_p)
-               *output_len_p = 0;
-           return SECSuccess;
-       }
-       /*
-        * Given the logic above, we expect to have a full block by now.
-        * If we do not, there is something wrong, either with our own
-        * logic or with (length of) the data given to us.
-        */
-       if ((padsize != 0) && (pcount % padsize) != 0) {
-           PORT_Assert (final);        
-           PORT_SetError (SEC_ERROR_BAD_DATA);
-           return SECFailure;
-       }
-       /*
-        * Decrypt the block.
-        */
-       rv = (*cc->doit)(cc->cx, output, &ofraglen, max_output_len,
-                           pbuf, pcount);
-       if (rv != SECSuccess)
-           return rv;
-
-       /*
-        * For now anyway, all of our ciphers have the same number of
-        * bytes of output as they do input.  If this ever becomes untrue,
-        * then SecCmsCipherContextDecryptLength needs to be made smarter!
-        */
-       PORT_Assert(ofraglen == pcount);
-
-       /*
-        * Account for the bytes now in output.
-        */
-       max_output_len -= ofraglen;
-       output_len += ofraglen;
-       output += ofraglen;
-    }
-
-    /*
-     * If this is our last call, we expect to have an exact number of
-     * blocks left to be decrypted; we will decrypt them all.
-     * 
-     * If not our last call, we always save between 1 and bsize bytes
-     * until next time.  (We must do this because we cannot be sure
-     * that none of the decrypted bytes are padding bytes until we
-     * have at least another whole block of data.  You cannot tell by
-     * looking -- the data could be anything -- you can only tell by
-     * context, knowing you are looking at the last block.)  We could
-     * decrypt a whole block now but it is easier if we just treat it
-     * the same way we treat partial block bytes.
-     */
-    if (final) {
-       if (padsize) {
-           blocks = input_len / padsize;
-           ifraglen = blocks * padsize;
-       } else ifraglen = input_len;
-       PORT_Assert (ifraglen == input_len);
-
-       if (ifraglen != input_len) {
-           PORT_SetError(SEC_ERROR_BAD_DATA);
-           return SECFailure;
-       }
-    } else {
-       blocks = (input_len - 1) / bsize;
-       ifraglen = blocks * bsize;
-       PORT_Assert (ifraglen < input_len);
-
-       pcount = input_len - ifraglen;
-       PORT_Memcpy (pbuf, input + ifraglen, pcount);
-       cc->pending_count = pcount;
-    }
-
-    if (ifraglen) {
-       rv = (* cc->doit)(cc->cx, output, &ofraglen, max_output_len,
-                           input, ifraglen);
-       if (rv != SECSuccess)
-           return rv;
-
-       /*
-        * For now anyway, all of our ciphers have the same number of
-        * bytes of output as they do input.  If this ever becomes untrue,
-        * then sec_PKCS7DecryptLength needs to be made smarter!
-        */
-       PORT_Assert (ifraglen == ofraglen);
-       if (ifraglen != ofraglen) {
-           PORT_SetError(SEC_ERROR_BAD_DATA);
-           return SECFailure;
-       }
-
-       output_len += ofraglen;
-    } else {
-       ofraglen = 0;
-    }
-
-    /*
-     * If we just did our very last block, "remove" the padding by
-     * adjusting the output length.
-     */
-    if (final && (padsize != 0)) {
-       unsigned int padlen = *(output + ofraglen - 1);
-
-       if (padlen == 0 || padlen > padsize) {
-           PORT_SetError(SEC_ERROR_BAD_DATA);
-           return SECFailure;
-       }
-       output_len -= padlen;
-    }
-
-    PORT_Assert (output_len_p != NULL || output_len == 0);
-    if (output_len_p != NULL)
-       *output_len_p = output_len;
-
-    return SECSuccess;
-#endif
 }
 
 /*
@@ -1050,150 +455,12 @@ SecCmsCipherContextDecrypt(SecCmsCipherContextRef cc, unsigned char *output,
  */ 
 OSStatus
 SecCmsCipherContextEncrypt(SecCmsCipherContextRef cc, unsigned char *output,
-                 size_t *output_len_p, size_t max_output_len,
-                 const unsigned char *input, size_t input_len,
+                 unsigned int *output_len_p, unsigned int max_output_len,
+                 const unsigned char *input, unsigned int input_len,
                  Boolean final)
 {
-#if 1
     return SecCmsCipherContextCrypt(cc, output,
                  output_len_p,  max_output_len,
                  input, input_len,
                  final, PR_TRUE);
-#else
-    int blocks, bsize, padlen, pcount, padsize;
-    unsigned int max_needed, ifraglen, ofraglen, output_len;
-    unsigned char *pbuf;
-    OSStatus rv;
-
-    PORT_Assert (cc->encrypt);
-
-    /*
-     * Check that we have enough room for the output.  Our caller should
-     * already handle this; failure is really an internal error (i.e. bug).
-     */
-    max_needed = SecCmsCipherContextEncryptLength (cc, input_len, final);
-    PORT_Assert (max_output_len >= max_needed);
-    if (max_output_len < max_needed) {
-       /* PORT_SetError (XXX); */
-       return SECFailure;
-    }
-
-    bsize = cc->block_size;
-    padsize = cc->pad_size;
-
-    /*
-     * When no blocking and padding work to do, we can simply call the
-     * cipher function and we are done.
-     */
-    if (bsize == 0) {
-       return (*cc->doit)(cc->cx, output, output_len_p, max_output_len,
-                             input, input_len);
-    }
-
-    pcount = cc->pending_count;
-    pbuf = cc->pending_buf;
-
-    output_len = 0;
-
-    if (pcount) {
-       /*
-        * Try to fill in an entire block, starting with the bytes
-        * we already have saved away.
-        */
-       while (input_len && pcount < bsize) {
-           pbuf[pcount++] = *input++;
-           input_len--;
-       }
-       /*
-        * If we do not have a full block and we know we will be
-        * called again, then we are done for now.
-        */
-       if (pcount < bsize && !final) {
-           cc->pending_count = pcount;
-           if (output_len_p != NULL)
-               *output_len_p = 0;
-           return SECSuccess;
-       }
-       /*
-        * If we have a whole block available, encrypt it.
-        */
-       if ((padsize == 0) || (pcount % padsize) == 0) {
-           rv = (* cc->doit) (cc->cx, output, &ofraglen, max_output_len,
-                               pbuf, pcount);
-           if (rv != SECSuccess)
-               return rv;
-
-           /*
-            * For now anyway, all of our ciphers have the same number of
-            * bytes of output as they do input.  If this ever becomes untrue,
-            * then sec_PKCS7EncryptLength needs to be made smarter!
-            */
-           PORT_Assert (ofraglen == pcount);
-
-           /*
-            * Account for the bytes now in output.
-            */
-           max_output_len -= ofraglen;
-           output_len += ofraglen;
-           output += ofraglen;
-
-           pcount = 0;
-       }
-    }
-
-    if (input_len) {
-       PORT_Assert (pcount == 0);
-
-       blocks = input_len / bsize;
-       ifraglen = blocks * bsize;
-
-       if (ifraglen) {
-           rv = (* cc->doit) (cc->cx, output, &ofraglen, max_output_len,
-                               input, ifraglen);
-           if (rv != SECSuccess)
-               return rv;
-
-           /*
-            * For now anyway, all of our ciphers have the same number of
-            * bytes of output as they do input.  If this ever becomes untrue,
-            * then sec_PKCS7EncryptLength needs to be made smarter!
-            */
-           PORT_Assert (ifraglen == ofraglen);
-
-           max_output_len -= ofraglen;
-           output_len += ofraglen;
-           output += ofraglen;
-       }
-
-       pcount = input_len - ifraglen;
-       PORT_Assert (pcount < bsize);
-       if (pcount)
-           PORT_Memcpy (pbuf, input + ifraglen, pcount);
-    }
-
-    if (final) {
-       padlen = padsize - (pcount % padsize);
-       PORT_Memset (pbuf + pcount, padlen, padlen);
-       rv = (* cc->doit) (cc->cx, output, &ofraglen, max_output_len,
-                           pbuf, pcount+padlen);
-       if (rv != SECSuccess)
-           return rv;
-
-       /*
-        * For now anyway, all of our ciphers have the same number of
-        * bytes of output as they do input.  If this ever becomes untrue,
-        * then sec_PKCS7EncryptLength needs to be made smarter!
-        */
-       PORT_Assert (ofraglen == (pcount+padlen));
-       output_len += ofraglen;
-    } else {
-       cc->pending_count = pcount;
-    }
-
-    PORT_Assert (output_len_p != NULL || output_len == 0);
-    if (output_len_p != NULL)
-       *output_len_p = output_len;
-
-    return SECSuccess;
-#endif
 }