1
1
镜像自地址 https://github.com/henrydcase/pqc.git 已同步 2024-11-24 16:31:29 +00:00

jitterentropy

这个提交包含在:
Henry Case 2023-01-27 22:49:21 +00:00
父节点 0a452b1220
当前提交 e7b5cfe9f8
共有 20 个文件被更改,包括 4387 次插入0 次删除

34
3rd/jitterentropy/LICENSE 普通文件
查看文件

@ -0,0 +1,34 @@
Copyright (C) 2017 - 2022, Stephan Mueller <smueller@chronox.de>
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.

查看文件

@ -0,0 +1,26 @@
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, this list of conditions and the following disclaimer.
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.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
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 ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

查看文件

@ -0,0 +1,147 @@
/*
* Non-physical true random number generator based on timing jitter.
*
* Copyright Stephan Mueller <smueller@chronox.de>, 2013 - 2022
*
* 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 GPL 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.
*/
#ifndef _JITTERENTROPY_BASE_POWER_H
#define _JITTERENTROPY_BASE_POWER_H
#include <sched.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
/* taken from http://www.ecrypt.eu.org/ebats/cpucycles.html */
static inline void jent_get_nstime(uint64_t *out)
{
unsigned long high;
unsigned long low;
unsigned long newhigh;
uint64_t result;
asm volatile(
"Lcpucycles:mftbu %0;mftb %1;mftbu %2;cmpw %0,%2;bne Lcpucycles"
: "=r" (high), "=r" (low), "=r" (newhigh)
);
result = high;
result <<= 32;
result |= low;
*out = result;
}
static inline void *jent_zalloc(size_t len)
{
void *tmp = NULL;
/* we have no secure memory allocation! Hence
* we do not sed CRYPTO_CPU_JITTERENTROPY_SECURE_MEMORY */
tmp = malloc(len);
if(NULL != tmp)
memset(tmp, 0, len);
return tmp;
}
static inline void jent_zfree(void *ptr, unsigned int len)
{
memset(ptr, 0, len);
free(ptr);
}
static inline int jent_fips_enabled(void)
{
return 0;
}
static inline long jent_ncpu(void)
{
/*
* TODO: return number of available CPUs -
* this code disables timer thread as only one CPU is "detected".
*/
return 1;
}
static inline void jent_yield(void)
{
sched_yield();
}
static inline uint32_t jent_cache_size_roundup(void)
{
#ifdef __linux__
long l1 = sysconf(_SC_LEVEL1_DCACHE_SIZE);
long l2 = sysconf(_SC_LEVEL2_CACHE_SIZE);
long l3 = sysconf(_SC_LEVEL3_CACHE_SIZE);
uint32_t cache_size = 0;
/* Cache size reported by system */
if (l1 > 0)
cache_size += (uint32_t)l1;
if (l2 > 0)
cache_size += (uint32_t)l2;
if (l3 > 0)
cache_size += (uint32_t)l3;
/* Force the output_size to be of the form (bounding_power_of_2 - 1). */
cache_size |= (cache_size >> 1);
cache_size |= (cache_size >> 2);
cache_size |= (cache_size >> 4);
cache_size |= (cache_size >> 8);
cache_size |= (cache_size >> 16);
if (cache_size == 0)
return 0;
/* Make the output_size the smallest power of 2 strictly greater than cache_size. */
cache_size++;
return cache_size;
#else
return 0;
#endif
}
/* --- helpers needed in user space -- */
static inline uint64_t rol64(uint64_t x, int n)
{
return ( (x << (n&(64-1))) | (x >> ((64-n)&(64-1))) );
}
#endif /* _JITTERENTROPY_BASE_POWER_H */

查看文件

@ -0,0 +1,140 @@
/*
* Non-physical true random number generator based on timing jitter.
*
* Copyright Stephan Mueller <smueller@chronox.de>, 2013 - 2022
*
* 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 GPL 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.
*/
#ifndef _JITTERENTROPY_BASE_S390_H
#define _JITTERENTROPY_BASE_S390_H
#include <sched.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
static inline void jent_get_nstime(uint64_t *out)
{
uint64_t clk;
/* this is MVS code! enable with -S in the compiler */
/*__asm__ volatile("stck %0" : "=m" (clk) : : "cc"); */
/* this is gcc */
asm volatile("stcke %0" : "=Q" (clk) : : "cc");
*out = (uint64_t)(clk);
}
static inline void *jent_zalloc(size_t len)
{
void *tmp = NULL;
/* we have no secure memory allocation! Hence
* we do not sed CRYPTO_CPU_JITTERENTROPY_SECURE_MEMORY */
tmp = malloc(len);
if(NULL != tmp)
memset(tmp, 0, len);
return tmp;
}
static inline void jent_zfree(void *ptr, unsigned int len)
{
memset(ptr, 0, len);
free(ptr);
}
static inline int jent_fips_enabled(void)
{
return 0;
}
static inline long jent_ncpu(void)
{
/*
* TODO: return number of available CPUs -
* this code disables timer thread as only one CPU is "detected".
*/
return 1;
}
static inline void jent_yield(void)
{
sched_yield();
}
static inline uint32_t jent_cache_size_roundup(void)
{
#ifdef __linux__
long l1 = sysconf(_SC_LEVEL1_DCACHE_SIZE);
long l2 = sysconf(_SC_LEVEL2_CACHE_SIZE);
long l3 = sysconf(_SC_LEVEL3_CACHE_SIZE);
uint32_t cache_size = 0;
/* Cache size reported by system */
if (l1 > 0)
cache_size += (uint32_t)l1;
if (l2 > 0)
cache_size += (uint32_t)l2;
if (l3 > 0)
cache_size += (uint32_t)l3;
/* Force the output_size to be of the form (bounding_power_of_2 - 1). */
cache_size |= (cache_size >> 1);
cache_size |= (cache_size >> 2);
cache_size |= (cache_size >> 4);
cache_size |= (cache_size >> 8);
cache_size |= (cache_size >> 16);
if (cache_size == 0)
return 0;
/* Make the output_size the smallest power of 2 strictly greater than cache_size. */
cache_size++;
return cache_size;
#else
return 0;
#endif
}
/* --- helpers needed in user space -- */
static inline uint64_t rol64(uint64_t x, int n)
{
return ( (x << (n&(64-1))) | (x >> ((64-n)&(64-1))) );
}
#endif /* _JITTERENTROPY_BASE_S390_H */

查看文件

@ -0,0 +1,151 @@
/*
* Non-physical true random number generator based on timing jitter.
*
* Copyright Stephan Mueller <smueller@chronox.de>, 2013 - 2022
*
* 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 GPL 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
e USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
#ifndef _JITTERENTROPY_BASE_X86_H
#define _JITTERENTROPY_BASE_X86_H
#if defined(_MSC_VER)
typedef __int64 ssize_t;
#include <windows.h>
#endif
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <intrin.h>
#if defined(AWSLC)
#include <openssl/crypto.h>
#endif
#if defined(_M_ARM) || defined(_M_ARM64)
#include <profileapi.h>
#include <windows.h>
#endif
static void jent_get_nstime(uint64_t *out)
{
#if defined(_M_ARM) || defined(_M_ARM64)
/* Generic code. */
LARGE_INTEGER ticks;
QueryPerformanceCounter(&ticks);
*out = ticks.QuadPart;
#else
/* x86, x86_64 intrinsic */
*out = __rdtsc();
#endif
}
static inline void *jent_zalloc(size_t len)
{
void *tmp = NULL;
/* we have no secure memory allocation! Hence
* we do not sed CRYPTO_CPU_JITTERENTROPY_SECURE_MEMORY */
#if defined(AWSLC)
tmp = OPENSSL_malloc(len);
#else
tmp = malloc(len);
#endif
if(NULL != tmp)
memset(tmp, 0, len);
return tmp;
}
static inline void jent_zfree(void *ptr, unsigned int len)
{
#if defined(AWSLC)
(void) len;
OPENSSL_free(ptr);
#else
memset(ptr, 0, len);
free(ptr);
#endif
}
static inline int jent_fips_enabled(void)
{
#if defined(AWSLC)
return FIPS_mode();
#else
return 0;
#endif
}
static inline void jent_memset_secure(void *s, size_t n)
{
#if defined(AWSLC)
OPENSSL_cleanse(s, n);
#else
SecureZeroMemory(s, n);
#endif
}
static inline long jent_ncpu(void)
{
/*
* TODO: return number of available CPUs -
* this code disables timer thread as only one CPU is "detected".
*/
return 1;
}
static inline void jent_yield(void) { }
static inline uint32_t jent_cache_size_roundup(void)
{
return 0;
}
/* --- helpers needed in user space -- */
/* note: these helper functions are shamelessly stolen from the kernel :-) */
static inline uint64_t rol64(uint64_t word, unsigned int shift)
{
return (word << shift) | (word >> (64 - shift));
}
#endif /* _JITTERENTROPY_BASE_X86_H */

查看文件

@ -0,0 +1,159 @@
/*
* Non-physical true random number generator based on timing jitter.
*
* Copyright Stephan Mueller <smueller@chronox.de>, 2013 - 2022
*
* 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 GPL 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.
*/
#ifndef _JITTERENTROPY_BASE_X86_H
#define _JITTERENTROPY_BASE_X86_H
#include <sched.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
/* Timer-less entropy source */
#include <pthread.h>
typedef uint64_t __u64;
/* taken from Linux kernel */
#ifdef __x86_64__
#define DECLARE_ARGS(val, low, high) unsigned long low, high
#define EAX_EDX_VAL(val, low, high) ((low) | (high) << 32)
#define EAX_EDX_RET(val, low, high) "=a" (low), "=d" (high)
#else
#define DECLARE_ARGS(val, low, high) unsigned long long val
#define EAX_EDX_VAL(val, low, high) (val)
#define EAX_EDX_RET(val, low, high) "=A" (val)
#endif
static inline void jent_get_nstime(uint64_t *out)
{
DECLARE_ARGS(val, low, high);
__asm__ __volatile__("rdtsc" : EAX_EDX_RET(val, low, high));
*out = EAX_EDX_VAL(val, low, high);
}
static inline void *jent_zalloc(size_t len)
{
void *tmp = NULL;
/* we have no secure memory allocation! Hence
* we do not sed CRYPTO_CPU_JITTERENTROPY_SECURE_MEMORY */
tmp = malloc(len);
if(NULL != tmp)
memset(tmp, 0, len);
return tmp;
}
static inline void jent_zfree(void *ptr, unsigned int len)
{
memset(ptr, 0, len);
free(ptr);
}
static inline int jent_fips_enabled(void)
{
return 0;
}
static inline void jent_memset_secure(void *s, size_t n)
{
memset(s, 0, n);
__asm__ __volatile__("" : : "r" (s) : "memory");
}
static inline long jent_ncpu(void)
{
/*
* TODO: return number of available CPUs -
* this code disables timer thread as only one CPU is "detected".
*/
return 1;
}
static inline void jent_yield(void)
{
sched_yield();
}
static inline uint32_t jent_cache_size_roundup(void)
{
#ifdef __linux__
long l1 = sysconf(_SC_LEVEL1_DCACHE_SIZE);
long l2 = sysconf(_SC_LEVEL2_CACHE_SIZE);
long l3 = sysconf(_SC_LEVEL3_CACHE_SIZE);
uint32_t cache_size = 0;
/* Cache size reported by system */
if (l1 > 0)
cache_size += (uint32_t)l1;
if (l2 > 0)
cache_size += (uint32_t)l2;
if (l3 > 0)
cache_size += (uint32_t)l3;
/* Force the output_size to be of the form (bounding_power_of_2 - 1). */
cache_size |= (cache_size >> 1);
cache_size |= (cache_size >> 2);
cache_size |= (cache_size >> 4);
cache_size |= (cache_size >> 8);
cache_size |= (cache_size >> 16);
if (cache_size == 0)
return 0;
/* Make the output_size the smallest power of 2 strictly greater than cache_size. */
cache_size++;
return cache_size;
#else
return 0;
#endif
}
/* --- helpers needed in user space -- */
static inline uint64_t rol64(uint64_t x, int n)
{
return ( (x << (n&(64-1))) | (x >> ((64-n)&(64-1))) );
}
#endif /* _JITTERENTROPY_BASE_X86_H */

查看文件

