2015-05-25 21:10:20 +08:00
/*
2015-06-23 22:18:54 +08:00
* Non - physical true random number generator based on timing jitter - -
* Jitter RNG standalone code .
2015-05-25 21:10:20 +08:00
*
2019-05-30 03:24:25 +08:00
* Copyright Stephan Mueller < smueller @ chronox . de > , 2015 - 2019
2015-05-25 21:10:20 +08:00
*
* Design
* = = = = = =
*
* See http : //www.chronox.de/jent.html
*
* License
* = = = = = = =
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions
* are met :
* 1. Redistributions of source code must retain the above copyright
* notice , and the entire permission notice in its entirety ,
* including the disclaimer of warranties .
* 2. Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution .
* 3. The name of the author may not be used to endorse or promote
* products derived from this software without specific prior
* written permission .
*
* ALTERNATIVELY , this product may be distributed under the terms of
* the GNU General Public License , in which case the provisions of the GPL2 are
* required INSTEAD OF the above restrictions . ( This clause is
* necessary due to a potential bad interaction between the GPL and
* the restrictions contained in a BSD - style copyright . )
*
* THIS SOFTWARE IS PROVIDED ` ` AS IS ' ' AND ANY EXPRESS OR IMPLIED
* WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE , ALL OF
* WHICH ARE HEREBY DISCLAIMED . IN NO EVENT SHALL THE AUTHOR BE
* LIABLE FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR
* CONSEQUENTIAL DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR
* BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE , EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE .
*/
/*
* This Jitterentropy RNG is based on the jitterentropy library
2019-05-30 03:24:25 +08:00
* version 2.1 .2 provided at http : //www.chronox.de/jent.html
2015-05-25 21:10:20 +08:00
*/
2015-06-23 22:18:54 +08:00
# ifdef __OPTIMIZE__
# error "The CPU Jitter random number generator must not be compiled with optimizations. See documentation. Use the compiler switch -O0 for compiling jitterentropy.c."
# endif
typedef unsigned long long __u64 ;
typedef long long __s64 ;
typedef unsigned int __u32 ;
# define NULL ((void *) 0)
2015-05-25 21:10:20 +08:00
/* The entropy pool */
struct rand_data {
/* all data values that are vital to maintain the security
* of the RNG are marked as SENSITIVE . A user must not
* access that information while the RNG executes its loops to
* calculate the next random value . */
__u64 data ; /* SENSITIVE Actual random number */
__u64 old_data ; /* SENSITIVE Previous random number */
__u64 prev_time ; /* SENSITIVE Previous time stamp */
# define DATA_SIZE_BITS ((sizeof(__u64)) * 8)
__u64 last_delta ; /* SENSITIVE stuck test */
__s64 last_delta2 ; /* SENSITIVE stuck test */
unsigned int osr ; /* Oversample rate */
# define JENT_MEMORY_BLOCKS 64
# define JENT_MEMORY_BLOCKSIZE 32
# define JENT_MEMORY_ACCESSLOOPS 128
# define JENT_MEMORY_SIZE (JENT_MEMORY_BLOCKS*JENT_MEMORY_BLOCKSIZE)
unsigned char * mem ; /* Memory access location with size of
* memblocks * memblocksize */
unsigned int memlocation ; /* Pointer to byte in *mem */
unsigned int memblocks ; /* Number of memory blocks in *mem */
unsigned int memblocksize ; /* Size of one memory block in bytes */
unsigned int memaccessloops ; /* Number of memory accesses per random
* bit generation */
} ;
/* Flags that can be used to initialize the RNG */
# define JENT_DISABLE_MEMORY_ACCESS (1<<2) / * Disable memory access for more
* entropy , saves MEMORY_SIZE RAM for
* entropy collector */
/* -- error codes for init function -- */
# define JENT_ENOTIME 1 /* Timer service not available */
# define JENT_ECOARSETIME 2 /* Timer too coarse for RNG */
# define JENT_ENOMONOTONIC 3 /* Timer is not monotonic increasing */
# define JENT_EVARVAR 5 / * Timer does not produce variations of
* variations ( 2 nd derivation of time is
* zero ) . */
2019-05-30 03:24:25 +08:00
# define JENT_ESTUCK 8 /* Too many stuck results during init. */
2015-05-25 21:10:20 +08:00
/***************************************************************************
* Helper functions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2015-06-23 22:18:54 +08:00
void jent_get_nstime ( __u64 * out ) ;
void * jent_zalloc ( unsigned int len ) ;
void jent_zfree ( void * ptr ) ;
int jent_fips_enabled ( void ) ;
void jent_panic ( char * s ) ;
void jent_memcpy ( void * dest , const void * src , unsigned int n ) ;
2015-05-25 21:10:20 +08:00
/**
* Update of the loop count used for the next round of
* an entropy collection .
*
* Input :
* @ ec entropy collector struct - - may be NULL
* @ bits is the number of low bits of the timer to consider
* @ min is the number of bits we shift the timer value to the right at
* the end to make sure we have a guaranteed minimum value
*
* @ return Newly calculated loop counter
*/
static __u64 jent_loop_shuffle ( struct rand_data * ec ,
unsigned int bits , unsigned int min )
{
__u64 time = 0 ;
__u64 shuffle = 0 ;
unsigned int i = 0 ;
unsigned int mask = ( 1 < < bits ) - 1 ;
jent_get_nstime ( & time ) ;
/*
2019-05-30 03:24:25 +08:00
* Mix the current state of the random number into the shuffle
* calculation to balance that shuffle a bit more .
2015-05-25 21:10:20 +08:00
*/
if ( ec )
time ^ = ec - > data ;
/*
2019-05-30 03:24:25 +08:00
* We fold the time value as much as possible to ensure that as many
* bits of the time stamp are included as possible .
2015-05-25 21:10:20 +08:00
*/
2019-05-30 03:24:25 +08:00
for ( i = 0 ; ( ( DATA_SIZE_BITS + bits - 1 ) / bits ) > i ; i + + ) {
2015-05-25 21:10:20 +08:00
shuffle ^ = time & mask ;
time = time > > bits ;
}
/*
* We add a lower boundary value to ensure we have a minimum
* RNG loop count .
*/
return ( shuffle + ( 1 < < min ) ) ;
}
/***************************************************************************
* Noise sources
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
* CPU Jitter noise source - - this is the noise source based on the CPU
* execution time jitter
*
2019-05-30 03:24:25 +08:00
* This function injects the individual bits of the time value into the
* entropy pool using an LFSR .
2015-05-25 21:10:20 +08:00
*
2019-05-30 03:24:25 +08:00
* The code is deliberately inefficient with respect to the bit shifting
* and shall stay that way . This function is the root cause why the code
* shall be compiled without optimization . This function not only acts as
* folding operation , but this function ' s execution is used to measure
* the CPU execution time jitter . Any change to the loop in this function
* implies that careful retesting must be done .
2015-05-25 21:10:20 +08:00
*
* Input :
* @ ec entropy collector struct - - may be NULL
2019-05-30 03:24:25 +08:00
* @ time time stamp to be injected
2015-05-25 21:10:20 +08:00
* @ loop_cnt if a value not equal to 0 is set , use the given value as number of
* loops to perform the folding
*
* Output :
2019-05-30 03:24:25 +08:00
* updated ec - > data
2015-05-25 21:10:20 +08:00
*
* @ return Number of loops the folding operation is performed
*/
2019-05-30 03:24:25 +08:00
static __u64 jent_lfsr_time ( struct rand_data * ec , __u64 time , __u64 loop_cnt )
2015-05-25 21:10:20 +08:00
{
unsigned int i ;
__u64 j = 0 ;
__u64 new = 0 ;
# define MAX_FOLD_LOOP_BIT 4
# define MIN_FOLD_LOOP_BIT 0
__u64 fold_loop_cnt =
jent_loop_shuffle ( ec , MAX_FOLD_LOOP_BIT , MIN_FOLD_LOOP_BIT ) ;
/*
* testing purposes - - allow test app to set the counter , not
* needed during runtime
*/
if ( loop_cnt )
fold_loop_cnt = loop_cnt ;
for ( j = 0 ; j < fold_loop_cnt ; j + + ) {
2019-05-30 03:24:25 +08:00
new = ec - > data ;
2015-05-25 21:10:20 +08:00
for ( i = 1 ; ( DATA_SIZE_BITS ) > = i ; i + + ) {
__u64 tmp = time < < ( DATA_SIZE_BITS - i ) ;
tmp = tmp > > ( DATA_SIZE_BITS - 1 ) ;
2019-05-30 03:24:25 +08:00
/*
* Fibonacci LSFR with polynomial of
* x ^ 64 + x ^ 61 + x ^ 56 + x ^ 31 + x ^ 28 + x ^ 23 + 1 which is
* primitive according to
* http : //poincare.matf.bg.ac.rs/~ezivkovm/publications/primpol1.pdf
* ( the shift values are the polynomial values minus one
* due to counting bits from 0 to 63 ) . As the current
* position is always the LSB , the polynomial only needs
* to shift data in from the left without wrap .
*/
tmp ^ = ( ( new > > 63 ) & 1 ) ;
tmp ^ = ( ( new > > 60 ) & 1 ) ;
tmp ^ = ( ( new > > 55 ) & 1 ) ;
tmp ^ = ( ( new > > 30 ) & 1 ) ;
tmp ^ = ( ( new > > 27 ) & 1 ) ;
tmp ^ = ( ( new > > 22 ) & 1 ) ;
new < < = 1 ;
2015-05-25 21:10:20 +08:00
new ^ = tmp ;
}
}
2019-05-30 03:24:25 +08:00
ec - > data = new ;
2015-05-25 21:10:20 +08:00
return fold_loop_cnt ;
}
/**
* Memory Access noise source - - this is a noise source based on variations in
* memory access times
*
* This function performs memory accesses which will add to the timing
* variations due to an unknown amount of CPU wait states that need to be
* added when accessing memory . The memory size should be larger than the L1
* caches as outlined in the documentation and the associated testing .
*
* The L1 cache has a very high bandwidth , albeit its access rate is usually
* slower than accessing CPU registers . Therefore , L1 accesses only add minimal
* variations as the CPU has hardly to wait . Starting with L2 , significant
* variations are added because L2 typically does not belong to the CPU any more
* and therefore a wider range of CPU wait states is necessary for accesses .
* L3 and real memory accesses have even a wider range of wait states . However ,
* to reliably access either L3 or memory , the ec - > mem memory must be quite
* large which is usually not desirable .
*
* Input :
* @ ec Reference to the entropy collector with the memory access data - - if
* the reference to the memory block to be accessed is NULL , this noise
* source is disabled
* @ loop_cnt if a value not equal to 0 is set , use the given value as number of
* loops to perform the folding
*
* @ return Number of memory access operations
*/
static unsigned int jent_memaccess ( struct rand_data * ec , __u64 loop_cnt )
{
unsigned int wrap = 0 ;
__u64 i = 0 ;
# define MAX_ACC_LOOP_BIT 7
# define MIN_ACC_LOOP_BIT 0
__u64 acc_loop_cnt =
jent_loop_shuffle ( ec , MAX_ACC_LOOP_BIT , MIN_ACC_LOOP_BIT ) ;
if ( NULL = = ec | | NULL = = ec - > mem )
return 0 ;
wrap = ec - > memblocksize * ec - > memblocks ;
/*
* testing purposes - - allow test app to set the counter , not
* needed during runtime
*/
if ( loop_cnt )
acc_loop_cnt = loop_cnt ;
for ( i = 0 ; i < ( ec - > memaccessloops + acc_loop_cnt ) ; i + + ) {
2019-05-30 03:24:25 +08:00
unsigned char * tmpval = ec - > mem + ec - > memlocation ;
2015-05-25 21:10:20 +08:00
/*
* memory access : just add 1 to one byte ,
* wrap at 255 - - memory access implies read
* from and write to memory location
*/
* tmpval = ( * tmpval + 1 ) & 0xff ;
/*
* Addition of memblocksize - 1 to pointer
* with wrap around logic to ensure that every
* memory location is hit evenly
*/
ec - > memlocation = ec - > memlocation + ec - > memblocksize - 1 ;
ec - > memlocation = ec - > memlocation % wrap ;
}
return i ;
}
/***************************************************************************
* Start of entropy processing logic
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
* Stuck test by checking the :
* 1 st derivation of the jitter measurement ( time delta )
* 2 nd derivation of the jitter measurement ( delta of time deltas )
* 3 rd derivation of the jitter measurement ( delta of delta of time deltas )
*
* All values must always be non - zero .
*
* Input :
* @ ec Reference to entropy collector
* @ current_delta Jitter time delta
*
* @ return
* 0 jitter measurement not stuck ( good bit )
* 1 jitter measurement stuck ( reject bit )
*/
2019-05-30 03:24:25 +08:00
static int jent_stuck ( struct rand_data * ec , __u64 current_delta )
2015-05-25 21:10:20 +08:00
{
__s64 delta2 = ec - > last_delta - current_delta ;
__s64 delta3 = delta2 - ec - > last_delta2 ;
ec - > last_delta = current_delta ;
ec - > last_delta2 = delta2 ;
if ( ! current_delta | | ! delta2 | | ! delta3 )
2019-05-30 03:24:25 +08:00
return 1 ;
return 0 ;
2015-05-25 21:10:20 +08:00
}
/**
* This is the heart of the entropy generation : calculate time deltas and
2019-05-30 03:24:25 +08:00
* use the CPU jitter in the time deltas . The jitter is injected into the
* entropy pool .
2015-05-25 21:10:20 +08:00
*
* WARNING : ensure that - > prev_time is primed before using the output
* of this function ! This can be done by calling this function
* and not using its result .
*
* Input :
* @ entropy_collector Reference to entropy collector
*
2019-05-30 03:24:25 +08:00
* @ return result of stuck test
2015-05-25 21:10:20 +08:00
*/
2019-05-30 03:24:25 +08:00
static int jent_measure_jitter ( struct rand_data * ec )
2015-05-25 21:10:20 +08:00
{
__u64 time = 0 ;
__u64 current_delta = 0 ;
/* Invoke one noise source before time measurement to add variations */
jent_memaccess ( ec , 0 ) ;
/*
* Get time stamp and calculate time delta to previous
* invocation to measure the timing variations
*/
jent_get_nstime ( & time ) ;
current_delta = time - ec - > prev_time ;
ec - > prev_time = time ;
2019-05-30 03:24:25 +08:00
/* Now call the next noise sources which also injects the data */
jent_lfsr_time ( ec , current_delta , 0 ) ;
2015-05-25 21:10:20 +08:00
2019-05-30 03:24:25 +08:00
/* Check whether we have a stuck measurement. */
return jent_stuck ( ec , current_delta ) ;
2015-05-25 21:10:20 +08:00
}
/**
* Generator of one 64 bit random number
* Function fills rand_data - > data
*
* Input :
* @ ec Reference to entropy collector
*/
static void jent_gen_entropy ( struct rand_data * ec )
{
unsigned int k = 0 ;
/* priming of the ->prev_time value */
jent_measure_jitter ( ec ) ;
while ( 1 ) {
2019-05-30 03:24:25 +08:00
/* If a stuck measurement is received, repeat measurement */
if ( jent_measure_jitter ( ec ) )
2015-05-25 21:10:20 +08:00
continue ;
/*
* We multiply the loop value with - > osr to obtain the
* oversampling rate requested by the caller
*/
if ( + + k > = ( DATA_SIZE_BITS * ec - > osr ) )
break ;
}
}
/**
* The continuous test required by FIPS 140 - 2 - - the function automatically
* primes the test if needed .
*
* Return :
* 0 if FIPS test passed
* < 0 if FIPS test failed
*/
static void jent_fips_test ( struct rand_data * ec )
{
2015-06-23 22:18:54 +08:00
if ( ! jent_fips_enabled ( ) )
2015-05-25 21:10:20 +08:00
return ;
/* prime the FIPS test */
if ( ! ec - > old_data ) {
ec - > old_data = ec - > data ;
jent_gen_entropy ( ec ) ;
}
if ( ec - > data = = ec - > old_data )
2015-06-23 22:18:54 +08:00
jent_panic ( " jitterentropy: Duplicate output detected \n " ) ;
2015-05-25 21:10:20 +08:00
ec - > old_data = ec - > data ;
}
/**
* Entry function : Obtain entropy for the caller .
*
* This function invokes the entropy gathering logic as often to generate
* as many bytes as requested by the caller . The entropy gathering logic
* creates 64 bit per invocation .
*
* This function truncates the last 64 bit entropy value output to the exact
* size specified by the caller .
*
* Input :
* @ ec Reference to entropy collector
* @ data pointer to buffer for storing random data - - buffer must already
* exist
* @ len size of the buffer , specifying also the requested number of random
* in bytes
*
* @ return 0 when request is fulfilled or an error
*
* The following error codes can occur :
* - 1 entropy_collector is NULL
*/
2015-06-23 22:18:54 +08:00
int jent_read_entropy ( struct rand_data * ec , unsigned char * data ,
unsigned int len )
2015-05-25 21:10:20 +08:00
{
2015-06-23 22:18:54 +08:00
unsigned char * p = data ;
2015-05-25 21:10:20 +08:00
if ( ! ec )
2015-06-23 22:18:54 +08:00
return - 1 ;
2015-05-25 21:10:20 +08:00
while ( 0 < len ) {
2015-06-23 22:18:54 +08:00
unsigned int tocopy ;
2015-05-25 21:10:20 +08:00
jent_gen_entropy ( ec ) ;
jent_fips_test ( ec ) ;
if ( ( DATA_SIZE_BITS / 8 ) < len )
tocopy = ( DATA_SIZE_BITS / 8 ) ;
else
tocopy = len ;
2015-06-23 22:18:54 +08:00
jent_memcpy ( p , & ec - > data , tocopy ) ;
2015-05-25 21:10:20 +08:00
len - = tocopy ;
p + = tocopy ;
}
return 0 ;
}
/***************************************************************************
* Initialization logic
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2015-06-23 22:18:54 +08:00
struct rand_data * jent_entropy_collector_alloc ( unsigned int osr ,
unsigned int flags )
2015-05-25 21:10:20 +08:00
{
struct rand_data * entropy_collector ;
2015-06-23 22:18:54 +08:00
entropy_collector = jent_zalloc ( sizeof ( struct rand_data ) ) ;
2015-05-25 21:10:20 +08:00
if ( ! entropy_collector )
return NULL ;
if ( ! ( flags & JENT_DISABLE_MEMORY_ACCESS ) ) {
/* Allocate memory for adding variations based on memory
* access
*/
2015-06-23 22:18:54 +08:00
entropy_collector - > mem = jent_zalloc ( JENT_MEMORY_SIZE ) ;
2015-05-25 21:10:20 +08:00
if ( ! entropy_collector - > mem ) {
2015-06-23 22:18:54 +08:00
jent_zfree ( entropy_collector ) ;
2015-05-25 21:10:20 +08:00
return NULL ;
}
entropy_collector - > memblocksize = JENT_MEMORY_BLOCKSIZE ;
entropy_collector - > memblocks = JENT_MEMORY_BLOCKS ;
entropy_collector - > memaccessloops = JENT_MEMORY_ACCESSLOOPS ;
}
/* verify and set the oversampling rate */
if ( 0 = = osr )
osr = 1 ; /* minimum sampling rate is 1 */
entropy_collector - > osr = osr ;
/* fill the data pad with non-zero values */
jent_gen_entropy ( entropy_collector ) ;
return entropy_collector ;
}
2015-06-23 22:18:54 +08:00
void jent_entropy_collector_free ( struct rand_data * entropy_collector )
2015-05-25 21:10:20 +08:00
{
2015-06-24 04:30:21 +08:00
jent_zfree ( entropy_collector - > mem ) ;
2015-05-25 21:10:20 +08:00
entropy_collector - > mem = NULL ;
2015-06-24 04:30:21 +08:00
jent_zfree ( entropy_collector ) ;
2015-05-25 21:10:20 +08:00
}
2015-06-23 22:18:54 +08:00
int jent_entropy_init ( void )
2015-05-25 21:10:20 +08:00
{
int i ;
__u64 delta_sum = 0 ;
__u64 old_delta = 0 ;
int time_backwards = 0 ;
int count_mod = 0 ;
2019-05-30 03:24:25 +08:00
int count_stuck = 0 ;
struct rand_data ec = { 0 } ;
2015-05-25 21:10:20 +08:00
/* We could perform statistical tests here, but the problem is
* that we only have a few loop counts to do testing . These
* loop counts may show some slight skew and we produce
* false positives .
*
* Moreover , only old systems show potentially problematic
* jitter entropy that could potentially be caught here . But
* the RNG is intended for hardware that is available or widely
* used , but not old systems that are long out of favor . Thus ,
* no statistical tests .
*/
/*
* We could add a check for system capabilities such as clock_getres or
* check for CONFIG_X86_TSC , but it does not make much sense as the
* following sanity checks verify that we have a high - resolution
* timer .
*/
/*
* TESTLOOPCOUNT needs some loops to identify edge systems . 100 is
* definitely too little .
*/
# define TESTLOOPCOUNT 300
# define CLEARCACHE 100
for ( i = 0 ; ( TESTLOOPCOUNT + CLEARCACHE ) > i ; i + + ) {
__u64 time = 0 ;
__u64 time2 = 0 ;
__u64 delta = 0 ;
unsigned int lowdelta = 0 ;
2019-05-30 03:24:25 +08:00
int stuck ;
2015-05-25 21:10:20 +08:00
2019-05-30 03:24:25 +08:00
/* Invoke core entropy collection logic */
2015-05-25 21:10:20 +08:00
jent_get_nstime ( & time ) ;
2019-05-30 03:24:25 +08:00
ec . prev_time = time ;
jent_lfsr_time ( & ec , time , 0 ) ;
2015-05-25 21:10:20 +08:00
jent_get_nstime ( & time2 ) ;
/* test whether timer works */
if ( ! time | | ! time2 )
return JENT_ENOTIME ;
delta = time2 - time ;
/*
* test whether timer is fine grained enough to provide
* delta even when called shortly after each other - - this
* implies that we also have a high resolution timer
*/
if ( ! delta )
return JENT_ECOARSETIME ;
2019-05-30 03:24:25 +08:00
stuck = jent_stuck ( & ec , delta ) ;
2015-05-25 21:10:20 +08:00
/*
* up to here we did not modify any variable that will be
* evaluated later , but we already performed some work . Thus we
* already have had an impact on the caches , branch prediction ,
* etc . with the goal to clear it to get the worst case
* measurements .
*/
if ( CLEARCACHE > i )
continue ;
2019-05-30 03:24:25 +08:00
if ( stuck )
count_stuck + + ;
2015-05-25 21:10:20 +08:00
/* test whether we have an increasing timer */
if ( ! ( time2 > time ) )
time_backwards + + ;
2019-05-30 03:24:25 +08:00
/* use 32 bit value to ensure compilation on 32 bit arches */
2015-05-25 21:10:20 +08:00
lowdelta = time2 - time ;
if ( ! ( lowdelta % 100 ) )
count_mod + + ;
/*
* ensure that we have a varying delta timer which is necessary
* for the calculation of entropy - - perform this check
* only after the first loop is executed as we need to prime
* the old_data value
*/
2019-05-30 03:24:25 +08:00
if ( delta > old_delta )
delta_sum + = ( delta - old_delta ) ;
else
delta_sum + = ( old_delta - delta ) ;
2015-05-25 21:10:20 +08:00
old_delta = delta ;
}
/*
* we allow up to three times the time running backwards .
* CLOCK_REALTIME is affected by adjtime and NTP operations . Thus ,
* if such an operation just happens to interfere with our test , it
* should not fail . The value of 3 should cover the NTP case being
* performed during our test run .
*/
if ( 3 < time_backwards )
return JENT_ENOMONOTONIC ;
/*
* Variations of deltas of time must on average be larger
* than 1 to ensure the entropy estimation
* implied with 1 is preserved
*/
2019-05-30 03:24:25 +08:00
if ( ( delta_sum ) < = 1 )
return JENT_EVARVAR ;
2015-05-25 21:10:20 +08:00
/*
* Ensure that we have variations in the time stamp below 10 for at
2019-05-30 03:24:25 +08:00
* least 10 % of all checks - - on some platforms , the counter increments
* in multiples of 100 , but not always
2015-05-25 21:10:20 +08:00
*/
if ( ( TESTLOOPCOUNT / 10 * 9 ) < count_mod )
return JENT_ECOARSETIME ;
2019-05-30 03:24:25 +08:00
/*
* If we have more than 90 % stuck results , then this Jitter RNG is
* likely to not work well .
*/
if ( ( TESTLOOPCOUNT / 10 * 9 ) < count_stuck )
return JENT_ESTUCK ;
2015-05-25 21:10:20 +08:00
return 0 ;
}