-
Notifications
You must be signed in to change notification settings - Fork 0
/
Fortuna.cpp
122 lines (112 loc) · 4.11 KB
/
Fortuna.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#include "Fortuna.h"
Fortuna::Fortuna()
: accumulator(Accumulator())
,prngState(PRNGState())
, seedFile(NULL)
, seedFileReseed(true)
{
reseedTime = getTime();
}
Fortuna::Fortuna(SeedFile *inSeedFile)
: accumulator(Accumulator())
, prngState(PRNGState())
, seedFile(inSeedFile)
, seedFileReseed(false)
{
if (!seedFile->firstTimeAccess())
{
uint8_t *seedData = seedFile->readSeedFile();
prngState.reseed(seedData, SEED_FILE_SIZE);
delete[] seedData;
}
reseedTime = getTime();
}
bool Fortuna::registerSource(Source *source)
{
accumulator.registerEntropySource(source);
}
uint8_t* Fortuna::getRandomData(uint32_t numberOfBytes)
{
//TODO: This needs to be changed as time is in seconds NOT mili seconds so should check reseed every 100mS not every 1000mS
if (prngState.getPool(0)->length() >= MIN_ENTROPY_POOL_SIZE && reseedTime + 1 < getTime())
{
uint16_t reseedCount = prngState.getReseedCount() + 1;
uint8_t poolUsageCount = 0;
for (uint8_t poolIndex = 0; poolIndex < prngState.getPoolSize(); poolIndex++)
{
double dRC = reseedCount;
double dPI = poolIndex;
double ans = fmod(dRC, pow(2.0, dPI));
if (ans == 0)
{
++poolUsageCount;
} else
{
break;
}
}
/*
* This is something that I am not keen on doing, however, I think with the
* structure this is the only way of doing this. When 128 bits of entropy
* are gathered instead of using it for the reseed of the generator it is
* instead to be used to re-write the seed file.
* 1. It means FORTUNA can continue to work and the data will still be random
* based on the use if the previous reseeded key
* 2. The only other way is to retrieve the first 128bits of entropy to put
* back into the seed file. If the seed file has been compromised this will
* mean that the first reseed will purt FORTUNA
* into an unkown state again.
*
*/
if (MIN_ENTROPY_POOL_SIZE * poolUsageCount >= 128 && seedFile && !seedFileReseed)
{
uint8_t *seed = new uint8_t[128];
for (uint8_t poolIndex = 0; poolIndex < poolUsageCount; poolIndex++)
{
uint8_t *entropyArray = prngState.getPool(poolIndex)->getEntropy();
for (uint8_t entropyIndex = 0; entropyIndex < ENTROPY_BLOCKS; entropyIndex++)
{
//TODO:VALIDATE THAT THIS puts the entropy in the correct place
seed[(poolIndex * MIN_ENTROPY_POOL_SIZE) + entropyIndex] = entropyArray[entropyIndex];
}
}
seedFile->writeSeedFile(seed);
delete[] seed;
seedFileReseed = true;
}
else
{
poolEntropy = new uint8_t[HASH_LENGTH * poolUsageCount];
for (uint8_t poolIndex = 0; poolIndex < poolUsageCount; poolIndex++)
{
sha.init();
uint8_t *entropyArray = prngState.getPool(poolIndex)->getEntropy();
for (uint8_t entropyIndex = 0; entropyIndex < ENTROPY_BLOCKS; entropyIndex++)
{
sha.write(entropyArray[entropyIndex]);
}
uint8_t* shaResult = sha.result();
#if defined(ARDUINO) && ARDUINO >= 100
memcpy(poolEntropy + (32 * poolIndex), shaResult, 32);
#else
std::copy(shaResult, shaResult + 32, poolEntropy + (POOL_SIZE * poolIndex));
#endif
prngState.getPool(poolIndex)->clear();
}
prngState.reseed(poolEntropy, POOL_SIZE * poolUsageCount);
delete[] poolEntropy;
}
reseedTime = getTime();
}
uint8_t *randomBytes = new uint8_t[numberOfBytes];
return prngState.generateRandomData(numberOfBytes, randomBytes);
}
time_t Fortuna::getTime()
{
#if defined(ARDUINO) && ARDUINO >= 100
return now();
#else
time_t t;
return time(&t);
#endif
}