@ -0,0 +1,478 @@
/*
* Non-physical true random number generator based on timing jitter.
*
* Copyright Stephan Mueller <smueller@chronox.de>, 2013 - 2022
*
* 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 GPL 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.
*/
#ifndef _JITTERENTROPY_BASE_USER_H
#define _JITTERENTROPY_BASE_USER_H
/*
* Set the following defines as needed for your environment
* Compilation for AWS-LC #define AWSLC
* Compilation for libgcrypt #define LIBGCRYPT
* Compilation for OpenSSL #define OPENSSL
*/
#include <limits.h>
#include <time.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sched.h>
/* Timer-less entropy source */
#ifdef JENT_CONF_ENABLE_INTERNAL_TIMER
#include <pthread.h>
#endif /* JENT_CONF_ENABLE_INTERNAL_TIMER */
#ifdef LIBGCRYPT
#include <config.h>
#include "g10lib.h"
#endif
#ifdef OPENSSL
#include <openssl/crypto.h>
#ifdef OPENSSL_FIPS
#include <openssl/fips.h>
#endif
#endif
#if defined(AWSLC)
#include <openssl/crypto.h>
#endif
#ifdef __MACH__
#include <assert.h>
#include <CoreServices/CoreServices.h>
#include <mach/mach.h>
#include <mach/mach_time.h>
#include <unistd.h>
#endif
#if (__x86_64__) || (__i386__)
/* Support rdtsc read on 64-bit and 32-bit x86 architectures */
#ifdef __x86_64__
/* specify 64 bit type since long is 32 bits in LLP64 x86_64 systems */
# define DECLARE_ARGS(val, low, high) uint64_t low, high
# define EAX_EDX_VAL(val, low, high) ((low) | (high) << 32)
# define EAX_EDX_RET(val, low, high) "=a" (low), "=d" (high)
#elif __i386__
# define DECLARE_ARGS(val, low, high) unsigned long val
# define EAX_EDX_VAL(val, low, high) val
# define EAX_EDX_RET(val, low, high) "=A" (val)
#endif
static inline void jent_get_nstime(uint64_t *out)
{
DECLARE_ARGS(val, low, high);
asm volatile("rdtsc" : EAX_EDX_RET(val, low, high));
*out = EAX_EDX_VAL(val, low, high);
}
#elif defined(__aarch64__)
static inline void jent_get_nstime(uint64_t *out)
{
uint64_t ctr_val;
/*
* Use the system counter for aarch64 (64 bit ARM).
*/
asm volatile("mrs %0, cntvct_el0" : "=r" (ctr_val));
*out = ctr_val;
}
#elif defined(__s390x__)
static inline void jent_get_nstime(uint64_t *out)
{
/*
* This is MVS+STCK code! Enable it with -S in the compiler.
*
* uint64_t clk;
* __asm__ volatile("stck %0" : "=m" (clk) : : "cc");
* *out = (uint64_t)(clk);
*/
/*
* This is GCC+STCKE code. STCKE command and data format:
* z/Architecture - Principles of Operation
* http://publibz.boulder.ibm.com/epubs/pdf/dz9zr007.pdf
*
* The current value of bits 0-103 of the TOD clock is stored in bytes
* 1-13 of the sixteen-byte output:
*
* bits 0-7: zeros (reserved for future extention)
* bits 8-111: TOD Clock value
* bits 112-127: Programmable Field
*
* Output bit 59 (TOD-Clock bit 51) effectively increments every
* microsecond. Bits 60 to 111 of STCKE output are fractions of
* a miscrosecond: bit 59 is 1.0us, bit 60 is .5us, bit 61 is .25us,
* bit 62 is .125us, bit 63 is 62.5ns, etc.
*
* Some of these bits can be implemented, some not. 64 bits of
* the TOD clock are implemented usually nowadays, these are
* bits 8-71 of the output.
*
* The stepping value of TOD-clock bit position 63, if implemented,
* is 2^-12 microseconds, or approximately 244 picoseconds. This value
* is called a clock unit.
*/
uint8_t clk[16];
asm volatile("stcke %0" : "=Q" (clk) : : "cc");
/* s390x is big-endian, so just perfom a byte-by-byte copy */
*out = *(uint64_t *)(clk + 1);
}
#elif defined(__powerpc)
/* taken from http://www.ecrypt.eu.org/ebats/cpucycles.html */
static inline void jent_get_nstime(uint64_t *out)
{
unsigned long high;
unsigned long low;
unsigned long newhigh;
uint64_t result;
asm volatile(
"Lcpucycles:mftbu %0;mftb %1;mftbu %2;cmpw %0,%2;bne Lcpucycles"
: "=r" (high), "=r" (low), "=r" (newhigh)
);
result = high;
result <<= 32;
result |= low;
*out = result;
}
#else /* (__x86_64__) || (__i386__) || (__aarch64__) || (__s390x__) || (__powerpc) */
static inline void jent_get_nstime(uint64_t *out)
{
/* OSX does not have clock_gettime -- taken from
* http://developer.apple.com/library/mac/qa/qa1398/_index.html */
# ifdef __MACH__
*out = mach_absolute_time();
# elif _AIX
/* clock_gettime() on AIX returns a timer value that increments in
* steps of 1000
*/
uint64_t tmp = 0;
timebasestruct_t aixtime;
read_real_time(&aixtime, TIMEBASE_SZ);
tmp = aixtime.tb_high;
tmp = tmp << 32;
tmp = tmp | aixtime.tb_low;
*out = tmp;
# else /* __MACH__ */
/* we could use CLOCK_MONOTONIC(_RAW), but with CLOCK_REALTIME
* we get some nice extra entropy once in a while from the NTP actions
* that we want to use as well... though, we do not rely on that
* extra little entropy */
uint64_t tmp = 0;
struct timespec time;
if (clock_gettime(CLOCK_REALTIME, &time) == 0)
{
tmp = ((uint64_t)time.tv_sec & 0xFFFFFFFF) * 1000000000UL;
tmp = tmp + (uint64_t)time.tv_nsec;
}
*out = tmp;
# endif /* __MACH__ */
}
#endif /* (__x86_64__) || (__i386__) || (__aarch64__) */
static inline void *jent_zalloc(size_t len)
{
void *tmp = NULL;
#ifdef LIBGCRYPT
/* When using the libgcrypt secure memory mechanism, all precautions
* are taken to protect our state. If the user disables secmem during
* runtime, it is his decision and we thus try not to overrule his
* decision for less memory protection. */
#define CONFIG_CRYPTO_CPU_JITTERENTROPY_SECURE_MEMORY
tmp = gcry_xmalloc_secure(len);
#elif defined(OPENSSL) || defined(AWSLC)
/* Does this allocation implies secure memory use? */
tmp = OPENSSL_malloc(len);
#else
/* we have no secure memory allocation! Hence
* we do not set CONFIG_CRYPTO_CPU_JITTERENTROPY_SECURE_MEMORY */
tmp = malloc(len);
#endif /* LIBGCRYPT */
if(NULL != tmp)
memset(tmp, 0, len);
return tmp;
}
static inline void jent_zfree(void *ptr, unsigned int len)
{
#ifdef LIBGCRYPT
memset(ptr, 0, len);
gcry_free(ptr);
#elif defined(AWSLC)
/* AWS-LC stores the length of allocated memory internally and automatically wipes it in OPENSSL_free */
(void) len;
OPENSSL_free(ptr);
#elif defined(OPENSSL)
OPENSSL_cleanse(ptr, len);
OPENSSL_free(ptr);
#else
memset(ptr, 0, len);
free(ptr);
#endif /* LIBGCRYPT */
}
static inline int jent_fips_enabled(void)
{
#ifdef LIBGCRYPT
return fips_mode();
#elif defined(AWSLC)
return FIPS_mode();
#elif defined(OPENSSL)
#ifdef OPENSSL_FIPS
return FIPS_mode();
#else
return 0;
#endif
#else
#define FIPS_MODE_SWITCH_FILE "/proc/sys/crypto/fips_enabled"
char buf[2] = "0";
int fd = 0;
if ((fd = open(FIPS_MODE_SWITCH_FILE, O_RDONLY)) >= 0) {
while (read(fd, buf, sizeof(buf)) < 0 && errno == EINTR);
close(fd);
}
if (buf[0] == '1')
return 1;
else
return 0;
#endif
}
static inline void jent_memset_secure(void *s, size_t n)
{
#if defined(AWSLC)
OPENSSL_cleanse(s, n);
#else
memset(s, 0, n);
__asm__ __volatile__("" : : "r" (s) : "memory");
#endif
}
static inline long jent_ncpu(void)
{
#ifdef _POSIX_SOURCE
long ncpu = sysconf(_SC_NPROCESSORS_ONLN);
if (ncpu == -1)
return -errno;
if (ncpu == 0)
return -EFAULT;
return ncpu;
#else
return 1;
#endif
}
#ifdef __linux__
# if defined(_SC_LEVEL1_DCACHE_SIZE) && \
defined(_SC_LEVEL2_CACHE_SIZE) && \
defined(_SC_LEVEL3_CACHE_SIZE)
static inline void jent_get_cachesize(long *l1, long *l2, long *l3)
{
*l1 = sysconf(_SC_LEVEL1_DCACHE_SIZE);
*l2 = sysconf(_SC_LEVEL2_CACHE_SIZE);
*l3 = sysconf(_SC_LEVEL3_CACHE_SIZE);
}
# else
static inline void jent_get_cachesize(long *l1, long *l2, long *l3)
{
#define JENT_SYSFS_CACHE_DIR "/sys/devices/system/cpu/cpu0/cache"
long val;
unsigned int i;
char buf[10], file[50];
int fd = 0;
/* Iterate over all caches */
for (i = 0; i < 4; i++) {
unsigned int shift = 0;
char *ext;
/*
* Check the cache type - we are only interested in Unified
* and Data caches.
*/
memset(buf, 0, sizeof(buf));
snprintf(file, sizeof(file), "%s/index%u/type",
JENT_SYSFS_CACHE_DIR, i);
fd = open(file, O_RDONLY);
if (fd < 0)
continue;
while (read(fd, buf, sizeof(buf)) < 0 && errno == EINTR);
close(fd);
buf[sizeof(buf) - 1] = '\0';
if (strncmp(buf, "Data", 4) && strncmp(buf, "Unified", 7))
continue;
/* Get size of cache */
memset(buf, 0, sizeof(buf));
snprintf(file, sizeof(file), "%s/index%u/size",
JENT_SYSFS_CACHE_DIR, i);
fd = open(file, O_RDONLY);
if (fd < 0)
continue;
while (read(fd, buf, sizeof(buf)) < 0 && errno == EINTR);
close(fd);
buf[sizeof(buf) - 1] = '\0';
ext = strstr(buf, "K");
if (ext) {
shift = 10;
*ext = '\0';
} else {
ext = strstr(buf, "M");
if (ext) {
shift = 20;
*ext = '\0';
}
}
val = strtol(buf, NULL, 10);
if (val == LONG_MAX)
continue;
val <<= shift;
if (!*l1)
*l1 = val;
else if (!*l2)
*l2 = val;
else {
*l3 = val;
break;
}
}
#undef JENT_SYSFS_CACHE_DIR
}
# endif
static inline uint32_t jent_cache_size_roundup(void)
{
static int checked = 0;
static uint32_t cache_size = 0;
if (!checked) {
long l1 = 0, l2 = 0, l3 = 0;
jent_get_cachesize(&l1, &l2, &l3);
checked = 1;
/* Cache size reported by system */
if (l1 > 0)
cache_size += (uint32_t)l1;
if (l2 > 0)
cache_size += (uint32_t)l2;
if (l3 > 0)
cache_size += (uint32_t)l3;
/*
* Force the output_size to be of the form
* (bounding_power_of_2 - 1).
*/
cache_size |= (cache_size >> 1);
cache_size |= (cache_size >> 2);
cache_size |= (cache_size >> 4);
cache_size |= (cache_size >> 8);
cache_size |= (cache_size >> 16);
if (cache_size == 0)
return 0;
/*
* Make the output_size the smallest power of 2 strictly
* greater than cache_size.
*/
cache_size++;
}
return cache_size;
}
#else /* __linux__ */
static inline uint32_t jent_cache_size_roundup(void)
{
return 0;
}
#endif /* __linux__ */
static inline void jent_yield(void)
{
sched_yield();
}
/* --- helpers needed in user space -- */
static inline uint64_t rol64(uint64_t x, int n)
{
return ( (x << (n&(64-1))) | (x >> ((64-n)&(64-1))) );
}
#endif /* _JITTERENTROPY_BASE_USER_H */

查看文件

