#include <CoreFoundation/CoreFoundation.h>
#include <security_cdsa_utilities/cssmdata.h>
#include <security_cdsa_utilities/cssmerrors.h>
#include <security_cdsa_client/genkey.h>
#include <security_cdsa_client/wrapkey.h>
#include <string.h>
#include "common.h"
#include <iomanip>
#include <iostream>
#include <memory>
using namespace std;
#define ALG_DEFAULT CSSM_ALGID_AES
#define ALG_STR_DEFAULT "AES"
#define CHAIN_DEFAULT CSSM_TRUE
#define KEY_SIZE_DEFAULT 128
#define BEGIN_FUNCTION try {
#define END_FUNCTION } \
catch (const CssmError &e) \
{ \
cssmPerror(__PRETTY_FUNCTION__, e.error); \
} \
catch (...) \
{ \
fprintf(stderr, "%s: failed\n", __PRETTY_FUNCTION__); \
} \
static void usage(char **argv)
{
printf("usage: %s iterations bufsize [options]\n", argv[0]);
printf(" Options:\n");
printf(" a=algorithm (s=ASC; d=DES; 3=3DES; 2=RC2; 4=RC4; 5=RC5;\n");
printf(" a=AES; b=Blowfish; c=CAST; n=NULL; default=AES)\n");
printf(" k=keySizeInBits\n");
printf(" b=blockSizeInBits\n");
printf(" e (ECB mode; default is CBC)\n");
printf(" i (re-set IV in each loop)\n");
printf(" v(erbose)\n");
printf(" h(elp)\n");
exit(1);
}
static void
cdsaSetupContexts(int iterations,
auto_ptr<Security::CssmClient::Encrypt> &encrypt,
auto_ptr<Security::CssmClient::Decrypt> &decrypt,
CSSM_ALGORITHMS keyAlg,
CSSM_ALGORITHMS encrAlg,
CSSM_ENCRYPT_MODE encrMode,
uint32 keySizeInBits,
uint32 blockSizeInBits) {
BEGIN_FUNCTION
Security::CssmClient::CSP csp(gGuidAppleCSP);
Security::CssmClient::GenerateKey keyGenerator(csp, keyAlg, keySizeInBits);
Security::CssmClient::Key key = keyGenerator(Security::CssmClient::KeySpec(
CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT,
CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE));
for (int ix=0; ix < iterations; ++ix)
{
encrypt.reset(new Security::CssmClient::Encrypt(csp, encrAlg));
encrypt->mode(encrMode);
encrypt->key(key);
if(blockSizeInBits) {
encrypt->add(CSSM_ATTRIBUTE_BLOCK_SIZE, blockSizeInBits / 8);
}
decrypt.reset(new Security::CssmClient::Decrypt(csp, encrAlg));
decrypt->mode(encrMode);
decrypt->key(key);
if(blockSizeInBits) {
decrypt->add(CSSM_ATTRIBUTE_BLOCK_SIZE, blockSizeInBits / 8);
}
}
END_FUNCTION
}
static void
cdsaEncrypt(int iterations, Security::CssmClient::Encrypt &encrypt,
uint8 *inBuf, uint32 bufLen, uint8 *outBuf, bool useIv, uint32 blockSizeBytes,
CSSM_BOOL resetIv)
{
BEGIN_FUNCTION
CssmData iv((uint8 *)"12345678123456781234567812345678", blockSizeBytes);
CssmData inData(inBuf, bufLen);
CssmData outData(outBuf, bufLen);
CssmData nullData(reinterpret_cast<uint8 *>(NULL) + 1, 0);
if(useIv) {
encrypt.initVector(iv);
}
if(useIv && resetIv) {
for (int ix=0; ix < iterations; ++ix)
{
encrypt.initVector(iv);
encrypt.encrypt(inData, outData, nullData);
}
}
else {
for (int ix=0; ix < iterations; ++ix)
{
encrypt.encrypt(inData, outData, nullData);
}
}
END_FUNCTION
}
static void
cdsaDecrypt(int iterations, Security::CssmClient::Decrypt &decrypt,
uint8 *inBuf, uint32 bufLen, uint8 *outBuf, bool useIv, uint32 blockSizeBytes,
CSSM_BOOL resetIv)
{
BEGIN_FUNCTION
CssmData iv((uint8 *)"12345678123456781234567812345678", blockSizeBytes);
CssmData inData(inBuf, bufLen);
CssmData outData(outBuf, bufLen);
CssmData nullData(reinterpret_cast<uint8 *>(NULL) + 1, 0);
if(useIv) {
decrypt.initVector(iv);
}
if(useIv && resetIv) {
for (int ix=0; ix < iterations; ++ix)
{
decrypt.initVector(iv);
decrypt.decrypt(inData, outData, nullData);
}
}
else {
for (int ix=0; ix < iterations; ++ix)
{
decrypt.decrypt(inData, outData, nullData);
}
}
END_FUNCTION
}
int main(int argc, char **argv)
{
int arg;
char *argp;
CSSM_ENCRYPT_MODE mode;
uint32 blockSizeBytes = 8;
CSSM_BOOL chainEnable = CHAIN_DEFAULT;
uint32 keySizeInBits = KEY_SIZE_DEFAULT;
uint32 blockSizeInBits = 0;
const char *algStr = ALG_STR_DEFAULT;
uint32 keyAlg = ALG_DEFAULT; uint32 encrAlg = ALG_DEFAULT; int iterations;
int bufSize;
CSSM_BOOL resetIv = CSSM_FALSE;
CSSM_BOOL verbose = false;
if(argc < 3) {
usage(argv);
}
iterations = atoi(argv[1]);
bufSize = atoi(argv[2]);
for(arg=3; arg<argc; arg++) {
argp = argv[arg];
switch(argp[0]) {
case 'a':
if(argp[1] != '=') {
usage(argv);
}
switch(argp[2]) {
case 's':
encrAlg = keyAlg = CSSM_ALGID_ASC;
algStr = "ASC";
break;
case 'd':
encrAlg = keyAlg = CSSM_ALGID_DES;
algStr = "DES";
keySizeInBits = 64;
break;
case '3':
keyAlg = CSSM_ALGID_3DES_3KEY;
encrAlg = CSSM_ALGID_3DES_3KEY_EDE;
algStr = "3DES";
keySizeInBits = 64 * 3;
break;
case '2':
encrAlg = keyAlg = CSSM_ALGID_RC2;
algStr = "RC2";
break;
case '4':
encrAlg = keyAlg = CSSM_ALGID_RC4;
algStr = "RC4";
chainEnable = CSSM_FALSE;
break;
case '5':
encrAlg = keyAlg = CSSM_ALGID_RC5;
algStr = "RC5";
break;
case 'a':
encrAlg = keyAlg = CSSM_ALGID_AES;
algStr = "AES";
break;
case 'b':
encrAlg = keyAlg = CSSM_ALGID_BLOWFISH;
algStr = "Blowfish";
break;
case 'c':
encrAlg = keyAlg = CSSM_ALGID_CAST;
algStr = "CAST";
break;
case 'n':
encrAlg = keyAlg = CSSM_ALGID_NONE;
algStr = "NULL";
break;
default:
usage(argv);
}
break;
case 'k':
keySizeInBits = atoi(&argp[2]);
break;
case 'b':
blockSizeInBits = atoi(&argp[2]);
break;
case 'e':
chainEnable = CSSM_FALSE;
break;
case 'i':
resetIv = CSSM_TRUE;
break;
case 'v':
verbose = CSSM_TRUE;
break;
case 'h':
default:
usage(argv);
}
}
switch(keyAlg) {
case CSSM_ALGID_RC4:
chainEnable = CSSM_FALSE;
mode = CSSM_ALGMODE_NONE;
if((iterations & 1) == 0) {
printf("***WARNING: an even number of iterations with RC4 results in\n"
" identical plaintext and ciphertext!\n");
}
break;
case CSSM_ALGID_AES:
case CSSM_ALGID_NONE:
blockSizeBytes = blockSizeInBits ? (blockSizeInBits / 8) : 16;
break;
default:
break;
}
if(chainEnable) {
mode = CSSM_ALGMODE_CBC_IV8;
}
else {
mode = CSSM_ALGMODE_ECB;
}
if(blockSizeInBits) {
printf("Algorithm: %s keySize: %u blockSize: %u mode: %s"
" iterations: %d bufSize %d\n",
algStr, (unsigned)keySizeInBits, (unsigned)blockSizeInBits,
chainEnable ? "CBC" : "ECB",
iterations, bufSize);
}
else {
printf("Algorithm: %s keySize: %u mode: %s iterations: %d "
"bufSize %d\n",
algStr, (unsigned)keySizeInBits, chainEnable ? "CBC" : "ECB",
iterations, bufSize);
}
CFAbsoluteTime start, end;
auto_array<uint8> buffer(bufSize), plain(bufSize);
auto_ptr<Security::CssmClient::Encrypt> encrypt(NULL);
auto_ptr<Security::CssmClient::Decrypt> decrypt(NULL);
uint8 *bp = buffer.get();
for(int ix=0; ix<bufSize; ix++) {
*bp++ = random();
}
memcpy(plain.get(), buffer.get(), bufSize);
if(verbose) {
printf("%d * cdsaSetupContexts", iterations);
}
fflush(stdout);
start = CFAbsoluteTimeGetCurrent();
cdsaSetupContexts(iterations, encrypt, decrypt,
keyAlg, encrAlg, mode, keySizeInBits, blockSizeInBits);
end = CFAbsoluteTimeGetCurrent();
if(verbose) {
printf(" took: %gs\n", end - start);
}
printf(" %d * cdsaEncrypt %d bytes", iterations, bufSize);
fflush(stdout);
start = CFAbsoluteTimeGetCurrent();
cdsaEncrypt(iterations, *encrypt.get(), buffer.get(), bufSize, buffer.get(),
chainEnable, blockSizeBytes, resetIv);
end = CFAbsoluteTimeGetCurrent();
printf(" took: %gs %.1f Kbytes/s\n", end - start,
(iterations * bufSize) / (end - start) / 1024.0);
if (!memcmp(buffer.get(), plain.get(), bufSize))
printf("*** ciphertext matches plaintext ***\n");
printf(" %d * cdsaDecrypt %d bytes", iterations, bufSize);
fflush(stdout);
start = CFAbsoluteTimeGetCurrent();
cdsaDecrypt(iterations, *decrypt.get(), buffer.get(), bufSize, buffer.get(),
chainEnable, blockSizeBytes, resetIv);
end = CFAbsoluteTimeGetCurrent();
printf(" took: %gs %.1f Kbytes/s\n", end - start,
(iterations * bufSize) / (end - start) / 1024.0);
if (memcmp(buffer.get(), plain.get(), bufSize))
printf("*** plaintext not recovered correctly ***\n");
return 0;
}