#include <CommonCrypto/CommonRandomSPI.h>
#include "CommonRandomPriv.h"
#include "ccDispatch.h"
#include <corecrypto/ccaes.h>
#include <corecrypto/ccdrbg.h>
#include <corecrypto/ccrng.h>
#include "ccGlobals.h"
#include "ccMemory.h"
#include "ccErrors.h"
#include "ccdebug.h"
static const ccInternalRandom ccRandomDefaultStruct = {
.rngtype = rng_default,
.drbgtype = 0,
.status = 0,
.rng = NULL
};
const CCRandomRef kCCRandomDefault = (CCRandomRef) &ccRandomDefaultStruct;
const CCRandomRef kCCRandomDevRandom = (CCRandomRef) &ccRandomDefaultStruct;
struct ccrng_state *
ccDRBGGetRngState(void)
{
int status;
struct ccrng_state *rng=ccrng(&status);
CC_DEBUG_LOG("ccrng returned %d\n", status);
return rng;
}
struct ccrng_state *
ccDevRandomGetRngState(void)
{
return ccDRBGGetRngState();
}
static struct ccrng_state *
ccRefGetRngState(CCRandomRef rnd)
{
struct ccrng_state *p=NULL;
if (rnd && rnd->status==0 && rnd->rng) {
p=rnd->rng;
}
return p;
}
CCRNGStatus
CCRNGCreate(uint32_t options, CCRandomRef *rngRef)
{
ccInternalRandomRef ref;
ref = CC_XMALLOC(sizeof(ccInternalRandom));
if(NULL == ref) return kCCMemoryFailure;
ref->rngtype = rng_created;
(void) options;
ref->rng=ccrng(&ref->status);
if(ref->status != 0) {
CC_XFREE(ref, sizeof(ccInternalRandom));
*rngRef = NULL;
return kCCUnspecifiedError;
}
*rngRef = ref;
return kCCSuccess;
}
CCRNGStatus
CCRNGRelease(CCRandomRef rng)
{
CC_DEBUG_LOG("Entering\n");
if(rng->rngtype == rng_created) {
cc_clear(sizeof(ccInternalRandom),rng);
CC_XFREE(rng, sizeof(ccInternalRandom));
}
return kCCSuccess;
}
static int
ccRNGReadBytes(struct ccrng_state *state, void *ptr, size_t length)
{
return ccrng_generate(state, length, ptr);
}
int CCRandomCopyBytes(CCRandomRef rnd, void *bytes, size_t count)
{
struct ccrng_state *rng;
if(0 == count) return 0;
if(NULL == bytes) return -1;
if(NULL == rnd) {
CC_DEBUG_LOG("Entering rnd(NULL)");
rng = ccDRBGGetRngState();
return ccRNGReadBytes(rng, bytes, count);
}
if (rnd->status!=0) {
CC_DEBUG_LOG("Entering rnd(!NULL), type %d, init status %d", rnd->rngtype, rnd->status);
return rnd->status; }
switch(rnd->rngtype) {
case rng_created:
rng = ccRefGetRngState(rnd);
return ccRNGReadBytes(rng, bytes, count);
break;
case rng_default:
default:
rng = ccDRBGGetRngState();
return ccRNGReadBytes(rng, bytes, count);
break;
}
}
CCRNGStatus CCRandomGenerateBytes(void *bytes, size_t count) {
if(CCRandomCopyBytes(kCCRandomDefault, bytes, count) == 0) return kCCSuccess;
return kCCRNGFailure;
}