@ -0,0 +1,757 @@
/*
* Non-physical true random number generator based on timing jitter.
*
* Copyright Stephan Mueller <smueller@chronox.de>, 2014 - 2022
*
* Design
* ======
*
* See documentation in doc/ folder.
*
* Interface
* =========
*
* See documentation in jitterentropy(3) man page.
*
* License: see LICENSE file in root directory
*
* 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.
*/
#include "jitterentropy.h"
#include "jitterentropy-base.h"
#include "jitterentropy-gcd.h"
#include "jitterentropy-health.h"
#include "jitterentropy-noise.h"
#include "jitterentropy-timer.h"
#include "jitterentropy-sha3.h"
#define MAJVERSION 3 /* API / ABI incompatible changes, functional changes that
* require consumer to be updated (as long as this number
* is zero, the API is not considered stable and can
* change without a bump of the major version) */
#define MINVERSION 4 /* API compatible, ABI may change, functional
* enhancements only, consumer can be left unchanged if
* enhancements are not considered */
#define PATCHLEVEL 1 /* API / ABI compatible, no functional changes, no
* enhancements, bug fixes only */
/***************************************************************************
* Jitter RNG Static Definitions
*
* None of the following should be altered
***************************************************************************/
#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
/*
* JENT_POWERUP_TESTLOOPCOUNT needs some loops to identify edge
* systems. 100 is definitely too little.
*
* SP800-90B requires at least 1024 initial test cycles.
*/
#define JENT_POWERUP_TESTLOOPCOUNT 1024
/**
* jent_version() - Return machine-usable version number of jent library
*
* The function returns a version number that is monotonic increasing
* for newer versions. The version numbers are multiples of 100. For example,
* version 1.2.3 is converted to 1020300 -- the last two digits are reserved
* for future use.
*
* The result of this function can be used in comparing the version number
* in a calling program if version-specific calls need to be make.
*
* @return Version number of jitterentropy library
*/
JENT_PRIVATE_STATIC
unsigned int jent_version(void)
{
unsigned int version = 0;
version = MAJVERSION * 1000000;
version += MINVERSION * 10000;
version += PATCHLEVEL * 100;
return version;
}
/***************************************************************************
* Helper
***************************************************************************/
/* Calculate log2 of given value assuming that the value is a power of 2 */
static inline unsigned int jent_log2_simple(unsigned int val)
{
unsigned int idx = 0;
while (val >>= 1)
idx++;
return idx;
}
/* Increase the memory size by one step */
static inline unsigned int jent_update_memsize(unsigned int flags)
{
unsigned int global_max = JENT_FLAGS_TO_MAX_MEMSIZE(
JENT_MAX_MEMSIZE_MAX);
unsigned int max;
max = JENT_FLAGS_TO_MAX_MEMSIZE(flags);
if (!max) {
/*
* The safe starting value is the amount of memory we allocated
* last round.
*/
max = jent_log2_simple(JENT_MEMORY_SIZE);
/* Adjust offset */
max = (max > JENT_MAX_MEMSIZE_OFFSET) ?
max - JENT_MAX_MEMSIZE_OFFSET : 0;
} else {
max++;
}
max = (max > global_max) ? global_max : max;
/* Clear out the max size */
flags &= ~JENT_MAX_MEMSIZE_MASK;
/* Set the freshly calculated max size */
flags |= JENT_MAX_MEMSIZE_TO_FLAGS(max);
return flags;
}
/***************************************************************************
* Random Number Generation
***************************************************************************/
/**
* 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.
*
* @ec [in] Reference to entropy collector
* @data [out] pointer to buffer for storing random data -- buffer must
* already exist
* @len [in] size of the buffer, specifying also the requested number of random
* in bytes
*
* @return number of bytes returned when request is fulfilled or an error
*
* The following error codes can occur:
* -1 entropy_collector is NULL
* -2 RCT failed
* -3 APT test failed
* -4 The timer cannot be initialized
* -5 LAG failure
*/
JENT_PRIVATE_STATIC
ssize_t jent_read_entropy(struct rand_data *ec, char *data, size_t len)
{
char *p = data;
size_t orig_len = len;
int ret = 0;
if (NULL == ec)
return -1;
if (jent_notime_settick(ec))
return -4;
while (len > 0) {
size_t tocopy;
unsigned int health_test_result;
jent_random_data(ec);
if ((health_test_result = jent_health_failure(ec))) {
if (health_test_result & JENT_RCT_FAILURE)
ret = -2;
else if (health_test_result & JENT_APT_FAILURE)
ret = -3;
else
ret = -5;
goto err;
}
if ((DATA_SIZE_BITS / 8) < len)
tocopy = (DATA_SIZE_BITS / 8);
else
tocopy = len;
jent_read_random_block(ec, p, tocopy);
len -= tocopy;
p += tocopy;
}
/*
* Enhanced backtracking support: At this point, the hash state
* contains the digest of the previous Jitter RNG collection round
* which is inserted there by jent_read_random_block with the SHA
* update operation. At the current code location we completed
* one request for a caller and we do not know how long it will
* take until a new request is sent to us. To guarantee enhanced
* backtracking resistance at this point (i.e. ensure that an attacker
* cannot obtain information about prior random numbers we generated),
* but still stirring the hash state with old data the Jitter RNG
* obtains a new message digest from its state and re-inserts it.
* After this operation, the Jitter RNG state is still stirred with
* the old data, but an attacker who gets access to the memory after
* this point cannot deduce the random numbers produced by the
* Jitter RNG prior to this point.
*/
/*
* If we use secured memory, where backtracking support may not be
* needed because the state is protected in a different method,
* it is permissible to drop this support. But strongly weigh the
* pros and cons considering that the SHA3 operation is not that
* expensive.
*/
#ifndef CONFIG_CRYPTO_CPU_JITTERENTROPY_SECURE_MEMORY
jent_read_random_block(ec, NULL, 0);
#endif
err:
jent_notime_unsettick(ec);
return ret ? ret : (ssize_t)orig_len;
}
static struct rand_data *_jent_entropy_collector_alloc(unsigned int osr,
unsigned int flags);
/**
* Entry function: Obtain entropy for the caller.
*
* This is a service function to jent_read_entropy() with the difference
* that it automatically re-allocates the entropy collector if a health
* test failure is observed. Before reallocation, a new power-on health test
* is performed. The allocation of the new entropy collector automatically
* increases the OSR by one. This is done based on the idea that a health
* test failure indicates that the assumed entropy rate is too high.
*
* Note the function returns with an health test error if the OSR is
* getting too large. If an error is returned by this function, the Jitter RNG
* is not safe to be used on the current system.
*
* @ec [in] Reference to entropy collector - this is a double pointer as
* The entropy collector may be freed and reallocated.
* @data [out] pointer to buffer for storing random data -- buffer must
* already exist
* @len [in] size of the buffer, specifying also the requested number of random
* in bytes
*
* @return see jent_read_entropy()
*/
JENT_PRIVATE_STATIC
ssize_t jent_read_entropy_safe(struct rand_data **ec, char *data, size_t len)
{
char *p = data;
size_t orig_len = len;
ssize_t ret = 0;
if (!ec)
return -1;
while (len > 0) {
unsigned int osr, flags, max_mem_set;
ret = jent_read_entropy(*ec, p, len);
switch (ret) {
case -1:
case -4:
return ret;
case -2:
case -3:
case -5:
osr = (*ec)->osr + 1;
flags = (*ec)->flags;
max_mem_set = (*ec)->max_mem_set;
/* generic arbitrary cutoff */
if (osr > 20)
return ret;
/*
* If the caller did not set any specific maximum value
* let the Jitter RNG increase the maximum memory by
* one step.
*/
if (!max_mem_set)
flags = jent_update_memsize(flags);
/*
* re-allocate entropy collector with higher OSR and
* memory size
*/
jent_entropy_collector_free(*ec);
/* Perform new health test with updated OSR */
if (jent_entropy_init_ex(osr, flags))
return -1;
*ec = _jent_entropy_collector_alloc(osr, flags);
if (!*ec)
return -1;
/* Remember whether caller configured memory size */
(*ec)->max_mem_set = !!max_mem_set;
break;
default:
len -= (size_t)ret;
p += (size_t)ret;
}
}
return (ssize_t)orig_len;
}
/***************************************************************************
* Initialization logic
***************************************************************************/
/*
* Obtain memory size to allocate for memory access variations.
*
* The maximum variations we can get from the memory access is when we allocate
* a bit more memory than we have as data cache. But allocating as much
* memory as we have as data cache might strain the resources on the system
* more than necessary.
*
* On a lot of systems it is not necessary to need so much memory as the
* variations coming from the general Jitter RNG execution commonly provide
* large amount of variations.
*
* Thus, the default is:
*
* min(JENT_MEMORY_SIZE, data cache size)
*
* In case the data cache size cannot be obtained, use JENT_MEMORY_SIZE.
*
* If the caller provides a maximum memory size, use
* min(provided max memory, data cache size).
*/
static inline uint32_t jent_memsize(unsigned int flags)
{
uint32_t memsize, max_memsize;
max_memsize = JENT_FLAGS_TO_MAX_MEMSIZE(flags);
if (max_memsize == 0) {
max_memsize = JENT_MEMORY_SIZE;
} else {
max_memsize = UINT32_C(1) << (max_memsize +
JENT_MAX_MEMSIZE_OFFSET);
}
/* Allocate memory for adding variations based on memory access */
memsize = jent_cache_size_roundup();
/* Limit the memory as defined by caller */
memsize = (memsize > max_memsize) ? max_memsize : memsize;
/* Set a value if none was found */
if (!memsize)
memsize = JENT_MEMORY_SIZE;
return memsize;
}
static int jent_selftest_run = 0;
static struct rand_data
*jent_entropy_collector_alloc_internal(unsigned int osr, unsigned int flags)
{
struct rand_data *entropy_collector;
uint32_t memsize = 0;
/*
* Requesting disabling and forcing of internal timer
* makes no sense.
*/
if ((flags & JENT_DISABLE_INTERNAL_TIMER) &&
(flags & JENT_FORCE_INTERNAL_TIMER))
return NULL;
/* Force the self test to be run */
if (!jent_selftest_run && jent_entropy_init_ex(osr, flags))
return NULL;
/*
* If the initial test code concludes to force the internal timer
* and the user requests it not to be used, do not allocate
* the Jitter RNG instance.
*/
if (jent_notime_forced() && (flags & JENT_DISABLE_INTERNAL_TIMER))
return NULL;
entropy_collector = jent_zalloc(sizeof(struct rand_data));
if (NULL == entropy_collector)
return NULL;
if (!(flags & JENT_DISABLE_MEMORY_ACCESS)) {
memsize = jent_memsize(flags);
entropy_collector->mem = (unsigned char *)jent_zalloc(memsize);
#ifdef JENT_RANDOM_MEMACCESS
/*
* Transform the size into a mask - it is assumed that size is
* a power of 2.
*/
entropy_collector->memmask = memsize - 1;
#else /* JENT_RANDOM_MEMACCESS */
entropy_collector->memblocksize = memsize / JENT_MEMORY_BLOCKS;
entropy_collector->memblocks = JENT_MEMORY_BLOCKS;
/* sanity check */
if (entropy_collector->memblocksize *
entropy_collector->memblocks != memsize)
goto err;
#endif /* JENT_RANDOM_MEMACCESS */
if (entropy_collector->mem == NULL)
goto err;
entropy_collector->memaccessloops = JENT_MEMORY_ACCESSLOOPS;
}
if (sha3_alloc(&entropy_collector->hash_state))
goto err;
/* Initialize the hash state */
sha3_256_init(entropy_collector->hash_state);
/* verify and set the oversampling rate */
if (osr < JENT_MIN_OSR)
osr = JENT_MIN_OSR;
entropy_collector->osr = osr;
entropy_collector->flags = flags;
if ((flags & JENT_FORCE_FIPS) || jent_fips_enabled())
entropy_collector->fips_enabled = 1;
/* Initialize the APT */
jent_apt_init(entropy_collector, osr);
/* Initialize the Lag Predictor Test */
jent_lag_init(entropy_collector, osr);
/* Was jent_entropy_init run (establishing the common GCD)? */
if (jent_gcd_get(&entropy_collector->jent_common_timer_gcd)) {
/*
* It was not. This should probably be an error, but this
* behavior breaks the test code. Set the gcd to a value that
* won't hurt anything.
*/
entropy_collector->jent_common_timer_gcd = 1;
}
/*
* Use timer-less noise source - note, OSR must be set in
* entropy_collector!
*/
if (!(flags & JENT_DISABLE_INTERNAL_TIMER)) {
if (jent_notime_enable(entropy_collector, flags))
goto err;
}
return entropy_collector;
err:
if (entropy_collector->mem != NULL)
jent_zfree(entropy_collector->mem, memsize);
jent_zfree(entropy_collector, sizeof(struct rand_data));
return NULL;
}
static struct rand_data *_jent_entropy_collector_alloc(unsigned int osr,
unsigned int flags)
{
struct rand_data *ec = jent_entropy_collector_alloc_internal(osr,
flags);
if (!ec)
return ec;
/* fill the data pad with non-zero values */
if (jent_notime_settick(ec)) {
jent_entropy_collector_free(ec);
return NULL;
}
jent_random_data(ec);
jent_notime_unsettick(ec);
return ec;
}
JENT_PRIVATE_STATIC
struct rand_data *jent_entropy_collector_alloc(unsigned int osr,
unsigned int flags)
{
struct rand_data *ec = _jent_entropy_collector_alloc(osr, flags);
/* Remember that the caller provided a maximum size flag */
if (ec)
ec->max_mem_set = !!JENT_FLAGS_TO_MAX_MEMSIZE(flags);
return ec;
}
JENT_PRIVATE_STATIC
void jent_entropy_collector_free(struct rand_data *entropy_collector)
{
if (entropy_collector != NULL) {
sha3_dealloc(entropy_collector->hash_state);
jent_notime_disable(entropy_collector);
if (entropy_collector->mem != NULL) {
jent_zfree(entropy_collector->mem,
jent_memsize(entropy_collector->flags));
entropy_collector->mem = NULL;
}
jent_zfree(entropy_collector, sizeof(struct rand_data));
}
}
int jent_time_entropy_init(unsigned int osr, unsigned int flags)
{
struct rand_data *ec;
uint64_t *delta_history;
int i, time_backwards = 0, count_stuck = 0, ret = 0;
unsigned int health_test_result;
delta_history = jent_gcd_init(JENT_POWERUP_TESTLOOPCOUNT);
if (!delta_history)
return EMEM;
if (flags & JENT_FORCE_INTERNAL_TIMER)
jent_notime_force();
else
flags |= JENT_DISABLE_INTERNAL_TIMER;
/*
* If the start-up health tests (including the APT and RCT) are not
* run, then the entropy source is not 90B compliant. We could test if
* fips_enabled should be set using the jent_fips_enabled() function,
* but this can be overridden using the JENT_FORCE_FIPS flag, which
* isn't passed in yet. It is better to run the tests on the small
* amount of data that we have, which should not fail unless things
* are really bad.
*/
flags |= JENT_FORCE_FIPS;
ec = jent_entropy_collector_alloc_internal(osr, flags);
if (!ec) {
ret = EMEM;
goto out;
}
if (jent_notime_settick(ec)) {
ret = EMEM;
goto out;
}
/* To initialize the prior time. */
jent_measure_jitter(ec, 0, NULL);
/* 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 leading to false positives.
*/
/*
* 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.
*/
#define CLEARCACHE 100
for (i = -CLEARCACHE; i < JENT_POWERUP_TESTLOOPCOUNT; i++) {
uint64_t start_time = 0, end_time = 0, delta = 0;
unsigned int stuck;
/* Invoke core entropy collection logic */
stuck = jent_measure_jitter(ec, 0, &delta);
end_time = ec->prev_time;
start_time = ec->prev_time - delta;
/* test whether timer works */
if (!start_time || !end_time) {
ret = ENOTIME;
goto out;
}
/*
* 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 || (end_time == start_time)) {
ret = ECOARSETIME;
goto out;
}
/*
* 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 (i < 0)
continue;
if (stuck)
count_stuck++;
/* test whether we have an increasing timer */
if (!(end_time > start_time))
time_backwards++;
/* Watch for common adjacent GCD values */
jent_gcd_add_value(delta_history, delta, i);
}
/*
* 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 (time_backwards > 3) {
ret = ENOMONOTONIC;
goto out;
}
/* First, did we encounter a health test failure? */
if ((health_test_result = jent_health_failure(ec))) {
ret = (health_test_result & JENT_RCT_FAILURE) ? ERCT : EHEALTH;
goto out;
}
ret = jent_gcd_analyze(delta_history, JENT_POWERUP_TESTLOOPCOUNT);
if (ret)
goto out;
/*
* If we have more than 90% stuck results, then this Jitter RNG is
* likely to not work well.
*/
if (JENT_STUCK_INIT_THRES(JENT_POWERUP_TESTLOOPCOUNT) < count_stuck)
ret = ESTUCK;
out:
jent_gcd_fini(delta_history, JENT_POWERUP_TESTLOOPCOUNT);
if ((flags & JENT_FORCE_INTERNAL_TIMER) && ec)
jent_notime_unsettick(ec);
jent_entropy_collector_free(ec);
return ret;
}
static inline int jent_entropy_init_common_pre(void)
{
int ret;
jent_notime_block_switch();
jent_health_cb_block_switch();
if (sha3_tester())
return EHASH;
ret = jent_gcd_selftest();
jent_selftest_run = 1;
return ret;
}
static inline int jent_entropy_init_common_post(int ret)
{
/* Unmark the execution of the self tests if they failed. */
if (ret)
jent_selftest_run = 0;
return ret;
}
JENT_PRIVATE_STATIC
int jent_entropy_init(void)
{
int ret = jent_entropy_init_common_pre();
if (ret)
return ret;
ret = jent_time_entropy_init(0, JENT_DISABLE_INTERNAL_TIMER);
#ifdef JENT_CONF_ENABLE_INTERNAL_TIMER
if (ret)
ret = jent_time_entropy_init(0, JENT_FORCE_INTERNAL_TIMER);
#endif /* JENT_CONF_ENABLE_INTERNAL_TIMER */
return jent_entropy_init_common_post(ret);
}
JENT_PRIVATE_STATIC
int jent_entropy_init_ex(unsigned int osr, unsigned int flags)
{
int ret = jent_entropy_init_common_pre();
if (ret)
return ret;
ret = ENOTIME;
/* Test without internal timer unless caller does not want it */
if (!(flags & JENT_FORCE_INTERNAL_TIMER))
ret = jent_time_entropy_init(osr,
flags | JENT_DISABLE_INTERNAL_TIMER);
#ifdef JENT_CONF_ENABLE_INTERNAL_TIMER
/* Test with internal timer unless caller does not want it */
if (ret && !(flags & JENT_DISABLE_INTERNAL_TIMER))
ret = jent_time_entropy_init(osr,
flags | JENT_FORCE_INTERNAL_TIMER);
#endif /* JENT_CONF_ENABLE_INTERNAL_TIMER */
return jent_entropy_init_common_post(ret);
}
JENT_PRIVATE_STATIC
int jent_entropy_switch_notime_impl(struct jent_notime_thread *new_thread)
{
return jent_notime_switch(new_thread);
}
JENT_PRIVATE_STATIC
int jent_set_fips_failure_callback(jent_fips_failure_cb cb)
{
return jent_set_fips_failure_callback_internal(cb);
}

查看文件

@ -0,0 +1,34 @@
/*
* Copyright (C) 2021 - 2022, Stephan Mueller <smueller@chronox.de>
*
* License: see LICENSE file in root directory
*
* 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.
*/
#ifndef JITTERENTROPY_BASE_H
#define JITTERENTROPY_BASE_H
#ifdef __cplusplus
extern "C"
{
#endif
int jent_time_entropy_init(unsigned int osr, unsigned int flags);
#ifdef __cplusplus
}
#endif
#endif /* JITTERENTROPY_BASE_H */

查看文件

