--- /dev/null
+/*
+ * ssleayUtils.c - common routines for CDSA/openssl compatibility testing
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <openssl/blowfish.h>
+#include <openssl/cast.h>
+#include <openssl/evp.h>
+#include "ssleayUtils.h"
+#include <Security/cssmerr.h>
+#include "common.h"
+
+/*
+ * Caller sees EAY_KEY, we see a pointer to this.
+ */
+typedef struct {
+ CSSM_ALGORITHMS alg;
+ union {
+ BF_KEY bf; // blowfish
+ CAST_KEY cast;
+ } key;
+} EayKeyPriv;
+
+/*
+ * Create a symmetric key.
+ */
+CSSM_RETURN eayGenSymKey(
+ CSSM_ALGORITHMS alg,
+ CSSM_BOOL forEncr,
+ const CSSM_DATA *keyData,
+ EAY_KEY *key) // RETURNED
+{
+ EayKeyPriv *ekp = (EayKeyPriv *)malloc(sizeof(EayKeyPriv));
+ memset(ekp, 0, sizeof(*ekp));
+ switch(alg) {
+ case CSSM_ALGID_BLOWFISH:
+ BF_set_key(&ekp->key.bf, keyData->Length, keyData->Data);
+ break;
+ case CSSM_ALGID_CAST: // cast128 only
+ CAST_set_key(&ekp->key.cast, keyData->Length, keyData->Data);
+ break;
+ default:
+ printf("***eayGenSymKey: bad alg\n");
+ return -1;
+ }
+ ekp->alg = alg;
+ *key = (EAY_KEY)ekp;
+ return CSSM_OK;
+}
+
+/*
+ * Free a key created in eayGenSymKey
+ */
+CSSM_RETURN eayFreeKey(
+ EAY_KEY key)
+{
+ memset(key, 0, sizeof(EayKeyPriv));
+ free(key);
+ return CSSM_OK;
+}
+
+/*
+ * encrypt/decrypt
+ */
+CSSM_RETURN eayEncryptDecrypt(
+ EAY_KEY key,
+ CSSM_BOOL forEncrypt,
+ CSSM_ALGORITHMS encrAlg,
+ CSSM_ENCRYPT_MODE mode, // CSSM_ALGMODE_CBC ONLY!
+ const CSSM_DATA *iv, //ĂŠoptional per mode
+ const CSSM_DATA *inData,
+ CSSM_DATA_PTR outData) // CSSM_MALLOCd and RETURNED
+{
+ EayKeyPriv *ekp = (EayKeyPriv *)key;
+ if((mode != CSSM_ALGMODE_CBC_IV8) && (mode != CSSM_ALGMODE_ECB)) {
+ printf("***eayEncryptDecrypt only does CBC_IV8, ECB\n");
+ return -1;
+ }
+
+ bool cbc = (mode == CSSM_ALGMODE_ECB) ? false : true;
+
+ outData->Data = (uint8 *)CSSM_MALLOC(inData->Length);
+ outData->Length = inData->Length;
+
+ /* BF_cbc_encrypt actually writes to IV */
+ CSSM_DATA ivc = {0, NULL};
+ if(cbc) {
+ ivc.Data = (uint8 *)malloc(iv->Length);
+ ivc.Length = iv->Length;
+ memmove(ivc.Data, iv->Data, ivc.Length);
+ }
+ switch(encrAlg) {
+ case CSSM_ALGID_BLOWFISH:
+ if(cbc) {
+ BF_cbc_encrypt(inData->Data,
+ outData->Data,
+ inData->Length,
+ &ekp->key.bf,
+ ivc.Data,
+ forEncrypt ? BF_ENCRYPT : BF_DECRYPT);
+ }
+ else {
+ CSSM_DATA intext = *inData;
+ CSSM_DATA outtext = *outData;
+ while(intext.Length) {
+ BF_ecb_encrypt(intext.Data,
+ outtext.Data,
+ &ekp->key.bf,
+ forEncrypt ? BF_ENCRYPT : BF_DECRYPT);
+ intext.Data += 8;
+ outtext.Data += 8;
+ intext.Length -= 8;
+ }
+ }
+ break;
+ case CSSM_ALGID_CAST: // cast128 only
+ CAST_cbc_encrypt(inData->Data,
+ outData->Data,
+ inData->Length,
+ &ekp->key.cast,
+ ivc.Data,
+ forEncrypt ? CAST_ENCRYPT : CAST_DECRYPT);
+ break;
+ default:
+ printf("***eayEncryptDecrypt: bad alg\n");
+ return -1;
+ }
+ if(ivc.Data) {
+ free(ivc.Data);
+ }
+ return CSSM_OK;
+}
+
+/*** EVP-based encrypt/decrypt ***/
+
+int evpEncryptDecrypt(
+ CSSM_ALGORITHMS alg, // AES 128 only for now
+ CSSM_BOOL forEncr,
+ const CSSM_DATA *keyData, // may be larger than the key size we use
+ unsigned keyLengthInBits,
+ CSSM_ENCRYPT_MODE mode, // CSSM_ALGMODE_CBC_IV8, ECB, always padding
+ const CSSM_DATA *iv, // optional per mode
+ const CSSM_DATA *inData,
+ CSSM_DATA_PTR outData) // CSSM_MALLOCd and RETURNED
+{
+ EVP_CIPHER_CTX ctx;
+ const EVP_CIPHER *cipher;
+ unsigned blockSize;
+ unsigned outLen = inData->Length;
+ bool noPad = false;
+
+ switch(alg) {
+ case CSSM_ALGID_AES:
+ switch(mode) {
+ case CSSM_ALGMODE_CBCPadIV8:
+ switch(keyLengthInBits) {
+ case 128:
+ cipher = EVP_aes_128_cbc();
+ break;
+ case 192:
+ cipher = EVP_aes_192_cbc();
+ break;
+ case 256:
+ cipher = EVP_aes_256_cbc();
+ break;
+ default:
+ printf("***Bad AES key length (%u)\n", keyLengthInBits);
+ return -1;
+ }
+ break;
+ case CSSM_ALGMODE_ECB:
+ switch(keyLengthInBits) {
+ case 128:
+ cipher = EVP_aes_128_ecb();
+ break;
+ case 192:
+ cipher = EVP_aes_192_ecb();
+ break;
+ case 256:
+ cipher = EVP_aes_256_ecb();
+ break;
+ default:
+ printf("***Bad AES key length (%u)\n", keyLengthInBits);
+ return -1;
+ }
+ noPad = true;
+ break;
+ default:
+ printf("***evpEncryptDecrypt only does CBC and ECB for now\n");
+ return -1;
+ }
+ blockSize = 16;
+ break;
+ case CSSM_ALGID_DES:
+ switch(mode) {
+ case CSSM_ALGMODE_CBCPadIV8:
+ cipher = EVP_des_cbc();
+ break;
+ case CSSM_ALGMODE_ECB:
+ cipher = EVP_des_ecb();
+ noPad = true;
+ break;
+ default:
+ printf("***evpEncryptDecrypt only does CBC and ECB for now\n");
+ return -1;
+ }
+ blockSize = 8;
+ break;
+ default:
+ printf("***evpEncryptDecrypt only does DES and AES 128 for now\n");
+ return -1;
+ }
+ outLen += blockSize;
+ unsigned char *outp = (uint8 *)CSSM_MALLOC(outLen);
+ int outl = outLen;
+ outData->Data = outp;
+
+ if(forEncr) {
+ int rtn = EVP_EncryptInit(&ctx, cipher, keyData->Data, iv ? iv->Data : NULL);
+ if(!rtn) {
+ printf("EVP_EncryptInit error\n");
+ return -1;
+ }
+ if(noPad) {
+ EVP_CIPHER_CTX_set_padding(&ctx, 0);
+ }
+ if(!EVP_EncryptUpdate(&ctx, outp, &outl, inData->Data, inData->Length)) {
+ printf("EVP_EncryptUpdate error\n");
+ return -1;
+ }
+ }
+ else {
+ int rtn = EVP_DecryptInit(&ctx, cipher, keyData->Data, iv ? iv->Data : NULL);
+ if(!rtn) {
+ printf("EVP_DecryptInit error\n");
+ return -1;
+ }
+ if(noPad) {
+ EVP_CIPHER_CTX_set_padding(&ctx, 0);
+ }
+
+ if(!EVP_DecryptUpdate(&ctx, outp, &outl, inData->Data, inData->Length)) {
+ printf("EVP_DecryptUpdate error\n");
+ return -1;
+ }
+ }
+ outData->Length = outl;
+ outp += outl;
+ outl = outLen - outl;
+ if(forEncr) {
+ if(!EVP_EncryptFinal(&ctx, outp, &outl)) {
+ printf("EVP_EncryptFinal error\n");
+ return -1;
+ }
+ }
+ else {
+ if(!EVP_DecryptFinal(&ctx, outp, &outl)) {
+ printf("EVP_DecryptFinal error\n");
+ return -1;
+ }
+ }
+ outData->Length += outl;
+ return 0;
+}