CommonKeyDerivation.c [plain text]
#include <CommonCrypto/CommonKeyDerivation.h>
#include <corecrypto/ccpbkdf2.h>
#include "CommonDigestPriv.h"
#include <CommonCrypto/CommonDigestSPI.h>
#include "ccdebug.h"
#include "ccGlobals.h"
int
CCKeyDerivationPBKDF( CCPBKDFAlgorithm algorithm, const char *password, size_t passwordLen,
const uint8_t *salt, size_t saltLen,
CCPseudoRandomAlgorithm prf, unsigned rounds,
uint8_t *derivedKey, size_t derivedKeyLen)
{
const struct ccdigest_info *di;
CC_DEBUG_LOG("PasswordLen %lu SaltLen %lU PRF %d Rounds %u DKLen %lu\n", passwordLen, saltLen, prf, rounds, derivedKeyLen);
if(algorithm != kCCPBKDF2) return kCCParamError;
switch(prf) {
case kCCPRFHmacAlgSHA1: di = CCDigestGetDigestInfo(kCCDigestSHA1); break;
case kCCPRFHmacAlgSHA224: di = CCDigestGetDigestInfo(kCCDigestSHA224); break;
case kCCPRFHmacAlgSHA256: di = CCDigestGetDigestInfo(kCCDigestSHA256); break;
case kCCPRFHmacAlgSHA384: di = CCDigestGetDigestInfo(kCCDigestSHA384); break;
case kCCPRFHmacAlgSHA512: di = CCDigestGetDigestInfo(kCCDigestSHA512); break;
default: return kCCParamError;
}
if(!password || !derivedKey || (derivedKeyLen == 0) || (rounds == 0)) return kCCParamError;
if(salt==NULL && saltLen!=0) return kCCParamError;
int rc = ccpbkdf2_hmac(di, passwordLen, password, saltLen, salt, rounds, derivedKeyLen, derivedKey);
return rc==0?kCCSuccess:kCCParamError ;
}
#if defined(_WIN32)
#include <windows.h>
static uint64_t absolute_time(void) {
LARGE_INTEGER time;
QueryPerformanceCounter(&time); return (uint64_t)time.QuadPart;
}
static uint64_t to_msec(uint64_t at){
LARGE_INTEGER freq;
QueryPerformanceFrequency(&freq); double msec = (double)at / freq.QuadPart / 1000;
return (uint64_t) msec;
}
#else
#include <mach/mach_time.h>
#define absolute_time() (mach_absolute_time())
static uint64_t to_msec(uint64_t at){
struct mach_timebase_info info;
mach_timebase_info(&info);
double msec = (double)at * info.numer / info.denom / 1000000;
return (uint64_t) msec;
}
#endif
#define ROUNDMEASURE 100000
#define CC_MAX_PRF_WORKSPACE 128+4
#define CC_MIN_PBKDF2_ITERATIONS 10000
unsigned CCCalibratePBKDF(CCPBKDFAlgorithm algorithm, size_t passwordLen, size_t saltLen,
CCPseudoRandomAlgorithm prf, size_t derivedKeyLen, uint32_t msec)
{
char *password;
uint8_t *salt=NULL, *derivedKey=NULL;
uint64_t startTime, elapsedTime;
size_t i;
int retval = -1;
CC_DEBUG_LOG("Entering\n");
if (derivedKeyLen == 0) return -1; if (saltLen > CC_MAX_PRF_WORKSPACE) return -1; if (passwordLen == 0 ) passwordLen = 1;
if(algorithm != kCCPBKDF2) return -1;
if((password = malloc(passwordLen)) == NULL) goto error;
for(i=0; i<passwordLen; i++) password[i] = 'a';
size_t saltLen2 = saltLen==0? 1: saltLen;
if((salt=malloc(saltLen2)) == NULL ) goto error;
for(i=0; i<saltLen2; i++) salt[i] = (uint8_t)(i%256);
if((derivedKey = malloc(derivedKeyLen)) == NULL) goto error;
for(elapsedTime=i=0; i < 5 && elapsedTime == 0; i++) {
startTime = absolute_time();
if(CCKeyDerivationPBKDF(algorithm, password, passwordLen, salt, saltLen, prf, ROUNDMEASURE, derivedKey, derivedKeyLen)) goto error;
elapsedTime = absolute_time() - startTime;
}
if(elapsedTime == 0){
retval = CC_MIN_PBKDF2_ITERATIONS; goto error;
}
retval = CC_MAX(CC_MIN_PBKDF2_ITERATIONS,(int)((msec * ROUNDMEASURE)/to_msec(elapsedTime)));
error:
free(password);
free(salt);
free(derivedKey);
return retval;
}