@ -0,0 +1,185 @@
/* Jitter RNG: GCD health test
*
* Copyright (C) 2021 - 2022, Joshua E. Hill <josh@keypair.us>
* Copyright (C) 2021 - 2022, Stephan Mueller <smueller@chronox.de>
*
* License: see LICENSE file in root directory
*
* 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.
*/
#include "jitterentropy.h"
#include "jitterentropy-gcd.h"
/* The common divisor for all timestamp deltas */
static uint64_t jent_common_timer_gcd = 0;
static inline int jent_gcd_tested(void)
{
return (jent_common_timer_gcd != 0);
}
/* A straight forward implementation of the Euclidean algorithm for GCD. */
static inline uint64_t jent_gcd64(uint64_t a, uint64_t b)
{
/* Make a greater a than or equal b. */
if (a < b) {
uint64_t c = a;
a = b;
b = c;
}
/* Now perform the standard inner-loop for this algorithm.*/
while (b != 0) {
uint64_t r;
r = a % b;
a = b;
b = r;
}
return a;
}
static int jent_gcd_analyze_internal(uint64_t *delta_history, size_t nelem,
uint64_t *running_gcd_out,
uint64_t *delta_sum_out)
{
uint64_t running_gcd, delta_sum = 0;
size_t i;
if (!delta_history)
return -EAGAIN;
running_gcd = delta_history[0];
/* Now perform the analysis on the accumulated delta data. */
for (i = 1; i < nelem; i++) {
/*
* 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
*/
if (delta_history[i] >= delta_history[i - 1])
delta_sum += delta_history[i] - delta_history[i - 1];
else
delta_sum += delta_history[i - 1] - delta_history[i];
/*
* This calculates the gcd of all the delta values. that is
* gcd(delta_1, delta_2, ..., delta_nelem)
* Some timers increment by a fixed (non-1) amount each step.
* This code checks for such increments, and allows the library
* to output the number of such changes have occurred.
*/
running_gcd = jent_gcd64(delta_history[i], running_gcd);
}
*running_gcd_out = running_gcd;
*delta_sum_out = delta_sum;
return 0;
}
int jent_gcd_analyze(uint64_t *delta_history, size_t nelem)
{
uint64_t running_gcd, delta_sum;
int ret = jent_gcd_analyze_internal(delta_history, nelem, &running_gcd,
&delta_sum);
if (ret == -EAGAIN)
return 0;
/*
* Variations of deltas of time must on average be larger than 1 to
* ensure the entropy estimation implied with 1 is preserved.
*/
if (delta_sum <= nelem - 1) {
ret = EMINVARVAR;
goto out;
}
/* Set a sensible maximum value. */
if (running_gcd >= UINT32_MAX / 2) {
ret = ECOARSETIME;
goto out;
}
/* Adjust all deltas by the observed (small) common factor. */
if (!jent_gcd_tested())
jent_common_timer_gcd = running_gcd;
out:
return ret;
}
uint64_t *jent_gcd_init(size_t nelem)
{
uint64_t *delta_history;
delta_history = jent_zalloc(nelem * sizeof(uint64_t));
if (!delta_history)
return NULL;
return delta_history;
}
void jent_gcd_fini(uint64_t *delta_history, size_t nelem)
{
if (delta_history)
jent_zfree(delta_history,
(unsigned int)(nelem * sizeof(uint64_t)));
}
int jent_gcd_get(uint64_t *value)
{
if (!jent_gcd_tested())
return 1;
*value = jent_common_timer_gcd;
return 0;
}
int jent_gcd_selftest(void)
{
#define JENT_GCD_SELFTEST_ELEM 10
#define JENT_GCD_SELFTEST_EXP 3ULL
uint64_t *gcd = jent_gcd_init(JENT_GCD_SELFTEST_ELEM);
uint64_t running_gcd, delta_sum;
unsigned int i;
int ret = EGCD;
if (!gcd)
return EMEM;
for (i = 0; i < JENT_GCD_SELFTEST_ELEM; i++)
jent_gcd_add_value(gcd, i * JENT_GCD_SELFTEST_EXP, i);
if (jent_gcd_analyze_internal(gcd, JENT_GCD_SELFTEST_ELEM,
&running_gcd, &delta_sum))
goto out;
if (running_gcd != JENT_GCD_SELFTEST_EXP)
goto out;
ret = 0;
out:
jent_gcd_fini(gcd, JENT_GCD_SELFTEST_ELEM);
return ret;
}

查看文件

@ -0,0 +1,42 @@
/*
* Copyright (C) 2021 - 2022, Stephan Mueller <smueller@chronox.de>
*
* License: see LICENSE file in root directory
*
* 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.
*/
#ifndef JITTERENTROPY_GCD_H
#define JITTERENTROPY_GCD_H
#ifdef __cplusplus
extern "C"
{
#endif
int jent_gcd_analyze(uint64_t *delta_history, size_t nelem);
uint64_t *jent_gcd_init(size_t nelem);
void jent_gcd_fini(uint64_t *delta_history, size_t nelem);
int jent_gcd_get(uint64_t *value);
int jent_gcd_selftest(void);
/* Watch for common adjacent GCD values */
#define jent_gcd_add_value(delta_history, delta, idx) \
delta_history[idx] = delta;
#ifdef __cplusplus
}
#endif
#endif /* JITTERENTROPY_GCD_H */

查看文件

@ -0,0 +1,457 @@
/* Jitter RNG: Health Tests
*
* Copyright (C) 2021 - 2022, Joshua E. Hill <josh@keypair.us>
* Copyright (C) 2021 - 2022, Stephan Mueller <smueller@chronox.de>
*
* License: see LICENSE file in root directory
*
* 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.
*/
#include "jitterentropy-health.h"
static jent_fips_failure_cb fips_cb = NULL;
static int jent_health_cb_switch_blocked = 0;
void jent_health_cb_block_switch(void)
{
jent_health_cb_switch_blocked = 1;
}
int jent_set_fips_failure_callback_internal(jent_fips_failure_cb cb)
{
if (jent_health_cb_switch_blocked)
return -EAGAIN;
fips_cb = cb;
return 0;
}
/***************************************************************************
* Lag Predictor Test
*
* This test is a vendor-defined conditional test that is designed to detect
* a known failure mode where the result becomes mostly deterministic
* Note that (lag_observations & JENT_LAG_MASK) is the index where the next
* value provided will be stored.
***************************************************************************/
#ifdef JENT_HEALTH_LAG_PREDICTOR
/*
* These cutoffs are configured using an entropy estimate of 1/osr under an
* alpha=2^(-22) for a window size of 131072. The other health tests use
* alpha=2^-30, but operate on much smaller window sizes. This larger selection
* of alpha makes the behavior per-lag-window similar to the APT test.
*
* The global cutoffs are calculated using the
* InverseBinomialCDF(n=(JENT_LAG_WINDOW_SIZE-JENT_LAG_HISTORY_SIZE), p=2^(-1/osr); 1-alpha)
* The local cutoffs are somewhat more complicated. For background, see Feller's
* _Introduction to Probability Theory and It's Applications_ Vol. 1,
* Chapter 13, section 7 (in particular see equation 7.11, where x is a root
* of the denominator of equation 7.6).
*
* We'll proceed using the notation of SP 800-90B Section 6.3.8 (which is
* developed in Kelsey-McKay-Turan paper "Predictive Models for Min-entropy
* Estimation".)
*
* Here, we set p=2^(-1/osr), seeking a run of successful guesses (r) with
* probability of less than (1-alpha). That is, it is very very likely
* (probability 1-alpha) that there is _no_ run of length r in a block of size
* JENT_LAG_WINDOW_SIZE-JENT_LAG_HISTORY_SIZE.
*
* We have to iteratively look for an appropriate value for the cutoff r.
*/
static const unsigned int jent_lag_global_cutoff_lookup[20] =
{ 66443, 93504, 104761, 110875, 114707, 117330, 119237, 120686, 121823,
122739, 123493, 124124, 124660, 125120, 125520, 125871, 126181, 126457,
126704, 126926 };
static const unsigned int jent_lag_local_cutoff_lookup[20] =
{ 38, 75, 111, 146, 181, 215, 250, 284, 318, 351,
385, 419, 452, 485, 518, 551, 584, 617, 650, 683 };
void jent_lag_init(struct rand_data *ec, unsigned int osr)
{
/*
* Establish the lag global and local cutoffs based on the presumed
* entropy rate of 1/osr.
*/
if (osr > ARRAY_SIZE(jent_lag_global_cutoff_lookup)) {
ec->lag_global_cutoff =
jent_lag_global_cutoff_lookup[
ARRAY_SIZE(jent_lag_global_cutoff_lookup) - 1];
} else {
ec->lag_global_cutoff = jent_lag_global_cutoff_lookup[osr - 1];
}
if (osr > ARRAY_SIZE(jent_lag_local_cutoff_lookup)) {
ec->lag_local_cutoff =
jent_lag_local_cutoff_lookup[
ARRAY_SIZE(jent_lag_local_cutoff_lookup) - 1];
} else {
ec->lag_local_cutoff = jent_lag_local_cutoff_lookup[osr - 1];
}
}
/**
* Reset the lag counters
*
* @ec [in] Reference to entropy collector
*/
static void jent_lag_reset(struct rand_data *ec)
{
unsigned int i;
/* Reset Lag counters */
ec->lag_prediction_success_count = 0;
ec->lag_prediction_success_run = 0;
ec->lag_best_predictor = 0; /* The first guess is basically arbitrary. */
ec->lag_observations = 0;
for (i = 0; i < JENT_LAG_HISTORY_SIZE; i++) {
ec->lag_scoreboard[i] = 0;
ec->lag_delta_history[i] = 0;
}
}
/*
* A macro for accessing the history. Index 0 is the last observed symbol
* index 1 is the symbol observed two inputs ago, etc.
*/
#define JENT_LAG_HISTORY(EC,LOC) \
((EC)->lag_delta_history[((EC)->lag_observations - (LOC) - 1) & \
JENT_LAG_MASK])
/**
* Insert a new entropy event into the lag predictor test
*
* @ec [in] Reference to entropy collector
* @current_delta [in] Current time delta
*/
static void jent_lag_insert(struct rand_data *ec, uint64_t current_delta)
{
uint64_t prediction;
unsigned int i;
/* Initialize the delta_history */
if (ec->lag_observations < JENT_LAG_HISTORY_SIZE) {
ec->lag_delta_history[ec->lag_observations] = current_delta;
ec->lag_observations++;
return;
}
/*
* The history is initialized. First make a guess and examine the
* results.
*/
prediction = JENT_LAG_HISTORY(ec, ec->lag_best_predictor);
if (prediction == current_delta) {
/* The prediction was correct. */
ec->lag_prediction_success_count++;
ec->lag_prediction_success_run++;
if ((ec->lag_prediction_success_run >= ec->lag_local_cutoff) ||
(ec->lag_prediction_success_count >= ec->lag_global_cutoff))
ec->health_failure |= JENT_LAG_FAILURE;
} else {
/* The prediction wasn't correct. End any run of successes.*/
ec->lag_prediction_success_run = 0;
}
/* Now update the predictors using the current data. */
for (i = 0; i < JENT_LAG_HISTORY_SIZE; i++) {
if (JENT_LAG_HISTORY(ec, i) == current_delta) {
/*
* The ith predictor (which guesses i + 1 symbols in
* the past) successfully guessed.
*/
ec->lag_scoreboard[i] ++;
/*
* Keep track of the best predictor (tie goes to the
* shortest lag)
*/
if (ec->lag_scoreboard[i] >
ec->lag_scoreboard[ec->lag_best_predictor])
ec->lag_best_predictor = i;
}
}
/*
* Finally, update the lag_delta_history array with the newly input
* value.
*/
ec->lag_delta_history[(ec->lag_observations) & JENT_LAG_MASK] =
current_delta;
ec->lag_observations++;
/*
* lag_best_predictor now is the index of the predictor with the largest
* number of correct guesses.
* This establishes our next guess.
*/
/* Do we now need a new window? */
if (ec->lag_observations >= JENT_LAG_WINDOW_SIZE)
jent_lag_reset(ec);
}
static inline uint64_t jent_delta2(struct rand_data *ec, uint64_t current_delta)
{
/* Note that delta2_n = delta_n - delta_{n-1} */
return jent_delta(JENT_LAG_HISTORY(ec, 0), current_delta);
}
static inline uint64_t jent_delta3(struct rand_data *ec, uint64_t delta2)
{
/*
* Note that delta3_n = delta2_n - delta2_{n-1}
* = delta2_n - (delta_{n-1} - delta_{n-2})
*/
return jent_delta(jent_delta(JENT_LAG_HISTORY(ec, 1),
JENT_LAG_HISTORY(ec, 0)), delta2);
}
#else /* JENT_HEALTH_LAG_PREDICTOR */
static inline void jent_lag_insert(struct rand_data *ec, uint64_t current_delta)
{
(void)ec;
(void)current_delta;
}
static inline uint64_t jent_delta2(struct rand_data *ec, uint64_t current_delta)
{
uint64_t delta2 = jent_delta(ec->last_delta, current_delta);
ec->last_delta = current_delta;
return delta2;
}
static inline uint64_t jent_delta3(struct rand_data *ec, uint64_t delta2)
{
uint64_t delta3 = jent_delta(ec->last_delta2, delta2);
ec->last_delta2 = delta2;
return delta3;
}
#endif /* JENT_HEALTH_LAG_PREDICTOR */
/***************************************************************************
* Adaptive Proportion Test
*
* This test complies with SP800-90B section 4.4.2.
***************************************************************************/
/*
* See the SP 800-90B comment #10b for the corrected cutoff for the SP 800-90B
* APT.
* http://www.untruth.org/~josh/sp80090b/UL%20SP800-90B-final%20comments%20v1.9%2020191212.pdf
* In in the syntax of R, this is C = 2 + qbinom(1 2^(30), 511, 2^(-1/osr)).
* (The original formula wasn't correct because the first symbol must
* necessarily have been observed, so there is no chance of observing 0 of these
* symbols.)
*
* For any value above 14, this yields the maximal allowable value of 512
* (by FIPS 140-2 IG 7.19 Resolution # 16, we cannot choose a cutoff value that
* renders the test unable to fail).
*/
static const unsigned int jent_apt_cutoff_lookup[15]=
{ 325, 422, 459, 477, 488, 494, 499, 502,
505, 507, 508, 509, 510, 511, 512 };
void jent_apt_init(struct rand_data *ec, unsigned int osr)
{
/*
* Establish the apt_cutoff based on the presumed entropy rate of
* 1/osr.
*/
if (osr >= ARRAY_SIZE(jent_apt_cutoff_lookup)) {
ec->apt_cutoff = jent_apt_cutoff_lookup[
ARRAY_SIZE(jent_apt_cutoff_lookup) - 1];
} else {
ec->apt_cutoff = jent_apt_cutoff_lookup[osr - 1];
}
}
/**
* Reset the APT counter
*
* @ec [in] Reference to entropy collector
*/
static void jent_apt_reset(struct rand_data *ec)
{
/* When reset, accept the _next_ value input as the new base. */
ec->apt_base_set = 0;
}
/**
* Insert a new entropy event into APT
*
* @ec [in] Reference to entropy collector
* @current_delta [in] Current time delta
*/
static void jent_apt_insert(struct rand_data *ec, uint64_t current_delta)
{
/* Initialize the base reference */
if (!ec->apt_base_set) {
ec->apt_base = current_delta; /* APT Step 1 */
ec->apt_base_set = 1; /* APT Step 2 */
/*
* Reset APT counter
* Note that we've taken in the first symbol in the window.
*/
ec->apt_count = 1; /* B = 1 */
ec->apt_observations = 1;
return;
}
if (current_delta == ec->apt_base) {
ec->apt_count++; /* B = B + 1 */
/* Note, ec->apt_count starts with one. */
if (ec->apt_count >= ec->apt_cutoff)
ec->health_failure |= JENT_APT_FAILURE;
}
ec->apt_observations++;
/* Completed one window, the next symbol input will be new apt_base. */
if (ec->apt_observations >= JENT_APT_WINDOW_SIZE)
jent_apt_reset(ec); /* APT Step 4 */
}
/***************************************************************************
* Stuck Test and its use as Repetition Count Test
*
* The Jitter RNG uses an enhanced version of the Repetition Count Test
* (RCT) specified in SP800-90B section 4.4.1. Instead of counting identical
* back-to-back values, the input to the RCT is the counting of the stuck
* values during the generation of one Jitter RNG output block.
*
* The RCT is applied with an alpha of 2^{-30} compliant to FIPS 140-2 IG 9.8.
*
* During the counting operation, the Jitter RNG always calculates the RCT
* cut-off value of C. If that value exceeds the allowed cut-off value,
* the Jitter RNG output block will be calculated completely but discarded at
* the end. The caller of the Jitter RNG is informed with an error code.
***************************************************************************/
/**
* Repetition Count Test as defined in SP800-90B section 4.4.1
*
* @ec [in] Reference to entropy collector
* @stuck [in] Indicator whether the value is stuck
*/
static void jent_rct_insert(struct rand_data *ec, int stuck)
{
/*
* If we have a count less than zero, a previous RCT round identified
* a failure. We will not overwrite it.
*/
if (ec->rct_count < 0)
return;
if (stuck) {
ec->rct_count++;
/*
* The cutoff value is based on the following consideration:
* alpha = 2^-30 as recommended in FIPS 140-2 IG 9.8.
* In addition, we require an entropy value H of 1/osr as this
* is the minimum entropy required to provide full entropy.
* Note, we collect (DATA_SIZE_BITS + ENTROPY_SAFETY_FACTOR)*osr
* deltas for inserting them into the entropy pool which should
* then have (close to) DATA_SIZE_BITS bits of entropy in the
* conditioned output.
*
* Note, ec->rct_count (which equals to value B in the pseudo
* code of SP800-90B section 4.4.1) starts with zero. Hence
* we need to subtract one from the cutoff value as calculated
* following SP800-90B. Thus C = ceil(-log_2(alpha)/H) = 30*osr.
*/
if ((unsigned int)ec->rct_count >= (30 * ec->osr)) {
ec->rct_count = -1;
ec->health_failure |= JENT_RCT_FAILURE;
}
} else {
ec->rct_count = 0;
}
}
/**
* Stuck test by checking the:
* 1st derivative of the jitter measurement (time delta)
* 2nd derivative of the jitter measurement (delta of time deltas)
* 3rd derivative of the jitter measurement (delta of delta of time deltas)
*
* All values must always be non-zero.
*
* @ec [in] Reference to entropy collector
* @current_delta [in] Jitter time delta
*
* @return
* 0 jitter measurement not stuck (good bit)
* 1 jitter measurement stuck (reject bit)
*/
unsigned int jent_stuck(struct rand_data *ec, uint64_t current_delta)
{
uint64_t delta2 = jent_delta2(ec, current_delta);
uint64_t delta3 = jent_delta3(ec, delta2);
/*
* Insert the result of the comparison of two back-to-back time
* deltas.
*/
jent_apt_insert(ec, current_delta);
jent_lag_insert(ec, current_delta);
if (!current_delta || !delta2 || !delta3) {
/* RCT with a stuck bit */
jent_rct_insert(ec, 1);
return 1;
}
/* RCT with a non-stuck bit */
jent_rct_insert(ec, 0);
return 0;
}
/**
* Report any health test failures
*
* @ec [in] Reference to entropy collector
*
* @return a bitmask indicating which tests failed
* 0 No health test failure
* 1 RCT failure
* 2 APT failure
* 4 Lag predictor test failure
*/
unsigned int jent_health_failure(struct rand_data *ec)
{
/* Test is only enabled in FIPS mode */
if (!ec->fips_enabled)
return 0;
if (fips_cb && ec->health_failure) {
fips_cb(ec, ec->health_failure);
}
return ec->health_failure;
}

