PageRenderTime 78ms CodeModel.GetById 13ms app.highlight 50ms RepoModel.GetById 1ms app.codeStats 1ms

/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}