PageRenderTime 53ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

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