#include "MacYarrow_OSX.h"
#include "entropyFile.h"
#include "systemEntropy.h"
#include <debug.h>
#include <Security/debugging.h>
#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
#include <sys/time.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
static int HardDiskPowered() { return 1; }
#define QUICK_TEST 0
#if QUICK_TEST
#define SYSTEM_ENTROPY_COLLECT_INTERVAL (10 * 1000)
#define UPDATE_SYSTEM_ENTROPY_FILE (30)
#else
#define SYSTEM_ENTROPY_COLLECT_INTERVAL (10 * 60 * 1000)
#define UPDATE_SYSTEM_ENTROPY_FILE (60 * 60)
#endif
typedef enum {
kYTSUninitialized = 0,
kYTSCollecting, kYTSCollectingInit, kYTSSleeping } yarrowTimerState;
#define SYSTEM_ENTROPY_SIZE 20
#define ENTROPY_FILE_SIZE 20
#define RESEED_TICKS 1000
static yarrowTimerState timerState = kYTSUninitialized;
static struct timeval lastFileUpdate;
static int gDevRandomRef = -1;
OSStatus yarrowServerInit(
const char *entropyFilePath,
unsigned *firstTimeout) {
UInt8 entropyFileData[ENTROPY_FILE_SIZE];
UInt32 actLen;
OSErr ortn;
gDevRandomRef = open ("/dev/random", O_RDWR);
if (gDevRandomRef == -1) {
return ioErr;
}
gettimeofday(&lastFileUpdate, NULL);
setEntropyFilePath(entropyFilePath);
ortn = readEntropyFile(entropyFileData,
ENTROPY_FILE_SIZE,
&actLen);
if((ortn == noErr) && (actLen > 0))
write(gDevRandomRef, entropyFileData, actLen);
memset(entropyFileData, 0, actLen);
systemEntropyBegin(SYSTEM_ENTROPY_SIZE);
*firstTimeout = SYSTEM_ENTROPY_COLLECT_TIME;
timerState = kYTSCollectingInit;
return noErr;
}
void yarrowServerFini()
{
}
OSStatus yarrowAddEntropy(
UInt8 *bytes,
UInt32 numBytes,
UInt32 bitsOfEntropy,
unsigned *nextTimeout) {
OSStatus rCode = noErr;
if (gDevRandomRef == -1) { return ioErr;
}
int result = write (gDevRandomRef, bytes, numBytes);
if (result == -1) {
rCode = ioErr;
}
debug("yarrow", "adding %ld bytes of entropy", numBytes);
if(timerState == kYTSSleeping) {
systemEntropyBegin(SYSTEM_ENTROPY_SIZE);
timerState = kYTSCollecting;
*nextTimeout = SYSTEM_ENTROPY_COLLECT_TIME;
}
return noErr;
}
OSStatus yarrowGetRandomBytes(
UInt8 *bytes,
UInt32 numBytes)
{
if (gDevRandomRef == -1) {
return ioErr;
}
int result = read (gDevRandomRef, bytes, numBytes);
if (result == -1) {
return ioErr;
} else {
return noErr;
}
}
unsigned yarrowTimerEvent()
{
UInt8 sysEntropyData[SYSTEM_ENTROPY_SIZE];
UInt32 numSysBytes;
UInt32 numSysEntropyBits;
int rtn;
unsigned nextTimeout;
switch(timerState) {
case kYTSCollecting:
case kYTSCollectingInit:
debug("yarrowtimer", "collecting system entropy");
nextTimeout = SYSTEM_ENTROPY_COLLECT_INTERVAL;
if(rtn = systemEntropyCollect(sysEntropyData, SYSTEM_ENTROPY_SIZE,
&numSysBytes, &numSysEntropyBits)) {
errorLog1("systemEntropyCollect() returned %d; aborting\n",
rtn);
timerState = kYTSSleeping;
break;
}
unsigned dummy;
yarrowAddEntropy (sysEntropyData, numSysBytes, 0, &dummy);
timerState = kYTSSleeping;
struct timeval now;
gettimeofday(&now, NULL);
if( ( (now.tv_sec - lastFileUpdate.tv_sec) > UPDATE_SYSTEM_ENTROPY_FILE) &&
HardDiskPowered() ) {
UInt8 entropyFileData[ENTROPY_FILE_SIZE];
OSErr ortn;
debug("yarrow", "writing new entropy file");
yarrowGetRandomBytes (entropyFileData, ENTROPY_FILE_SIZE);
ortn = writeEntropyFile(entropyFileData, ENTROPY_FILE_SIZE);
if(ortn) {
errorLog1("....writeEntropyFile returned %d\n", ortn);
}
lastFileUpdate = now;
}
break;
case kYTSSleeping:
debug("yarrowtimer", "start gathering entropy");
systemEntropyBegin(SYSTEM_ENTROPY_SIZE);
timerState = kYTSCollecting;
nextTimeout = SYSTEM_ENTROPY_COLLECT_TIME;
break;
default:
errorLog1("yarrowTimerEvent with timerState %d\n", timerState);
nextTimeout = SYSTEM_ENTROPY_COLLECT_INTERVAL;
break;
}
debug("yarrowtimer", "timer rescheduling for %d msecs", nextTimeout);
return nextTimeout;
}