#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"
typedef struct {
CSSM_ALGORITHMS alg;
union {
BF_KEY bf; CAST_KEY cast;
} key;
} EayKeyPriv;
CSSM_RETURN eayGenSymKey(
CSSM_ALGORITHMS alg,
CSSM_BOOL forEncr,
const CSSM_DATA *keyData,
EAY_KEY *key) {
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: 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;
}
CSSM_RETURN eayFreeKey(
EAY_KEY key)
{
memset(key, 0, sizeof(EayKeyPriv));
free(key);
return CSSM_OK;
}
CSSM_RETURN eayEncryptDecrypt(
EAY_KEY key,
CSSM_BOOL forEncrypt,
CSSM_ALGORITHMS encrAlg,
CSSM_ENCRYPT_MODE mode, const CSSM_DATA *iv, const CSSM_DATA *inData,
CSSM_DATA_PTR outData) {
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;
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: 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;
}
int evpEncryptDecrypt(
CSSM_ALGORITHMS alg, CSSM_BOOL forEncr,
const CSSM_DATA *keyData, unsigned keyLengthInBits,
CSSM_ENCRYPT_MODE mode, const CSSM_DATA *iv, const CSSM_DATA *inData,
CSSM_DATA_PTR outData) {
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;
}