/* * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved. * * The contents of this file constitute Original Code as defined in and are * subject to the Apple Public Source License Version 1.2 (the 'License'). * You may not use this file except in compliance with the License. Please obtain * a copy of the License at http://www.apple.com/publicsource and read it before * using this file. * * This Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the * specific language governing rights and limitations under the License. */ /* File: symCipher.c Contains: CDSA-based symmetric cipher module Written by: Doug Mitchell Copyright: (c) 1999 by Apple Computer, Inc., all rights reserved. */ #include "sslContext.h" #include "cryptType.h" #include "sslDebug.h" #include "sslMemory.h" #include "appleCdsa.h" #include "symCipher.h" #include #include /* dispose of dynamically allocated resources in a CipherContext */ static void disposeCipherCtx( CipherContext *cipherCtx) { assert(cipherCtx != NULL); if(cipherCtx->symKey != NULL) { assert(cipherCtx->cspHand != 0); CSSM_FreeKey(cipherCtx->cspHand, NULL, cipherCtx->symKey, CSSM_FALSE); sslFree(cipherCtx->symKey); cipherCtx->symKey = NULL; } cipherCtx->cspHand = 0; if(cipherCtx->ccHand != 0) { CSSM_DeleteContext(cipherCtx->ccHand); cipherCtx->ccHand = 0; } } OSStatus CDSASymmInit( uint8 *key, uint8* iv, CipherContext *cipherCtx, SSLContext *ctx) { /* * Cook up a symmetric key and a CCSM_CC_HANDLE. Assumes: * cipherCtx->symCipher.keyAlg * ctx->cspHand * key (raw key bytes) * On successful exit: * Resulting CSSM_KEY_PTR --> cipherCtx->symKey * Resulting CSSM_CC_HANDLE --> cipherCtx->ccHand * (Currently) a copy of ctx->cspHand --> cipherCtx->cspHand * * FIXME - for now we assume that ctx->cspHand is capable of * using the specified algorithm, keysize, and mode. This * may need revisiting. */ OSStatus serr = errSSLInternal; CSSM_RETURN crtn; const SSLSymmetricCipher *symCipher; CSSM_DATA ivData; CSSM_DATA_PTR ivDataPtr = NULL; CSSM_KEY_PTR symKey = NULL; CSSM_CC_HANDLE ccHand = 0; char *op; assert(cipherCtx != NULL); assert(cipherCtx->symCipher != NULL); assert(ctx != NULL); if(ctx->cspHand == 0) { sslErrorLog("CDSASymmInit: NULL cspHand!\n"); return errSSLInternal; } /* clean up cipherCtx */ disposeCipherCtx(cipherCtx); /* cook up a raw key */ symKey = (CSSM_KEY_PTR)sslMalloc(sizeof(CSSM_KEY)); if(symKey == NULL) { return memFullErr; } serr = sslSetUpSymmKey(symKey, cipherCtx->symCipher->keyAlg, CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT, CSSM_TRUE, key, cipherCtx->symCipher->keySize); if(serr) { sslFree(symKey); return serr; } cipherCtx->symKey = symKey; /* now the crypt handle */ symCipher = cipherCtx->symCipher; if(symCipher->ivSize != 0) { ivData.Data = iv; ivData.Length = symCipher->ivSize; ivDataPtr = &ivData; } crtn = CSSM_CSP_CreateSymmetricContext(ctx->cspHand, symCipher->encrAlg, symCipher->encrMode, NULL, symKey, ivDataPtr, symCipher->encrPad, 0, // Params &ccHand); if(crtn) { stPrintCdsaError("CSSM_CSP_CreateSymmetricContext", crtn); serr = errSSLCrypto; goto errOut; } cipherCtx->ccHand = ccHand; /* after this, each en/decrypt is merely an update */ if(cipherCtx->encrypting) { crtn = CSSM_EncryptDataInit(ccHand); op = "CSSM_EncryptDataInit"; } else { crtn = CSSM_DecryptDataInit(ccHand); op = "CSSM_DecryptDataInit"; } if(crtn) { stPrintCdsaError("CSSM_CSP_EncryptDataInit", crtn); serr = errSSLCrypto; goto errOut; } /* success */ cipherCtx->cspHand = ctx->cspHand; serr = noErr; errOut: if(serr) { /* dispose of the stuff we created */ disposeCipherCtx(cipherCtx); } return serr; } #define REDECRYPT_DATA 0 #define LOG_SYMM_DATA 0 #if LOG_SYMM_DATA static void logSymmData( char *field, SSLBuffer *data, int maxLen) { int i; printf("%s: ", field); for(i=0; ilength; i++) { if(i == maxLen) { break; } printf("%02X", data->data[i]); if((i % 4) == 3) { printf(" "); } } printf("\n"); } #else /* LOG_SYMM_DATA */ #define logSymmData(f, d, l) #endif /* LOG_SYMM_DATA */ #define IS_ALIGNED(count, blockSize) ((count % blockSize) == 0) OSStatus CDSASymmEncrypt( SSLBuffer src, SSLBuffer dest, CipherContext *cipherCtx, SSLContext *ctx) { CSSM_RETURN crtn; CSSM_DATA ptextData; CSSM_DATA ctextData; uint32 bytesEncrypted; OSStatus serr = errSSLInternal; uint32 origLen = dest.length; /* * Valid on entry: * cipherCtx->ccHand * cipherCtx->cspHand */ assert(ctx != NULL); assert(cipherCtx != NULL); logSymmData("Symm encrypt ptext", &src, 48); /* this requirement allows us to avoid a malloc and copy */ assert(dest.length >= src.length); #if SSL_DEBUG { unsigned blockSize = cipherCtx->symCipher->blockSize; if(blockSize) { if(!IS_ALIGNED(src.length, blockSize)) { sslErrorLog("CDSASymmEncrypt: unaligned ptext (len %ld bs %d)\n", src.length, blockSize); return errSSLInternal; } if(!IS_ALIGNED(dest.length, blockSize)) { sslErrorLog("CDSASymmEncrypt: unaligned ctext (len %ld bs %d)\n", dest.length, blockSize); return errSSLInternal; } } } #endif if((cipherCtx->ccHand == 0) || (cipherCtx->cspHand == 0)) { sslErrorLog("CDSASymmEncrypt: null args\n"); return errSSLInternal; } SSLBUF_TO_CSSM(&src, &ptextData); SSLBUF_TO_CSSM(&dest, &ctextData); crtn = CSSM_EncryptDataUpdate(cipherCtx->ccHand, &ptextData, 1, &ctextData, 1, &bytesEncrypted); if(crtn) { stPrintCdsaError("CSSM_EncryptDataUpdate", crtn); serr = errSSLCrypto; goto errOut; } if(bytesEncrypted > origLen) { /* should never happen, callers always give us block-aligned * plaintext and CSP padding is disabled. */ sslErrorLog("Symmetric encrypt overflow: bytesEncrypted %ld destLen %ld\n", bytesEncrypted, dest.length); serr = errSSLCrypto; goto errOut; } dest.length = bytesEncrypted; logSymmData("Symm encrypt ctext", &dest, 48); serr = noErr; errOut: return serr; } OSStatus CDSASymmDecrypt( SSLBuffer src, SSLBuffer dest, CipherContext *cipherCtx, SSLContext *ctx) { CSSM_RETURN crtn; CSSM_DATA ptextData = {0, NULL}; CSSM_DATA ctextData; uint32 bytesDecrypted; OSStatus serr = errSSLInternal; uint32 origLen = dest.length; /* * Valid on entry: * cipherCtx->cspHand * cipherCtx->ccHand */ assert(ctx != NULL); assert(cipherCtx != NULL); if((cipherCtx->ccHand == 0) || (cipherCtx->cspHand == 0)) { sslErrorLog("CDSASymmDecrypt: null args\n"); return errSSLInternal; } /* this requirement allows us to avoid a malloc and copy */ assert(dest.length >= src.length); #if SSL_DEBUG { unsigned blockSize = cipherCtx->symCipher->blockSize; if(blockSize) { if(!IS_ALIGNED(src.length, blockSize)) { sslErrorLog("CDSASymmDecrypt: unaligned ctext (len %ld bs %d)\n", src.length, blockSize); return errSSLInternal; } if(!IS_ALIGNED(dest.length, blockSize)) { sslErrorLog("CDSASymmDecrypt: unaligned ptext (len %ld bs %d)\n", dest.length, blockSize); return errSSLInternal; } } } #endif SSLBUF_TO_CSSM(&src, &ctextData); SSLBUF_TO_CSSM(&dest, &ptextData); crtn = CSSM_DecryptDataUpdate(cipherCtx->ccHand, &ctextData, 1, &ptextData, 1, &bytesDecrypted); if(crtn) { stPrintCdsaError("CSSM_DecryptDataUpdate", crtn); serr = errSSLCrypto; goto errOut; } if(bytesDecrypted > origLen) { /* FIXME - can this happen? Should we remalloc? */ sslErrorLog("Symmetric decrypt overflow: bytesDecrypted %ld destLen %ld\n", bytesDecrypted, dest.length); serr = errSSLCrypto; goto errOut; } dest.length = bytesDecrypted; serr = noErr; logSymmData("Symm decrypt ptext(1)", &dest, 48); errOut: return serr; } OSStatus CDSASymmFinish( CipherContext *cipherCtx, SSLContext *ctx) { /* dispose of cipherCtx->{symKey,cspHand,ccHand} */ disposeCipherCtx(cipherCtx); return noErr; }