查看文件

@ -0,0 +1,56 @@
/*
* Copyright (C) 2021 - 2022, Stephan Mueller <smueller@chronox.de>
*
* License: see LICENSE file in root directory
*
* 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.
*/
#ifndef JITTERENTROPY_HEALTH_H
#define JITTERENTROPY_HEALTH_H
#include "jitterentropy.h"
#ifdef __cplusplus
extern "C"
{
#endif
void jent_health_cb_block_switch(void);
int jent_set_fips_failure_callback_internal(jent_fips_failure_cb cb);
static inline uint64_t jent_delta(uint64_t prev, uint64_t next)
{
return (next - prev);
}
#ifdef JENT_HEALTH_LAG_PREDICTOR
void jent_lag_init(struct rand_data *ec, unsigned int osr);
#else /* JENT_HEALTH_LAG_PREDICTOR */
static inline void jent_lag_init(struct rand_data *ec, unsigned int osr)
{
(void)ec;
(void)osr;
}
#endif /* JENT_HEALTH_LAG_PREDICTOR */
void jent_apt_init(struct rand_data *ec, unsigned int osr);
unsigned int jent_stuck(struct rand_data *ec, uint64_t current_delta);
unsigned int jent_health_failure(struct rand_data *ec);
#ifdef __cplusplus
}
#endif
#endif /* JITTERENTROPY_HEALTH_H */

查看文件

