-
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathinfnoise_win.c
271 lines (253 loc) · 9.52 KB
/
infnoise_win.c
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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
/* Driver for the Infinite Noise Multiplier USB stick */
#include <stdlib.h>
#include <share.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "infnoise_win.h"
#include "KeccakF-1600-interface.h"
#include "VisualStudio\ftdi\ftd2xx.h"
// Pipes in Windows basically don't work, so if you want output from a program to redirect to a file
// you are forced to write to the file directly, rather than do infnoise > foo.
FILE *outFile;
// Convert an address value 0 to 15 to an 8-bit value using ADDR0 .. ADDR3.
static uint8_t makeAddress(uint8_t addr) {
uint8_t value = 0;
if (addr & 1) {
value |= 1 << ADDR0;
}
if (addr & 2) {
value |= 1 << ADDR1;
}
if (addr & 4) {
value |= 1 << ADDR2;
}
if (addr & 8) {
value |= 1 << ADDR3;
}
return value;
}
// Extract a value form 0 to 15 from the ADDR0 .. ADDR3 bits.
static uint8_t extractAddress(uint8_t value) {
uint8_t addr = 0;
if (value & (1 << ADDR0)) {
addr |= 1;
}
if (value & (1 << ADDR1)) {
addr |= 2;
}
if (value & (1 << ADDR2)) {
addr |= 4;
}
if (value & (1 << ADDR3)) {
addr |= 8;
}
return addr;
}
// Extract the INM output from the data received. Basically, either COMP1 or COMP2
// changes, not both, so alternate reading bits from them. We get 1 INM bit of output
// per byte read. Feed bits from the INM to the health checker. Return the expected
// bits of entropy.
static uint32_t extractBytes(uint8_t *bytes, uint8_t *inBuf, bool raw) {
inmClearEntropyLevel();
//printf("New batch\n");
uint32_t i;
for (i = 0; i < BUFLEN / 8; i++) {
uint32_t j;
uint8_t byte = 0;
for (j = 0; j < 8; j++) {
//printf("%x ", inBuf[i*8 + j] & ~MASK);
uint8_t val = inBuf[i * 8 + j];
uint8_t evenBit = (val >> COMP2) & 1;
uint8_t oddBit = (val >> COMP1) & 1;
bool even = j & 1; // Use the even bit if j is odd
uint8_t bit = even ? oddBit : evenBit;
byte = (byte << 1) | bit;
// This is a good place to feed the bit from the INM to the health checker.
// uint8_t addr = extractAddress(val);
//printf("Address: %u, adding evenBit:%u oddBit:%u even:%u\n", addr, evenBit, oddBit, even);
if (!inmHealthCheckAddBit(evenBit, oddBit, even)) {
fputs("Health check of Infinite Noise Multiplier failed!\n", stderr);
exit(1);
}
}
//printf("extracted byte:%x\n", byte);
bytes[i] = byte;
}
return inmGetEntropyLevel();
}
// Write the bytes to either stdout, or /dev/random. Use the lower of the measured
// entropy and the provable lower bound on average entropy.
static void outputBytes(uint8_t *bytes, uint32_t length, uint32_t entropy) {
if (entropy > inmExpectedEntropyPerBit*BUFLEN / INM_ACCURACY) {
entropy = (uint32_t)(inmExpectedEntropyPerBit*BUFLEN / INM_ACCURACY);
}
if (fwrite(bytes, 1, length, outFile) != length) {
fputs("Unable to write output from Infinite Noise Multiplier\n", stderr);
exit(1);
}
fflush(outFile);
}
// Whiten the output, if requested, with a Keccak sponge. Output bytes only if the health
// checker says it's OK. Using outputMultiplier > 1 is a nice way to generate a lot more
// cryptographically secure pseudo-random data than the INM generates. This allows a user
// to generate hundreds of MiB per second if needed, for use as cryptogrpahic keys.
static void processBytes(uint8_t *keccakState, uint8_t *bytes, uint32_t entropy, bool raw,
uint32_t outputMultiplier) {
if (raw) {
// In raw mode, we just output raw data from the INM.
outputBytes(bytes, BUFLEN / 8, entropy);
return;
}
// Note that BUFLEN has to be less than 1600 by enough to make the sponge secure,
// since outputing all 1600 bits would tell an attacker the Keccak state, allowing
// him to predict any further output, when outputMultiplier > 1, until the next call
// to processBytes. All 512 bits are absorbed before sqeezing data out to insure that
// we instantly recover (reseed) from a state compromise, which is when an attacker
// gets a snapshot of the keccak state. BUFLEN must be a multiple of 64, since
// Keccak-1600 uses 64-bit "lanes".
KeccakAbsorb(keccakState, bytes, BUFLEN / 64);
uint8_t dataOut[16 * 8];
while (outputMultiplier > 0) {
// Write up to 1024 bits at a time.
uint32_t numLanes = 16;
if (outputMultiplier < 4) {
numLanes = outputMultiplier * 4;
}
KeccakExtract(keccakState, dataOut, numLanes);
// Extract does not do a permute, so do it here.
KeccakPermutation(keccakState);
uint32_t entropyThisTime = entropy;
if (entropyThisTime > numLanes * 64) {
entropyThisTime = numLanes * 64;
}
outputBytes(dataOut, numLanes * 8, entropyThisTime);
outputMultiplier -= numLanes / 4;
entropy -= entropyThisTime;
}
}
// Initialize the Infinite Noise Multiplier USB ineterface.
static bool initializeUSB(FT_HANDLE *ftdic, char **message) {
*message = NULL;
// Open FTDI device based on FT240X vendor & product IDs
if (FT_Open(0, ftdic) != FT_OK) {
*message = "Can't find Infinite Noise Multiplier\n";
return false;
}
// Set high baud rate
if (FT_SetBaudRate(*ftdic, 30000) != FT_OK) {
*message = "Setting baud rate failed\n";
return false;
}
// Enable syncrhonous bitbang mode
if (FT_SetBitMode(*ftdic, MASK, BITMODE_SYNCBB) != FT_OK) {
*message = "Can't enable bit-bang mode\n";
return false;
}
// Just test to see that we can write and read.
uint8_t buf[64] = { 0, };
uint32_t bytesWritten;
if (FT_Write(*ftdic, buf, 64, &bytesWritten) != FT_OK || bytesWritten != 64) {
*message = "USB write failed\n";
return false;
}
uint32_t bytesRead;
if (FT_Read(*ftdic, buf, 64, &bytesRead) != FT_OK || bytesRead != 64) {
*message = "USB read failed\n";
return false;
}
return true;
}
int main(int argc, char **argv)
{
FT_HANDLE ftdic;
bool raw = false;
bool debug = false;
bool noOutput = false;
uint32_t outputMultiplier = 2;
uint32_t xArg;
// Process arguments
for (xArg = 1; xArg < (uint32_t)(argc - 1); xArg++) {
if (!strcmp(argv[xArg], "--raw")) {
raw = true;
}
else if (!strcmp(argv[xArg], "--debug")) {
debug = true;
}
else if (!strcmp(argv[xArg], "--no-output")) {
noOutput = true;
}
else if (!strcmp(argv[xArg], "--multiplier") && xArg + 1 < (uint32_t)argc) {
xArg++;
outputMultiplier = atoi(argv[xArg]);
if (outputMultiplier == 0) {
fputs("Multiplier must be > 0\n", stderr);
return 1;
}
}
else {
fputs("Usage: infnoise [options] outFile\n"
"Options are:\n"
" --debug - turn on some debug output\n"
" --raw - do not whiten the output\n"
" --multiplier <value> - write 256 bits * value for each 512 bits written to\n"
" the Keccak sponge\n"
" --no-output - do not write random output data\n", stderr);
return 1;
}
}
if (argc < 2) {
fprintf(stderr, "No output file specified\n");
return 1;
}
outFile = _fsopen(argv[xArg], "wb", _SH_DENYWR);
if (outFile == NULL) {
fprintf(stderr, "Unable to open file %s\n", argv[xArg]);
return 1;
}
if (!inmHealthCheckStart(PREDICTION_BITS, DESIGN_K, debug)) {
fputs("Can't intialize health checker\n", stderr);
return 1;
}
uint8_t keccakState[KeccakPermutationSizeInBytes];
KeccakInitializeState(keccakState);
char *message;
if (!initializeUSB(&ftdic, &message)) {
// Sometimes have to do it twice - not sure why
if (!initializeUSB(&ftdic, &message)) {
fputs(message, stderr);
return 1;
}
}
// Endless loop: set SW1EN and SW2EN alternately
uint32_t i;
uint8_t outBuf[BUFLEN], inBuf[BUFLEN];
for (i = 0; i < BUFLEN; i++) {
// Alternate Ph1 and Ph2 - maybe should have both off in between
outBuf[i] = i & 1 ? (1 << SWEN2) : (1 << SWEN1);
outBuf[i] |= makeAddress(i & 0xf);
}
uint64_t good = 0, bad = 0;
while (true) {
uint32_t numBytes;
if (FT_Write(ftdic, outBuf, BUFLEN, &numBytes) != FT_OK || numBytes != BUFLEN) {
fputs("USB write failed\n", stderr);
return -1;
}
if (FT_Read(ftdic, inBuf, BUFLEN, &numBytes) != FT_OK || numBytes != BUFLEN) {
fputs("USB read failed\n", stderr);
return -1;
}
uint8_t bytes[BUFLEN / 8];
uint32_t entropy = extractBytes(bytes, inBuf, raw);
if (!noOutput && inmHealthCheckOkToUseData() && inmEntropyOnTarget(entropy, BUFLEN)) {
processBytes(keccakState, bytes, entropy, raw, outputMultiplier);
}
good++;
fflush(stdout);
fflush(stderr);
}
return 0;
}