/haveged-1.4/src/havegecollect.c
C | 420 lines | 294 code | 14 blank | 112 comment | 43 complexity | 781ae29e75a4c681b10201c105bf2cc7 MD5 | raw file
Possible License(s): GPL-3.0
1/**
2 ** Simple entropy harvester based upon the havege RNG
3 **
4 ** Copyright 2009-2012 Gary Wuertz gary@issiweb.com
5 ** Copyright 2011-2012 BenEleventh Consulting manolson@beneleventh.com
6 **
7 ** This program is free software: you can redistribute it and/or modify
8 ** it under the terms of the GNU General Public License as published by
9 ** the Free Software Foundation, either version 3 of the License, or
10 ** (at your option) any later version.
11 **
12 ** This program is distributed in the hope that it will be useful,
13 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 ** GNU General Public License for more details.
16 **
17 ** You should have received a copy of the GNU General Public License
18 ** along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20/**
21 * This compile unit isolates the operation of the HAVEGE algorithm to better
22 * deal with compiler issues. Portability of the algorithm is improved by
23 * isolating environmental dependencies in the HARDCLOCK and CSZ macros.
24 */
25#include "config.h"
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#include "havege.h"
30#include "havegecollect.h"
31
32#define SZH_INIT sizeof(H_COLLECT)+sizeof(char *)*(LOOP_CT + 2)
33#define SZH_COLLECT(a) sizeof(H_COLLECT)+sizeof(U_INT)*(a+16384-1)
34/**
35 * These macros below bind the code contained in oneiteration.h to the H_COLLECT
36 * instance defined above
37 */
38#define ANDPT (h_ctxt->havege_andpt)
39#define HTICK1 (h_ctxt->havege_hardtick1)
40#define HTICK2 (h_ctxt->havege_hardtick2)
41#define PTTEST (h_ctxt->havege_PTtest)
42#define PT (h_ctxt->havege_PT)
43#define PT1 (h_ctxt->havege_pt2)
44#define PT2 (h_ctxt->havege_PT2)
45#define PWALK (h_ctxt->havege_pwalk)
46#define RESULT (h_ctxt->havege_bigarray)
47/**
48 * The HAVEGE collector is created by interleaving instructions generated by
49 * oneiteration.h with the LOOP() output to control the sequence. At each
50 * LOOP() point, the following actions are possible.
51 */
52typedef enum {
53 LOOP_NEXT, /* Next loop */
54 LOOP_ENTER, /* First loop */
55 LOOP_EXIT, /* Last loop */
56 LOOP_THIS /* This loop */
57} LOOP_BRANCH;
58/**
59 * The LOOP macro labels calculation sequences generated by oneiteration.h in
60 * decreasing order from LOOPCT down to 0. During a normal collection, the
61 * loop construct only introduces an extra conditional branch into the instruction
62 * stream. For the exceptional conditions (initialization, end-of-loop, and
63 * raw HARDCLOCK capture), the return from havege_cp() is used to determine
64 * the action to be taken.
65 */
66#define LOOP(n,m) loop##n: if (n < h_ctxt->havege_cdidx) { \
67 switch(havege_cp(h_ctxt,i,n,LOOP_PT(n))) { \
68 case LOOP_NEXT: goto loop##m; \
69 case LOOP_ENTER: goto loop_enter; \
70 case LOOP_EXIT: goto loop_exit; \
71 case LOOP_THIS: break; \
72 } \
73 }
74
75
76/**
77 * RAW mode is a diagnostic mode that gives access to HARDCLOCK() inputs. In RAW
78 * mode havege_cp() is called at every control point. Raw modes must be enabled
79 * be defining the corresponding symbols RAW_IN_ENABLE, RAW_OUT_ENABLE. Both
80 * functions reuse portions of the collection buffer and cause havege_cp() to
81 * be called on each and every control point and thus should not be enabled
82 * in any production build.
83 *
84 * In order to use RAW_IN, a rawInput callback must be provided in NPRNG_INST
85 * and DEBUG_RAW_IN must be passed as an input option. RAW_IN_ENABLE replaces
86 * HARDCLOCKR() with code to select an input source based upon the DEBUG_RAW_IN
87 * option. This changes the nature of the collection loop and should only be
88 * enabled only during development.
89 *
90 * RAW_OUT does not modify the collection loop however, since RAW data is
91 * 8 times more dense that normal output, nd_read() compensates for this
92 * compression to deliver the requested output range.
93 */
94#define RAW_SHIFT 3 /* RAW compression factor */
95/**
96 * Derived constants for RAW mode
97 */
98#define DEBUG_RAW (DEBUG_RAW_IN|DEBUG_RAW_OUT)
99#define RAW_RANGE (h_ctxt->havege_szCollect >> RAW_SHIFT)
100#define RAW_INJECT (h_ctxt->havege_szCollect - RAW_RANGE)
101
102#ifdef RAW_IN_ENABLE
103#undef RAW_IN_ENABLE
104#define RAW_IN_ENABLE DEBUG_RAW_IN
105#define HARDCLOCKR(x) if (0==(h_ctxt->havege_raw & DEBUG_RAW_IN)){HARDCLOCK(x);}
106#else
107#define RAW_IN_ENABLE 0
108#define HARDCLOCKR(x) HARDCLOCK(x)
109#endif
110#ifdef RAW_OUT_ENABLE
111#undef RAW_OUT_ENABLE
112#define RAW_OUT_ENABLE DEBUG_RAW_OUT
113#else
114#define RAW_OUT_ENABLE 0
115#endif
116/**
117 * Wrapper for inline optimization
118 */
119#if 0
120#define ROR32(value,shift) ((value >> (shift)) | (value << (32-shift)))
121#else
122inline U_INT ror32(const U_INT value, const U_INT shift) {
123 return (value >> shift) | (value << (32 - shift));
124}
125#define ROR32(value,shift) ror32(value, shift)
126#endif
127/**
128 * Local prototypes
129 */
130static LOOP_BRANCH havege_cp(H_COLLECT *h_ctxt, U_INT i, U_INT n, char *p);
131/**
132 * Protect the collection mechanism against ever-increasing gcc optimization
133 */
134#if defined (GCC_VERSION) && GCC_VERSION >= 40400
135static int havege_gather(H_COLLECT * h_ctxt) __attribute__((optimize(1)));
136#else
137static int havege_gather(H_COLLECT * h_ctxt);
138#endif
139static void havege_ndinit(H_PTR h_ptr, struct h_collect *h_ctxt);
140/**
141 * Create a collector
142 */
143H_COLLECT *havege_ndcreate(/* RETURN: NULL on failure */
144 H_PTR h_ptr, /* IN-OUT: application instance */
145 U_INT nCollector) /* IN: The collector instance */
146{
147 U_INT i,offs,*p,d_cache;
148 U_INT szBuffer, t0;
149 H_COLLECT *h_ctxt;
150
151 szBuffer = h_ptr->i_collectSz;
152 d_cache = h_ptr->dataCache->size;
153 h_ctxt = (H_COLLECT *) malloc(SZH_COLLECT(szBuffer));
154 if (NULL != h_ctxt) {
155 h_ctxt->havege_app = h_ptr;
156 h_ctxt->havege_idx = nCollector;
157 h_ctxt->havege_raw = 0;
158 h_ctxt->havege_rawInput = h_ptr->params->injection;
159 h_ctxt->havege_meter = h_ptr->params->metering;
160 h_ctxt->havege_szCollect = h_ctxt->havege_szFill = szBuffer;
161 h_ctxt->havege_cdidx = h_ptr->i_idx;
162
163 /** An intermediate walk table twice the size of the L1 cache is allocated
164 ** for use in permuting time stamp readings. The is meant to exercise
165 ** processor TLBs.
166 */
167 ANDPT = ((2*d_cache*1024)/sizeof(int))-1;
168 p = (U_INT *) malloc((ANDPT + 4097)*sizeof(int));
169 if (NULL != p) {
170 offs = (U_INT)((((unsigned long)&p[4096])&0xfff)/sizeof(int));
171 PWALK = &p[4096-offs];
172 /**
173 * Run a short timer sanity test while warming up the generator.
174 */
175 (void)havege_gather(h_ctxt);
176 t0 = HTICK2;
177 for(i=1;i<MININITRAND;i++) {
178 (void)havege_gather(h_ctxt);
179 if (HTICK1==HTICK2 && HTICK2==t0) {
180 h_ptr->error = H_NOTIMER;
181 return NULL;
182 }
183 t0 = HTICK2;
184 }
185 h_ctxt->havege_nptr = h_ctxt->havege_szCollect;
186 if (0 != (h_ptr->havege_opts & DEBUG_RAW)) {
187 h_ctxt->havege_raw = h_ctxt->havege_cdidx | (h_ptr->havege_opts & DEBUG_RAW) ;
188 if (0 != (h_ctxt->havege_raw & DEBUG_RAW_OUT))
189 h_ctxt->havege_szFill = RAW_RANGE;
190 h_ctxt->havege_cdidx = LOOP_CT + 1;
191 }
192 }
193 else {
194 h_ptr->error = H_NOWALK;
195 return NULL;
196 }
197 }
198 h_ptr->error = H_NOCOLLECT;
199 return h_ctxt;
200}
201/**
202 * Read from the collector. For the RAW_OUT, additional collection cycles are run
203 * in order to fill the buffer.
204 */
205U_INT havege_ndread( /* RETURN: data value */
206 H_COLLECT *h_ctxt) /* IN: collector context */
207{
208 if (h_ctxt->havege_nptr >= h_ctxt->havege_szFill) {
209 if (NULL != h_ctxt->havege_rawInput)
210 (*h_ctxt->havege_rawInput)(RESULT + RAW_INJECT, RAW_RANGE);
211 if (NULL != h_ctxt->havege_meter)
212 (*h_ctxt->havege_meter)(h_ctxt->havege_idx, 0);
213 (void) havege_gather(h_ctxt);
214 if (NULL != h_ctxt->havege_meter)
215 (*h_ctxt->havege_meter)(h_ctxt->havege_idx, 1);
216 h_ctxt->havege_nptr = 0;
217 }
218 return RESULT[h_ctxt->havege_nptr++];
219}
220/**
221 * Setup haveged
222 */
223void havege_ndsetup( /* RETURN: None */
224 H_PTR h_ptr) /* IN-OUT: application instance */
225{
226 char wkspc[SZH_INIT];
227
228 memset(wkspc, 0, SZH_INIT);
229 havege_ndinit(h_ptr, (struct h_collect *) wkspc);
230}
231
232#ifdef HAVE_ISA_GENERIC
233#include <time.h>
234/**
235 * Provide a timer fallback
236 */
237static U_INT havege_clock(void)
238{
239 struct timespec ts;
240
241 clock_gettime(CLOCK_MONOTONIC, &ts);
242 return (U_INT)(ts.tv_nsec + ts.tv_sec * 1000000000LL);
243}
244#endif
245/**
246 * This method is called only for control points NOT part of a normal collection:
247 *
248 * a) For a collection loop after all iterations are performed, this function
249 * determines if the collection buffer is full. This applies to both RAW
250 * and normal collections.
251 * b) For initialization, this method saves the address of the collection point
252 * for analysis at the end of the loop.
253 * c) For RAW_IN model control points which would be part of a normal collection,
254 * hardtick variables for the NEXT interaction are loaded from the prepared data.
255 * d) For RAW_OUT mode control points which would be part of a normal collection,
256 * hardtick variables are saved in the beginning of the buffer (overwriting
257 * previously generated output).
258 */
259static LOOP_BRANCH havege_cp( /* RETURN: branch to take */
260 H_COLLECT *h_ctxt, /* IN: collection context */
261 U_INT i, /* IN: collection offset */
262 U_INT n, /* IN: iteration index */
263 char *p) /* IN: code pointer */
264{
265 U_INT block, fn, loop;
266
267 if (0 != (fn = h_ctxt->havege_raw & DEBUG_RAW)) {
268 loop = h_ctxt->havege_raw & ~fn;
269 if (0 != (fn & DEBUG_RAW_OUT && i > RAW_SHIFT)) {
270 block = i >> RAW_SHIFT;
271 RESULT[block-2] = h_ctxt->havege_hardtick1;
272 RESULT[block-1] = h_ctxt->havege_hardtick2;
273 }
274 if (n >= loop) {
275 if (0 != (fn & DEBUG_RAW_IN) && i< h_ctxt->havege_szCollect) {
276 block = RAW_INJECT + (i >> RAW_SHIFT);
277 h_ctxt->havege_hardtick1 = RESULT[block++];
278 h_ctxt->havege_hardtick2 = RESULT[block];
279 }
280 return LOOP_THIS;
281 }
282 }
283 else loop = h_ctxt->havege_cdidx;
284 if (loop <= LOOP_CT)
285 return i < h_ctxt->havege_szCollect? LOOP_ENTER : LOOP_EXIT;
286 ((char **)RESULT)[n] = CODE_PT(p);
287 if (n==0) h_ctxt->havege_cdidx = 0;
288 return LOOP_NEXT;
289}
290
291/**
292 * The collection loop is constructed by repetitions of oneinteration.h interleaved
293 * with control points generated by the LOOP macro.
294 */
295static int havege_gather( /* RETURN: 1 if initialized */
296 H_COLLECT * h_ctxt) /* IN: collector context */
297{
298 U_INT i=0,pt=0,inter=0;
299 U_INT *Pt0, *Pt1, *Pt2, *Pt3, *Ptinter;
300
301loop_enter:
302LOOP(40,39)
303 #include "oneiteration.h"
304LOOP(39,38)
305 #include "oneiteration.h"
306LOOP(38,37)
307 #include "oneiteration.h"
308LOOP(37,36)
309 #include "oneiteration.h"
310LOOP(36,35)
311 #include "oneiteration.h"
312LOOP(35,34)
313 #include "oneiteration.h"
314LOOP(34,33)
315 #include "oneiteration.h"
316LOOP(33,32)
317 #include "oneiteration.h"
318LOOP(32,31)
319 #include "oneiteration.h"
320LOOP(31,30)
321 #include "oneiteration.h"
322LOOP(30,29)
323 #include "oneiteration.h"
324LOOP(29,28)
325 #include "oneiteration.h"
326LOOP(28,27)
327 #include "oneiteration.h"
328LOOP(27,26)
329 #include "oneiteration.h"
330LOOP(26,25)
331 #include "oneiteration.h"
332LOOP(25,24)
333 #include "oneiteration.h"
334LOOP(24,23)
335 #include "oneiteration.h"
336LOOP(23,22)
337 #include "oneiteration.h"
338LOOP(22,21)
339 #include "oneiteration.h"
340LOOP(21,20)
341 #include "oneiteration.h"
342LOOP(20,19)
343 #include "oneiteration.h"
344LOOP(19,18)
345 #include "oneiteration.h"
346LOOP(18,17)
347 #include "oneiteration.h"
348LOOP(17,16)
349 #include "oneiteration.h"
350LOOP(16,15)
351 #include "oneiteration.h"
352LOOP(15,14)
353 #include "oneiteration.h"
354LOOP(14,13)
355 #include "oneiteration.h"
356LOOP(13,12)
357 #include "oneiteration.h"
358LOOP(12,11)
359 #include "oneiteration.h"
360LOOP(11,10)
361 #include "oneiteration.h"
362LOOP(10,9)
363 #include "oneiteration.h"
364LOOP(9,8)
365 #include "oneiteration.h"
366LOOP(8,7)
367 #include "oneiteration.h"
368LOOP(7,6)
369 #include "oneiteration.h"
370LOOP(6,5)
371 #include "oneiteration.h"
372LOOP(5,4)
373 #include "oneiteration.h"
374LOOP(4,3)
375 #include "oneiteration.h"
376LOOP(3,2)
377 #include "oneiteration.h"
378LOOP(2,1)
379 #include "oneiteration.h"
380LOOP(1,0)
381 #include "oneiteration.h"
382LOOP(0,0)
383 (void)havege_cp(h_ctxt, i,0,LOOP_PT(0));
384loop_exit:
385 return ANDPT==0? 0 : 1;
386}
387/**
388 * Initialize the collection loop
389 */
390#if defined (GCC_VERSION) && GCC_VERSION >= 40600
391#pragma GCC diagnostic ignored "-Warray-bounds"
392#endif
393
394static void havege_ndinit( /* RETURN: None */
395 H_PTR h_ptr, /* IN-OUT: application instance */
396 struct h_collect *h_ctxt) /* IN: workspace */
397{
398 char **addr = (char **)(&RESULT[0]);
399 int i, sz;
400
401 h_ctxt->havege_cdidx = LOOP_CT + 1;
402 (void)havege_gather(h_ctxt);
403 for (i=0;i<=LOOP_CT;i++) {
404 if (0 != (h_ptr->havege_opts & DEBUG_COMPILE)) {
405 DEBUG_OUT("Address %u=%p\n", i, addr[i]);
406 }
407 RESULT[i] = abs(addr[i] - addr[LOOP_CT]);
408 if (i > 0 && 0 != (h_ptr->havege_opts & DEBUG_LOOP)) {
409 DEBUG_OUT("Loop %u: offset=%u, delta=%u\n", i,RESULT[i],RESULT[i-1]-RESULT[i]);
410 }
411 }
412 h_ptr->i_maxidx = LOOP_CT;
413 h_ptr->i_maxsz = RESULT[1];
414 sz = h_ptr->instCache->size * 1024;
415 for(i=LOOP_CT;i>0;i--)
416 if (RESULT[i]>sz)
417 break;
418 h_ptr->i_idx = ++i;
419 h_ptr->i_sz = RESULT[i];
420}