/** ** Simple entropy harvester based upon the havege RNG ** ** Copyright 2018-2022 Jirka Hladky hladky DOT jiri AT gmail DOT com ** Copyright 2009-2014 Gary Wuertz gary@issiweb.com ** Copyright 2011-2012 BenEleventh Consulting manolson@beneleventh.com ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . */ #ifndef HAVEGE_H #define HAVEGE_H #include #include #ifdef __cplusplus extern "C" { #endif /** * header/package version as a numeric major, minor, patch triple. See havege_version() * below for usage. */ #define HAVEGE_PREP_VERSION "1.9.19" /** * Basic types */ #define H_UINT uint32_t #define H_UINT8 uint8_t /** * Optional metering call-back. Called with event=0 at start of collection buffer fill. * Called with event=1 at end of collection buffer fill. The nCollect parameter indicates * the calling process if multiple collection processes are enabled. Use a value of 0 * to disable metering. */ typedef void (*pMeter)(H_UINT nCollect, H_UINT event); /** * Optional message display call-back. This printf style method is used for all diagnostic * output including havege_status(). Use a value of 0 to disable output. */ typedef void (*pMsg)(const char *format, ...); /** * Injection call-back for RAW diagnostics. Use a value of 0 to disable diagnostic. Ignored * except for diaqnotic builds. */ typedef int (*pRawIn)(volatile H_UINT *pData, H_UINT szData); /** * options for H_PARAMS below. Lower byte transferred from verbose settings * upper byte set by diagnositic run options */ #define H_VERBOSE 0x001 /* deprecated from ver 1.7 */ #define H_DEBUG_INFO 0x001 /* Show config info, retries */ #define H_DEBUG_OLTR 0x002 /* Show detailed test retry info */ #define H_DEBUG_TIME 0x004 /* Show collection times */ #define H_DEBUG_LOOP 0x008 /* Show loop parameters */ #define H_DEBUG_COMPILE 0x010 /* Show assembly info */ #define H_DEBUG_OLT 0x020 /* Show all test info */ #define H_RNDADDENTROPY_INFO 0x040 /* RNDADDENTROPY info */ #define H_DEBUG_RAW_OUT 0x100 /* diagnostic output */ #define H_DEBUG_RAW_IN 0x200 /* diagnostic input */ #define H_DEBUG_TEST_IN 0x400 /* input test data */ /** * Initialization parameters. Use non-zero values to override default values. * Notes: * * 1) Correspondence between provided value and value of H_PTR members are: * ioSz <==> i_readSz, collectSize <==> i_collectSz, nCores <==> n_cores, * options <==> havege_opts * 2) ioSz is specified in bytes. collectSize sizes is specified as number * of H_UINT. The default for ioSz is 1024*sizeof(H_UINT). The default * for collecSize is 128K * sizeof(H_UINT). * 3) The icacheSize and dcacheSize override cache sizes. Both are specified in KB. * Either may be specified to override the tuning value. If both are provided, * tuning code is bypassed. The fallback tuning values can be overridden * by defining GENERIC_DCACHE and GENERIC_ICACHE (16 will be used if not * otherwise defined) * 4) null callback values suppress the function. * 5) sysFs default is '/sys', procFs default is '/proc'. * 6) testSpec same as haveged option "[t][c] x=[a[n][w]][b[w]]". If * not specified (NULL) the default is "ta8b" - i.e. run the tot tests */ typedef struct { H_UINT ioSz; /* size of write buffer */ H_UINT collectSize; /* size of collection buffer */ H_UINT icacheSize; /* Instruction cache size */ H_UINT dcacheSize; /* Data cache size */ H_UINT options; /* Other options */ H_UINT nCores; /* If multi-core */ pMeter metering; /* meterming method */ pMsg msg_out; /* output display method */ pRawIn injection; /* injection method */ char *procFs; /* proc mount point override */ char *sysFs; /* sys mount point override */ char *testSpec; /* test specification */ } H_PARAMS; /** * Status codes used in the error member of h_anchor */ typedef enum { H_NOERR, /* 00 No error */ H_NOHANDLE, /* 01 No memory for handle */ H_NOBUF, /* 02 Output buffer allocation failed */ H_NOINIT, /* 03 semaphore init failed */ H_NOCOLLECT, /* 04 H_COLLECT allocation failed */ H_NOWALK, /* 05 Walk buffer allocation failed */ H_NOTESTSPEC, /* 06 invalid test specification */ H_NOTESTINIT, /* 07 test setup failed */ H_NOTESTMEM, /* 08 Unable to allocate test memory */ H_NOTESTTOT, /* 09 tot test failed */ H_NOTESTRUN, /* 10 production test failed */ H_NOCORES, /* 11 too many cores specified */ H_NOTASK, /* 12 Unable to create child task */ H_NOWAIT, /* 13 sem_wait failed */ H_NOPOST, /* 14 sem_post failed */ H_NODONE, /* 15 sem_post done failed */ H_NORQST, /* 16 sem_post request failed */ H_NOCOMP, /* 17 wait for completion failed */ H_EXIT, /* 18 Exit signal */ H_NOTIMER /* 19 timer failed */ } H_ERR; /** * Keep compiler honest */ typedef volatile void *H_VOL; /** * Anchor for the RNG. Should be read only at devel level and above. */ typedef struct h_anchor { H_UINT *io_buf; /* output buffer */ char *arch; /* "x86","sparc","ppc","ia64",etc */ void *cpu; /* information on the cpu */ void *instCache; /* instruction cache info */ void *dataCache; /* data cache info */ pMsg print_msg; /* output display method */ pMeter metering; /* metering method */ pRawIn inject; /* Injection diagnostic only */ H_VOL collector; /* single thread collector */ H_VOL threads; /* multi thread collectors */ void *testData; /* online test data */ void *tuneData; /* tuning data */ H_UINT error; /* H_ERR enum for status */ H_UINT havege_opts; /* option flags */ H_UINT i_maxidx; /* maximum instruction loop index */ H_UINT i_maxsz; /* maximum code size */ H_UINT i_idx; /* code index used */ H_UINT i_sz; /* code size used */ H_UINT i_collectSz; /* size of collection buffer */ H_UINT i_readSz; /* size of read buffer (bytes) */ H_UINT m_sz; /* size of thread ipc area (bytes) */ H_UINT n_cores; /* number of cores */ H_UINT n_fills; /* number of buffer fills */ size_t n_entropy_bytes; /* total amount of entropy (byte) */ } *H_PTR; /** * Fail/Success counters for tot and production tests. */ typedef enum { H_OLT_TOT_A_F, /* tot Procedure A failed */ H_OLT_TOT_A_P, /* tot Procedure A passed */ H_OLT_TOT_B_F, /* tot Procedure B failed */ H_OLT_TOT_B_P, /* tot Procedure B passed */ H_OLT_PROD_A_F, /* prod Procedure A failed */ H_OLT_PROD_A_P, /* prod Procedure A passed */ H_OLT_PROD_B_F, /* prod Procedure B failed */ H_OLT_PROD_B_P /* prod Procedure B passed */ } H_OLT_METERS; /** * Structure used to query RNG anchor settings for information not exposed by * H_PTR. List formats are strings with one or more tokens separated by space. * Sources lists show how tuning parameters are derived. D is a build default, * P is a run time override, items V* come from linux virtual file system, * other items trace various cpuid sources. Tuning is skipped if both cache * sizes have 'P' sources. * * Notes: * * 1) Build: package version of source * 2) Build options: compiler version followed by build configuration encoded * as string of: [C][I][M][T][V] where C=clock_gettime, I=tune with cpuid, * M=multi-core, T=online-test, V=tune with vfs * 3) Tuning source lists: D=default, P=parameter, C=cpuid present, * H=hyperthreading, A=AMD cpuid, A5=AMD fn5, A6=AMD fn6, A8=AMD fn8 * L2=Intel has leaf2, L4=Intel has leaf4, B=Intel leaf b, * 4=intel leaf4, V=virtual file system available * VS=/sys/devices/system/cpu/cpu%d/cache/index/level, * VO=/sys/devices/system/cpu/online, VI=/proc/cpuinfo * VC=/sys/devices/system/cpu * 4) test spec [A[1..8]][B], see H_PARAMS above. * 5) zero unless tests are enabled * 6) Last Coron's entropy estimate from Procedure B, test 8 */ typedef struct h_status { const char *version; /* Package version [1] */ const char *buildOptions; /* Options [2] */ const char *vendor; /* cpuid machines only */ const char *cpuSources; /* Tuning sources list [3] */ const char *i_cacheSources; /* Tuning sources list [3] */ const char *d_cacheSources; /* Tuning sources list [3] */ const char *tot_tests; /* tot test spec [4] */ const char *prod_tests; /* prod test spec [4] */ H_UINT i_cache; /* size of L1 instruction cache KB */ H_UINT d_cache; /* size of L1 data cache KB */ H_UINT n_tests[H_OLT_PROD_B_P+1]; /* test statistics [5] */ double last_test8; /* last test8 result [6] */ } *H_STATUS; /** * Standard presentation formats for havege_status_dump. */ typedef enum { H_SD_TOPIC_BUILD, /* ver: %s; arch: %s; vend: %s; build: (%s); collect: %dK */ H_SD_TOPIC_TUNE, /* cpu: (%s); data: %dK (%s); inst: %dK (%s); idx: %d/%d; sz: %d/%d */ H_SD_TOPIC_TEST, /* [tot tests (%s): A:%d/%d B: %d/%d;][continuous tests (%s): A:%d/%d B: %d/%d;][last entropy estimate %g] */ H_SD_TOPIC_SUM, /* fills: %d, generated: %.4g %c bytes */ } H_SD_TOPIC; /** * Public prototypes. Library users note that "havege_*" is reserved for library * public functions. Note that the multi-core option is experimental and must * enabled in the build. */ /** * Create an anchor. The caller should check for a non-null return value with * a error value of H_NOERR. Any non-null return should be disposed of by a * call to havege_destroy() to free all allocated resources. * * Possible error values: H_NOERR, H_NOTESTSPEC, H_NOBUF, H_NOTESTMEM, * H_NOINIT */ H_PTR havege_create(H_PARAMS *params); /** * haveger_create() remembers parent pid and uses it to identify deallocating thread. * daemonize() forks parent and effectively loses parent thread. * havege_reparent(void) allows recovering new parent pid before havege_run() is started. */ void havege_reparent(H_PTR hptr); /** * Frees all allocated anchor resources. If the multi-core option is used, this * method should be called from a signal handler to prevent zombie processes. * If called by the process that called haveged_create(), hptr will be freed * when all child processes (if any) have terminated. If called by a child * process, H_EXIT will be set and all children awakened to exit. */ void havege_destroy(H_PTR hptr); /** * Read random words from an active anchor. The RNG must have been readied * by a previous call to havege_run(). The read must take place within the * allocated buffer, hptr->io_buf, and the range is specified in number of * H_UINT to read. If the multi-core option is used, this buffer is * memory-mapped between collectors. * * Returns the number of H_UINT read. * * Possible error values: H_NOERR, H_NOTESRUN, H_NOPOST, H_NODONE, * H_NORQST, H_NOCOMP, H_EXIT */ int havege_rng(H_PTR hptr, H_UINT *buf, H_UINT sz); /** * Warm up the RNG and run the start-up tests. The operation suceeded if the * error member of the handle is H_NOERR. A failed handle should be disposed * of by a call to havege_destroy(). * * Returns non-zero on failure. * * Possible error values: H_NOERR, H_NOCOLLECT, H_NOWALK, H_NOTESTMEM, * H_NOTASK, H_NOTESTTOT, H_NOWAIT, * any havege_rng error */ int havege_run(H_PTR hptr); /** * Fill in the h_status structure with read-only information collected from * the package build, run-time tuning, and test components. */ void havege_status(H_PTR hptr, H_STATUS hsts); /** * Call havege_status() and generate a standard presentation of H_STATUS content. * See the H_SD_TOPIC enum above for the formats. * * Returns the number of bytes placed in buf. */ int havege_status_dump(H_PTR hptr, H_SD_TOPIC topic, char *buf, size_t len); /** * Return/check library prep version. Calling havege_version() with a NULL version * returns the definition of HAVEGE_PREP_VERSION used to build the library. Calling * with HAVEGE_PREP_VERSION as the version checks if this headers definition is * compatible with that of the library, returning NULL if the input is incompatible * with the library. */ const char *havege_version(const char *version); #ifdef __cplusplus } #endif #endif