#include "ccGlobals.h"
#include "ccMemory.h"
#include "ccdebug.h"
#include <CommonCrypto/CommonCryptor.h>
#include <CommonCrypto/CommonCryptorSPI.h>
#include "CommonCryptorPriv.h"
#include "CCCryptorReset_internal.h"
#ifdef DEBUG
#include <stdio.h>
#include "CommonRandomSPI.h"
#endif
static inline uint32_t ccGetCipherBlockSize(CCCryptor *ref) {
switch(ref->cipher) {
case kCCAlgorithmAES128: return kCCBlockSizeAES128;
case kCCAlgorithmDES: return kCCBlockSizeDES;
case kCCAlgorithm3DES: return kCCBlockSize3DES;
case kCCAlgorithmCAST: return kCCBlockSizeCAST;
case kCCAlgorithmRC4: return 1;
case kCCAlgorithmRC2: return kCCBlockSizeRC2;
case kCCAlgorithmBlowfish: return kCCBlockSizeBlowfish;
default: return kCCBlockSizeAES128;
}
}
struct info_pack{
int i;
CCAlgorithm cipher;
};
static void init_globals(void *info){
int i = ((struct info_pack *)info)->i;
CCAlgorithm cipher = ((struct info_pack *)info)->cipher;
cc_globals_t globals = _cc_globals();
globals->cipherModeTab[cipher][i].ecb = ccmodeList[cipher][i].ecb();
globals->cipherModeTab[cipher][i].cbc = ccmodeList[cipher][i].cbc();
globals->cipherModeTab[cipher][i].cfb = ccmodeList[cipher][i].cfb();
globals->cipherModeTab[cipher][i].cfb8 = ccmodeList[cipher][i].cfb8();
globals->cipherModeTab[cipher][i].ctr = ccmodeList[cipher][i].ctr();
globals->cipherModeTab[cipher][i].ofb = ccmodeList[cipher][i].ofb();
globals->cipherModeTab[cipher][i].xts = ccmodeList[cipher][i].xts();
globals->cipherModeTab[cipher][i].gcm = ccmodeList[cipher][i].gcm();
globals->cipherModeTab[cipher][i].ccm = ccmodeList[cipher][i].ccm();
}
const corecryptoMode getCipherMode(CCAlgorithm cipher, CCMode mode, CCOperation direction)
{
cc_globals_t globals = _cc_globals();
for(int i = 0; i<2; i++) {
struct info_pack info = {i, cipher};
cc_dispatch_once(&(globals->cipherModeTab[cipher][i].init), &info, init_globals);
}
switch(mode) {
case kCCModeECB: return (corecryptoMode) globals->cipherModeTab[cipher][direction].ecb;
case kCCModeCBC: return (corecryptoMode) globals->cipherModeTab[cipher][direction].cbc;
case kCCModeCFB: return (corecryptoMode) globals->cipherModeTab[cipher][direction].cfb;
case kCCModeCFB8: return (corecryptoMode) globals->cipherModeTab[cipher][direction].cfb8;
case kCCModeCTR: return (corecryptoMode) globals->cipherModeTab[cipher][direction].ctr;
case kCCModeOFB: return (corecryptoMode) globals->cipherModeTab[cipher][direction].ofb;
case kCCModeXTS: return (corecryptoMode) globals->cipherModeTab[cipher][direction].xts;
case kCCModeGCM: return (corecryptoMode) globals->cipherModeTab[cipher][direction].gcm;
case kCCModeCCM: return (corecryptoMode) globals->cipherModeTab[cipher][direction].ccm;
}
return (corecryptoMode) (const struct ccmode_ecb*) NULL;
}
static inline CCCryptorStatus setCryptorCipherMode(CCCryptor *ref, CCAlgorithm cipher, CCMode mode, CCOperation direction) {
switch(mode) {
case kCCModeECB: if((ref->symMode[direction].ecb = getCipherMode(cipher, mode, direction).ecb) == NULL) return kCCUnimplemented;
ref->modeDesc = &ccecb_mode; break;
case kCCModeCBC: if((ref->symMode[direction].cbc = getCipherMode(cipher, mode, direction).cbc) == NULL) return kCCUnimplemented;
ref->modeDesc = &cccbc_mode; break;
case kCCModeCFB: if((ref->symMode[direction].cfb = getCipherMode(cipher, mode, direction).cfb) == NULL) return kCCUnimplemented;
ref->modeDesc = &cccfb_mode; break;
case kCCModeCFB8: if((ref->symMode[direction].cfb8 = getCipherMode(cipher, mode, direction).cfb8) == NULL) return kCCUnimplemented;
ref->modeDesc = &cccfb8_mode; break;
case kCCModeCTR: if((ref->symMode[direction].ctr = getCipherMode(cipher, mode, direction).ctr) == NULL) return kCCUnimplemented;
ref->modeDesc = &ccctr_mode; break;
case kCCModeOFB: if((ref->symMode[direction].ofb = getCipherMode(cipher, mode, direction).ofb) == NULL) return kCCUnimplemented;
ref->modeDesc = &ccofb_mode; break;
case kCCModeXTS: if((ref->symMode[direction].xts = getCipherMode(cipher, mode, direction).xts) == NULL) return kCCUnimplemented;
ref->modeDesc = &ccxts_mode; break;
case kCCModeGCM: if((ref->symMode[direction].gcm = getCipherMode(cipher, mode, direction).gcm) == NULL) return kCCUnimplemented;
ref->modeDesc = &ccgcm_mode; break;
case kCCModeCCM: if((ref->symMode[direction].ccm = getCipherMode(cipher, mode, direction).ccm) == NULL) return kCCUnimplemented;
ref->modeDesc = &ccccm_mode; break;
default: return kCCParamError;
}
return kCCSuccess;
}
static inline CCCryptorStatus ccSetupCryptor(CCCryptor *ref, CCAlgorithm cipher, CCMode mode, CCOperation direction, CCPadding padding)
{
CCCryptorStatus retval;
if(cipher > 6) return kCCParamError;
if(direction > kCCBoth) return kCCParamError;
if(cipher == kCCAlgorithmRC4) mode = kCCModeOFB;
ref->mode = mode;
CCOperation op = direction;
if(ref->mode == kCCModeXTS || ref->mode == kCCModeECB || ref->mode == kCCModeCBC) op = kCCBoth;
ref->ctx[kCCEncrypt].data = NULL;
ref->ctx[kCCDecrypt].data = NULL;
switch(op) {
case kCCEncrypt:
case kCCDecrypt:
if((retval = setCryptorCipherMode(ref, cipher, mode, op)) != kCCSuccess) return retval;
if((ref->ctx[op].data = CC_XMALLOC(ref->modeDesc->mode_get_ctx_size(ref->symMode[op]))) == NULL) return kCCMemoryFailure;
break;
case kCCBoth:
if((retval = setCryptorCipherMode(ref, cipher, mode, kCCEncrypt)) != kCCSuccess) return retval;
if((ref->ctx[kCCEncrypt].data = CC_XMALLOC(ref->modeDesc->mode_get_ctx_size(ref->symMode[kCCEncrypt]))) == NULL) return kCCMemoryFailure;
if((retval = setCryptorCipherMode(ref, cipher, mode, kCCDecrypt)) != kCCSuccess) return retval;
if((ref->ctx[kCCDecrypt].data = CC_XMALLOC(ref->modeDesc->mode_get_ctx_size(ref->symMode[kCCDecrypt]))) == NULL) return kCCMemoryFailure;
break;
}
switch(padding) {
case ccNoPadding:
ref->padptr = &ccnopad_pad;
break;
case ccPKCS7Padding:
if(mode == kCCModeCBC)
ref->padptr = &ccpkcs7_pad;
else
ref->padptr = &ccpkcs7_ecb_pad;
break;
case ccCBCCTS1:
ref->padptr = &cccts1_pad;
break;
case ccCBCCTS2:
ref->padptr = &cccts2_pad;
break;
case ccCBCCTS3:
ref->padptr = &cccts3_pad;
break;
default:
ref->padptr = &ccnopad_pad;
}
ref->cipher = cipher;
ref->cipherBlocksize = ccGetCipherBlockSize(ref);
ref->op = direction;
ref->bufferPos = 0;
ref->bytesProcessed = 0;
return kCCSuccess;
}
#define OP4INFO(X) (((X)->op == 3) ? 0: (X)->op)
#if 0
static inline size_t ccGetBlockSize(CCCryptor *ref) {
return ref->modeDesc->mode_get_block_size(ref->symMode[OP4INFO(ref)]);
}
#endif
static inline bool ccIsStreaming(CCCryptor *ref) {
return ref->modeDesc->mode_get_block_size(ref->symMode[ref->op]) == 1;
}
static int check_algorithm_keysize(CCAlgorithm alg, size_t keysize)
{
int rc;
#if (kCCAlgorithmAES128!= kCCAlgorithmAES)
#error If kCCAlgorithmAES128 and kCCAlgorithmAES are not the same, a case statement must be defined
#endif
switch (alg) {
case kCCAlgorithmAES: rc = keysize==kCCKeySizeAES128 || keysize==kCCKeySizeAES192 || keysize==kCCKeySizeAES256; break;
case kCCAlgorithmDES: rc = keysize==kCCKeySizeDES; break;
case kCCAlgorithm3DES:rc = keysize==kCCKeySize3DES; break;
case kCCAlgorithmCAST:rc = keysize>=kCCKeySizeMinCAST && keysize<=kCCKeySizeMaxCAST; break;
case kCCAlgorithmRC4: rc = keysize>=kCCKeySizeMinRC4 && keysize<=kCCKeySizeMaxRC4; break;
case kCCAlgorithmRC2: rc = keysize>=kCCKeySizeMinRC2 && keysize<=kCCKeySizeMaxRC2; break;
case kCCAlgorithmBlowfish: rc = keysize>=kCCKeySizeMinBlowfish && keysize<=kCCKeySizeMaxBlowfish; break;
default: rc=0;
}
return rc==1?0:-1;
}
static inline CCCryptorStatus ccInitCryptor(CCCryptor *ref, const void *key, unsigned long key_len, const void *tweak_key, const void *iv)
{
if( check_algorithm_keysize(ref->cipher, key_len) <0 )
return kCCKeySizeError;
size_t blocksize = ccGetCipherBlockSize(ref);
uint8_t defaultIV[blocksize];
if(iv == NULL) {
CC_XZEROMEM(defaultIV, blocksize);
iv = defaultIV;
}
CCOperation op = ref->op;
if(ref->mode == kCCModeXTS || ref->mode == kCCModeECB || ref->mode == kCCModeCBC) op = kCCBoth;
switch(op) {
case kCCEncrypt:
case kCCDecrypt:
ref->modeDesc->mode_setup(ref->symMode[ref->op], iv, key, key_len, tweak_key, 0, 0, ref->ctx[ref->op]);
break;
case kCCBoth:
ref->modeDesc->mode_setup(ref->symMode[kCCEncrypt], iv, key, key_len, tweak_key, 0, 0, ref->ctx[kCCEncrypt]);
ref->modeDesc->mode_setup(ref->symMode[kCCDecrypt], iv, key, key_len, tweak_key, 0, 0, ref->ctx[kCCDecrypt]);
break;
}
return kCCSuccess;
}
static inline CCCryptorStatus ccDoEnCrypt(CCCryptor *ref, const void *dataIn, size_t dataInLength, void *dataOut) {
if(!ref->modeDesc->mode_encrypt) return kCCParamError;
ref->modeDesc->mode_encrypt(ref->symMode[kCCEncrypt], dataIn, dataOut, dataInLength, ref->ctx[kCCEncrypt]);
return kCCSuccess;
}
static inline CCCryptorStatus ccDoDeCrypt(CCCryptor *ref, const void *dataIn, size_t dataInLength, void *dataOut) {
if(!ref->modeDesc->mode_decrypt) return kCCParamError;
ref->modeDesc->mode_decrypt(ref->symMode[kCCDecrypt], dataIn, dataOut, dataInLength, ref->ctx[kCCDecrypt]);
return kCCSuccess;
}
static inline CCCryptorStatus ccDoEnCryptTweaked(CCCryptor *ref, const void *dataIn, size_t dataInLength, void *dataOut, const void *tweak) {
if(!ref->modeDesc->mode_encrypt_tweaked) return kCCParamError;
ref->modeDesc->mode_encrypt_tweaked(ref->symMode[kCCEncrypt], dataIn, dataInLength, dataOut, tweak, ref->ctx[kCCEncrypt]);
return kCCSuccess;
}
static inline CCCryptorStatus ccDoDeCryptTweaked(CCCryptor *ref, const void *dataIn, size_t dataInLength, void *dataOut, const void *tweak) {
if(!ref->modeDesc->mode_decrypt_tweaked) return kCCParamError;
ref->modeDesc->mode_decrypt_tweaked(ref->symMode[kCCDecrypt], dataIn, dataInLength, dataOut, tweak, ref->ctx[kCCDecrypt]);
return kCCSuccess;
}
static inline CCCryptorStatus ccGetIV(CCCryptor *ref, void *iv, size_t *ivLen) {
if(ref->modeDesc->mode_getiv == NULL) return kCCParamError;
uint32_t tmp = (uint32_t) *ivLen;
if(ref->modeDesc->mode_getiv(ref->symMode[OP4INFO(ref)], iv, &tmp, ref->ctx[OP4INFO(ref)]) != 0) return kCCMemoryFailure;
*ivLen = tmp;
return kCCSuccess;
}
static inline CCCryptorStatus ccSetIV(CCCryptor *ref, const void *iv, size_t ivLen) {
if(ref->modeDesc->mode_setiv == NULL) return kCCParamError;
if(ref->modeDesc->mode_setiv(ref->symMode[OP4INFO(ref)], iv, (uint32_t ) ivLen, ref->ctx[OP4INFO(ref)]) != 0) return kCCMemoryFailure;
return kCCSuccess;
}
static inline void ccClearCryptor(CCCryptor *ref) {
CC_XZEROMEM(ref->buffptr, sizeof(ref->buffptr));
CCOperation op = ref->op;
if(ref->mode == kCCModeXTS || ref->mode == kCCModeECB || ref->mode == kCCModeCBC) op = kCCBoth;
switch(op) {
case kCCEncrypt:
case kCCDecrypt:
CC_XZEROMEM(ref->ctx[ref->op].data, ref->modeDesc->mode_get_ctx_size(ref->symMode[ref->op]));
CC_XFREE(ref->ctx[ref->op].data, ref->modeDesc->mode_get_ctx_size(ref->symMode[ref->op]));
break;
case kCCBoth:
for(int i = 0; i<2; i++) {
CC_XZEROMEM(ref->ctx[i].data, ref->modeDesc->mode_get_ctx_size(ref->symMode[i]));
CC_XFREE(ref->ctx[i].data, ref->modeDesc->mode_get_ctx_size(ref->symMode[i]));
}
break;
}
cc_clear(CCCRYPTOR_SIZE, ref);
}
static inline void returnLengthIfPossible(size_t length, size_t *returnPtr) {
if(returnPtr) *returnPtr = length;
}
static inline CCCryptorStatus ccEncryptPad(CCCryptor *cryptor, void *buf, size_t *moved) {
if(cryptor->padptr->encrypt_pad(cryptor->ctx[cryptor->op], cryptor->modeDesc, cryptor->symMode[cryptor->op], cryptor->buffptr, cryptor->bufferPos, buf, moved)) return kCCAlignmentError;
return kCCSuccess;
}
static inline CCCryptorStatus ccDecryptPad(CCCryptor *cryptor, void *buf, size_t *moved) {
if(cryptor->padptr->decrypt_pad(cryptor->ctx[cryptor->op], cryptor->modeDesc, cryptor->symMode[cryptor->op], cryptor->buffptr, cryptor->bufferPos, buf, moved)) return kCCAlignmentError;
return kCCSuccess;
}
static inline size_t ccGetReserve(CCCryptor *cryptor) {
return cryptor->padptr->padreserve(cryptor->op == kCCEncrypt, cryptor->modeDesc, cryptor->symMode[cryptor->op]);
}
static inline size_t ccGetPadOutputlen(CCCryptor *cryptor, size_t inputLength, bool final) {
size_t totalLen = cryptor->bufferPos + inputLength;
return cryptor->padptr->padlen(cryptor->op == kCCEncrypt, cryptor->modeDesc, cryptor->symMode[cryptor->op], totalLen, final);
}
static inline CCCryptor *
ccCreateCompatCryptorFromData(const void *data, size_t dataLength, size_t *dataUsed) {
uintptr_t startptr = (uintptr_t) data;
uintptr_t retval = (uintptr_t) data;
if((retval & 0x07) ) retval = ((startptr / 8) * 8 + 8);
size_t usedLen = retval - startptr + CC_COMPAT_SIZE;
returnLengthIfPossible(usedLen, dataUsed);
if(usedLen > dataLength) return NULL;
return (CCCryptor *) retval;
}
static inline int ccAddBuff(CCCryptor *cryptor, const void *dataIn, size_t dataInLength) {
CC_XMEMCPY((char *) cryptor->buffptr + cryptor->bufferPos, dataIn, dataInLength);
cryptor->bufferPos += dataInLength;
return (int) dataInLength;
}
CCCryptorStatus CCCryptorCreateFromData(
CCOperation op,
CCAlgorithm alg,
CCOptions options,
const void *key,
size_t keyLength,
const void *iv,
const void *data,
size_t dataLength,
CCCryptorRef *cryptorRef,
size_t *dataUsed)
{
CCCryptor *cryptor = ccCreateCompatCryptorFromData(data, dataLength, dataUsed);
if(!cryptor) return kCCBufferTooSmall;
CCCryptorStatus err = CCCryptorCreate(op, alg, options, key, keyLength, iv, &cryptor->compat);
if(err == kCCSuccess) *cryptorRef = cryptor;
return err;
}
CCCryptorStatus CCCryptorCreate(
CCOperation op,
CCAlgorithm alg,
CCOptions options,
const void *key,
size_t keyLength,
const void *iv,
CCCryptorRef *cryptorRef)
{
CCMode mode;
CCPadding padding;
const void *tweak;
size_t tweakLength;
int numRounds;
CCModeOptions modeOptions;
CC_DEBUG_LOG("Entering\n");
if(alg == kCCAlgorithmRC4) mode = kCCModeRC4;
else if(options & kCCOptionECBMode) mode = kCCModeECB;
else mode = kCCModeCBC;
padding = ccNoPadding;
if(options & kCCOptionPKCS7Padding) padding = ccPKCS7Padding;
tweak = NULL;
tweakLength = 0;
numRounds = 0;
modeOptions = 0;
return CCCryptorCreateWithMode(op, mode, alg, padding, iv, key, keyLength, tweak, tweakLength, numRounds, modeOptions, cryptorRef);
}
CCCryptorStatus CCCryptorCreateFromDataWithMode(
CCOperation op,
CCMode mode,
CCAlgorithm alg,
CCPadding padding,
const void *iv,
const void *key,
size_t keyLength,
const void *tweak,
size_t tweakLength,
int numRounds,
CCModeOptions options,
const void *data,
size_t dataLength,
CCCryptorRef *cryptorRef,
size_t *dataUsed)
{
CCCryptor *cryptor = ccCreateCompatCryptorFromData(data, dataLength, dataUsed);
if(!cryptor) return kCCBufferTooSmall;
CCCryptorStatus err = CCCryptorCreateWithMode(op, mode, alg, padding, iv, key, keyLength, tweak, tweakLength, numRounds, options, &cryptor->compat);
if(err == kCCSuccess) *cryptorRef = cryptor;
return err;
}
#define KEYALIGNMENT (sizeof(int)-1)
CCCryptorStatus CCCryptorCreateWithMode(
CCOperation op,
CCMode mode,
CCAlgorithm alg,
CCPadding padding,
const void *iv,
const void *key,
size_t keyLength,
const void *tweak,
size_t __unused tweakLength,
int __unused numRounds,
CCModeOptions options,
CCCryptorRef *cryptorRef)
{
CCCryptorStatus retval = kCCSuccess;
CCCryptor *cryptor = NULL;
uint8_t *alignedKey = NULL;
CC_DEBUG_LOG("Entering Op: %d Mode: %d Cipher: %d Padding: %d\n", op, mode, alg, padding);
if(alg == kCCAlgorithmAES128NoHardware || alg == kCCAlgorithmAES128WithHardware)
alg = kCCAlgorithmAES128;
if(mode == kCCModeCTR && options != kCCModeOptionCTR_BE) {
CC_DEBUG_LOG("Mode is CTR, but options isn't BE\n", op, mode, alg, padding);
return kCCUnimplemented;
}
if((cryptorRef == NULL) || (key == NULL)) {
CC_DEBUG_LOG("bad arguments\n", 0);
return kCCParamError;
}
if((intptr_t) key & KEYALIGNMENT) {
if((alignedKey = CC_XMALLOC(keyLength)) == NULL) {
return kCCMemoryFailure;
}
CC_XMEMCPY(alignedKey, key, keyLength);
key = alignedKey;
}
if((cryptor = (CCCryptor *)CC_XMALLOC(DEFAULT_CRYPTOR_MALLOC)) == NULL) {
retval = kCCMemoryFailure;
goto out;
}
cryptor->compat = NULL;
if((retval = ccSetupCryptor(cryptor, alg, mode, op, padding)) != kCCSuccess) {
goto out;
}
if((retval = ccInitCryptor(cryptor, key, keyLength, tweak, iv)) != kCCSuccess) {
goto out;
}
*cryptorRef = cryptor;
#ifdef DEBUG
cryptor->active = ACTIVE;
retval=CCRandomGenerateBytes(&cryptor->cryptorID, sizeof(cryptor->cryptorID));
#endif
out:
if(retval) {
*cryptorRef = NULL;
if(cryptor) {
ccClearCryptor(cryptor);
CC_XFREE(cryptor, DEFAULT_CRYPTOR_MALLOC);
}
} else {
}
if(alignedKey) {
CC_XZEROMEM(alignedKey, keyLength);
CC_XFREE(alignedKey, keyLength);
}
return retval;
}
CCCryptorStatus CCCryptorRelease(
CCCryptorRef cryptorRef)
{
CCCryptor *cryptor = getRealCryptor(cryptorRef, 0);
CC_DEBUG_LOG("Entering\n");
if(cryptor) {
ccClearCryptor(cryptor);
CC_XFREE(cryptor, DEFAULT_CRYPTOR_MALLOC);
}
return kCCSuccess;
}
#define FULLBLOCKSIZE(X,BLOCKSIZE) (((X)/(BLOCKSIZE))*BLOCKSIZE)
#define FULLBLOCKREMAINDER(X,BLOCKSIZE) ((X)%(BLOCKSIZE))
static CCCryptorStatus ccSimpleUpdate(CCCryptor *cryptor, const void *dataIn, size_t dataInLength, void **dataOut, size_t *dataOutAvailable, size_t *dataOutMoved)
{
CCCryptorStatus retval;
if(cryptor->op == kCCEncrypt) {
if((retval = ccDoEnCrypt(cryptor, dataIn, dataInLength, *dataOut)) != kCCSuccess) return retval;
} else {
if((retval = ccDoDeCrypt(cryptor, dataIn, dataInLength, *dataOut)) != kCCSuccess) return retval;
}
if(dataOutMoved) *dataOutMoved += dataInLength;
if(*dataOutAvailable < dataInLength) return kCCBufferTooSmall;
cryptor->bytesProcessed += dataInLength;
*dataOut += dataInLength;
*dataOutAvailable -= dataInLength;
return kCCSuccess;
}
static CCCryptorStatus ccBlockUpdate(CCCryptor *cryptor, const void *dataIn, size_t dataInLength, void *dataOut, size_t *dataOutAvailable, size_t *dataOutMoved)
{
CCCryptorStatus retval;
size_t dataCount = cryptor->bufferPos + dataInLength;
size_t reserve = ccGetReserve(cryptor);
size_t blocksize = ccGetCipherBlockSize(cryptor);
size_t buffsize = (reserve) ? reserve: blocksize;
size_t dataCountToHold, dataCountToProcess;
size_t remainder, movecnt;
if(reserve == 0 && cryptor->bufferPos == 0 && (dataInLength % blocksize) == 0) { return ccSimpleUpdate(cryptor, dataIn, dataInLength, &dataOut, dataOutAvailable, dataOutMoved);
}
if(dataCount <= reserve) {
dataCountToHold = dataCount;
} else {
remainder = FULLBLOCKREMAINDER(dataCount, blocksize);
dataCountToHold = buffsize - blocksize + remainder;
dataCountToHold = (remainder) ? dataCountToHold: reserve;
}
dataCountToProcess = dataCount - dataCountToHold;
if(dataCountToProcess > 0) {
if(cryptor->bufferPos == 0) {
} else if(cryptor->bufferPos < dataCountToProcess) {
movecnt = blocksize - (cryptor->bufferPos % blocksize);
ccAddBuff(cryptor, dataIn, movecnt);
dataIn += movecnt; dataInLength -= movecnt;
if((retval = ccSimpleUpdate(cryptor, cryptor->buffptr, cryptor->bufferPos, &dataOut, dataOutAvailable, dataOutMoved)) != kCCSuccess) {
return retval;
}
dataCountToProcess -= cryptor->bufferPos;
cryptor->bufferPos = 0;
} else if(cryptor->bufferPos == dataCountToProcess) {
if((retval = ccSimpleUpdate(cryptor, cryptor->buffptr, cryptor->bufferPos, &dataOut, dataOutAvailable, dataOutMoved)) != kCCSuccess) {
return retval;
}
dataCountToProcess -= cryptor->bufferPos;
cryptor->bufferPos = 0;
} else {
if(dataCountToHold) {
return kCCDecodeError;
}
if((retval = ccSimpleUpdate(cryptor, cryptor->buffptr, dataCountToProcess, &dataOut, dataOutAvailable, dataOutMoved)) != kCCSuccess) {
return retval;
}
cryptor->bufferPos = (uint32_t) (reserve - dataCountToProcess);
memmove(cryptor->buffptr, ((uint8_t *) cryptor->buffptr)+ dataCountToProcess, cryptor->bufferPos);
return kCCSuccess;
}
if(dataCountToProcess > 0) {
movecnt = FULLBLOCKREMAINDER(dataCountToProcess, blocksize);
if(movecnt) {
return kCCDecodeError;
}
if((retval = ccSimpleUpdate(cryptor, dataIn, dataCountToProcess, &dataOut, dataOutAvailable, dataOutMoved)) != kCCSuccess) return retval;
dataIn += dataCountToProcess; dataInLength -= dataCountToProcess;
}
}
if(dataCountToHold) {
movecnt = dataCountToHold - cryptor->bufferPos;
if(movecnt) {
if(movecnt != dataInLength) {
return kCCDecodeError;
}
ccAddBuff(cryptor, dataIn, movecnt);
dataInLength -= movecnt;
}
}
if(dataInLength) {
return kCCDecodeError;
}
return kCCSuccess;
}
static inline size_t ccGetOutputLength(CCCryptor *cryptor, size_t inputLength, bool final) {
if(ccIsStreaming(cryptor)) return inputLength;
return ccGetPadOutputlen(cryptor, inputLength, final);
}
size_t CCCryptorGetOutputLength(
CCCryptorRef cryptorRef,
size_t inputLength,
bool final)
{
CC_DEBUG_LOG("Entering\n");
CCCryptor *cryptor = getRealCryptor(cryptorRef, 1);
if(cryptor == NULL) return kCCParamError;
return ccGetOutputLength(cryptor, inputLength, final);
}
CCCryptorStatus CCCryptorUpdate(
CCCryptorRef cryptorRef,
const void *dataIn,
size_t dataInLength,
void *dataOut,
size_t dataOutAvailable,
size_t *dataOutMoved)
{
CC_DEBUG_LOG("Entering\n");
CCCryptorStatus retval;
CCCryptor *cryptor = getRealCryptor(cryptorRef, 1);
if(!cryptor) return kCCParamError;
if(dataOutMoved) *dataOutMoved = 0;
if(0 == dataInLength) return kCCSuccess;
size_t needed = ccGetOutputLength(cryptor, dataInLength, false);
if(needed > dataOutAvailable) {
if(dataOutMoved) *dataOutMoved = needed;
return kCCBufferTooSmall;
}
if(ccIsStreaming(cryptor))
retval = ccSimpleUpdate(cryptor, dataIn, dataInLength, &dataOut, &dataOutAvailable, dataOutMoved);
else
retval = ccBlockUpdate(cryptor, dataIn, dataInLength, dataOut, &dataOutAvailable, dataOutMoved);
return retval;
}
CCCryptorStatus CCCryptorFinal(
CCCryptorRef cryptorRef,
void *dataOut,
size_t dataOutAvailable,
size_t *dataOutMoved)
{
CC_DEBUG_LOG("Entering\n");
CCCryptor *cryptor = getRealCryptor(cryptorRef, 0);
if(cryptor == NULL) return kCCSuccess;
CCCryptorStatus retval;
int encrypting = (cryptor->op == kCCEncrypt);
uint32_t blocksize = ccGetCipherBlockSize(cryptor);
size_t moved;
char tmpbuf[blocksize*2];
if(dataOutMoved) *dataOutMoved = 0;
if(ccIsStreaming(cryptor)) {
if(cryptor->modeDesc->mode_done) {
cryptor->modeDesc->mode_done(cryptor->symMode[cryptor->op], cryptor->ctx[cryptor->op]);
}
return kCCSuccess;
}
if(encrypting) {
retval = ccEncryptPad(cryptor, tmpbuf, &moved);
if(retval != kCCSuccess) return retval;
if(dataOutAvailable < moved) {
return kCCBufferTooSmall;
}
if(dataOut) {
CC_XMEMCPY(dataOut, tmpbuf, moved);
if(dataOutMoved) *dataOutMoved = moved;
}
cryptor->bufferPos = 0;
} else {
retval = ccDecryptPad(cryptor, tmpbuf, &moved);
if(retval != kCCSuccess) return retval;
if(dataOutAvailable < moved) {
return kCCBufferTooSmall;
}
if(dataOut) {
CC_XMEMCPY(dataOut, tmpbuf, moved);
if(dataOutMoved) *dataOutMoved = moved;
}
cryptor->bytesProcessed += moved;
cryptor->bufferPos = 0;
}
cryptor->bufferPos = 0;
#ifdef DEBUG
cryptor->active = RELEASED;
#endif
return kCCSuccess;
}
CCCryptorStatus CCCryptorReset_binary_compatibility(
CCCryptorRef cryptorRef,
const void *iv)
{ CC_DEBUG_LOG("Entering\n");
CCCryptor *cryptor = getRealCryptor(cryptorRef, 1);
if(!cryptor) return kCCParamError;
CCCryptorStatus retval;
cryptor->bytesProcessed = cryptor->bufferPos = 0;
if(iv) {
retval = ccSetIV(cryptor, iv, ccGetCipherBlockSize(cryptor));
} else {
uint8_t ivzero[ccGetCipherBlockSize(cryptor)];
CC_XZEROMEM(ivzero, ccGetCipherBlockSize(cryptor));
retval = ccSetIV(cryptor, ivzero, ccGetCipherBlockSize(cryptor));
}
if(retval == kCCParamError) return kCCSuccess; return retval;
}
CCCryptorStatus CCCryptorReset(CCCryptorRef cryptorRef, const void *iv)
{
if(!ProgramLinkedOnOrAfter_macOS1013_iOS11()) return CCCryptorReset_binary_compatibility(cryptorRef, iv);
CC_DEBUG_LOG("Entering\n");
CCCryptor *cryptor = getRealCryptor(cryptorRef, 1);
if(!cryptor) return kCCParamError;
if(cryptor->mode!=kCCModeCBC) return kCCUnimplemented;
CCCryptorStatus retval;
cryptor->bytesProcessed = cryptor->bufferPos = 0;
if(iv) {
retval = ccSetIV(cryptor, iv, ccGetCipherBlockSize(cryptor));
} else {
uint8_t ivzero[ccGetCipherBlockSize(cryptor)];
CC_XZEROMEM(ivzero, ccGetCipherBlockSize(cryptor));
retval = ccSetIV(cryptor, ivzero, ccGetCipherBlockSize(cryptor));
}
return retval;
}
CCCryptorStatus
CCCryptorGetIV(CCCryptorRef cryptorRef, void *iv)
{
CCCryptor *cryptor = getRealCryptor(cryptorRef, 1);
CC_DEBUG_LOG("Entering\n");
if(!cryptor) return kCCParamError;
if(ccIsStreaming(cryptor)) return kCCParamError;
size_t blocksize = ccGetCipherBlockSize(cryptor);
return ccGetIV(cryptor, iv, &blocksize);
}
CCCryptorStatus CCCrypt(
CCOperation op,
CCAlgorithm alg,
CCOptions options,
const void *key,
size_t keyLength,
const void *iv,
const void *dataIn,
size_t dataInLength,
void *dataOut,
size_t dataOutAvailable,
size_t *dataOutMoved)
{
CC_DEBUG_LOG("Entering\n");
CCCryptorRef cryptor = NULL;
CCCryptorStatus retval;
size_t updateLen, finalLen;
if(kCCSuccess != (retval = CCCryptorCreate(op, alg, options, key, keyLength, iv, &cryptor))) return retval;
size_t needed = CCCryptorGetOutputLength(cryptor, dataInLength, true);
if(dataOutMoved != NULL) *dataOutMoved = needed;
if(needed > dataOutAvailable) {
retval = kCCBufferTooSmall;
goto out;
}
if(kCCSuccess != (retval = CCCryptorUpdate(cryptor, dataIn, dataInLength, dataOut, dataOutAvailable, &updateLen))) {
goto out;
}
dataOut += updateLen; dataOutAvailable -= updateLen;
retval = CCCryptorFinal(cryptor, dataOut, dataOutAvailable, &finalLen);
if(dataOutMoved != NULL) *dataOutMoved = updateLen + finalLen;
out:
CCCryptorRelease(cryptor);
return retval;
}
CCCryptorStatus CCCryptorEncryptDataBlock(
CCCryptorRef cryptorRef,
const void *iv,
const void *dataIn,
size_t dataInLength,
void *dataOut)
{
CC_DEBUG_LOG("Entering\n");
CCCryptor *cryptor = getRealCryptor(cryptorRef, 1);
if(!cryptor) return kCCParamError;
if(ccIsStreaming(cryptor)) return kCCParamError;
if(!iv) return ccDoEnCrypt(cryptor, dataIn, dataInLength, dataOut);
return ccDoEnCryptTweaked(cryptor, dataIn, dataInLength, dataOut, iv);
}
CCCryptorStatus CCCryptorDecryptDataBlock(
CCCryptorRef cryptorRef,
const void *iv,
const void *dataIn,
size_t dataInLength,
void *dataOut)
{
CC_DEBUG_LOG("Entering\n");
CCCryptor *cryptor = getRealCryptor(cryptorRef, 1);
if(!cryptor) return kCCParamError;
if(ccIsStreaming(cryptor)) return kCCParamError;
if(!iv) return ccDoDeCrypt(cryptor, dataIn, dataInLength, dataOut);
return ccDoDeCryptTweaked(cryptor, dataIn, dataInLength, dataOut, iv);
}
static bool ccm_ready(modeCtx ctx) {
if(ctx.ccm->mac_size == (size_t) 0xffffffffffffffff ||
ctx.ccm->nonce_size == (size_t) 0xffffffffffffffff ||
ctx.ccm->total_len == (size_t) 0xffffffffffffffff) return false;
return true;
}
CCCryptorStatus CCCryptorAddParameter(
CCCryptorRef cryptorRef,
CCParameter parameter,
const void *data,
size_t dataSize)
{
CC_DEBUG_LOG("Entering\n");
CCCryptor *cryptor = getRealCryptor(cryptorRef, 1);
if(!cryptor) return kCCParamError;
switch(parameter) {
case kCCParameterIV:
if(cryptor->mode == kCCModeGCM) {
int rc = ccgcm_set_iv_legacy(cryptor->symMode[cryptor->op].gcm,cryptor->ctx[cryptor->op].gcm, dataSize, data);
if (rc) return kCCParamError;
} else if(cryptor->mode == kCCModeCCM) {
ccm_nonce_ctx *ccm = cryptor->ctx[cryptor->op].ccm;
ccm->nonce_size = dataSize;
CC_XMEMCPY(ccm->nonce_buf, data, dataSize);
} else return kCCUnimplemented;
break;
case kCCParameterAuthData:
if(cryptor->mode == kCCModeGCM) {
ccgcm_gmac(cryptor->symMode[cryptor->op].gcm,cryptor->ctx[cryptor->op].gcm, dataSize, data);
} else if(cryptor->mode == kCCModeCCM) {
if(!ccm_ready(cryptor->ctx[cryptor->op])) return kCCParamError;
ccm_nonce_ctx *ccm = cryptor->ctx[cryptor->op].ccm;
const struct ccmode_ccm *mode = cryptor->symMode[cryptor->op].ccm;
ccm->ad_len = dataSize;
ccccm_set_iv(mode,&ccm->ccm, (ccccm_nonce *) &ccm->nonce,
ccm->nonce_size, ccm->nonce_buf, ccm->mac_size, ccm->ad_len, ccm->total_len);
ccccm_cbcmac(mode,&ccm->ccm, (ccccm_nonce *) &ccm->nonce,
ccm->ad_len, data);
} else return kCCUnimplemented;
break;
case kCCMacSize:
if(cryptor->mode == kCCModeCCM) {
cryptor->ctx[cryptor->op].ccm->mac_size = dataSize;
} else return kCCUnimplemented;
break;
case kCCDataSize:
if(cryptor->mode == kCCModeCCM) {
cryptor->ctx[cryptor->op].ccm->total_len = dataSize;
} else return kCCUnimplemented;
break;
default:
return kCCParamError;
}
return kCCSuccess;
}
CCCryptorStatus CCCryptorGetParameter(
CCCryptorRef cryptorRef,
CCParameter parameter,
void *data,
size_t *dataSize)
{
CC_DEBUG_LOG("Entering\n");
CCCryptor *cryptor = getRealCryptor(cryptorRef, 1);
if(!cryptor) return kCCParamError;
switch(parameter) {
case kCCParameterAuthTag:
if(cryptor->mode == kCCModeGCM) {
return kCCUnimplemented;
} else if(cryptor->mode == kCCModeCCM) {
ccm_nonce_ctx *ccm = cryptor->ctx[cryptor->op].ccm;
CC_XMEMCPY(data, ccm->mac, ccm->mac_size);
*dataSize = ccm->mac_size;
} else return kCCUnimplemented;
break;
default:
return kCCParamError;
}
return kCCSuccess;
}