--- /dev/null
+/*
+ * 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 <Security/cssm.h>
+
+#include <string.h>
+
+/* 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; i<data->length; 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;
+}
+