CommonCryptoSymRegression.c [plain text]
#include "testmore.h"
#include "capabilities.h"
#if (CCSYMREGRESSION == 0)
entryPoint(CommonCryptoSymRegression,"CommonCrypto Base Behavior Regression Tests")
#else
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <CommonCrypto/CommonCryptor.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#define LOOPS_DEF 500
#define MIN_DATA_SIZE 8
#define MAX_DATA_SIZE 10000
#define MAX_KEY_SIZE kCCKeySizeMaxRC4
#define MAX_BLOCK_SIZE kCCBlockSizeAES128
#define LOOP_NOTIFY 250
typedef enum {
ALG_AES_128 = 1,
ALG_AES_192,
ALG_AES_256,
ALG_DES,
ALG_3DES,
ALG_CAST,
ALG_RC4,
ALG_RC2,
ALG_RC5,
ALG_BFISH,
ALG_ASC,
ALG_NULL
} SymAlg;
#define ALG_FIRST ALG_AES_128
#define ALG_LAST ALG_RC4
#define LOG_SIZE 0
#if LOG_SIZE
#define logSize(s) diag s
#else
#define logSize(s)
#endif
static void
appGetRandomBytes(void *keyBytes, size_t keySizeInBytes)
{
int fd;
if((fd = open("/dev/random", O_RDONLY)) < 0) {
diag("Can't open Random\n");
exit(0);
}
if(read(fd, keyBytes, keySizeInBytes) != keySizeInBytes) {
diag("Can't read Random\n");
exit(0);
}
close(fd);
}
static unsigned
genRand(unsigned min, unsigned max)
{
unsigned i;
if(min == max) {
return min;
}
appGetRandomBytes(&i, 4);
return (min + (i % (max - min + 1)));
}
static void printCCError(const char *str, CCCryptorStatus crtn)
{
const char *errStr;
char unknownStr[200];
switch(crtn) {
case kCCSuccess: errStr = "kCCSuccess"; break;
case kCCParamError: errStr = "kCCParamError"; break;
case kCCBufferTooSmall: errStr = "kCCBufferTooSmall"; break;
case kCCMemoryFailure: errStr = "kCCMemoryFailure"; break;
case kCCAlignmentError: errStr = "kCCAlignmentError"; break;
case kCCDecodeError: errStr = "kCCDecodeError"; break;
case kCCUnimplemented: errStr = "kCCUnimplemented"; break;
default:
sprintf(unknownStr, "Unknown(%ld)\n", (long)crtn);
errStr = unknownStr;
break;
}
diag("***%s returned %s\n", str, errStr);
}
#define CC_MAX_CTX_SIZE kCCContextSizeRC4
#define MARKER_LENGTH 8
#define MARKER_BYTE 0x7e
static CCCryptorStatus doCCCrypt(
bool forEncrypt,
CCAlgorithm encrAlg,
bool doCbc,
bool doPadding,
const void *keyBytes, size_t keyLen,
const void *iv,
bool randUpdates,
bool inPlace,
size_t ctxSize,
bool askOutSize,
const uint8_t *inText, size_t inTextLen,
uint8_t **outText, size_t *outTextLen)
{
CCCryptorRef cryptor = NULL;
CCCryptorStatus crtn;
CCOperation op = forEncrypt ? kCCEncrypt : kCCDecrypt;
CCOptions options = 0;
uint8_t *outBuf = NULL;
uint8_t *outp;
const uint8_t *inp;
size_t outLen = 0;
size_t toMove;
size_t thisMoveOut;
size_t outBytes;
char ctx[CC_MAX_CTX_SIZE];
uint8_t *textMarker = NULL;
char *ctxMarker = NULL;
unsigned dex;
size_t askedOutSize;
size_t thisOutLen;
if(0) diag("%s %s %s keylen %d %s %s %s %s %s input length %ld\n",
forEncrypt ? "Encrypting": "Decrypting",
doCbc ? "CBC": "ECB",
doPadding ? "Padding ON": "Padding OFF",
(int) keyLen,
iv ? "IV Provided": "No IV Provided",
randUpdates ? "Random Updates": "Non-Random Updates",
inPlace ? "In Place": "Separate Buffers",
ctxSize ? "We Allocate": "CC Allocated",
askOutSize ? "Ask OutSize": "Don't Ask OutSize",
inTextLen);
if(ctxSize > CC_MAX_CTX_SIZE) {
diag("***HEY! Adjust CC_MAX_CTX_SIZE!\n");
exit(1);
}
if(!doCbc) {
options |= kCCOptionECBMode;
}
if(doPadding) {
options |= kCCOptionPKCS7Padding;
}
outLen = inTextLen;
if(forEncrypt) {
outLen += MAX_BLOCK_SIZE;
}
outBuf = (uint8_t *)malloc(outLen + MARKER_LENGTH);
memset(outBuf, 0xEE, outLen + MARKER_LENGTH);
textMarker = outBuf + outLen;
memset(textMarker, MARKER_BYTE, MARKER_LENGTH);
if(inPlace) {
memmove(outBuf, inText, inTextLen);
inp = outBuf;
}
else {
inp = inText;
}
if(!randUpdates) {
if(askOutSize) {
crtn = CCCrypt(op, encrAlg, options,
keyBytes, keyLen, iv,
inp, inTextLen,
outBuf, 0, &askedOutSize);
if(crtn != kCCBufferTooSmall) {
diag("***Did not get kCCBufferTooSmall as expected\n");
diag(" alg %d inTextLen %lu cbc %d padding %d keyLen %lu\n",
(int)encrAlg, (unsigned long)inTextLen, (int)doCbc, (int)doPadding,
(unsigned long)keyLen);
printCCError("CCCrypt", crtn);
crtn = -1;
goto errOut;
}
outLen = askedOutSize;
}
crtn = CCCrypt(op, encrAlg, options,
keyBytes, keyLen, iv,
inp, inTextLen,
outBuf, outLen, &outLen);
if(crtn) {
printCCError("CCCrypt", crtn);
goto errOut;
}
*outText = outBuf;
*outTextLen = outLen;
goto errOut;
}
if(ctxSize) {
size_t ctxSizeCreated;
if(askOutSize) {
crtn = CCCryptorCreateFromData(op, encrAlg, options,
keyBytes, keyLen, iv,
ctx, 0 ,
&cryptor, &askedOutSize);
if(crtn != kCCBufferTooSmall) {
diag("***Did not get kCCBufferTooSmall as expected\n");
printCCError("CCCryptorCreateFromData", crtn);
crtn = -1;
goto errOut;
}
ctxSize = askedOutSize;
}
crtn = CCCryptorCreateFromData(op, encrAlg, options,
keyBytes, keyLen, iv,
ctx, ctxSize, &cryptor, &ctxSizeCreated);
if(crtn) {
printCCError("CCCryptorCreateFromData", crtn);
return crtn;
}
ctxMarker = ctx + ctxSizeCreated;
memset(ctxMarker, MARKER_BYTE, MARKER_LENGTH);
}
else {
crtn = CCCryptorCreate(op, encrAlg, options,
keyBytes, keyLen, iv,
&cryptor);
if(crtn) {
printCCError("CCCryptorCreate", crtn);
return crtn;
}
}
toMove = inTextLen;
outp = outBuf;
outBytes = 0;
while(toMove) {
size_t thisMoveIn;
thisMoveIn = (size_t) genRand(1, (unsigned int) toMove);
logSize(("###ptext segment len %lu\n", (unsigned long)thisMoveIn));
if(askOutSize) {
thisOutLen = CCCryptorGetOutputLength(cryptor, thisMoveIn, false);
}
else {
thisOutLen = outLen;
}
crtn = CCCryptorUpdate(cryptor, inp, thisMoveIn,
outp, thisOutLen, &thisMoveOut);
if(crtn) {
printCCError("CCCryptorUpdate", crtn);
goto errOut;
}
inp += thisMoveIn;
toMove -= thisMoveIn;
outp += thisMoveOut;
outLen -= thisMoveOut;
outBytes += thisMoveOut;
}
if(doPadding) {
if(askOutSize) {
thisOutLen = CCCryptorGetOutputLength(cryptor, 0, true);
}
else {
thisOutLen = outLen;
}
crtn = CCCryptorFinal(cryptor, outp, thisOutLen, &thisMoveOut);
}
else {
thisMoveOut = 0;
crtn = kCCSuccess;
}
if(crtn) {
printCCError("CCCryptorFinal", crtn);
goto errOut;
}
outBytes += thisMoveOut;
*outText = outBuf;
*outTextLen = outBytes;
crtn = kCCSuccess;
for(dex=0; dex<MARKER_LENGTH; dex++) {
if(textMarker[dex] != MARKER_BYTE) {
diag("***lib scribbled on our textMarker memory (op=%s)!\n",
forEncrypt ? "encrypt" : "decrypt");
crtn = (CCCryptorStatus)-1;
}
}
if(ctxSize) {
for(dex=0; dex<MARKER_LENGTH; dex++) {
if(ctxMarker[dex] != MARKER_BYTE) {
diag("***lib scribbled on our ctxMarker memory (op=%s)!\n",
forEncrypt ? "encrypt" : "decrypt");
crtn = (CCCryptorStatus)-1;
}
}
}
errOut:
if(crtn) {
if(outBuf) {
free(outBuf);
}
}
if(cryptor) {
CCCryptorRelease(cryptor);
}
return crtn;
}
static int doTest(const uint8_t *ptext,
size_t ptextLen,
CCAlgorithm encrAlg,
bool doCbc,
bool doPadding,
bool nullIV,
uint32_t keySizeInBytes,
bool stagedEncr,
bool stagedDecr,
bool inPlace,
size_t ctxSize,
bool askOutSize,
bool quiet)
{
uint8_t keyBytes[MAX_KEY_SIZE];
uint8_t iv[MAX_BLOCK_SIZE];
uint8_t *ivPtrEncrypt;
uint8_t *ivPtrDecrypt;
uint8_t *ctext = NULL;
size_t ctextLen = 0;
uint8_t *rptext = NULL;
size_t rptextLen;
CCCryptorStatus crtn;
int rtn = 0;
appGetRandomBytes(keyBytes, keySizeInBytes);
if(doCbc) {
if(nullIV) {
memset(iv, 0, MAX_BLOCK_SIZE);
if(genRand(1,2) == 1) {
ivPtrEncrypt = NULL;
ivPtrDecrypt = iv;
}
else {
ivPtrEncrypt = iv;
ivPtrDecrypt = NULL;
}
}
else {
appGetRandomBytes(iv, MAX_BLOCK_SIZE);
ivPtrEncrypt = iv;
ivPtrDecrypt = iv;
}
}
else {
ivPtrEncrypt = NULL;
ivPtrDecrypt = NULL;
}
crtn = doCCCrypt(true, encrAlg, doCbc, doPadding,
keyBytes, keySizeInBytes, ivPtrEncrypt,
stagedEncr, inPlace, ctxSize, askOutSize,
ptext, ptextLen,
&ctext, &ctextLen);
ok(crtn == 0, "doCCCrypt");
if(crtn) {
diag("Test Failure Encrypt encrAlg = %d dodCbc = %d doPadding %d\n", encrAlg, doCbc, doPadding);
}
logSize(("###ctext len %lu\n", ctextLen));
crtn = doCCCrypt(false, encrAlg, doCbc, doPadding,
keyBytes, keySizeInBytes, ivPtrDecrypt,
stagedDecr, inPlace, ctxSize, askOutSize,
ctext, ctextLen,
&rptext, &rptextLen);
ok(crtn == 0, "doCCCrypt");
if(crtn) {
diag("Test Failure Encrypt encrAlg = %d dodCbc = %d doPadding %d\n", encrAlg, doCbc, doPadding);
}
logSize(("###rptext len %lu\n", rptextLen));
if(ptextLen != rptextLen) {
diag("Ptext length mismatch: expect %lu, got %lu\n", ptextLen, rptextLen);
}
if(memcmp(ptext, rptext, ptextLen)) {
diag("***data miscompare\n");
}
abort:
if(ctext) {
free(ctext);
}
if(rptext) {
free(rptext);
}
return rtn;
}
static bool isBitSet(unsigned bit, unsigned word)
{
if(bit > 31) {
diag("We don't have that many bits\n");
exit(1);
}
unsigned mask = 1 << bit;
return (word & mask) ? true : false;
}
static int kTestTestCount = 1;
int CommonCryptoSymRegression(int argc, char *const *argv)
{
unsigned loop;
uint8_t *ptext;
size_t ptextLen;
bool stagedEncr = false;
bool stagedDecr = false;
bool doPadding;
bool doCbc = false;
bool nullIV;
const char *algStr;
CCAlgorithm encrAlg;
int i;
int currAlg; uint32_t minKeySizeInBytes;
uint32_t maxKeySizeInBytes;
uint32_t keySizeInBytes = 0;
int rtn = 0;
uint32_t blockSize; size_t ctxSize; size_t ctxSizeUsed; bool askOutSize;
bool keySizeSpec = false; SymAlg minAlg = ALG_FIRST;
SymAlg maxAlg = ALG_LAST;
unsigned loops = LOOPS_DEF;
bool verbose = false;
size_t minPtextSize = MIN_DATA_SIZE;
size_t maxPtextSize = MAX_DATA_SIZE;
bool quiet = true;
unsigned pauseInterval = 0;
bool paddingSpec = false; bool cbcSpec = false; bool stagedSpec = false; bool inPlace = false; bool allocCtxSpec = false; bool allocCtx = false;
plan_tests(kTestTestCount);
ptext = (uint8_t *)malloc(maxPtextSize);
if(ptext == NULL) {
diag("Insufficient heap space\n");
exit(1);
}
if(!quiet) diag("Starting ccSymTest; args: ");
for(i=1; i<argc; i++) {
if(!quiet) diag("%s ", argv[i]);
}
if(!quiet) diag("\n");
if(pauseInterval) {
fpurge(stdin);
diag("Top of test; hit CR to proceed: ");
getchar();
}
for(currAlg=minAlg; currAlg<=maxAlg; currAlg++) {
switch(currAlg) {
case ALG_DES:
encrAlg = kCCAlgorithmDES;
blockSize = kCCBlockSizeDES;
minKeySizeInBytes = kCCKeySizeDES;
maxKeySizeInBytes = minKeySizeInBytes;
ctxSize = kCCContextSizeDES;
algStr = "DES";
diag("Running DES Tests");
break;
case ALG_3DES:
encrAlg = kCCAlgorithm3DES;
blockSize = kCCBlockSize3DES;
minKeySizeInBytes = kCCKeySize3DES;
maxKeySizeInBytes = minKeySizeInBytes;
ctxSize = kCCContextSize3DES;
algStr = "3DES";
diag("Running 3DES Tests");
break;
case ALG_AES_128:
encrAlg = kCCAlgorithmAES128;
blockSize = kCCBlockSizeAES128;
minKeySizeInBytes = kCCKeySizeAES128;
maxKeySizeInBytes = minKeySizeInBytes;
ctxSize = kCCContextSizeAES128;
algStr = "AES128";
diag("Running AES (128 bit key) Tests");
break;
case ALG_AES_192:
encrAlg = kCCAlgorithmAES128;
blockSize = kCCBlockSizeAES128;
minKeySizeInBytes = kCCKeySizeAES192;
maxKeySizeInBytes = minKeySizeInBytes;
ctxSize = kCCContextSizeAES128;
algStr = "AES192";
diag("Running AES (192 bit key) Tests");
break;
case ALG_AES_256:
encrAlg = kCCAlgorithmAES128;
blockSize = kCCBlockSizeAES128;
minKeySizeInBytes = kCCKeySizeAES256;
maxKeySizeInBytes = minKeySizeInBytes;
ctxSize = kCCContextSizeAES128;
algStr = "AES256";
diag("Running AES (256 bit key) Tests");
break;
case ALG_CAST:
encrAlg = kCCAlgorithmCAST;
blockSize = kCCBlockSizeCAST;
minKeySizeInBytes = kCCKeySizeMinCAST;
maxKeySizeInBytes = kCCKeySizeMaxCAST;
ctxSize = kCCContextSizeCAST;
algStr = "CAST";
diag("Running CAST Tests");
break;
case ALG_RC4:
encrAlg = kCCAlgorithmRC4;
blockSize = 0;
minKeySizeInBytes = kCCKeySizeMinRC4;
maxKeySizeInBytes = kCCKeySizeMaxRC4;
ctxSize = kCCContextSizeRC4;
algStr = "RC4";
diag("Running RC4 Tests");
break;
default:
diag("***BRRZAP!\n");
exit(1);
}
if(!quiet || verbose) {
diag("Testing alg %s\n", algStr);
}
for(loop=1; ; loop++) {
ptextLen = (size_t) genRand((unsigned int) minPtextSize, (unsigned int) maxPtextSize);
appGetRandomBytes(ptext, ptextLen);
if(!keySizeSpec) {
if(minKeySizeInBytes == maxKeySizeInBytes) {
keySizeInBytes = minKeySizeInBytes;
}
else {
keySizeInBytes = genRand(minKeySizeInBytes, maxKeySizeInBytes);
}
}
if(blockSize == 0) {
doCbc = false;
doPadding = false;
}
else {
if(!cbcSpec) {
doCbc = isBitSet(0, loop);
}
if(!paddingSpec) {
doPadding = isBitSet(1, loop);
}
}
if(!doPadding && (blockSize != 0)) {
ptextLen = (ptextLen / blockSize) * blockSize;
if(ptextLen == 0) {
ptextLen = blockSize;
}
}
if(!stagedSpec) {
stagedEncr = isBitSet(2, loop);
stagedDecr = isBitSet(3, loop);
}
if(doCbc) {
nullIV = isBitSet(4, loop);
}
else {
nullIV = false;
}
inPlace = isBitSet(5, loop);
if(allocCtxSpec) {
ctxSizeUsed = allocCtx ? ctxSize : 0;
}
else if(isBitSet(6, loop)) {
ctxSizeUsed = ctxSize;
}
else {
ctxSizeUsed = 0;
}
askOutSize = isBitSet(7, loop);
if(!quiet) {
if(verbose || ((loop % LOOP_NOTIFY) == 0)) {
diag("..loop %3d ptextLen %lu keyLen %d cbc=%d padding=%d stagedEncr=%d "
"stagedDecr=%d\n",
loop, (unsigned long)ptextLen, (int)keySizeInBytes,
(int)doCbc, (int)doPadding,
(int)stagedEncr, (int)stagedDecr);
diag(" nullIV %d inPlace %d ctxSize %d askOutSize %d\n",
(int)nullIV, (int)inPlace, (int)ctxSizeUsed, (int)askOutSize);
}
}
if(doTest(ptext, ptextLen,
encrAlg, doCbc, doPadding, nullIV,
keySizeInBytes,
stagedEncr, stagedDecr, inPlace, ctxSizeUsed, askOutSize,
quiet)) {
rtn = 1;
break;
}
if(pauseInterval && ((loop % pauseInterval) == 0)) {
char c;
fpurge(stdin);
diag("Hit CR to proceed, q to abort: ");
c = getchar();
if(c == 'q') {
goto testDone;
}
}
if(loops && (loop == loops)) {
break;
}
}
if(rtn) {
break;
}
}
testDone:
ok(rtn == 0, "ccSymTest");
if(pauseInterval) {
fpurge(stdin);
diag("ModuleDetach/Unload complete; hit CR to exit: ");
getchar();
}
if((rtn == 0) && !quiet) {
diag("%s test complete\n", argv[0]);
}
free(ptext);
return rtn;
}
#endif