@ -0,0 +1,424 @@
/* Jitter RNG: Noise Sources
*
* Copyright (C) 2021 - 2022, Stephan Mueller <smueller@chronox.de>
*
* License: see LICENSE file in root directory
*
* 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.
*/
#include "jitterentropy-noise.h"
#include "jitterentropy-health.h"
#include "jitterentropy-timer.h"
#include "jitterentropy-sha3.h"
#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
/***************************************************************************
* Noise sources
***************************************************************************/
/**
* Update of the loop count used for the next round of
* an entropy collection.
*
* @ec [in] entropy collector struct
* @bits [in] is the number of low bits of the timer to consider
* @min [in] 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 uint64_t jent_loop_shuffle(struct rand_data *ec,
unsigned int bits, unsigned int min)
{
#ifdef JENT_CONF_DISABLE_LOOP_SHUFFLE
(void)ec;
(void)bits;
return (UINT64_C(1)<<min);
#else /* JENT_CONF_DISABLE_LOOP_SHUFFLE */
uint64_t time = 0;
uint64_t shuffle = 0;
uint64_t mask = (UINT64_C(1)<<bits) - 1;
unsigned int i = 0;
/*
* Mix the current state of the random number into the shuffle
* calculation to balance that shuffle a bit more.
*/
jent_get_nstime_internal(ec, &time);
/*
* We fold the time value as much as possible to ensure that as many
* bits of the time stamp are included as possible.
*/
for (i = 0; (((sizeof(time) << 3) + bits - 1) / bits) > i; i++) {
shuffle ^= time & mask;
time = time >> bits;
}
/*
* We add a lower boundary value to ensure we have a minimum
* RNG loop count.
*/
return (shuffle + (UINT64_C(1)<<min));
#endif /* JENT_CONF_DISABLE_LOOP_SHUFFLE */
}
/**
* CPU Jitter noise source -- this is the noise source based on the CPU
* execution time jitter
*
* This function injects the individual bits of the time value into the
* entropy pool using a hash.
*
* @ec [in] entropy collector struct
* @time [in] time delta to be injected
* @loop_cnt [in] if a value not equal to 0 is set, use the given value as
* number of loops to perform the hash operation
* @stuck [in] Is the time delta identified as stuck?
*
* Output:
* updated hash context
*/
static void jent_hash_time(struct rand_data *ec, uint64_t time,
uint64_t loop_cnt, unsigned int stuck)
{
HASH_CTX_ON_STACK(ctx);
uint8_t intermediary[SHA3_256_SIZE_DIGEST];
uint64_t j = 0;
#define MAX_HASH_LOOP 3
#define MIN_HASH_LOOP 0
/* Ensure that macros cannot overflow jent_loop_shuffle() */
BUILD_BUG_ON((MAX_HASH_LOOP + MIN_HASH_LOOP) > 63);
uint64_t hash_loop_cnt =
jent_loop_shuffle(ec, MAX_HASH_LOOP, MIN_HASH_LOOP);
/* Use the memset to shut up valgrind */
memset(intermediary, 0, sizeof(intermediary));
sha3_256_init(&ctx);
/*
* testing purposes -- allow test app to set the counter, not
* needed during runtime
*/
if (loop_cnt)
hash_loop_cnt = loop_cnt;
/*
* This loop fills a buffer which is injected into the entropy pool.
* The main reason for this loop is to execute something over which we
* can perform a timing measurement. The injection of the resulting
* data into the pool is performed to ensure the result is used and
* the compiler cannot optimize the loop away in case the result is not
* used at all. Yet that data is considered "additional information"
* considering the terminology from SP800-90A without any entropy.
*
* Note, it does not matter which or how much data you inject, we are
* interested in one Keccack1600 compression operation performed with
* the sha3_final.
*/
for (j = 0; j < hash_loop_cnt; j++) {
sha3_update(&ctx, intermediary, sizeof(intermediary));
sha3_update(&ctx, (uint8_t *)&ec->rct_count,
sizeof(ec->rct_count));
sha3_update(&ctx, (uint8_t *)&ec->apt_cutoff,
sizeof(ec->apt_cutoff));
sha3_update(&ctx, (uint8_t *)&ec->apt_observations,
sizeof(ec->apt_observations));
sha3_update(&ctx, (uint8_t *)&ec->apt_count,
sizeof(ec->apt_count));
sha3_update(&ctx,(uint8_t *) &ec->apt_base,
sizeof(ec->apt_base));
sha3_update(&ctx, (uint8_t *)&j, sizeof(uint64_t));
sha3_final(&ctx, intermediary);
}
/*
* Inject the data from the previous loop into the pool. This data is
* not considered to contain any entropy, but it stirs the pool a bit.
*/
sha3_update(ec->hash_state, intermediary, sizeof(intermediary));
/*
* Insert the time stamp into the hash context representing the pool.
*
* If the time stamp is stuck, do not finally insert the value into the
* entropy pool. Although this operation should not do any harm even
* when the time stamp has no entropy, SP800-90B requires that any
* conditioning operation to have an identical amount of input data
* according to section 3.1.5.
*/
if (!stuck)
sha3_update(ec->hash_state, (uint8_t *)&time, sizeof(uint64_t));
jent_memset_secure(&ctx, SHA_MAX_CTX_SIZE);
jent_memset_secure(intermediary, sizeof(intermediary));
}
#define MAX_ACC_LOOP_BIT 7
#define MIN_ACC_LOOP_BIT 0
#ifdef JENT_RANDOM_MEMACCESS
static inline uint32_t uint32rotl(const uint32_t x, int k)
{
return (x << k) | (x >> (32 - k));
}
static inline uint32_t xoshiro128starstar(uint32_t *s)
{
const uint32_t result = uint32rotl(s[1] * 5, 7) * 9;
const uint32_t t = s[1] << 9;
s[2] ^= s[0];
s[3] ^= s[1];
s[1] ^= s[2];
s[0] ^= s[3];
s[2] ^= t;
s[3] = uint32rotl(s[3], 11);
return result;
}
static void jent_memaccess(struct rand_data *ec, uint64_t loop_cnt)
{
uint64_t i = 0, time = 0;
union {
uint32_t u[4];
uint8_t b[sizeof(uint32_t) * 4];
} prngState = { .u = {0x8e93eec0, 0xce65608a, 0xa8d46b46, 0xe83cef69} };
uint32_t addressMask;
/* Ensure that macros cannot overflow jent_loop_shuffle() */
BUILD_BUG_ON((MAX_ACC_LOOP_BIT + MIN_ACC_LOOP_BIT) > 63);
uint64_t acc_loop_cnt =
jent_loop_shuffle(ec, MAX_ACC_LOOP_BIT, MIN_ACC_LOOP_BIT);
if (NULL == ec || NULL == ec->mem)
return;
addressMask = ec->memmask;
/*
* Mix the current data into prngState
*
* Any time you see a PRNG in a noise source, you should be concerned.
*
* The PRNG doesnt directly produce the raw noise, it just adjusts the
* location being updated. The timing of the update is part of the raw
* sample. The main thing this process gets you isnt better
* per-update timing, it gets you mostly independent per-update
* timing, so we can now benefit from the Central Limit Theorem!
*/
for (i = 0; i < sizeof(prngState); i++) {
jent_get_nstime_internal(ec, &time);
prngState.b[i] ^= (uint8_t)(time & 0xff);
}
/*
* 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++) {
/* Take PRNG output to find the memory location to update. */
unsigned char *tmpval = ec->mem +
(xoshiro128starstar(prngState.u) &
addressMask);
/*
* memory access: just add 1 to one byte,
* wrap at 255 -- memory access implies read
* from and write to memory location
*/
*tmpval = (unsigned char)((*tmpval + 1) & 0xff);
}
}
#else /* JENT_RANDOM_MEMACCESS */
/**
* 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.
*
* @ec [in] 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 [in] if a value not equal to 0 is set, use the given value as
* number of loops to perform the hash operation
*/
static void jent_memaccess(struct rand_data *ec, uint64_t loop_cnt)
{
unsigned int wrap = 0;
uint64_t i = 0;
/* Ensure that macros cannot overflow jent_loop_shuffle() */
BUILD_BUG_ON((MAX_ACC_LOOP_BIT + MIN_ACC_LOOP_BIT) > 63);
uint64_t acc_loop_cnt =
jent_loop_shuffle(ec, MAX_ACC_LOOP_BIT, MIN_ACC_LOOP_BIT);
if (NULL == ec || NULL == ec->mem)
return;
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++) {
unsigned char *tmpval = ec->mem + ec->memlocation;
/*
* memory access: just add 1 to one byte,
* wrap at 255 -- memory access implies read
* from and write to memory location
*/
*tmpval = (unsigned char)((*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;
}
}
#endif /* JENT_RANDOM_MEMACCESS */
/***************************************************************************
* Start of entropy processing logic
***************************************************************************/
/**
* This is the heart of the entropy generation: calculate time deltas and
* use the CPU jitter in the time deltas. The jitter is injected into the
* entropy pool.
*
* 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.
*
* @ec [in] Reference to entropy collector
* @loop_cnt [in] see jent_hash_time
* @ret_current_delta [out] Test interface: return time delta - may be NULL
*
* @return: result of stuck test
*/
unsigned int jent_measure_jitter(struct rand_data *ec,
uint64_t loop_cnt,
uint64_t *ret_current_delta)
{
uint64_t time = 0;
uint64_t current_delta = 0;
unsigned int stuck;
/* Invoke one noise source before time measurement to add variations */
jent_memaccess(ec, loop_cnt);
/*
* Get time stamp and calculate time delta to previous
* invocation to measure the timing variations
*/
jent_get_nstime_internal(ec, &time);
current_delta = jent_delta(ec->prev_time, time) /
ec->jent_common_timer_gcd;
ec->prev_time = time;
/* Check whether we have a stuck measurement. */
stuck = jent_stuck(ec, current_delta);
/* Now call the next noise sources which also injects the data */
jent_hash_time(ec, current_delta, loop_cnt, stuck);
/* return the raw entropy value */
if (ret_current_delta)
*ret_current_delta = current_delta;
return stuck;
}
/**
* Generator of one 256 bit random number
* Function fills rand_data->hash_state
*
* @ec [in] Reference to entropy collector
*/
void jent_random_data(struct rand_data *ec)
{
unsigned int k = 0, safety_factor = 0;
if (ec->fips_enabled)
safety_factor = ENTROPY_SAFETY_FACTOR;
/* priming of the ->prev_time value */
jent_measure_jitter(ec, 0, NULL);
while (!jent_health_failure(ec)) {
/* If a stuck measurement is received, repeat measurement */
if (jent_measure_jitter(ec, 0, NULL))
continue;
/*
* We multiply the loop value with ->osr to obtain the
* oversampling rate requested by the caller
*/
if (++k >= ((DATA_SIZE_BITS + safety_factor) * ec->osr))
break;
}
}
void jent_read_random_block(struct rand_data *ec, char *dst, size_t dst_len)
{
uint8_t jent_block[SHA3_256_SIZE_DIGEST];
BUILD_BUG_ON(SHA3_256_SIZE_DIGEST != (DATA_SIZE_BITS / 8));
/* The final operation automatically re-initializes the ->hash_state */
sha3_final(ec->hash_state, jent_block);
if (dst_len)
memcpy(dst, jent_block, dst_len);
/*
* Stir the new state with the data from the old state - the digest
* of the old data is not considered to have entropy.
*/
sha3_update(ec->hash_state, jent_block, sizeof(jent_block));
jent_memset_secure(jent_block, sizeof(jent_block));
}

查看文件

@ -0,0 +1,40 @@
/*
* Copyright (C) 2021 - 2022, Stephan Mueller <smueller@chronox.de>
*
* License: see LICENSE file in root directory
*
* 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.
*/
#ifndef JITTERENTROPY_NOISE_H
#define JITTERENTROPY_NOISE_H
#include "jitterentropy.h"
#ifdef __cplusplus
extern "C"
{
#endif
unsigned int jent_measure_jitter(struct rand_data *ec,
uint64_t loop_cnt,
uint64_t *ret_current_delta);
void jent_random_data(struct rand_data *ec);
void jent_read_random_block(struct rand_data *ec, char *dst, size_t dst_len);
#ifdef __cplusplus
}
#endif
#endif /* JITTERENTROPY_NOISE_H */

查看文件

@ -0,0 +1,403 @@
/* Jitter RNG: SHA-3 Implementation
*
* Copyright (C) 2021 - 2022, Stephan Mueller <smueller@chronox.de>
*
* License: see LICENSE file in root directory
*
* 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.
*/
#include "jitterentropy-sha3.h"
#include "jitterentropy.h"
/***************************************************************************
* Message Digest Implementation
***************************************************************************/
/*
* Conversion of Little-Endian representations in byte streams - the data
* representation in the integer values is the host representation.
*/
static inline uint32_t ptr_to_le32(const uint8_t *p)
{
return (uint32_t)p[0] | (uint32_t)p[1] << 8 |
(uint32_t)p[2] << 16 | (uint32_t)p[3] << 24;
}
static inline uint64_t ptr_to_le64(const uint8_t *p)
{
return (uint64_t)ptr_to_le32(p) | (uint64_t)ptr_to_le32(p + 4) << 32;
}
static inline void le32_to_ptr(uint8_t *p, const uint32_t value)
{
p[0] = (uint8_t)(value);
p[1] = (uint8_t)(value >> 8);
p[2] = (uint8_t)(value >> 16);
p[3] = (uint8_t)(value >> 24);
}
static inline void le64_to_ptr(uint8_t *p, const uint64_t value)
{
le32_to_ptr(p + 4, (uint32_t)(value >> 32));
le32_to_ptr(p, (uint32_t)(value));
}
/*********************************** Keccak ***********************************/
/* state[x + y*5] */
#define A(x, y) (x + 5 * y)
static inline void keccakp_theta(uint64_t s[25])
{
uint64_t C[5], D[5];
/* Step 1 */
C[0] = s[A(0, 0)] ^ s[A(0, 1)] ^ s[A(0, 2)] ^ s[A(0, 3)] ^ s[A(0, 4)];
C[1] = s[A(1, 0)] ^ s[A(1, 1)] ^ s[A(1, 2)] ^ s[A(1, 3)] ^ s[A(1, 4)];
C[2] = s[A(2, 0)] ^ s[A(2, 1)] ^ s[A(2, 2)] ^ s[A(2, 3)] ^ s[A(2, 4)];
C[3] = s[A(3, 0)] ^ s[A(3, 1)] ^ s[A(3, 2)] ^ s[A(3, 3)] ^ s[A(3, 4)];
C[4] = s[A(4, 0)] ^ s[A(4, 1)] ^ s[A(4, 2)] ^ s[A(4, 3)] ^ s[A(4, 4)];
/* Step 2 */
D[0] = C[4] ^ rol64(C[1], 1);
D[1] = C[0] ^ rol64(C[2], 1);
D[2] = C[1] ^ rol64(C[3], 1);
D[3] = C[2] ^ rol64(C[4], 1);
D[4] = C[3] ^ rol64(C[0], 1);
/* Step 3 */
s[A(0, 0)] ^= D[0];
s[A(1, 0)] ^= D[1];
s[A(2, 0)] ^= D[2];
s[A(3, 0)] ^= D[3];
s[A(4, 0)] ^= D[4];
s[A(0, 1)] ^= D[0];
s[A(1, 1)] ^= D[1];
s[A(2, 1)] ^= D[2];
s[A(3, 1)] ^= D[3];
s[A(4, 1)] ^= D[4];
s[A(0, 2)] ^= D[0];
s[A(1, 2)] ^= D[1];
s[A(2, 2)] ^= D[2];
s[A(3, 2)] ^= D[3];
s[A(4, 2)] ^= D[4];
s[A(0, 3)] ^= D[0];
s[A(1, 3)] ^= D[1];
s[A(2, 3)] ^= D[2];
s[A(3, 3)] ^= D[3];
s[A(4, 3)] ^= D[4];
s[A(0, 4)] ^= D[0];
s[A(1, 4)] ^= D[1];
s[A(2, 4)] ^= D[2];
s[A(3, 4)] ^= D[3];
s[A(4, 4)] ^= D[4];
}
static inline void keccakp_rho(uint64_t s[25])
{
/* Step 1 */
/* s[A(0, 0)] = s[A(0, 0)]; */
#define RHO_ROL(t) (((t + 1) * (t + 2) / 2) % 64)
/* Step 3 */
s[A(1, 0)] = rol64(s[A(1, 0)], RHO_ROL(0));
s[A(0, 2)] = rol64(s[A(0, 2)], RHO_ROL(1));
s[A(2, 1)] = rol64(s[A(2, 1)], RHO_ROL(2));
s[A(1, 2)] = rol64(s[A(1, 2)], RHO_ROL(3));
s[A(2, 3)] = rol64(s[A(2, 3)], RHO_ROL(4));
s[A(3, 3)] = rol64(s[A(3, 3)], RHO_ROL(5));
s[A(3, 0)] = rol64(s[A(3, 0)], RHO_ROL(6));
s[A(0, 1)] = rol64(s[A(0, 1)], RHO_ROL(7));
s[A(1, 3)] = rol64(s[A(1, 3)], RHO_ROL(8));
s[A(3, 1)] = rol64(s[A(3, 1)], RHO_ROL(9));
s[A(1, 4)] = rol64(s[A(1, 4)], RHO_ROL(10));
s[A(4, 4)] = rol64(s[A(4, 4)], RHO_ROL(11));
s[A(4, 0)] = rol64(s[A(4, 0)], RHO_ROL(12));
s[A(0, 3)] = rol64(s[A(0, 3)], RHO_ROL(13));
s[A(3, 4)] = rol64(s[A(3, 4)], RHO_ROL(14));
s[A(4, 3)] = rol64(s[A(4, 3)], RHO_ROL(15));
s[A(3, 2)] = rol64(s[A(3, 2)], RHO_ROL(16));
s[A(2, 2)] = rol64(s[A(2, 2)], RHO_ROL(17));
s[A(2, 0)] = rol64(s[A(2, 0)], RHO_ROL(18));
s[A(0, 4)] = rol64(s[A(0, 4)], RHO_ROL(19));
s[A(4, 2)] = rol64(s[A(4, 2)], RHO_ROL(20));
s[A(2, 4)] = rol64(s[A(2, 4)], RHO_ROL(21));
s[A(4, 1)] = rol64(s[A(4, 1)], RHO_ROL(22));
s[A(1, 1)] = rol64(s[A(1, 1)], RHO_ROL(23));
}
static inline void keccakp_pi(uint64_t s[25])
{
uint64_t t = s[A(4, 4)];
/* Step 1 */
/* s[A(0, 0)] = s[A(0, 0)]; */
s[A(4, 4)] = s[A(1, 4)];
s[A(1, 4)] = s[A(3, 1)];
s[A(3, 1)] = s[A(1, 3)];
s[A(1, 3)] = s[A(0, 1)];
s[A(0, 1)] = s[A(3, 0)];
s[A(3, 0)] = s[A(3, 3)];
s[A(3, 3)] = s[A(2, 3)];
s[A(2, 3)] = s[A(1, 2)];
s[A(1, 2)] = s[A(2, 1)];
s[A(2, 1)] = s[A(0, 2)];
s[A(0, 2)] = s[A(1, 0)];
s[A(1, 0)] = s[A(1, 1)];
s[A(1, 1)] = s[A(4, 1)];
s[A(4, 1)] = s[A(2, 4)];
s[A(2, 4)] = s[A(4, 2)];
s[A(4, 2)] = s[A(0, 4)];
s[A(0, 4)] = s[A(2, 0)];
s[A(2, 0)] = s[A(2, 2)];
s[A(2, 2)] = s[A(3, 2)];
s[A(3, 2)] = s[A(4, 3)];
s[A(4, 3)] = s[A(3, 4)];
s[A(3, 4)] = s[A(0, 3)];
s[A(0, 3)] = s[A(4, 0)];
s[A(4, 0)] = t;
}
static inline void keccakp_chi(uint64_t s[25])
{
uint64_t t0[5], t1[5];
t0[0] = s[A(0, 0)];
t0[1] = s[A(0, 1)];
t0[2] = s[A(0, 2)];
t0[3] = s[A(0, 3)];
t0[4] = s[A(0, 4)];
t1[0] = s[A(1, 0)];
t1[1] = s[A(1, 1)];
t1[2] = s[A(1, 2)];
t1[3] = s[A(1, 3)];
t1[4] = s[A(1, 4)];
s[A(0, 0)] ^= ~s[A(1, 0)] & s[A(2, 0)];
s[A(0, 1)] ^= ~s[A(1, 1)] & s[A(2, 1)];
s[A(0, 2)] ^= ~s[A(1, 2)] & s[A(2, 2)];
s[A(0, 3)] ^= ~s[A(1, 3)] & s[A(2, 3)];
s[A(0, 4)] ^= ~s[A(1, 4)] & s[A(2, 4)];
s[A(1, 0)] ^= ~s[A(2, 0)] & s[A(3, 0)];
s[A(1, 1)] ^= ~s[A(2, 1)] & s[A(3, 1)];
s[A(1, 2)] ^= ~s[A(2, 2)] & s[A(3, 2)];
s[A(1, 3)] ^= ~s[A(2, 3)] & s[A(3, 3)];
s[A(1, 4)] ^= ~s[A(2, 4)] & s[A(3, 4)];
s[A(2, 0)] ^= ~s[A(3, 0)] & s[A(4, 0)];
s[A(2, 1)] ^= ~s[A(3, 1)] & s[A(4, 1)];
s[A(2, 2)] ^= ~s[A(3, 2)] & s[A(4, 2)];
s[A(2, 3)] ^= ~s[A(3, 3)] & s[A(4, 3)];
s[A(2, 4)] ^= ~s[A(3, 4)] & s[A(4, 4)];
s[A(3, 0)] ^= ~s[A(4, 0)] & t0[0];
s[A(3, 1)] ^= ~s[A(4, 1)] & t0[1];
s[A(3, 2)] ^= ~s[A(4, 2)] & t0[2];
s[A(3, 3)] ^= ~s[A(4, 3)] & t0[3];
s[A(3, 4)] ^= ~s[A(4, 4)] & t0[4];
s[A(4, 0)] ^= ~t0[0] & t1[0];
s[A(4, 1)] ^= ~t0[1] & t1[1];
s[A(4, 2)] ^= ~t0[2] & t1[2];
s[A(4, 3)] ^= ~t0[3] & t1[3];
s[A(4, 4)] ^= ~t0[4] & t1[4];
}
static const uint64_t keccakp_iota_vals[] = {
0x0000000000000001ULL, 0x0000000000008082ULL, 0x800000000000808aULL,
0x8000000080008000ULL, 0x000000000000808bULL, 0x0000000080000001ULL,
0x8000000080008081ULL, 0x8000000000008009ULL, 0x000000000000008aULL,
0x0000000000000088ULL, 0x0000000080008009ULL, 0x000000008000000aULL,
0x000000008000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL,
0x8000000000008003ULL, 0x8000000000008002ULL, 0x8000000000000080ULL,
0x000000000000800aULL, 0x800000008000000aULL, 0x8000000080008081ULL,
0x8000000000008080ULL, 0x0000000080000001ULL, 0x8000000080008008ULL
};
static inline void keccakp_iota(uint64_t s[25], unsigned int round)
{
s[0] ^= keccakp_iota_vals[round];
}
static inline void keccakp_1600(uint64_t s[25])
{
unsigned int round;
for (round = 0; round < 24; round++) {
keccakp_theta(s);
keccakp_rho(s);
keccakp_pi(s);
keccakp_chi(s);
keccakp_iota(s, round);
}
}
/*********************************** SHA-3 ************************************/
static inline void sha3_init(struct sha_ctx *ctx)
{
unsigned int i;
for (i = 0; i < 25; i++)
ctx->state[i] = 0;
ctx->msg_len = 0;
}
void sha3_256_init(struct sha_ctx *ctx)
{
sha3_init(ctx);
ctx->r = SHA3_256_SIZE_BLOCK;
ctx->rword = SHA3_256_SIZE_BLOCK / sizeof(uint64_t);
ctx->digestsize = SHA3_256_SIZE_DIGEST;
}
static inline void sha3_fill_state(struct sha_ctx *ctx, const uint8_t *in)
{
unsigned int i;
for (i = 0; i < ctx->rword; i++) {
ctx->state[i] ^= ptr_to_le64(in);
in += 8;
}
}
void sha3_update(struct sha_ctx *ctx, const uint8_t *in, size_t inlen)
{
size_t partial = ctx->msg_len % ctx->r;
ctx->msg_len += inlen;
/* Sponge absorbing phase */
/* Check if we have a partial block stored */
if (partial) {
size_t todo = ctx->r - partial;
/*
* If the provided data is small enough to fit in the partial
* buffer, copy it and leave it unprocessed.
*/
if (inlen < todo) {
memcpy(ctx->partial + partial, in, inlen);
return;
}
/*
* The input data is large enough to fill the entire partial
* block buffer. Thus, we fill it and transform it.
*/
memcpy(ctx->partial + partial, in, todo);
inlen -= todo;
in += todo;
sha3_fill_state(ctx, ctx->partial);
keccakp_1600(ctx->state);
}
/* Perform a transformation of full block-size messages */
for (; inlen >= ctx->r; inlen -= ctx->r, in += ctx->r) {
sha3_fill_state(ctx, in);
keccakp_1600(ctx->state);
}
/* If we have data left, copy it into the partial block buffer */
memcpy(ctx->partial, in, inlen);
}
void sha3_final(struct sha_ctx *ctx, uint8_t *digest)
{
size_t partial = ctx->msg_len % ctx->r;
unsigned int i;
/* Final round in sponge absorbing phase */
/* Fill the unused part of the partial buffer with zeros */
memset(ctx->partial + partial, 0, ctx->r - partial);
/*
* Add the leading and trailing bit as well as the 01 bits for the
* SHA-3 suffix.
*/
ctx->partial[partial] = 0x06;
ctx->partial[ctx->r - 1] |= 0x80;
/* Final transformation */
sha3_fill_state(ctx, ctx->partial);
keccakp_1600(ctx->state);
/*
* Sponge squeeze phase - the digest size is always smaller as the
* state size r which implies we only have one squeeze round.
*/
for (i = 0; i < ctx->digestsize / 8; i++, digest += 8)
le64_to_ptr(digest, ctx->state[i]);
/* Add remaining 4 bytes if we use SHA3-224 */
if (ctx->digestsize % 8)
le32_to_ptr(digest, (uint32_t)(ctx->state[i]));
memset(ctx->partial, 0, ctx->r);
sha3_init(ctx);
}
int sha3_tester(void)
{
HASH_CTX_ON_STACK(ctx);
static const uint8_t msg_256[] = { 0x5E, 0x5E, 0xD6 };
static const uint8_t exp_256[] = { 0xF1, 0x6E, 0x66, 0xC0, 0x43, 0x72,
0xB4, 0xA3, 0xE1, 0xE3, 0x2E, 0x07,
0xC4, 0x1C, 0x03, 0x40, 0x8A, 0xD5,
0x43, 0x86, 0x8C, 0xC4, 0x0E, 0xC5,
0x5E, 0x00, 0xBB, 0xBB, 0xBD, 0xF5,
0x91, 0x1E };
uint8_t act[SHA3_256_SIZE_DIGEST] = { 0 };
unsigned int i;
sha3_256_init(&ctx);
sha3_update(&ctx, msg_256, 3);
sha3_final(&ctx, act);
for (i = 0; i < SHA3_256_SIZE_DIGEST; i++) {
if (exp_256[i] != act[i])
return 1;
}
return 0;
}
int sha3_alloc(void **hash_state)
{
struct sha_ctx *tmp;
tmp = jent_zalloc(SHA_MAX_CTX_SIZE);
if (!tmp)
return 1;
*hash_state = tmp;
return 0;
}
void sha3_dealloc(void *hash_state)
{
struct sha_ctx *ctx = (struct sha_ctx *)hash_state;
jent_zfree(ctx, SHA_MAX_CTX_SIZE);
}

查看文件

@ -0,0 +1,58 @@
/*
* Copyright (C) 2021 - 2022, Stephan Mueller <smueller@chronox.de>
*
* License: see LICENSE file in root directory
*
* 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.
*/
#ifndef JITTERENTROPY_SHA3_H
#define JITTERENTROPY_SHA3_H
#include "jitterentropy.h"
#ifdef __cplusplus
extern "C"
{
#endif
#define SHA3_SIZE_BLOCK(bits) ((1600 - 2 * bits) >> 3)
#define SHA3_256_SIZE_BLOCK SHA3_SIZE_BLOCK(SHA3_256_SIZE_DIGEST_BITS)
#define SHA3_MAX_SIZE_BLOCK SHA3_256_SIZE_BLOCK
struct sha_ctx {
uint64_t state[25];
size_t msg_len;
unsigned int r;
unsigned int rword;
unsigned int digestsize;
uint8_t partial[SHA3_MAX_SIZE_BLOCK];
};
#define SHA_MAX_CTX_SIZE (sizeof(struct sha_ctx))
#define HASH_CTX_ON_STACK(name) \
struct sha_ctx name
void sha3_256_init(struct sha_ctx *ctx);
void sha3_update(struct sha_ctx *ctx, const uint8_t *in, size_t inlen);
void sha3_final(struct sha_ctx *ctx, uint8_t *digest);
int sha3_alloc(void **hash_state);
void sha3_dealloc(void *hash_state);
int sha3_tester(void);
#ifdef __cplusplus
}
#endif
#endif /* JITTERENTROPY_SHA3_H */

查看文件

@ -0,0 +1,233 @@
/* Jitter RNG: Internal timer implementation
*
* Copyright (C) 2021 - 2022, Stephan Mueller <smueller@chronox.de>
*
* License: see LICENSE file in root directory
*
* 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.
*/
#include "jitterentropy-base.h"
#include "jitterentropy-timer.h"
#ifdef JENT_CONF_ENABLE_INTERNAL_TIMER
/***************************************************************************
* Thread handler
***************************************************************************/
JENT_PRIVATE_STATIC
int jent_notime_init(void **ctx)
{
struct jent_notime_ctx *thread_ctx;
long ncpu = jent_ncpu();
if (ncpu < 0)
return (int)ncpu;
/* We need at least two CPUs to enable the timer thread */
if (ncpu < 2)
return -EOPNOTSUPP;
thread_ctx = calloc(1, sizeof(struct jent_notime_ctx));
if (!thread_ctx)
return -errno;
*ctx = thread_ctx;
return 0;
}
JENT_PRIVATE_STATIC
void jent_notime_fini(void *ctx)
{
struct jent_notime_ctx *thread_ctx = (struct jent_notime_ctx *)ctx;
if (thread_ctx)
free(thread_ctx);
}
static int jent_notime_start(void *ctx,
void *(*start_routine) (void *), void *arg)
{
struct jent_notime_ctx *thread_ctx = (struct jent_notime_ctx *)ctx;
int ret;
if (!thread_ctx)
return -EINVAL;
ret = -pthread_attr_init(&thread_ctx->notime_pthread_attr);
if (ret)
return ret;
return -pthread_create(&thread_ctx->notime_thread_id,
&thread_ctx->notime_pthread_attr,
start_routine, arg);
}
static void jent_notime_stop(void *ctx)
{
struct jent_notime_ctx *thread_ctx = (struct jent_notime_ctx *)ctx;
pthread_join(thread_ctx->notime_thread_id, NULL);
pthread_attr_destroy(&thread_ctx->notime_pthread_attr);
}
static struct jent_notime_thread jent_notime_thread_builtin = {
.jent_notime_init = jent_notime_init,
.jent_notime_fini = jent_notime_fini,
.jent_notime_start = jent_notime_start,
.jent_notime_stop = jent_notime_stop
};
/***************************************************************************
* Timer-less timer replacement
*
* If there is no high-resolution hardware timer available, we create one
* ourselves. This logic is only used when the initialization identifies
* that no suitable time source is available.
***************************************************************************/
static int jent_force_internal_timer = 0;
static int jent_notime_switch_blocked = 0;
void jent_notime_block_switch(void)
{
jent_notime_switch_blocked = 1;
}
static struct jent_notime_thread *notime_thread = &jent_notime_thread_builtin;
/**
* Timer-replacement loop
*
* @brief The measurement loop triggers the read of the value from the
* counter function. It conceptually acts as the low resolution
* samples timer from a ring oscillator.
*/
static void *jent_notime_sample_timer(void *arg)
{
struct rand_data *ec = (struct rand_data *)arg;
ec->notime_timer = 0;
while (1) {
if (ec->notime_interrupt)
return NULL;
ec->notime_timer++;
}
return NULL;
}
/*
* Enable the clock: spawn a new thread that holds a counter.
*
* Note, although creating a thread is expensive, we do that every time a
* caller wants entropy from us and terminate the thread afterwards. This
* is to ensure an attacker cannot easily identify the ticking thread.
*/
int jent_notime_settick(struct rand_data *ec)
{
if (!ec->enable_notime || !notime_thread)
return 0;
ec->notime_interrupt = 0;
ec->notime_prev_timer = 0;
ec->notime_timer = 0;
return notime_thread->jent_notime_start(ec->notime_thread_ctx,
jent_notime_sample_timer, ec);
}
void jent_notime_unsettick(struct rand_data *ec)
{
if (!ec->enable_notime || !notime_thread)
return;
ec->notime_interrupt = 1;
notime_thread->jent_notime_stop(ec->notime_thread_ctx);
}
void jent_get_nstime_internal(struct rand_data *ec, uint64_t *out)
{
if (ec->enable_notime) {
/*
* Allow the counting thread to be initialized and guarantee
* that it ticked since last time we looked.
*
* Note, we do not use an atomic operation here for reading
* jent_notime_timer since if this integer is garbled, it even
* adds to entropy. But on most architectures, read/write
* of an uint64_t should be atomic anyway.
*/
while (ec->notime_timer == ec->notime_prev_timer)
jent_yield();
ec->notime_prev_timer = ec->notime_timer;
*out = ec->notime_prev_timer;
} else {
jent_get_nstime(out);
}
}
static inline int jent_notime_enable_thread(struct rand_data *ec)
{
if (notime_thread)
return notime_thread->jent_notime_init(&ec->notime_thread_ctx);
return 0;
}
void jent_notime_disable(struct rand_data *ec)
{
if (notime_thread)
notime_thread->jent_notime_fini(ec->notime_thread_ctx);
}
int jent_notime_enable(struct rand_data *ec, unsigned int flags)
{
/* Use internal timer */
if (jent_force_internal_timer || (flags & JENT_FORCE_INTERNAL_TIMER)) {
/* Self test not run yet */
if (!jent_force_internal_timer &&
jent_time_entropy_init(ec->osr,
flags | JENT_FORCE_INTERNAL_TIMER))
return EHEALTH;
ec->enable_notime = 1;
return jent_notime_enable_thread(ec);
}
return 0;
}
int jent_notime_switch(struct jent_notime_thread *new_thread)
{
if (jent_notime_switch_blocked)
return -EAGAIN;
notime_thread = new_thread;
return 0;
}
void jent_notime_force(void)
{
jent_force_internal_timer = 1;
}
int jent_notime_forced(void)
{
return jent_force_internal_timer;
}
#endif /* JENT_CONF_ENABLE_INTERNAL_TIMER */

查看文件

@ -0,0 +1,92 @@
/*
* Copyright (C) 2021 - 2022, Stephan Mueller <smueller@chronox.de>
*
* License: see LICENSE file in root directory
*
* 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.
*/
#ifndef JITTERENTROPY_TIMER_H
#define JITTERENTROPY_TIMER_H
#include "jitterentropy.h"
#ifdef __cplusplus
extern "C"
{
#endif
#ifdef JENT_CONF_ENABLE_INTERNAL_TIMER
void jent_notime_block_switch(void);
int jent_notime_settick(struct rand_data *ec);
void jent_notime_unsettick(struct rand_data *ec);
void jent_get_nstime_internal(struct rand_data *ec, uint64_t *out);
int jent_notime_enable(struct rand_data *ec, unsigned int flags);
void jent_notime_disable(struct rand_data *ec);
int jent_notime_switch(struct jent_notime_thread *new_thread);
void jent_notime_force(void);
int jent_notime_forced(void);
#else /* JENT_CONF_ENABLE_INTERNAL_TIMER */
static inline void jent_notime_block_switch(void) { }
static inline int jent_notime_settick(struct rand_data *ec)
{
(void)ec;
return 0;
}
static inline void jent_notime_unsettick(struct rand_data *ec) { (void)ec; }
static inline void jent_get_nstime_internal(struct rand_data *ec, uint64_t *out)
{
(void)ec;
jent_get_nstime(out);
}
static inline int jent_notime_enable(struct rand_data *ec, unsigned int flags)
{
(void)ec;
/* If we force the timer-less noise source, we return an error */
if (flags & JENT_FORCE_INTERNAL_TIMER)
return EHEALTH;
return 0;
}
static inline void jent_notime_disable(struct rand_data *ec)
{
(void)ec;
}
static inline int jent_notime_switch(struct jent_notime_thread *new_thread)
{
(void)new_thread;
return -EOPNOTSUPP;
}
static inline void jent_notime_force(void) { }
static inline int jent_notime_forced(void) { return 0; }
#endif /* JENT_CONF_ENABLE_INTERNAL_TIMER */
#ifdef __cplusplus
}
#endif
#endif /* JITTERENTROPY-TIMER_H */

查看文件

@ -0,0 +1,471 @@
/*
* Non-physical true random number generator based on timing jitter.
*
* Copyright Stephan Mueller <smueller@chronox.de>, 2014 - 2022
*
* 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 GPL 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.
*/
#ifndef _JITTERENTROPY_H
#define _JITTERENTROPY_H
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************
* Jitter RNG Configuration Section
*
* You may alter the following options
***************************************************************************/
/*
* Enable timer-less timer support with JENT_CONF_ENABLE_INTERNAL_TIMER
*
* In case the hardware is identified to not provide a high-resolution time
* stamp, this option enables a built-in high-resolution time stamp mechanism.
*
* The timer-less noise source is based on threads. This noise source requires
* the linking with the POSIX threads library. I.e. the executing environment
* must offer POSIX threads. If this option is disabled, no linking
* with the POSIX threads library is needed.
*/
/*
* Disable the loop shuffle operation
*
* The shuffle operation enlarges the timing of the conditioning function
* by a variable length defined by the LSB of a time stamp. Some mathematicians
* are concerned that this pseudo-random selection of the loop iteration count
* may create some form of dependency between the different loop counts
* and the associated time duration of the conditioning function. It
* also complicates entropy assessment because it effectively combines a bunch
* of shifted/scaled copies the same distribution and masks failures from the
* health testing.
*
* By enabling this flag, the loop shuffle operation is disabled and
* the entropy collection operates in a way that honor the concerns.
*
* By enabling this flag, the time of collecting entropy may be enlarged.
*/
#define JENT_CONF_DISABLE_LOOP_SHUFFLE
/*
* Shall the LAG predictor health test be enabled?
*/
#define JENT_HEALTH_LAG_PREDICTOR
/*
* Shall the jent_memaccess use a (statistically) random selection for the
* memory to update?
*/
#define JENT_RANDOM_MEMACCESS
/***************************************************************************
* Jitter RNG State Definition Section
***************************************************************************/
#if defined(_MSC_VER)
#include "arch/jitterentropy-base-windows.h"
#else
#include "jitterentropy-base-user.h"
#endif
#define SHA3_256_SIZE_DIGEST_BITS 256
#define SHA3_256_SIZE_DIGEST (SHA3_256_SIZE_DIGEST_BITS >> 3)
/*
* The output 256 bits can receive more than 256 bits of min entropy,
* of course, but the 256-bit output of SHA3-256(M) can only asymptotically
* approach 256 bits of min entropy, not attain that bound. Random maps will
* tend to have output collisions, which reduces the creditable output entropy
* (that is what SP 800-90B Section 3.1.5.1.2 attempts to bound).
*
* The value "64" is justified in Appendix A.4 of the current 90C draft,
* and aligns with NIST's in "epsilon" definition in this document, which is
* that a string can be considered "full entropy" if you can bound the min
* entropy in each bit of output to at least 1-epsilon, where epsilon is
* required to be <= 2^(-32).
*/
#define ENTROPY_SAFETY_FACTOR 64
/**
* Function pointer data structure to register an external thread handler
* used for the timer-less mode of the Jitter RNG.
*
* The external caller provides these function pointers to handle the
* management of the timer thread that is spawned by the Jitter RNG.
*
* @var jent_notime_init This function is intended to initialze the threading
* support. All data that is required by the threading code must be
* held in the data structure @param ctx. The Jitter RNG maintains the
* data structure and uses it for every invocation of the following calls.
*
* @var jent_notime_fini This function shall terminate the threading support.
* The function must dispose of all memory and resources used for the
* threading operation. It must also dispose of the @param ctx memory.
*
* @var jent_notime_start This function is called when the Jitter RNG wants
* to start a thread. Besides providing a pointer to the @param ctx
* allocated during initialization time, the Jitter RNG provides a
* pointer to the function the thread shall execute and the argument
* the function shall be invoked with. These two parameters have the
* same purpose as the trailing two parameters of pthread_create(3).
*
* @var jent_notime_stop This function is invoked by the Jitter RNG when the
* thread should be stopped. Note, the Jitter RNG intends to start/stop
* the thread frequently.
*
* An example implementation is found in the Jitter RNG itself with its
* default thread handler of jent_notime_thread_builtin.
*
* If the caller wants to register its own thread handler, it must be done
* with the API call jent_entropy_switch_notime_impl as the first
* call to interact with the Jitter RNG, even before jent_entropy_init.
* After jent_entropy_init is called, changing of the threading implementation
* is not allowed.
*/
struct jent_notime_thread {
int (*jent_notime_init)(void **ctx);
void (*jent_notime_fini)(void *ctx);
int (*jent_notime_start)(void *ctx,
void *(*start_routine) (void *), void *arg);
void (*jent_notime_stop)(void *ctx);
};
/* 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. */
void *hash_state; /* SENSITIVE hash state entropy pool */
uint64_t prev_time; /* SENSITIVE Previous time stamp */
#define DATA_SIZE_BITS (SHA3_256_SIZE_DIGEST_BITS)
#ifndef JENT_HEALTH_LAG_PREDICTOR
uint64_t last_delta; /* SENSITIVE stuck test */
uint64_t last_delta2; /* SENSITIVE stuck test */
#endif /* JENT_HEALTH_LAG_PREDICTOR */
unsigned int flags; /* Flags used to initialize */
unsigned int osr; /* Oversampling rate */
#ifdef JENT_RANDOM_MEMACCESS
/* The step size should be larger than the cacheline size. */
# ifndef JENT_MEMORY_BITS
# define JENT_MEMORY_BITS 17
# endif
# ifndef JENT_MEMORY_SIZE
# define JENT_MEMORY_SIZE (UINT32_C(1)<<JENT_MEMORY_BITS)
# endif
#else /* JENT_RANDOM_MEMACCESS */
# ifndef JENT_MEMORY_BLOCKS
# define JENT_MEMORY_BLOCKS 512
# endif
# ifndef JENT_MEMORY_BLOCKSIZE
# define JENT_MEMORY_BLOCKSIZE 128
# endif
# ifndef JENT_MEMORY_SIZE
# define JENT_MEMORY_SIZE (JENT_MEMORY_BLOCKS*JENT_MEMORY_BLOCKSIZE)
# endif
#endif /* JENT_RANDOM_MEMACCESS */
#define JENT_MEMORY_ACCESSLOOPS 128
unsigned char *mem; /* Memory access location with size of
* JENT_MEMORY_SIZE or memsize */
#ifdef JENT_RANDOM_MEMACCESS
uint32_t memmask; /* Memory mask (size of memory - 1) */
#else
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 */
#endif
unsigned int memaccessloops; /* Number of memory accesses per random
* bit generation */
/* Repetition Count Test */
int rct_count; /* Number of stuck values */
/* Adaptive Proportion Test for a significance level of 2^-30 */
unsigned int apt_cutoff; /* Calculated using a corrected version
* of the SP800-90B sec 4.4.2 formula */
#define JENT_APT_WINDOW_SIZE 512 /* Data window size */
unsigned int apt_observations; /* Number of collected observations in
* current window. */
unsigned int apt_count; /* The number of times the reference
* symbol been encountered in the
* window. */
uint64_t apt_base; /* APT base reference */
unsigned int health_failure; /* Permanent health failure */
unsigned int apt_base_set:1; /* APT base reference set? */
unsigned int fips_enabled:1;
unsigned int enable_notime:1; /* Use internal high-res timer */
unsigned int max_mem_set:1; /* Maximum memory configured by user */
#ifdef JENT_CONF_ENABLE_INTERNAL_TIMER
volatile uint8_t notime_interrupt; /* indicator to interrupt ctr */
volatile uint64_t notime_timer; /* high-res timer mock-up */
uint64_t notime_prev_timer; /* previous timer value */
void *notime_thread_ctx; /* register thread data */
#endif /* JENT_CONF_ENABLE_INTERNAL_TIMER */
uint64_t jent_common_timer_gcd; /* Common divisor for all time deltas */
#ifdef JENT_HEALTH_LAG_PREDICTOR
/* Lag predictor test to look for re-occurring patterns. */
/* The lag global cutoff selected based on the selection of osr. */
unsigned int lag_global_cutoff;
/* The lag local cutoff selected based on the selection of osr. */
unsigned int lag_local_cutoff;
/*
* The number of times the lag predictor was correct. Compared to the
* global cutoff.
*/
unsigned int lag_prediction_success_count;
/*
* The size of the current run of successes. Compared to the local
* cutoff.
*/
unsigned int lag_prediction_success_run;
/*
* The total number of collected observations since the health test was
* last reset.
*/
unsigned int lag_best_predictor;
/*
* The total number of collected observations since the health test was
* last reset.
*/
unsigned int lag_observations;
/*
* This is the size of the window used by the predictor. The predictor
* is reset between windows.
*/
#define JENT_LAG_WINDOW_SIZE (1U<<17)
/*
* The amount of history to base predictions on. This must be a power
* of 2. Must be 4 or greater.
*/
#define JENT_LAG_HISTORY_SIZE 8
#define JENT_LAG_MASK (JENT_LAG_HISTORY_SIZE - 1)
/* The delta history for the lag predictor. */
uint64_t lag_delta_history[JENT_LAG_HISTORY_SIZE];
/* The scoreboard that tracks how successful each predictor lag is. */
unsigned int lag_scoreboard[JENT_LAG_HISTORY_SIZE];
#endif /* JENT_HEALTH_LAG_PREDICTOR */
};
/* Flags that can be used to initialize the RNG */
#define JENT_DISABLE_STIR (1<<0) /* UNUSED */
#define JENT_DISABLE_UNBIAS (1<<1) /* UNUSED */
#define JENT_DISABLE_MEMORY_ACCESS (1<<2) /* Disable memory access for more
entropy, saves MEMORY_SIZE RAM for
entropy collector */
#define JENT_FORCE_INTERNAL_TIMER (1<<3) /* Force the use of the internal
timer */
#define JENT_DISABLE_INTERNAL_TIMER (1<<4) /* Disable the potential use of
the internal timer. */
#define JENT_FORCE_FIPS (1<<5) /* Force FIPS compliant mode
including full SP800-90B
compliance. */
/* Flags field limiting the amount of memory to be used for memory access */
#define JENT_FLAGS_TO_MEMSIZE_SHIFT 28
#define JENT_FLAGS_TO_MAX_MEMSIZE(val) (val >> JENT_FLAGS_TO_MEMSIZE_SHIFT)
#define JENT_MAX_MEMSIZE_TO_FLAGS(val) (val << JENT_FLAGS_TO_MEMSIZE_SHIFT)
#define JENT_MAX_MEMSIZE_32kB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C( 1))
#define JENT_MAX_MEMSIZE_64kB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C( 2))
#define JENT_MAX_MEMSIZE_128kB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C( 3))
#define JENT_MAX_MEMSIZE_256kB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C( 4))
#define JENT_MAX_MEMSIZE_512kB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C( 5))
#define JENT_MAX_MEMSIZE_1MB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C( 6))
#define JENT_MAX_MEMSIZE_2MB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C( 7))
#define JENT_MAX_MEMSIZE_4MB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C( 8))
#define JENT_MAX_MEMSIZE_8MB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C( 9))
#define JENT_MAX_MEMSIZE_16MB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C(10))
#define JENT_MAX_MEMSIZE_32MB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C(11))
#define JENT_MAX_MEMSIZE_64MB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C(12))
#define JENT_MAX_MEMSIZE_128MB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C(13))
#define JENT_MAX_MEMSIZE_256MB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C(14))
#define JENT_MAX_MEMSIZE_512MB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C(15))
#define JENT_MAX_MEMSIZE_MAX JENT_MAX_MEMSIZE_512MB
#define JENT_MAX_MEMSIZE_MASK JENT_MAX_MEMSIZE_MAX
/* We start at 32kB -> offset is log2(32768) */
#define JENT_MAX_MEMSIZE_OFFSET 14
#ifdef JENT_CONF_DISABLE_LOOP_SHUFFLE
# define JENT_MIN_OSR 3
#else
# define JENT_MIN_OSR 1
#endif
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
/* -- BEGIN Main interface functions -- */
#ifndef JENT_STUCK_INIT_THRES
/*
* Per default, not more than 90% of all measurements during initialization
* are allowed to be stuck.
*
* It is allowed to change this value as required for the intended environment.
*/
#define JENT_STUCK_INIT_THRES(x) ((x*9) / 10)
#endif
#ifdef JENT_PRIVATE_COMPILE
# define JENT_PRIVATE_STATIC static
#else /* JENT_PRIVATE_COMPILE */
#if defined(_MSC_VER)
#define JENT_PRIVATE_STATIC __declspec(dllexport)
#else
#define JENT_PRIVATE_STATIC __attribute__((visibility("default")))
#endif
#endif
/* Number of low bits of the time value that we want to consider */
/* get raw entropy */
JENT_PRIVATE_STATIC
ssize_t jent_read_entropy(struct rand_data *ec, char *data, size_t len);
JENT_PRIVATE_STATIC
ssize_t jent_read_entropy_safe(struct rand_data **ec, char *data, size_t len);
/* initialize an instance of the entropy collector */
JENT_PRIVATE_STATIC
struct rand_data *jent_entropy_collector_alloc(unsigned int osr,
unsigned int flags);
/* clearing of entropy collector */
JENT_PRIVATE_STATIC
void jent_entropy_collector_free(struct rand_data *entropy_collector);
/* initialization of entropy collector */
JENT_PRIVATE_STATIC
int jent_entropy_init(void);
JENT_PRIVATE_STATIC
int jent_entropy_init_ex(unsigned int osr, unsigned int flags);
/*
* Set a callback to run on health failure in FIPS mode.
* This function will take an action determined by the caller.
*/
typedef void (*jent_fips_failure_cb)(struct rand_data *ec,
unsigned int health_failure);
JENT_PRIVATE_STATIC
int jent_set_fips_failure_callback(jent_fips_failure_cb cb);
/* return version number of core library */
JENT_PRIVATE_STATIC
unsigned int jent_version(void);
/* Set a different thread handling logic for the notimer support */
JENT_PRIVATE_STATIC
int jent_entropy_switch_notime_impl(struct jent_notime_thread *new_thread);
/* -- END of Main interface functions -- */
/* -- BEGIN timer-less threading support functions to prevent code dupes -- */
#ifdef JENT_CONF_ENABLE_INTERNAL_TIMER
struct jent_notime_ctx {
pthread_attr_t notime_pthread_attr; /* pthreads library */
pthread_t notime_thread_id; /* pthreads thread ID */
};
JENT_PRIVATE_STATIC
int jent_notime_init(void **ctx);
JENT_PRIVATE_STATIC
void jent_notime_fini(void *ctx);
#else
static inline int jent_notime_init(void **ctx) { (void)ctx; return 0; }
static inline void jent_notime_fini(void *ctx) { (void)ctx; }
#endif /* JENT_CONF_ENABLE_INTERNAL_TIMER */
/* -- END timer-less threading support functions to prevent code dupes -- */
/* -- BEGIN error codes for init function -- */
#define ENOTIME 1 /* Timer service not available */
#define ECOARSETIME 2 /* Timer too coarse for RNG */
#define ENOMONOTONIC 3 /* Timer is not monotonic increasing */
#define EMINVARIATION 4 /* Timer variations too small for RNG */
#define EVARVAR 5 /* Timer does not produce variations of variations
(2nd derivation of time is zero) */
#define EMINVARVAR 6 /* Timer variations of variations is too small */
#define EPROGERR 7 /* Programming error */
#define ESTUCK 8 /* Too many stuck results during init. */
#define EHEALTH 9 /* Health test failed during initialization */
#define ERCT 10 /* RCT failed during initialization */
#define EHASH 11 /* Hash self test failed */
#define EMEM 12 /* Can't allocate memory for initialization */
#define EGCD 13 /* GCD self-test failed */
/* -- END error codes for init function -- */
/* -- BEGIN error masks for health tests -- */
#define JENT_RCT_FAILURE 1 /* Failure in RCT health test. */
#define JENT_APT_FAILURE 2 /* Failure in APT health test. */
#define JENT_LAG_FAILURE 4 /* Failure in Lag predictor health test. */
/* -- END error masks for health tests -- */
/* -- BEGIN statistical test functions only complied with CONFIG_CRYPTO_CPU_JITTERENTROPY_STAT -- */
#ifdef CONFIG_CRYPTO_CPU_JITTERENTROPY_STAT
JENT_PRIVATE_STATIC
uint64_t jent_lfsr_var_stat(struct rand_data *ec, unsigned int min);
#endif /* CONFIG_CRYPTO_CPU_JITTERENTROPY_STAT */
/* -- END of statistical test function -- */
#ifdef __cplusplus
}
#endif
#endif /* _JITTERENTROPY_H */