diff --git a/libgcrypt-FIPS-SLI-pk.patch b/libgcrypt-FIPS-SLI-pk.patch new file mode 100644 index 0000000..d7b5ee6 --- /dev/null +++ b/libgcrypt-FIPS-SLI-pk.patch @@ -0,0 +1,160 @@ +Index: libgcrypt-1.9.4/src/fips.c +=================================================================== +--- libgcrypt-1.9.4.orig/src/fips.c ++++ libgcrypt-1.9.4/src/fips.c +@@ -32,6 +32,7 @@ + + #include "g10lib.h" + #include "cipher-proto.h" ++#include "cipher.h" + #include "hmac256.h" + + +@@ -482,6 +483,78 @@ _gcry_fips_indicator_kdf (va_list arg_pt + default: + return GPG_ERR_NOT_SUPPORTED; + } ++} ++ ++ ++/* FIPS approved curves, extracted from: ++ * cipher/ecc-curves.c:curve_aliases[] and domain_parms[]. */ ++static const struct ++{ ++ const char *name; /* Our name. */ ++ const char *other; /* Other name. */ ++} fips_approved_curve[] = ++ { ++ /* "NIST P-192" is non-approved if FIPS 140-3 */ ++ /* { "NIST P-192", "1.2.840.10045.3.1.1" }, /\* X9.62 OID *\/ */ ++ /* { "NIST P-192", "prime192v1" }, /\* X9.62 name. *\/ */ ++ /* { "NIST P-192", "secp192r1" }, /\* SECP name. *\/ */ ++ /* { "NIST P-192", "nistp192" }, /\* rfc5656. *\/ */ ++ ++ { "NIST P-224", "secp224r1" }, ++ { "NIST P-224", "1.3.132.0.33" }, /* SECP OID. */ ++ { "NIST P-224", "nistp224" }, /* rfc5656. */ ++ ++ { "NIST P-256", "1.2.840.10045.3.1.7" }, /* From NIST SP 800-78-1. */ ++ { "NIST P-256", "prime256v1" }, ++ { "NIST P-256", "secp256r1" }, ++ { "NIST P-256", "nistp256" }, /* rfc5656. */ ++ ++ { "NIST P-384", "secp384r1" }, ++ { "NIST P-384", "1.3.132.0.34" }, ++ { "NIST P-384", "nistp384" }, /* rfc5656. */ ++ ++ { "NIST P-521", "secp521r1" }, ++ { "NIST P-521", "1.3.132.0.35" }, ++ { "NIST P-521", "nistp521" }, /* rfc5656. */ ++ { NULL, NULL} ++ }; ++ ++int ++_gcry_fips_indicator_pk (va_list arg_ptr) ++{ ++ enum gcry_pk_algos alg = va_arg (arg_ptr, enum gcry_pk_algos); ++ enum pk_operation oper; ++ const char *curve_name; ++ ++ switch (alg) ++ { ++ case GCRY_PK_RSA: ++ case GCRY_PK_RSA_E: ++ case GCRY_PK_RSA_S: ++ oper = va_arg (arg_ptr, enum pk_operation); ++ switch (oper) ++ { ++ case PUBKEY_OP_ENCRYPT: ++ case PUBKEY_OP_DECRYPT: ++ return GPG_ERR_NOT_SUPPORTED; ++ default: ++ return GPG_ERR_NO_ERROR; ++ } ++ case GCRY_PK_ECC: ++ case GCRY_PK_ECDH: ++ case GCRY_PK_ECDSA: ++ curve_name = va_arg (arg_ptr, const char *); ++ for (int idx = 0; fips_approved_curve[idx].name; ++idx) ++ { ++ /* Check for the usual name and an alias. */ ++ if (!strcmp (curve_name, fips_approved_curve[idx].name) || ++ !strcmp (curve_name, fips_approved_curve[idx].other)) ++ return GPG_ERR_NO_ERROR; ++ } ++ return GPG_ERR_NOT_SUPPORTED; ++ default: ++ return GPG_ERR_NOT_SUPPORTED; ++ } + } + + +Index: libgcrypt-1.9.4/src/gcrypt.h.in +=================================================================== +--- libgcrypt-1.9.4.orig/src/gcrypt.h.in ++++ libgcrypt-1.9.4/src/gcrypt.h.in +@@ -336,7 +336,8 @@ enum gcry_ctl_cmds + GCRYCTL_AUTO_EXPAND_SECMEM = 78, + GCRYCTL_SET_ALLOW_WEAK_KEY = 79, + GCRYCTL_FIPS_SERVICE_INDICATOR_CIPHER = 81, +- GCRYCTL_FIPS_SERVICE_INDICATOR_KDF = 82 ++ GCRYCTL_FIPS_SERVICE_INDICATOR_KDF = 82, ++ GCRYCTL_FIPS_SERVICE_INDICATOR_PK = 83 + }; + + /* Perform various operations defined by CMD. */ +Index: libgcrypt-1.9.4/doc/gcrypt.texi +=================================================================== +--- libgcrypt-1.9.4.orig/doc/gcrypt.texi ++++ libgcrypt-1.9.4/doc/gcrypt.texi +@@ -975,6 +975,18 @@ certification. If the KDF is approved, t + @code{GPG_ERR_NO_ERROR}. Otherwise @code{GPG_ERR_NOT_SUPPORTED} + is returned. + ++@item GCRYCTL_FIPS_SERVICE_INDICATOR_PK; Arguments: enum gcry_pk_algos ++[, enum pk_operation (only for GCRY_PK_RSA)] [, const char * (only for ++GCRY_PK_ECC, GCRY_PK_ECDH or GCRY_PK_ECDSA)] ++ ++Check if the given asymmetric cipher is approved under the current FIPS ++140-3 certification. For GCRY_PK_RSA, an additional parameter for the ++operation mode @code{enum pk_operation} is required. For GCRY_PK_ECC, ++GCRY_PK_ECDH and GCRY_PK_ECDSA, the additional parameter is the curve ++name or its alias as @code{const char *}. If the combination is ++approved, this function returns @code{GPG_ERR_NO_ERROR}. Otherwise ++@code{GPG_ERR_NOT_SUPPORTED} is returned. ++ + @end table + + @end deftypefun +Index: libgcrypt-1.9.4/src/g10lib.h +=================================================================== +--- libgcrypt-1.9.4.orig/src/g10lib.h ++++ libgcrypt-1.9.4/src/g10lib.h +@@ -489,6 +489,7 @@ void _gcry_fips_signal_error (const char + + int _gcry_fips_indicator_cipher (va_list arg_ptr); + int _gcry_fips_indicator_kdf (va_list arg_ptr); ++int _gcry_fips_indicator_pk (va_list arg_ptr); + + int _gcry_fips_is_operational (void); + +Index: libgcrypt-1.9.4/src/global.c +=================================================================== +--- libgcrypt-1.9.4.orig/src/global.c ++++ libgcrypt-1.9.4/src/global.c +@@ -768,6 +768,15 @@ _gcry_vcontrol (enum gcry_ctl_cmds cmd, + rc = _gcry_fips_indicator_kdf (arg_ptr); + break; + ++ case GCRYCTL_FIPS_SERVICE_INDICATOR_PK: ++ /* Get FIPS Service Indicator for a given asymmetric algorithm. For ++ * GCRY_PK_RSA, an additional parameter for the operation mode is ++ * required. For ECC, ECDH and ECDSA, the additional parameter is the ++ * curve name or its alias. Returns GPG_ERR_NO_ERROR if the ++ * algorithm is allowed or GPG_ERR_NOT_SUPPORTED otherwise. */ ++ rc = _gcry_fips_indicator_pk (arg_ptr); ++ break; ++ + case PRIV_CTL_INIT_EXTRNG_TEST: /* Init external random test. */ + rc = GPG_ERR_NOT_SUPPORTED; + break; diff --git a/libgcrypt-FIPS-service-indicators.patch b/libgcrypt-FIPS-service-indicators.patch index c5e063d..ccbea90 100644 --- a/libgcrypt-FIPS-service-indicators.patch +++ b/libgcrypt-FIPS-service-indicators.patch @@ -2,7 +2,7 @@ Index: libgcrypt-1.9.4/src/fips.c =================================================================== --- libgcrypt-1.9.4.orig/src/fips.c +++ libgcrypt-1.9.4/src/fips.c -@@ -437,6 +437,59 @@ _gcry_fips_test_operational (void) +@@ -437,6 +437,54 @@ _gcry_fips_test_operational (void) } @@ -14,11 +14,6 @@ Index: libgcrypt-1.9.4/src/fips.c + + switch (alg) + { -+ case GCRY_CIPHER_AES: -+ case GCRY_CIPHER_AES192: -+ case GCRY_CIPHER_AES256: -+ mode = va_arg (arg_ptr, enum gcry_cipher_modes); -+ switch (mode) + case GCRY_CIPHER_AES: + case GCRY_CIPHER_AES192: + case GCRY_CIPHER_AES256: diff --git a/libgcrypt-FIPS-verify-unsupported-KDF-test.patch b/libgcrypt-FIPS-verify-unsupported-KDF-test.patch index 6e440b5..46bba96 100644 --- a/libgcrypt-FIPS-verify-unsupported-KDF-test.patch +++ b/libgcrypt-FIPS-verify-unsupported-KDF-test.patch @@ -12,10 +12,46 @@ Signed-off-by: Jakub Jelen tests/t-kdf.c | 7 +++++++ 1 file changed, 7 insertions(+) -diff --git a/tests/t-kdf.c b/tests/t-kdf.c -index 7a48e98a..48309b9a 100644 ---- a/tests/t-kdf.c -+++ b/tests/t-kdf.c +Index: libgcrypt-1.9.4/tests/t-kdf.c +=================================================================== +--- libgcrypt-1.9.4.orig/tests/t-kdf.c ++++ libgcrypt-1.9.4/tests/t-kdf.c +@@ -998,7 +998,7 @@ check_pbkdf2 (void) + "\xa5\x7a\xe5\xa6\x08\x83\x96\xd1\x20\x85\x0c\x5c\x09\xde\x0a\x52" + "\x51\x00\x93\x8a\x59\xb1\xb5\xc3\xf7\x81\x09\x10\xd0\x5f\xcd\x97" + }, */ +- { ++ /* { -- not FIPS approved + "passwordPASSWORDpassword", 24, + "saltSALTsaltSALTsaltSALTsaltSALTsalt", 36, + GCRY_MD_GOSTR3411_CP, +@@ -1007,7 +1007,7 @@ check_pbkdf2 (void) + "\x78\x83\x58\xc6\x9c\xb2\xdb\xe2\x51\xa7\xbb\x17\xd5\xf4\x24\x1f" + "\x26\x5a\x79\x2a\x35\xbe\xcd\xe8\xd5\x6f\x32\x6b\x49\xc8\x50\x47" + "\xb7\x63\x8a\xcb\x47\x64\xb1\xfd" +- }, ++ }, */ + { + "pass\0word", 9, + "sa\0lt", 5, +@@ -1061,7 +1061,7 @@ check_pbkdf2 (void) + "\x1a\xdb\x60\x1c\x7e\x2a\x31\x4e\x8c\xb7\xb1\xe9\xdf\x84\x0e\x36" + "\xab\x56\x15\xbe\x5d\x74\x2b\x6c\xf2\x03\xfb\x55\xfd\xc4\x80\x71" + }, */ +- { ++ /* { -- not FIPS approved + "passwordPASSWORDpassword", 24, + "saltSALTsaltSALTsaltSALTsaltSALTsalt", 36, + GCRY_MD_STRIBOG512, +@@ -1074,7 +1074,7 @@ check_pbkdf2 (void) + "\xbd\x24\x21\xee\x9b\xb7\x11\x83\xba\x88\x2c\xee\xbf\xef\x25\x9f" + "\x33\xf9\xe2\x7d\xc6\x17\x8c\xb8\x9d\xc3\x74\x28\xcf\x9c\xc5\x2a" + "\x2b\xaa\x2d\x3a" +- }, ++ }, */ + { + "pass\0word", 9, + "sa\0lt", 5, @@ -1104,6 +1104,13 @@ check_pbkdf2 (void) GCRY_KDF_PBKDF2, tv[tvidx].hashalgo, tv[tvidx].salt, tv[tvidx].saltlen, @@ -30,6 +66,3 @@ index 7a48e98a..48309b9a 100644 if (err) fail ("pbkdf2 test %d failed: %s\n", tvidx, gpg_strerror (err)); else if (memcmp (outbuf, tv[tvidx].dk, tv[tvidx].dklen)) --- -2.34.1 - diff --git a/libgcrypt-indicate-shake.patch b/libgcrypt-indicate-shake.patch new file mode 100644 index 0000000..bf2ece5 --- /dev/null +++ b/libgcrypt-indicate-shake.patch @@ -0,0 +1,13 @@ +Index: libgcrypt-1.9.4/src/fips.c +=================================================================== +--- libgcrypt-1.9.4.orig/src/fips.c ++++ libgcrypt-1.9.4/src/fips.c +@@ -593,6 +593,8 @@ _gcry_fips_indicator_hash (va_list arg_p + case GCRY_MD_SHA3_256: + case GCRY_MD_SHA3_384: + case GCRY_MD_SHA3_512: ++ case GCRY_MD_SHAKE128: ++ case GCRY_MD_SHAKE256: + return GPG_ERR_NO_ERROR; + default: + return GPG_ERR_NOT_SUPPORTED; diff --git a/libgcrypt-jitterentropy-3.3.0.patch b/libgcrypt-jitterentropy-3.3.0.patch new file mode 100644 index 0000000..65ebf25 --- /dev/null +++ b/libgcrypt-jitterentropy-3.3.0.patch @@ -0,0 +1,4168 @@ +Index: libgcrypt-1.9.4/LICENSES +=================================================================== +--- libgcrypt-1.9.4.orig/LICENSES ++++ libgcrypt-1.9.4/LICENSES +@@ -57,46 +57,53 @@ with any binary distributions derived fr + + For files: + - random/jitterentropy-base.c ++ - random/jitterentropy-gcd.c ++ - random/jitterentropy-gcd.h ++ - random/jitterentropy-health.c ++ - random/jitterentropy-health.h ++ - random/jitterentropy-noise.c ++ - random/jitterentropy-noise.h ++ - random/jitterentropy-sha3.c ++ - random/jitterentropy-sha3.h ++ - random/jitterentropy-timer.c ++ - random/jitterentropy-timer.h + - random/jitterentropy.h + - random/rndjent.c (plus common Libgcrypt copyright holders) + + #+begin_quote +- * Copyright Stephan Mueller , 2013 +- * +- * 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. ++ Copyright (C) 2017 - 2021, Stephan Mueller ++ ++ 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. + #+end_quote + + For files: +Index: libgcrypt-1.9.4/random/jitterentropy-base.c +=================================================================== +--- libgcrypt-1.9.4.orig/random/jitterentropy-base.c ++++ libgcrypt-1.9.4/random/jitterentropy-base.c +@@ -11,29 +11,9 @@ + * Interface + * ========= + * +- * See documentation in doc/ folder. +- * +- * License +- * ======= ++ * See documentation in jitterentropy(3) man page. + * +- * 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.) ++ * 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 +@@ -49,30 +29,43 @@ + * DAMAGE. + */ + +-#undef _FORTIFY_SOURCE +-#ifdef __OPTIMIZE__ +-#pragma GCC optimize ("O0") +-#endif +- + #include "jitterentropy.h" + +-#ifndef CONFIG_CRYPTO_CPU_JITTERENTROPY_STAT +- /* only check optimization in a compilation for real work */ +- #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-base.c." +- #endif +-#endif ++#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 2 /* API / ABI incompatible changes, functional changes that ++#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 1 /* API compatible, ABI may change, functional ++#define MINVERSION 3 /* API compatible, ABI may change, functional + * enhancements only, consumer can be left unchanged if + * enhancements are not considered */ + #define PATCHLEVEL 0 /* 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 + * +@@ -84,7 +77,7 @@ + * 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 kcapi library ++ * @return Version number of jitterentropy library + */ + JENT_PRIVATE_STATIC + unsigned int jent_version(void) +@@ -98,414 +91,57 @@ unsigned int jent_version(void) + return version; + } + +-/** +- * Update of the loop count used for the next round of +- * an entropy collection. +- * +- * Input: +- * @ec entropy collector struct -- may be NULL +- * @bits is the number of low bits of the timer to consider +- * @min is the number of bits we shift the timer value to the right at +- * the end to make sure we have a guaranteed minimum value +- * +- * @return Newly calculated loop counter +- */ +-static uint64_t jent_loop_shuffle(struct rand_data *ec, +- unsigned int bits, unsigned int min) +-{ +- uint64_t time = 0; +- uint64_t shuffle = 0; +- unsigned int i = 0; +- unsigned int mask = (1<data; +- /* +- * 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; (DATA_SIZE_BITS / 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 + (1<data +- * +- * @return Number of loops the folding operation is performed +- */ +-static uint64_t jent_lfsr_time(struct rand_data *ec, uint64_t time, +- uint64_t loop_cnt) ++/* 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 i; +- uint64_t j = 0; +- uint64_t new = 0; +-#define MAX_FOLD_LOOP_BIT 4 +-#define MIN_FOLD_LOOP_BIT 0 +- uint64_t fold_loop_cnt = +- jent_loop_shuffle(ec, MAX_FOLD_LOOP_BIT, MIN_FOLD_LOOP_BIT); +- +- /* +- * testing purposes -- allow test app to set the counter, not +- * needed during runtime +- */ +- if (loop_cnt) +- fold_loop_cnt = loop_cnt; +- for (j = 0; j < fold_loop_cnt; j++) { +- new = ec->data; +- for (i = 1; (DATA_SIZE_BITS) >= i; i++) { +- uint64_t tmp = time << (DATA_SIZE_BITS - i); +- +- tmp = tmp >> (DATA_SIZE_BITS - 1); ++ unsigned int idx = 0; + +- /* +- * Fibonacci LSFR with polynomial of +- * x^64 + x^61 + x^56 + x^31 + x^28 + x^23 + 1 which is +- * primitive according to +- * http://poincare.matf.bg.ac.rs/~ezivkovm/publications/primpol1.pdf +- * (the shift values are the polynomial values minus one +- * due to counting bits from 0 to 63). As the current +- * position is always the LSB, the polynomial only needs +- * to shift data in from the left without wrap. +- */ +- new ^= tmp; +- new ^= ((new >> 63) & 1); +- new ^= ((new >> 60) & 1); +- new ^= ((new >> 55) & 1); +- new ^= ((new >> 30) & 1); +- new ^= ((new >> 27) & 1); +- new ^= ((new >> 22) & 1); +- new = rol64(new, 1); +- } +- } +- ec->data = new; +- +- return fold_loop_cnt; ++ while (val >>= 1) ++ idx++; ++ return idx; + } + +-/** +- * Memory Access noise source -- this is a noise source based on variations in +- * memory access times +- * +- * This function performs memory accesses which will add to the timing +- * variations due to an unknown amount of CPU wait states that need to be +- * added when accessing memory. The memory size should be larger than the L1 +- * caches as outlined in the documentation and the associated testing. +- * +- * The L1 cache has a very high bandwidth, albeit its access rate is usually +- * slower than accessing CPU registers. Therefore, L1 accesses only add minimal +- * variations as the CPU has hardly to wait. Starting with L2, significant +- * variations are added because L2 typically does not belong to the CPU any more +- * and therefore a wider range of CPU wait states is necessary for accesses. +- * L3 and real memory accesses have even a wider range of wait states. However, +- * to reliably access either L3 or memory, the ec->mem memory must be quite +- * large which is usually not desirable. +- * +- * Input: +- * @ec Reference to the entropy collector with the memory access data -- if +- * the reference to the memory block to be accessed is NULL, this noise +- * source is disabled +- * @loop_cnt if a value not equal to 0 is set, use the given value as number of +- * loops to perform the folding +- * +- * @return Number of memory access operations +- */ +-static unsigned int jent_memaccess(struct rand_data *ec, uint64_t loop_cnt) ++/* Increase the memory size by one step */ ++static inline unsigned int jent_update_memsize(unsigned int flags) + { +- unsigned int wrap = 0; +- uint64_t i = 0; +-#define MAX_ACC_LOOP_BIT 7 +-#define MIN_ACC_LOOP_BIT 0 +- uint64_t acc_loop_cnt = +- jent_loop_shuffle(ec, MAX_ACC_LOOP_BIT, MIN_ACC_LOOP_BIT); +- +- if (NULL == ec || NULL == ec->mem) +- return 0; +- wrap = ec->memblocksize * ec->memblocks; ++ unsigned int global_max = JENT_FLAGS_TO_MAX_MEMSIZE( ++ JENT_MAX_MEMSIZE_MAX); ++ unsigned int max; + +- /* +- * testing purposes -- allow test app to set the counter, not +- * needed during runtime +- */ +- if (loop_cnt) +- acc_loop_cnt = loop_cnt; ++ max = JENT_FLAGS_TO_MAX_MEMSIZE(flags); + +- 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 = (*tmpval + 1) & 0xff; ++ if (!max) { + /* +- * Addition of memblocksize - 1 to pointer +- * with wrap around logic to ensure that every +- * memory location is hit evenly ++ * The safe starting value is the amount of memory we allocated ++ * last round. + */ +- ec->memlocation = ec->memlocation + ec->memblocksize - 1; +- ec->memlocation = ec->memlocation % wrap; +- } +- return i; ++ 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; + } + + /*************************************************************************** +- * Start of entropy processing logic ++ * Random Number Generation + ***************************************************************************/ + + /** +- * Stuck test by checking the: +- * 1st derivation of the jitter measurement (time delta) +- * 2nd derivation of the jitter measurement (delta of time deltas) +- * 3rd derivation of the jitter measurement (delta of delta of time deltas) +- * +- * All values must always be non-zero. +- * +- * Input: +- * @ec Reference to entropy collector +- * @current_delta Jitter time delta +- * +- * @return +- * 0 jitter measurement not stuck (good bit) +- * 1 jitter measurement stuck (reject bit) +- */ +-static int jent_stuck(struct rand_data *ec, uint64_t current_delta) +-{ +- int64_t delta2 = ec->last_delta - current_delta; +- int64_t delta3 = (uint64_t)delta2 - (uint64_t)ec->last_delta2; +- +- ec->last_delta = current_delta; +- ec->last_delta2 = delta2; +- +- if (!current_delta || !delta2 || !delta3) +- return 1; +- +- return 0; +-} +- +-/** +- * 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. +- * +- * Input: +- * @entropy_collector Reference to entropy collector +- * +- * @return: result of stuck test +- */ +-static int jent_measure_jitter(struct rand_data *ec) +-{ +- uint64_t time = 0; +- uint64_t current_delta = 0; +- int stuck; +- +- /* Invoke one noise source before time measurement to add variations */ +- jent_memaccess(ec, 0); +- +- /* +- * Get time stamp and calculate time delta to previous +- * invocation to measure the timing variations +- */ +- jent_get_nstime(&time); +- current_delta = time - ec->prev_time; +- ec->prev_time = time; +- +- /* Now call the next noise sources which also injects the data */ +- jent_lfsr_time(ec, current_delta, 0); +- +- /* Check whether we have a stuck measurement. */ +- stuck = jent_stuck(ec, current_delta); +- +- /* +- * Rotate the data buffer by a prime number (any odd number would +- * do) to ensure that every bit position of the input time stamp +- * has an even chance of being merged with a bit position in the +- * entropy pool. We do not use one here as the adjacent bits in +- * successive time deltas may have some form of dependency. The +- * chosen value of 7 implies that the low 7 bits of the next +- * time delta value is concatenated with the current time delta. +- */ +- if (!stuck) +- ec->data = rol64(ec->data, 7); +- +- return stuck; +-} +- +-/** +- * Shuffle the pool a bit by mixing some value with a bijective function (XOR) +- * into the pool. +- * +- * The function generates a mixer value that depends on the bits set and the +- * location of the set bits in the random number generated by the entropy +- * source. Therefore, based on the generated random number, this mixer value +- * can have 2**64 different values. That mixer value is initialized with the +- * first two SHA-1 constants. After obtaining the mixer value, it is XORed into +- * the random number. +- * +- * The mixer value is not assumed to contain any entropy. But due to the XOR +- * operation, it can also not destroy any entropy present in the entropy pool. +- * +- * Input: +- * @entropy_collector Reference to entropy collector +- */ +-static void jent_stir_pool(struct rand_data *entropy_collector) +-{ +- /* +- * to shut up GCC on 32 bit, we have to initialize the 64 variable +- * with two 32 bit variables +- */ +- union c { +- uint64_t uint64; +- uint32_t uint32[2]; +- }; +- /* +- * This constant is derived from the first two 32 bit initialization +- * vectors of SHA-1 as defined in FIPS 180-4 section 5.3.1 +- */ +- union c constant; +- /* +- * The start value of the mixer variable is derived from the third +- * and fourth 32 bit initialization vector of SHA-1 as defined in +- * FIPS 180-4 section 5.3.1 +- */ +- union c mixer; +- unsigned int i = 0; +- +- /* Ensure that the function implements a constant time operation. */ +- union c throw_away; +- +- /* +- * Store the SHA-1 constants in reverse order to make up the 64 bit +- * value -- this applies to a little endian system, on a big endian +- * system, it reverses as expected. But this really does not matter +- * as we do not rely on the specific numbers. We just pick the SHA-1 +- * constants as they have a good mix of bit set and unset. +- */ +- constant.uint32[1] = 0x67452301; +- constant.uint32[0] = 0xefcdab89; +- mixer.uint32[1] = 0x98badcfe; +- mixer.uint32[0] = 0x10325476; +- +- for (i = 0; i < DATA_SIZE_BITS; i++) { +- /* +- * get the i-th bit of the input random number and only XOR +- * the constant into the mixer value when that bit is set +- */ +- if ((entropy_collector->data >> i) & 1) +- mixer.uint64 ^= constant.uint64; +- else +- throw_away.uint64 ^= constant.uint64; +- mixer.uint64 = rol64(mixer.uint64, 1); +- } +- entropy_collector->data ^= mixer.uint64; +-} +- +-/** +- * Generator of one 64 bit random number +- * Function fills rand_data->data +- * +- * Input: +- * @ec Reference to entropy collector +- */ +-static void jent_gen_entropy(struct rand_data *ec) +-{ +- unsigned int k = 0; +- +- /* priming of the ->prev_time value */ +- jent_measure_jitter(ec); +- +- while (1) { +- /* If a stuck measurement is received, repeat measurement */ +- if (jent_measure_jitter(ec)) +- continue; +- +- /* +- * We multiply the loop value with ->osr to obtain the +- * oversampling rate requested by the caller +- */ +- if (++k >= (DATA_SIZE_BITS * ec->osr)) +- break; +- } +- if (ec->stir) +- jent_stir_pool(ec); +-} +- +-/** +- * The continuous test required by FIPS 140-2 -- the function automatically +- * primes the test if needed. +- * +- * Return: +- * 0 if FIPS test passed +- * < 0 if FIPS test failed +- */ +-static int jent_fips_test(struct rand_data *ec) +-{ +- if (ec->fips_enabled == -1) +- return 0; +- +- if (ec->fips_enabled == 0) { +- if (!jent_fips_enabled()) { +- ec->fips_enabled = -1; +- return 0; +- } else +- ec->fips_enabled = 1; +- } +- +- /* prime the FIPS test */ +- if (!ec->old_data) { +- ec->old_data = ec->data; +- jent_gen_entropy(ec); +- } +- +- if (ec->data == ec->old_data) +- return -1; +- +- ec->old_data = ec->data; +- +- return 0; +-} +- +-/** + * Entry function: Obtain entropy for the caller. + * + * This function invokes the entropy gathering logic as often to generate +@@ -515,34 +151,50 @@ static int jent_fips_test(struct rand_da + * This function truncates the last 64 bit entropy value output to the exact + * size specified by the caller. + * +- * Input: +- * @ec Reference to entropy collector +- * @data pointer to buffer for storing random data -- buffer must already +- * exist +- * @len size of the buffer, specifying also the requested number of random +- * in bytes ++ * @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 FIPS test failed ++ * -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; + +- while (0 < len) { ++ if (jent_notime_settick(ec)) ++ return -4; ++ ++ while (len > 0) { + size_t tocopy; ++ unsigned int health_test_result; + +- jent_gen_entropy(ec); +- if (jent_fips_test(ec)) +- return -2; ++ 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); +@@ -569,93 +221,349 @@ ssize_t jent_read_entropy(struct rand_da + * memory protects the entropy pool. Moreover, note that using this + * call reduces the speed of the RNG by up to half + */ +-#ifndef CONFIG_CRYPTO_CPU_JITTERENTROPY_SECURE_MEMORY +- jent_gen_entropy(ec); ++#ifndef JENT_CPU_JITTERENTROPY_SECURE_MEMORY ++ jent_random_data(ec); + #endif +- return orig_len; ++ ++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 + ***************************************************************************/ + +-JENT_PRIVATE_STATIC +-struct rand_data *jent_entropy_collector_alloc(unsigned int osr, +- unsigned int flags) ++/* ++ * 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; + ++ /* ++ * 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)) { +- /* Allocate memory for adding variations based on memory +- * access ++ uint32_t memsize = jent_memsize(flags); ++ ++ entropy_collector->mem = _gcry_calloc (1, memsize); ++ ++#ifdef JENT_RANDOM_MEMACCESS ++ /* ++ * Transform the size into a mask - it is assumed that size is ++ * a power of 2. + */ +- entropy_collector->mem = +- (unsigned char *)jent_zalloc(JENT_MEMORY_SIZE); +- if (NULL == entropy_collector->mem) { +- jent_zfree(entropy_collector, sizeof(struct rand_data)); +- return NULL; +- } +- entropy_collector->memblocksize = JENT_MEMORY_BLOCKSIZE; ++ 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; + } + + /* verify and set the oversampling rate */ +- if (0 == osr) +- osr = 1; /* minimum sampling rate is 1 */ ++ if (osr < JENT_MIN_OSR) ++ osr = JENT_MIN_OSR; + entropy_collector->osr = osr; ++ entropy_collector->flags = flags; + +- entropy_collector->stir = 1; +- if (flags & JENT_DISABLE_STIR) +- entropy_collector->stir = 0; +- if (flags & JENT_DISABLE_UNBIAS) +- entropy_collector->disable_unbias = 1; ++ if (jent_fips_enabled() || (flags & JENT_FORCE_FIPS)) ++ entropy_collector->fips_enabled = 1; + +- /* fill the data pad with non-zero values */ +- jent_gen_entropy(entropy_collector); ++ /* 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, JENT_MEMORY_SIZE); ++ 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 (NULL != entropy_collector) { +- if (NULL != entropy_collector->mem) { +- jent_zfree(entropy_collector->mem, JENT_MEMORY_SIZE); ++ if (entropy_collector != NULL) { ++ 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)); + } + } + +-JENT_PRIVATE_STATIC +-int jent_entropy_init(void) ++int jent_time_entropy_init(unsigned int osr, unsigned int flags) + { +- int i; +- uint64_t delta_sum = 0; +- uint64_t old_delta = 0; +- int time_backwards = 0; +- int count_mod = 0; +- int count_stuck = 0; +- struct rand_data ec; ++ struct rand_data *ec; ++ uint64_t *delta_history; ++ int i, time_backwards = 0, count_stuck = 0, ret = 0; ++ unsigned int health_test_result; + +- memset(&ec, 0, sizeof(ec)); ++ 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 and we produce +- * false positives. +- * +- * Moreover, only old systems show potentially problematic +- * jitter entropy that could potentially be caught here. But +- * the RNG is intended for hardware that is available or widely +- * used, but not old systems that are long out of favor. Thus, +- * no statistical tests. ++ * loop counts may show some slight skew leading to false positives. + */ + + /* +@@ -664,38 +572,31 @@ int jent_entropy_init(void) + * following sanity checks verify that we have a high-resolution + * timer. + */ +- /* +- * TESTLOOPCOUNT needs some loops to identify edge systems. 100 is +- * definitely too little. +- */ +-#define TESTLOOPCOUNT 300 + #define CLEARCACHE 100 +- for (i = 0; (TESTLOOPCOUNT + CLEARCACHE) > i; i++) { +- uint64_t time = 0; +- uint64_t time2 = 0; +- uint64_t delta = 0; +- unsigned int lowdelta = 0; +- int stuck; ++ 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 */ +- jent_get_nstime(&time); +- ec.prev_time = time; +- jent_lfsr_time(&ec, time, 0); +- jent_get_nstime(&time2); ++ stuck = jent_measure_jitter(ec, 0, &delta); ++ end_time = ec->prev_time; ++ start_time = ec->prev_time - delta; + + /* test whether timer works */ +- if (!time || !time2) +- return ENOTIME; +- delta = time2 - time; ++ 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) +- return ECOARSETIME; +- +- stuck = jent_stuck(&ec, delta); ++ if (!delta || (end_time == start_time)) { ++ ret = ECOARSETIME; ++ goto out; ++ } + + /* + * up to here we did not modify any variable that will be +@@ -704,32 +605,18 @@ int jent_entropy_init(void) + * etc. with the goal to clear it to get the worst case + * measurements. + */ +- if (CLEARCACHE > i) ++ if (i < 0) + continue; + + if (stuck) + count_stuck++; + + /* test whether we have an increasing timer */ +- if (!(time2 > time)) ++ if (!(end_time > start_time)) + time_backwards++; + +- /* use 32 bit value to ensure compilation on 32 bit arches */ +- lowdelta = time2 - time; +- if (!(lowdelta % 100)) +- count_mod++; +- +- /* +- * ensure that we have a varying delta timer which is necessary +- * for the calculation of entropy -- perform this check +- * only after the first loop is executed as we need to prime +- * the old_data value +- */ +- if (delta > old_delta) +- delta_sum += (delta - old_delta); +- else +- delta_sum += (old_delta - delta); +- old_delta = delta; ++ /* Watch for common adjacent GCD values */ ++ jent_gcd_add_value(delta_history, delta, i); + } + + /* +@@ -739,55 +626,109 @@ int jent_entropy_init(void) + * should not fail. The value of 3 should cover the NTP case being + * performed during our test run. + */ +- if (3 < time_backwards) +- return ENOMONOTONIC; ++ if (time_backwards > 3) { ++ ret = ENOMONOTONIC; ++ goto out; ++ } + +- /* +- * 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) <= 1) +- return EMINVARVAR; ++ /* 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; ++ } + +- /* +- * Ensure that we have variations in the time stamp below 10 for at least +- * 10% of all checks -- on some platforms, the counter increments in +- * multiples of 100, but not always +- */ +- if ((TESTLOOPCOUNT/10 * 9) < count_mod) +- return ECOARSETIME; ++ 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(TESTLOOPCOUNT) < count_stuck) +- return ESTUCK; ++ 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 0; ++ return ret; + } + +-/*************************************************************************** +- * Statistical test logic not compiled for regular operation +- ***************************************************************************/ ++static inline int jent_entropy_init_common_pre(void) ++{ ++ int ret; ++ ++ jent_notime_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); ++} + +-#ifdef CONFIG_CRYPTO_CPU_JITTERENTROPY_STAT +-/* +- * Statistical test: return the time duration for the folding operation. If min +- * is set, perform the given number of LFSR ops. Otherwise, allow the +- * loop count shuffling to define the number of LFSR ops. +- */ + JENT_PRIVATE_STATIC +-uint64_t jent_lfsr_var_stat(struct rand_data *ec, unsigned int min) ++int jent_entropy_init_ex(unsigned int osr, unsigned int flags) + { +- uint64_t time = 0; +- uint64_t time2 = 0; ++ int ret = jent_entropy_init_common_pre(); ++ ++ if (ret) ++ return ret; ++ ++ /* 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); + +- jent_get_nstime(&time); +- jent_memaccess(ec, min); +- jent_lfsr_time(ec, time, min); +- jent_get_nstime(&time2); +- return ((time2 - time)); ++#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); + } +-#endif /* CONFIG_CRYPTO_CPU_JITTERENTROPY_STAT */ ++ ++#ifdef JENT_CONF_ENABLE_INTERNAL_TIMER ++JENT_PRIVATE_STATIC ++int jent_entropy_switch_notime_impl(struct jent_notime_thread *new_thread) ++{ ++ return jent_notime_switch(new_thread); ++} ++#endif +Index: libgcrypt-1.9.4/random/jitterentropy-base.h +=================================================================== +--- /dev/null ++++ libgcrypt-1.9.4/random/jitterentropy-base.h +@@ -0,0 +1,34 @@ ++/* ++ * Copyright (C) 2021, Stephan Mueller ++ * ++ * 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 */ +Index: libgcrypt-1.9.4/random/jitterentropy-base-user.h +=================================================================== +--- libgcrypt-1.9.4.orig/random/jitterentropy-base-user.h ++++ libgcrypt-1.9.4/random/jitterentropy-base-user.h +@@ -39,6 +39,9 @@ + * DAMAGE. + */ + ++#include ++#include ++ + #ifndef GCRYPT_JITTERENTROPY_BASE_USER_H + #define GCRYPT_JITTERENTROPY_BASE_USER_H + +@@ -131,4 +134,174 @@ jent_fips_enabled(void) + } + + ++static inline void jent_memset_secure(void *s, size_t n) ++{ ++ wipememory (s, n); ++} ++ ++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__ */ ++ ++#ifdef JENT_CONF_ENABLE_INTERNAL_TIMER ++#include ++ ++static inline void jent_yield(void) ++{ ++ sched_yield(); ++} ++#endif ++ + #endif /* GCRYPT_JITTERENTROPY_BASE_USER_H */ +Index: libgcrypt-1.9.4/random/jitterentropy-gcd.c +=================================================================== +--- /dev/null ++++ libgcrypt-1.9.4/random/jitterentropy-gcd.c +@@ -0,0 +1,188 @@ ++/* Jitter RNG: GCD health test ++ * ++ * Copyright (C) 2021, Joshua E. Hill ++ * Copyright (C) 2021, Stephan Mueller ++ * ++ * 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; ++ } ++ ++ /* ++ * Ensure that we have variations in the time stamp below 100 for at ++ * least 10% of all checks -- on some platforms, the counter increments ++ * in multiples of 100, but not always ++ */ ++ if (running_gcd >= 100) { ++ 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; ++} +Index: libgcrypt-1.9.4/random/jitterentropy-gcd.h +=================================================================== +--- /dev/null ++++ libgcrypt-1.9.4/random/jitterentropy-gcd.h +@@ -0,0 +1,42 @@ ++/* ++ * Copyright (C) 2021, Stephan Mueller ++ * ++ * 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 */ +Index: libgcrypt-1.9.4/random/jitterentropy.h +=================================================================== +--- libgcrypt-1.9.4.orig/random/jitterentropy.h ++++ libgcrypt-1.9.4/random/jitterentropy.h +@@ -42,11 +42,122 @@ + #ifndef _JITTERENTROPY_H + #define _JITTERENTROPY_H + +-#ifdef __KERNEL__ +-#include "jitterentropy-base-kernel.h" +-#else ++/*************************************************************************** ++ * Jitter RNG Configuration Section ++ * ++ * You may alter the following options ++ ***************************************************************************/ ++ ++/* ++ * Enable timer-less timer support ++ * ++ * 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. ++ */ ++#undef JENT_CONF_ENABLE_INTERNAL_TIMER ++ ++/* ++ * 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 ++ ***************************************************************************/ ++ + #include "jitterentropy-base-user.h" +-#endif /* __KERNEL__ */ ++ ++#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 +@@ -55,35 +166,179 @@ struct rand_data + * 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. */ +- uint64_t data; /* SENSITIVE Actual random number */ +- uint64_t old_data; /* SENSITIVE Previous random number */ +- uint64_t prev_time; /* SENSITIVE Previous time stamp */ +-#define DATA_SIZE_BITS ((sizeof(uint64_t)) * 8) +- uint64_t last_delta; /* SENSITIVE stuck test */ +- int64_t last_delta2; /* SENSITIVE stuck test */ +- unsigned int osr; /* Oversample rate */ +- int fips_enabled; /* FIPS enabled? */ +- unsigned int stir:1; /* Post-processing stirring */ +- unsigned int disable_unbias:1; /* Deactivate Von-Neuman unbias */ +-#define JENT_MEMORY_BLOCKS 64 +-#define JENT_MEMORY_BLOCKSIZE 32 ++ uint8_t data[SHA3_256_SIZE_DIGEST]; /* SENSITIVE Actual random number */ ++ 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_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 -- */ + +@@ -94,19 +349,21 @@ struct rand_data + * + * It is allowed to change this value as required for the intended environment. + */ +-#define JENT_STUCK_INIT_THRES(x) (x/10 * 9) ++#define JENT_STUCK_INIT_THRES(x) ((x*9) / 10) + #endif + + #ifdef JENT_PRIVATE_COMPILE + # define JENT_PRIVATE_STATIC static + #else /* JENT_PRIVATE_COMPILE */ +-# define JENT_PRIVATE_STATIC ++# define JENT_PRIVATE_STATIC __attribute__((visibility("default"))) + #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, +@@ -118,13 +375,47 @@ void jent_entropy_collector_free(struct + /* 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); + + /* return version number of core library */ + JENT_PRIVATE_STATIC + unsigned int jent_version(void); + ++#ifdef JENT_CONF_ENABLE_INTERNAL_TIMER ++/* 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); ++#endif ++ + /* -- END of Main interface functions -- */ + ++/* -- BEGIN timer-less threading support functions to prevent code dupes -- */ ++ ++struct jent_notime_ctx { ++#ifdef JENT_CONF_ENABLE_INTERNAL_TIMER ++ pthread_attr_t notime_pthread_attr; /* pthreads library */ ++ pthread_t notime_thread_id; /* pthreads thread ID */ ++#endif ++}; ++ ++#ifdef JENT_CONF_ENABLE_INTERNAL_TIMER ++ ++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 */ +@@ -135,6 +426,18 @@ unsigned int jent_version(void); + #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 -- */ + +Index: libgcrypt-1.9.4/random/jitterentropy-health.c +=================================================================== +--- /dev/null ++++ libgcrypt-1.9.4/random/jitterentropy-health.c +@@ -0,0 +1,438 @@ ++/* Jitter RNG: Health Tests ++ * ++ * Copyright (C) 2021, Joshua E. Hill ++ * Copyright (C) 2021, Stephan Mueller ++ * ++ * 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-health.h" ++ ++/*************************************************************************** ++ * 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; ++ ++ return ec->health_failure; ++} +Index: libgcrypt-1.9.4/random/jitterentropy-health.h +=================================================================== +--- /dev/null ++++ libgcrypt-1.9.4/random/jitterentropy-health.h +@@ -0,0 +1,51 @@ ++/* ++ * Copyright (C) 2021, Stephan Mueller ++ * ++ * 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 ++ ++#ifdef __cplusplus ++extern "C" ++{ ++#endif ++ ++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 */ +Index: libgcrypt-1.9.4/random/jitterentropy-noise.c +=================================================================== +--- /dev/null ++++ libgcrypt-1.9.4/random/jitterentropy-noise.c +@@ -0,0 +1,387 @@ ++/* Jitter RNG: Noise Sources ++ * ++ * Copyright (C) 2021, Stephan Mueller ++ * ++ * 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 -- may be NULL ++ * @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)<data[0]; ++ } ++ ++ /* ++ * 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; ((DATA_SIZE_BITS + 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)< 63); ++ hash_loop_cnt = ++ jent_loop_shuffle(ec, MAX_HASH_LOOP, MIN_HASH_LOOP); ++ ++ 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 basically slows down the SHA-3 operation depending ++ * on the hash_loop_cnt. Each iteration of the loop generates the ++ * same result. ++ */ ++ for (j = 0; j < hash_loop_cnt; j++) { ++ sha3_update(&ctx, ec->data, SHA3_256_SIZE_DIGEST); ++ sha3_update(&ctx, (uint8_t *)&time, sizeof(uint64_t)); ++ sha3_update(&ctx, (uint8_t *)&j, sizeof(uint64_t)); ++ ++ /* ++ * 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. ++ */ ++ ++ /* ++ * The sha3_final operations re-initialize the context for the ++ * next loop iteration. ++ */ ++ if (stuck || (j < hash_loop_cnt - 1)) ++ sha3_final(&ctx, itermediary); ++ else ++ sha3_final(&ctx, ec->data); ++ } ++ ++ jent_memset_secure(&ctx, SHA_MAX_CTX_SIZE); ++ jent_memset_secure(itermediary, sizeof(itermediary)); ++} ++ ++#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; ++ union { ++ uint32_t u[4]; ++ uint8_t b[sizeof(uint32_t) * 4]; ++ } prngState = { .u = {0x8e93eec0, 0xce65608a, 0xa8d46b46, 0xe83cef69} }; ++ uint32_t addressMask; ++ uint64_t acc_loop_cnt; ++ ++ if (NULL == ec || NULL == ec->mem) ++ return; ++ ++ addressMask = ec->memmask; ++ ++ /* Ensure that macros cannot overflow jent_loop_shuffle() */ ++ BUILD_BUG_ON((MAX_ACC_LOOP_BIT + MIN_ACC_LOOP_BIT) > 63); ++ acc_loop_cnt = ++ jent_loop_shuffle(ec, MAX_ACC_LOOP_BIT, MIN_ACC_LOOP_BIT); ++ ++ /* ++ * Mix the current data into prngState ++ * ++ * Any time you see a PRNG in a noise source, you should be concerned. ++ * ++ * The PRNG doesn't 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 isn't 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++) ++ prngState.b[i] ^= ec->data[i]; ++ ++ /* ++ * 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->data ++ * ++ * @ec [in] Reference to entropy collector ++ */ ++void jent_random_data(struct rand_data *ec) ++{ ++ unsigned int k = 0, safety_factor = ENTROPY_SAFETY_FACTOR; ++ ++ if (!ec->fips_enabled) ++ safety_factor = 0; ++ ++ /* priming of the ->prev_time value */ ++ jent_measure_jitter(ec, 0, NULL); ++ ++ while (1) { ++ /* 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; ++ } ++} +Index: libgcrypt-1.9.4/random/jitterentropy-noise.h +=================================================================== +--- /dev/null ++++ libgcrypt-1.9.4/random/jitterentropy-noise.h +@@ -0,0 +1,39 @@ ++/* ++ * Copyright (C) 2021, Stephan Mueller ++ * ++ * 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); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* JITTERENTROPY_NOISE_H */ +Index: libgcrypt-1.9.4/random/jitterentropy-sha3.c +=================================================================== +--- /dev/null ++++ libgcrypt-1.9.4/random/jitterentropy-sha3.c +@@ -0,0 +1,382 @@ ++/* Jitter RNG: SHA-3 Implementation ++ * ++ * Copyright (C) 2021, Stephan Mueller ++ * ++ * 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" ++ ++/*************************************************************************** ++ * 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; ++} +Index: libgcrypt-1.9.4/random/jitterentropy-sha3.h +=================================================================== +--- /dev/null ++++ libgcrypt-1.9.4/random/jitterentropy-sha3.h +@@ -0,0 +1,56 @@ ++/* ++ * Copyright (C) 2021, Stephan Mueller ++ * ++ * 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_tester(void); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* JITTERENTROPY_SHA3_H */ +Index: libgcrypt-1.9.4/random/jitterentropy-timer.c +=================================================================== +--- /dev/null ++++ libgcrypt-1.9.4/random/jitterentropy-timer.c +@@ -0,0 +1,234 @@ ++/* Jitter RNG: Internal timer implementation ++ * ++ * Copyright (C) 2021, Stephan Mueller ++ * ++ * 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(flags | JENT_FORCE_INTERNAL_TIMER, ++ ec->osr)) ++ 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 */ +Index: libgcrypt-1.9.4/random/jitterentropy-timer.h +=================================================================== +--- /dev/null ++++ libgcrypt-1.9.4/random/jitterentropy-timer.h +@@ -0,0 +1,92 @@ ++/* ++ * Copyright (C) 2021, Stephan Mueller ++ * ++ * 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 */ +Index: libgcrypt-1.9.4/random/Makefile.am +=================================================================== +--- libgcrypt-1.9.4.orig/random/Makefile.am ++++ libgcrypt-1.9.4/random/Makefile.am +@@ -50,9 +50,14 @@ rndegd.c \ + rndunix.c \ + rndw32.c \ + rndw32ce.c \ ++jitterentropy-gcd.c jitterentropy-gcd.h \ ++jitterentropy-health.c jitterentropy-health.h \ ++jitterentropy-noise.c jitterentropy-noise.h \ ++jitterentropy-sha3.c jitterentropy-sha3.h \ ++jitterentropy-timer.c jitterentropy-timer.h \ ++jitterentropy-base.h \ + jitterentropy-base.c jitterentropy.h jitterentropy-base-user.h + +- + # The rndjent module needs to be compiled without optimization. */ + if ENABLE_O_FLAG_MUNGING + o_flag_munging = sed -e 's/-O\([1-9sg][1-9sg]*\)/-O0/g' -e 's/-Ofast/-O0/g' +@@ -61,9 +66,19 @@ o_flag_munging = cat + endif + + rndjent.o: $(srcdir)/rndjent.c jitterentropy-base-user.h \ ++ $(srcdir)/jitterentropy-gcd.c $(srcdir)/jitterentropy-gcd.h \ ++ $(srcdir)/jitterentropy-health.c $(srcdir)/jitterentropy-health.h \ ++ $(srcdir)/jitterentropy-noise.c $(srcdir)/jitterentropy-noise.h \ ++ $(srcdir)/jitterentropy-sha3.c $(srcdir)/jitterentropy-sha3.h \ ++ $(srcdir)/jitterentropy-timer.c $(srcdir)/jitterentropy-timer.h \ + $(srcdir)/jitterentropy-base.c $(srcdir)/jitterentropy.h + `echo $(COMPILE) -c $(srcdir)/rndjent.c | $(o_flag_munging) ` + + rndjent.lo: $(srcdir)/rndjent.c jitterentropy-base-user.h \ ++ $(srcdir)/jitterentropy-gcd.c $(srcdir)/jitterentropy-gcd.h \ ++ $(srcdir)/jitterentropy-health.c $(srcdir)/jitterentropy-health.h \ ++ $(srcdir)/jitterentropy-noise.c $(srcdir)/jitterentropy-noise.h \ ++ $(srcdir)/jitterentropy-sha3.c $(srcdir)/jitterentropy-sha3.h \ ++ $(srcdir)/jitterentropy-timer.c $(srcdir)/jitterentropy-timer.h \ + $(srcdir)/jitterentropy-base.c $(srcdir)/jitterentropy.h + `echo $(LTCOMPILE) -c $(srcdir)/rndjent.c | $(o_flag_munging) ` +Index: libgcrypt-1.9.4/random/Makefile.in +=================================================================== +--- libgcrypt-1.9.4.orig/random/Makefile.in ++++ libgcrypt-1.9.4/random/Makefile.in +@@ -156,6 +156,11 @@ am__depfiles_remade = ./$(DEPDIR)/jitter + ./$(DEPDIR)/random-csprng.Plo ./$(DEPDIR)/random-daemon.Plo \ + ./$(DEPDIR)/random-drbg.Plo ./$(DEPDIR)/random-system.Plo \ + ./$(DEPDIR)/random.Plo ./$(DEPDIR)/rndegd.Plo \ ++ ./$(DEPDIR)/jitterentropy-gcd.Plo \ ++ ./$(DEPDIR)/jitterentropy-health.Plo \ ++ ./$(DEPDIR)/jitterentropy-noise.Plo \ ++ ./$(DEPDIR)/jitterentropy-sha3.Plo \ ++ ./$(DEPDIR)/jitterentropy-timer.Plo \ + ./$(DEPDIR)/rndhw.Plo ./$(DEPDIR)/rndjent.Plo \ + ./$(DEPDIR)/rndlinux.Plo ./$(DEPDIR)/rndunix.Plo \ + ./$(DEPDIR)/rndw32.Plo ./$(DEPDIR)/rndw32ce.Plo +@@ -391,6 +396,12 @@ rndegd.c \ + rndunix.c \ + rndw32.c \ + rndw32ce.c \ ++jitterentropy-gcd.c jitterentropy-gcd.h \ ++jitterentropy-health.c jitterentropy-health.h \ ++jitterentropy-noise.c jitterentropy-noise.h \ ++jitterentropy-sha3.c jitterentropy-sha3.h \ ++jitterentropy-timer.c jitterentropy-timer.h \ ++jitterentropy-base.h \ + jitterentropy-base.c jitterentropy.h jitterentropy-base-user.h + + @ENABLE_O_FLAG_MUNGING_FALSE@o_flag_munging = cat +@@ -452,6 +463,11 @@ distclean-compile: + -rm -f *.tab.c + + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jitterentropy-base.Plo@am__quote@ # am--include-marker ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jitterentropy-gcd.Plo@am__quote@ # am--include-marker ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jitterentropy-health.Plo@am__quote@ # am--include-marker ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jitterentropy-noise.Plo@am__quote@ # am--include-marker ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jitterentropy-sha3.Plo@am__quote@ # am--include-marker ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jitterentropy-timer.Plo@am__quote@ # am--include-marker + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/random-csprng.Plo@am__quote@ # am--include-marker + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/random-daemon.Plo@am__quote@ # am--include-marker + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/random-drbg.Plo@am__quote@ # am--include-marker +@@ -624,6 +640,11 @@ clean-am: clean-generic clean-libtool cl + + distclean: distclean-am + -rm -f ./$(DEPDIR)/jitterentropy-base.Plo ++ -rm -f ./$(DEPDIR)/jitterentropy-gcd.Plo ++ -rm -f ./$(DEPDIR)/jitterentropy-health.Plo ++ -rm -f ./$(DEPDIR)/jitterentropy-noise.Plo ++ -rm -f ./$(DEPDIR)/jitterentropy-sha3.Plo ++ -rm -f ./$(DEPDIR)/jitterentropy-timer.Plo + -rm -f ./$(DEPDIR)/random-csprng.Plo + -rm -f ./$(DEPDIR)/random-daemon.Plo + -rm -f ./$(DEPDIR)/random-drbg.Plo +@@ -682,6 +703,11 @@ installcheck-am: + + maintainer-clean: maintainer-clean-am + -rm -f ./$(DEPDIR)/jitterentropy-base.Plo ++ -rm -f ./$(DEPDIR)/jitterentropy-gcd.Plo ++ -rm -f ./$(DEPDIR)/jitterentropy-health.Plo ++ -rm -f ./$(DEPDIR)/jitterentropy-noise.Plo ++ -rm -f ./$(DEPDIR)/jitterentropy-sha3.Plo ++ -rm -f ./$(DEPDIR)/jitterentropy-timer.Plo + -rm -f ./$(DEPDIR)/random-csprng.Plo + -rm -f ./$(DEPDIR)/random-daemon.Plo + -rm -f ./$(DEPDIR)/random-drbg.Plo +@@ -732,10 +758,20 @@ uninstall-am: + + + rndjent.o: $(srcdir)/rndjent.c jitterentropy-base-user.h \ ++ $(srcdir)/jitterentropy-gcd.c $(srcdir)/jitterentropy-gcd.h \ ++ $(srcdir)/jitterentropy-health.c $(srcdir)/jitterentropy-health.h \ ++ $(srcdir)/jitterentropy-noise.c $(srcdir)/jitterentropy-noise.h \ ++ $(srcdir)/jitterentropy-sha3.c $(srcdir)/jitterentropy-sha3.h \ ++ $(srcdir)/jitterentropy-timer.c $(srcdir)/jitterentropy-timer.h \ + $(srcdir)/jitterentropy-base.c $(srcdir)/jitterentropy.h + `echo $(COMPILE) -c $(srcdir)/rndjent.c | $(o_flag_munging) ` + + rndjent.lo: $(srcdir)/rndjent.c jitterentropy-base-user.h \ ++ $(srcdir)/jitterentropy-gcd.c $(srcdir)/jitterentropy-gcd.h \ ++ $(srcdir)/jitterentropy-health.c $(srcdir)/jitterentropy-health.h \ ++ $(srcdir)/jitterentropy-noise.c $(srcdir)/jitterentropy-noise.h \ ++ $(srcdir)/jitterentropy-sha3.c $(srcdir)/jitterentropy-sha3.h \ ++ $(srcdir)/jitterentropy-timer.c $(srcdir)/jitterentropy-timer.h \ + $(srcdir)/jitterentropy-base.c $(srcdir)/jitterentropy.h + `echo $(LTCOMPILE) -c $(srcdir)/rndjent.c | $(o_flag_munging) ` + +Index: libgcrypt-1.9.4/random/random-csprng.c +=================================================================== +--- libgcrypt-1.9.4.orig/random/random-csprng.c ++++ libgcrypt-1.9.4/random/random-csprng.c +@@ -357,6 +357,17 @@ _gcry_rngcsprng_close_fds (void) + _gcry_rndlinux_gather_random (NULL, 0, 0, 0); + pool_filled = 0; /* Force re-open on next use. */ + #endif ++ pool_writepos = 0; ++ pool_readpos = 0; ++ pool_filled = 0; ++ pool_filled_counter = 0; ++ did_initial_extra_seeding = 0; ++ pool_balance = 0; ++ just_mixed = 0; ++ xfree (rndpool); ++ xfree (keypool); ++ rndpool = NULL; ++ keypool = NULL; + unlock_pool (); + } + +Index: libgcrypt-1.9.4/random/random-drbg.c +=================================================================== +--- libgcrypt-1.9.4.orig/random/random-drbg.c ++++ libgcrypt-1.9.4/random/random-drbg.c +@@ -1860,16 +1860,23 @@ _gcry_rngdrbg_reinit (const char *flagst + return ret; + } + +-/* Try to close the FDs of the random gather module. This is +- * currently only implemented for rndlinux. */ ++/* Release resources used by this DRBG module. That is, close the FDs ++ * of the random gather module (if any), and release memory used. ++ */ + void + _gcry_rngdrbg_close_fds (void) + { +-#if USE_RNDLINUX + drbg_lock (); ++#if USE_RNDLINUX + _gcry_rndlinux_gather_random (NULL, 0, 0, 0); +- drbg_unlock (); + #endif ++ if (drbg_state) ++ { ++ drbg_uninstantiate (drbg_state); ++ xfree (drbg_state); ++ drbg_state = NULL; ++ } ++ drbg_unlock (); + } + + /* Print some statistics about the RNG. */ +Index: libgcrypt-1.9.4/random/rndjent.c +=================================================================== +--- libgcrypt-1.9.4.orig/random/rndjent.c ++++ libgcrypt-1.9.4/random/rndjent.c +@@ -43,6 +43,8 @@ + #ifdef HAVE_STDINT_H + # include + #endif ++#include ++#include + + #include "types.h" + #include "g10lib.h" +@@ -84,7 +86,14 @@ + #define JENT_PRIVATE_COMPILE 1 + + #include "jitterentropy-base.c" +- ++#ifdef JENT_CONF_ENABLE_INTERNAL_TIMER ++#include ++#endif /* JENT_CONF_ENABLE_INTERNAL_TIMER */ ++#include "jitterentropy-gcd.c" ++#include "jitterentropy-health.c" ++#include "jitterentropy-noise.c" ++#include "jitterentropy-sha3.c" ++#include "jitterentropy-timer.c" + + /* This is the lock we use to serialize access to this RNG. The extra + * integer variable is only used to check the locking state; that is, +@@ -291,7 +300,7 @@ _gcry_rndjent_poll (void (*add)(const vo + size_t n = length < sizeof(buffer)? length : sizeof (buffer); + + jent_rng_totalcalls++; +- rc = jent_read_entropy (jent_rng_collector, buffer, n); ++ rc = jent_read_entropy_safe (&jent_rng_collector, buffer, n); + if (rc < 0) + break; + /* We need to hash the output to conform to the BSI diff --git a/libgcrypt-jitterentropy-3.4.0.patch b/libgcrypt-jitterentropy-3.4.0.patch new file mode 100644 index 0000000..2ba40e3 --- /dev/null +++ b/libgcrypt-jitterentropy-3.4.0.patch @@ -0,0 +1,661 @@ +Index: libgcrypt-1.9.4/random/jitterentropy-base.c +=================================================================== +--- libgcrypt-1.9.4.orig/random/jitterentropy-base.c ++++ libgcrypt-1.9.4/random/jitterentropy-base.c +@@ -42,7 +42,7 @@ + * 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 3 /* API compatible, ABI may change, functional ++#define MINVERSION 4 /* API compatible, ABI may change, functional + * enhancements only, consumer can be left unchanged if + * enhancements are not considered */ + #define PATCHLEVEL 0 /* API / ABI compatible, no functional changes, no +@@ -200,29 +200,38 @@ ssize_t jent_read_entropy(struct rand_da + tocopy = (DATA_SIZE_BITS / 8); + else + tocopy = len; +- memcpy(p, &ec->data, tocopy); ++ ++ jent_read_random_block(ec, p, tocopy); + + len -= tocopy; + p += tocopy; + } + + /* +- * To be on the safe side, we generate one more round of entropy +- * which we do not give out to the caller. That round shall ensure +- * that in case the calling application crashes, memory dumps, pages +- * out, or due to the CPU Jitter RNG lingering in memory for long +- * time without being moved and an attacker cracks the application, +- * all he reads in the entropy pool is a value that is NEVER EVER +- * being used for anything. Thus, he does NOT see the previous value +- * that was returned to the caller for cryptographic purposes. ++ * 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, do not use that precaution as the secure +- * memory protects the entropy pool. Moreover, note that using this +- * call reduces the speed of the RNG by up to half ++ * 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 JENT_CPU_JITTERENTROPY_SECURE_MEMORY +- jent_random_data(ec); ++#ifndef CONFIG_CRYPTO_CPU_JITTERENTROPY_SECURE_MEMORY ++ jent_read_random_block(ec, NULL, 0); + #endif + + err: +@@ -379,6 +388,7 @@ 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 +@@ -405,9 +415,8 @@ static struct rand_data + return NULL; + + if (!(flags & JENT_DISABLE_MEMORY_ACCESS)) { +- uint32_t memsize = jent_memsize(flags); +- +- entropy_collector->mem = _gcry_calloc (1, memsize); ++ memsize = jent_memsize(flags); ++ entropy_collector->mem = (unsigned char *)jent_zalloc(memsize); + + #ifdef JENT_RANDOM_MEMACCESS + /* +@@ -431,13 +440,19 @@ static struct rand_data + 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 (jent_fips_enabled() || (flags & JENT_FORCE_FIPS)) ++ if ((flags & JENT_FORCE_FIPS) || jent_fips_enabled()) + entropy_collector->fips_enabled = 1; + + /* Initialize the APT */ +@@ -469,7 +484,7 @@ static struct rand_data + + err: + if (entropy_collector->mem != NULL) +- jent_zfree(entropy_collector->mem, JENT_MEMORY_SIZE); ++ jent_zfree(entropy_collector->mem, memsize); + jent_zfree(entropy_collector, sizeof(struct rand_data)); + return NULL; + } +@@ -511,6 +526,7 @@ 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, +@@ -664,6 +680,7 @@ static inline int jent_entropy_init_comm + int ret; + + jent_notime_block_switch(); ++ jent_health_cb_block_switch(); + + if (sha3_tester()) + return EHASH; +@@ -710,6 +727,8 @@ int jent_entropy_init_ex(unsigned int os + 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, +@@ -725,10 +744,14 @@ int jent_entropy_init_ex(unsigned int os + return jent_entropy_init_common_post(ret); + } + +-#ifdef JENT_CONF_ENABLE_INTERNAL_TIMER + JENT_PRIVATE_STATIC + int jent_entropy_switch_notime_impl(struct jent_notime_thread *new_thread) + { + return jent_notime_switch(new_thread); + } +-#endif ++ ++JENT_PRIVATE_STATIC ++int jent_set_fips_failure_callback(jent_fips_failure_cb cb) ++{ ++ return jent_set_fips_failure_callback_internal(cb); ++} +Index: libgcrypt-1.9.4/random/jitterentropy-gcd.c +=================================================================== +--- libgcrypt-1.9.4.orig/random/jitterentropy-gcd.c ++++ libgcrypt-1.9.4/random/jitterentropy-gcd.c +@@ -113,12 +113,8 @@ int jent_gcd_analyze(uint64_t *delta_his + goto out; + } + +- /* +- * Ensure that we have variations in the time stamp below 100 for at +- * least 10% of all checks -- on some platforms, the counter increments +- * in multiples of 100, but not always +- */ +- if (running_gcd >= 100) { ++ /* Set a sensible maximum value. */ ++ if (running_gcd >= UINT32_MAX / 2) { + ret = ECOARSETIME; + goto out; + } +Index: libgcrypt-1.9.4/random/jitterentropy-health.c +=================================================================== +--- libgcrypt-1.9.4.orig/random/jitterentropy-health.c ++++ libgcrypt-1.9.4/random/jitterentropy-health.c +@@ -19,9 +19,24 @@ + * DAMAGE. + */ + +-#include "jitterentropy.h" + #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 + * +@@ -434,5 +449,9 @@ unsigned int jent_health_failure(struct + if (!ec->fips_enabled) + return 0; + ++ if (fips_cb && ec->health_failure) { ++ fips_cb(ec, ec->health_failure); ++ } ++ + return ec->health_failure; + } +Index: libgcrypt-1.9.4/random/jitterentropy-health.h +=================================================================== +--- libgcrypt-1.9.4.orig/random/jitterentropy-health.h ++++ libgcrypt-1.9.4/random/jitterentropy-health.h +@@ -20,11 +20,16 @@ + #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); +Index: libgcrypt-1.9.4/random/jitterentropy-noise.c +=================================================================== +--- libgcrypt-1.9.4.orig/random/jitterentropy-noise.c ++++ libgcrypt-1.9.4/random/jitterentropy-noise.c +@@ -33,7 +33,7 @@ + * Update of the loop count used for the next round of + * an entropy collection. + * +- * @ec [in] entropy collector struct -- may be NULL ++ * @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 +@@ -61,16 +61,13 @@ static uint64_t jent_loop_shuffle(struct + * Mix the current state of the random number into the shuffle + * calculation to balance that shuffle a bit more. + */ +- if (ec) { +- jent_get_nstime_internal(ec, &time); +- time ^= ec->data[0]; +- } ++ 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; ((DATA_SIZE_BITS + bits - 1) / bits) > i; i++) { ++ for (i = 0; (((sizeof(time) << 3) + bits - 1) / bits) > i; i++) { + shuffle ^= time & mask; + time = time >> bits; + } +@@ -91,11 +88,11 @@ static uint64_t jent_loop_shuffle(struct + * This function injects the individual bits of the time value into the + * entropy pool using a hash. + * +- * @ec [in] entropy collector struct -- may be NULL +- * @time [in] time stamp to be injected ++ * @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 stamp identified as stuck? ++ * @stuck [in] Is the time delta identified as stuck? + * + * Output: + * updated hash context +@@ -104,17 +101,19 @@ static void jent_hash_time(struct rand_d + uint64_t loop_cnt, unsigned int stuck) + { + HASH_CTX_ON_STACK(ctx); +- uint8_t itermediary[SHA3_256_SIZE_DIGEST]; ++ uint8_t intermediary[SHA3_256_SIZE_DIGEST]; + uint64_t j = 0; +- uint64_t hash_loop_cnt; + #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); +- hash_loop_cnt = ++ 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); + + /* +@@ -125,35 +124,54 @@ static void jent_hash_time(struct rand_d + hash_loop_cnt = loop_cnt; + + /* +- * This loop basically slows down the SHA-3 operation depending +- * on the hash_loop_cnt. Each iteration of the loop generates the +- * same result. ++ * 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, ec->data, SHA3_256_SIZE_DIGEST); +- sha3_update(&ctx, (uint8_t *)&time, sizeof(uint64_t)); ++ 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); ++ } + +- /* +- * 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. +- */ ++ /* ++ * 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)); + +- /* +- * The sha3_final operations re-initialize the context for the +- * next loop iteration. +- */ +- if (stuck || (j < hash_loop_cnt - 1)) +- sha3_final(&ctx, itermediary); +- else +- sha3_final(&ctx, ec->data); +- } ++ /* ++ * 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(itermediary, sizeof(itermediary)); ++ jent_memset_secure(intermediary, sizeof(intermediary)); + } + + #define MAX_ACC_LOOP_BIT 7 +@@ -184,37 +202,37 @@ static inline uint32_t xoshiro128starsta + + static void jent_memaccess(struct rand_data *ec, uint64_t loop_cnt) + { +- uint64_t i = 0; ++ 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; +- uint64_t acc_loop_cnt; +- +- if (NULL == ec || NULL == ec->mem) +- return; +- +- addressMask = ec->memmask; + + /* Ensure that macros cannot overflow jent_loop_shuffle() */ + BUILD_BUG_ON((MAX_ACC_LOOP_BIT + MIN_ACC_LOOP_BIT) > 63); +- acc_loop_cnt = ++ 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 doesn't 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 isn't 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++) +- prngState.b[i] ^= ec->data[i]; ++ 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 +@@ -358,21 +376,21 @@ unsigned int jent_measure_jitter(struct + + /** + * Generator of one 256 bit random number +- * Function fills rand_data->data ++ * 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 = ENTROPY_SAFETY_FACTOR; ++ unsigned int k = 0, safety_factor = 0; + +- if (!ec->fips_enabled) +- 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 (1) { ++ while (!jent_health_failure(ec)) { + /* If a stuck measurement is received, repeat measurement */ + if (jent_measure_jitter(ec, 0, NULL)) + continue; +@@ -385,3 +403,22 @@ void jent_random_data(struct rand_data * + 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)); ++} +Index: libgcrypt-1.9.4/random/jitterentropy-noise.h +=================================================================== +--- libgcrypt-1.9.4.orig/random/jitterentropy-noise.h ++++ libgcrypt-1.9.4/random/jitterentropy-noise.h +@@ -31,6 +31,7 @@ unsigned int jent_measure_jitter(struct + 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 + } +Index: libgcrypt-1.9.4/random/jitterentropy-sha3.c +=================================================================== +--- libgcrypt-1.9.4.orig/random/jitterentropy-sha3.c ++++ libgcrypt-1.9.4/random/jitterentropy-sha3.c +@@ -19,6 +19,7 @@ + */ + + #include "jitterentropy-sha3.h" ++#include "jitterentropy.h" + + /*************************************************************************** + * Message Digest Implementation +@@ -380,3 +381,23 @@ int sha3_tester(void) + + 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); ++} +Index: libgcrypt-1.9.4/random/jitterentropy-sha3.h +=================================================================== +--- libgcrypt-1.9.4.orig/random/jitterentropy-sha3.h ++++ libgcrypt-1.9.4/random/jitterentropy-sha3.h +@@ -47,6 +47,8 @@ struct sha_ctx { + 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 +Index: libgcrypt-1.9.4/random/jitterentropy-timer.c +=================================================================== +--- libgcrypt-1.9.4.orig/random/jitterentropy-timer.c ++++ libgcrypt-1.9.4/random/jitterentropy-timer.c +@@ -202,8 +202,8 @@ int jent_notime_enable(struct rand_data + if (jent_force_internal_timer || (flags & JENT_FORCE_INTERNAL_TIMER)) { + /* Self test not run yet */ + if (!jent_force_internal_timer && +- jent_time_entropy_init(flags | JENT_FORCE_INTERNAL_TIMER, +- ec->osr)) ++ jent_time_entropy_init(ec->osr, ++ flags | JENT_FORCE_INTERNAL_TIMER)) + return EHEALTH; + + ec->enable_notime = 1; +Index: libgcrypt-1.9.4/random/jitterentropy.h +=================================================================== +--- libgcrypt-1.9.4.orig/random/jitterentropy.h ++++ libgcrypt-1.9.4/random/jitterentropy.h +@@ -42,6 +42,10 @@ + #ifndef _JITTERENTROPY_H + #define _JITTERENTROPY_H + ++#ifdef __cplusplus ++extern "C" { ++#endif ++ + /*************************************************************************** + * Jitter RNG Configuration Section + * +@@ -49,7 +53,7 @@ + ***************************************************************************/ + + /* +- * Enable timer-less timer support ++ * 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. +@@ -166,7 +173,7 @@ struct rand_data + * 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. */ +- uint8_t data[SHA3_256_SIZE_DIGEST]; /* SENSITIVE Actual random number */ ++ 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) + +@@ -378,29 +389,34 @@ 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); + +-#ifdef JENT_CONF_ENABLE_INTERNAL_TIMER + /* 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); +-#endif + + /* -- END of Main interface functions -- */ + + /* -- BEGIN timer-less threading support functions to prevent code dupes -- */ + +-struct jent_notime_ctx { + #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 */ +-#endif + }; + +-#ifdef JENT_CONF_ENABLE_INTERNAL_TIMER +- + JENT_PRIVATE_STATIC + int jent_notime_init(void **ctx); + +@@ -448,4 +464,8 @@ uint64_t jent_lfsr_var_stat(struct rand_ + + /* -- END of statistical test function -- */ + ++#ifdef __cplusplus ++} ++#endif ++ + #endif /* _JITTERENTROPY_H */ +Index: libgcrypt-1.9.4/random/jitterentropy-base-user.h +=================================================================== +--- libgcrypt-1.9.4.orig/random/jitterentropy-base-user.h ++++ libgcrypt-1.9.4/random/jitterentropy-base-user.h +@@ -216,12 +216,12 @@ static inline void jent_get_cachesize(lo + ext = strstr(buf, "K"); + if (ext) { + shift = 10; +- ext = '\0'; ++ *ext = '\0'; + } else { + ext = strstr(buf, "M"); + if (ext) { + shift = 20; +- ext = '\0'; ++ *ext = '\0'; + } + } + diff --git a/libgcrypt-out-of-core-handler.patch b/libgcrypt-out-of-core-handler.patch new file mode 100644 index 0000000..e7cd22a --- /dev/null +++ b/libgcrypt-out-of-core-handler.patch @@ -0,0 +1,12 @@ +Index: libgcrypt-1.9.4/src/global.c +=================================================================== +--- libgcrypt-1.9.4.orig/src/global.c ++++ libgcrypt-1.9.4/src/global.c +@@ -951,7 +951,6 @@ _gcry_set_outofcore_handler (int (*f)(vo + + if (fips_mode () ) + { +- log_info ("out of core handler ignored in FIPS mode\n"); + return; + } + diff --git a/libgcrypt.changes b/libgcrypt.changes index c8c7d4c..d61904f 100644 --- a/libgcrypt.changes +++ b/libgcrypt.changes @@ -1,3 +1,19 @@ +------------------------------------------------------------------- +Tue Aug 23 09:19:00 UTC 2022 - Pedro Monreal + +- FIPS: gpg/gpg2 gets out of core handler in FIPS mode while + typing Tab key to Auto-Completion. [bsc#1182983] + * Add libgcrypt-out-of-core-handler.patch + +------------------------------------------------------------------- +Mon Aug 8 11:33:03 UTC 2022 - Pedro Monreal + +- FIPS: Port libgcrypt to use jitterentropy [bsc#1202117, jsc#SLE-24941] + * Enable the jitter based entropy generator by default in random.conf + - Add libgcrypt-jitterentropy-3.3.0.patch + * Update the internal jitterentropy to version 3.4.0 + - Add libgcrypt-jitterentropy-3.4.0.patch + ------------------------------------------------------------------- Mon Aug 1 07:27:35 UTC 2022 - Stephan Kulow @@ -5,6 +21,31 @@ Mon Aug 1 07:27:35 UTC 2022 - Stephan Kulow - Do not use %release in binaries (but use SOURCE_DATE_EPOCH) - Fix date call messed up by spec-cleaner +------------------------------------------------------------------- +Thu Apr 14 12:30:36 UTC 2022 - Dennis Knorr + +- FIPS: extend the service indicator [bsc#1190700] + * introduced a pk indicator function + * adapted the approved and non approved ciphersuites + * Add libgcrypt_indicators_changes.patch + * Add libgcrypt-indicate-shake.patch + +------------------------------------------------------------------- +Tue Mar 22 12:32:09 UTC 2022 - Pedro Monreal + +- FIPS: Implement a service indicator for asymmetric ciphers [bsc#1190700] + * Mark RSA public key encryption and private key decryption with + padding (e.g. OAEP, PKCS) as non-approved since RSA-OAEP lacks + peer key assurance validation requirements per SP800-56Brev2. + * Mark ECC as approved only for NIST curves P-224, P-256, P-384 + and P-521 with check for common NIST names and aliases. + * Mark DSA, ELG, EDDSA, ECDSA and ECDH as non-approved. + * Add libgcrypt-FIPS-SLI-pk.patch + * Rebase libgcrypt-FIPS-service-indicators.patch +- Run the regression tests also in FIPS mode. + * Disable tests for non-FIPS approved algos. + * Rebase: libgcrypt-FIPS-verify-unsupported-KDF-test.patch + ------------------------------------------------------------------- Tue Feb 1 11:28:51 UTC 2022 - Pedro Monreal diff --git a/libgcrypt.spec b/libgcrypt.spec index 65b5a93..f90d6bf 100644 --- a/libgcrypt.spec +++ b/libgcrypt.spec @@ -96,6 +96,17 @@ Patch39: libgcrypt-FIPS-HMAC-short-keylen.patch Patch40: libgcrypt-FIPS-service-indicators.patch #PATCH-FIX-UPSTREAM bsc#1195385 FIPS: Disable DSA in FIPS mode Patch41: libgcrypt-FIPS-disable-DSA.patch +#PATCH-FIX-UPSTREAM bsc#1190700 FIPS: Provide a service-level indicator for PK +Patch42: libgcrypt-FIPS-SLI-pk.patch +#PATCH-FIX-SUSE bsc#1190700 FIPS add indicators +Patch43: libgcrypt_indicators_changes.patch +#PATCH-FIX-SUSE bsc#1190700 FIPS allow shake +Patch44: libgcrypt-indicate-shake.patch +#PATCH-FIX-UPSTREAM bsc#1202117 jsc#SLE-24941 FIPS: Port libgcrypt to use jitterentropy +Patch45: libgcrypt-jitterentropy-3.3.0.patch +Patch46: libgcrypt-jitterentropy-3.4.0.patch +#PATCH-FIX-SUSE bsc#1182983 gpg: out of core handler ignored in FIPS mode while typing Tab key to Auto-Completion +Patch47: libgcrypt-out-of-core-handler.patch BuildRequires: automake >= 1.14 BuildRequires: fipscheck BuildRequires: libgpg-error-devel >= 1.27 @@ -213,6 +224,9 @@ export CFLAGS="%{optflags} $(getconf LFS_CFLAGS)" fipshmac src/.libs/libgcrypt.so.?? %make_build check +# run the regression tests also in FIPS mode +LIBGCRYPT_FORCE_FIPS_MODE=1 make -k check VERBOSE=1 || true + %install %make_install rm %{buildroot}%{_libdir}/%{name}.la diff --git a/libgcrypt_indicators_changes.patch b/libgcrypt_indicators_changes.patch new file mode 100644 index 0000000..53010cc --- /dev/null +++ b/libgcrypt_indicators_changes.patch @@ -0,0 +1,238 @@ +diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi +index afb8a05..c613577 100644 +--- a/doc/gcrypt.texi ++++ b/doc/gcrypt.texi +@@ -968,23 +968,39 @@ is approved under the current FIPS 140-3 certification. If the + combination is approved, this function returns @code{GPG_ERR_NO_ERROR}. + Otherwise @code{GPG_ERR_NOT_SUPPORTED} is returned. + ++@item GCRYCTL_FIPS_SERVICE_INDICATOR_HASH; Arguments: enum gcry_md_algos ++ ++Check if the given HASH is approved under the current FIPS 140-3 ++certification. If the HASH is approved, this function returns ++@code{GPS_ERR_NO_ERROR}. Otherwise @code{GPG_ERR_NOT_SUPPORTED} ++is returned. ++ ++@item GCRYCTL_FIPS_SERVICE_INDICATOR_MAC; Arguments: enum gcry_mac_algos [, unsigned int] ++ ++Check if the given MAC is approved under the current FIPS 140-3 ++certification. The second parameter provides the keylen (if the ++algorithm supports different key sizes). If the MAC is approved, ++this function returns @code{GPS_ERR_NO_ERROR}. Otherwise @code{GPG_ERR_NOT_SUPPORTED} ++is returned. ++ + @item GCRYCTL_FIPS_SERVICE_INDICATOR_KDF; Arguments: enum gcry_kdf_algos + + Check if the given KDF is approved under the current FIPS 140-3 +-certification. If the KDF is approved, this function returns +-@code{GPG_ERR_NO_ERROR}. Otherwise @code{GPG_ERR_NOT_SUPPORTED} +-is returned. ++certification. If the KDF is approved, this function returns @code{GPG_ERR_NO_ERROR}. ++Otherwise @code{GPG_ERR_NOT_SUPPORTED} is returned. + + @item GCRYCTL_FIPS_SERVICE_INDICATOR_PK; Arguments: enum gcry_pk_algos +-[, enum pk_operation (only for GCRY_PK_RSA)] [, const char * (only for +-GCRY_PK_ECC, GCRY_PK_ECDH or GCRY_PK_ECDSA)] ++[, constants GCRY_PK_USAGE_ENCR or GCRY_PK_USAGE_SIGN, unsigned int (only for GCRY_PK_RSA)] ++[, const char * (only for GCRY_PK_ECC, GCRY_PK_ECDH or GCRY_PK_ECDSA)] + + Check if the given asymmetric cipher is approved under the current FIPS +-140-3 certification. For GCRY_PK_RSA, an additional parameter for the +-operation mode @code{enum pk_operation} is required. For GCRY_PK_ECC, +-GCRY_PK_ECDH and GCRY_PK_ECDSA, the additional parameter is the curve +-name or its alias as @code{const char *}. If the combination is +-approved, this function returns @code{GPG_ERR_NO_ERROR}. Otherwise ++140-3 certification. For GCRY_PK_RSA, two additional parameter are required: ++first describes the purpose of the algorithm through one of the constants ++(GCRY_PK_USAGE_ENCR for encryption or decryption operations; GCRY_PK_USAGE_SIGN for ++sign or verify operations). ++Second one is the key length. For GCRY_PK_ECC, GCRY_PK_ECDH and GCRY_PK_ECDSA, ++only a single parameter is needed: the curve name or its alias as @code{const char *}. ++If the combination is approved, this function returns @code{GPG_ERR_NO_ERROR}. Otherwise + @code{GPG_ERR_NOT_SUPPORTED} is returned. + + @end table +diff --git a/src/fips.c b/src/fips.c +index f523e7d..d5ca482 100644 +--- a/src/fips.c ++++ b/src/fips.c +@@ -452,6 +452,7 @@ _gcry_fips_indicator_cipher (va_list arg_ptr) + mode = va_arg (arg_ptr, enum gcry_cipher_modes); + switch (mode) + { ++ case GCRY_CIPHER_MODE_AESWRAP: + case GCRY_CIPHER_MODE_ECB: + case GCRY_CIPHER_MODE_CBC: + case GCRY_CIPHER_MODE_CFB: +@@ -459,7 +460,6 @@ _gcry_fips_indicator_cipher (va_list arg_ptr) + case GCRY_CIPHER_MODE_OFB: + case GCRY_CIPHER_MODE_CTR: + case GCRY_CIPHER_MODE_CCM: +- case GCRY_CIPHER_MODE_GCM: + case GCRY_CIPHER_MODE_XTS: + return GPG_ERR_NO_ERROR; + default: +@@ -519,11 +519,25 @@ static const struct + { NULL, NULL} + }; + ++enum pk_operation convert_from_pk_usage(unsigned int pk_usage) ++{ ++ switch (pk_usage) ++ { ++ case GCRY_PK_USAGE_SIGN: ++ return PUBKEY_OP_SIGN; ++ case GCRY_PK_USAGE_ENCR: ++ return PUBKEY_OP_ENCRYPT; ++ default: ++ return PUBKEY_OP_DECRYPT; ++ } ++} ++ + int + _gcry_fips_indicator_pk (va_list arg_ptr) + { + enum gcry_pk_algos alg = va_arg (arg_ptr, enum gcry_pk_algos); + enum pk_operation oper; ++ unsigned int keylen; + const char *curve_name; + + switch (alg) +@@ -531,13 +545,17 @@ _gcry_fips_indicator_pk (va_list arg_ptr) + case GCRY_PK_RSA: + case GCRY_PK_RSA_E: + case GCRY_PK_RSA_S: +- oper = va_arg (arg_ptr, enum pk_operation); ++ oper = convert_from_pk_usage(va_arg (arg_ptr, unsigned int)); + switch (oper) + { + case PUBKEY_OP_ENCRYPT: + case PUBKEY_OP_DECRYPT: + return GPG_ERR_NOT_SUPPORTED; + default: ++ keylen = va_arg (arg_ptr, unsigned int); ++ if (keylen < 2048) { ++ return GPG_ERR_NOT_SUPPORTED; ++ } + return GPG_ERR_NO_ERROR; + } + case GCRY_PK_ECC: +@@ -557,6 +575,60 @@ _gcry_fips_indicator_pk (va_list arg_ptr) + } + } + ++int ++_gcry_fips_indicator_hash (va_list arg_ptr) ++{ ++ enum gcry_md_algos alg = va_arg (arg_ptr, enum gcry_md_algos); ++ ++ switch (alg) ++ { ++ case GCRY_MD_SHA1: ++ case GCRY_MD_SHA224: ++ case GCRY_MD_SHA256: ++ case GCRY_MD_SHA384: ++ case GCRY_MD_SHA512: ++ case GCRY_MD_SHA512_224: ++ case GCRY_MD_SHA512_256: ++ case GCRY_MD_SHA3_224: ++ case GCRY_MD_SHA3_256: ++ case GCRY_MD_SHA3_384: ++ case GCRY_MD_SHA3_512: ++ return GPG_ERR_NO_ERROR; ++ default: ++ return GPG_ERR_NOT_SUPPORTED; ++ } ++} ++ ++int ++_gcry_fips_indicator_mac (va_list arg_ptr) ++{ ++ enum gcry_mac_algos alg = va_arg (arg_ptr, enum gcry_mac_algos); ++ unsigned int keylen = va_arg (arg_ptr, unsigned int); ++ ++ switch (alg) ++ { ++ case GCRY_MAC_HMAC_SHA1: ++ case GCRY_MAC_HMAC_SHA224: ++ case GCRY_MAC_HMAC_SHA256: ++ case GCRY_MAC_HMAC_SHA384: ++ case GCRY_MAC_HMAC_SHA512: ++ case GCRY_MAC_HMAC_SHA512_224: ++ case GCRY_MAC_HMAC_SHA512_256: ++ case GCRY_MAC_HMAC_SHA3_224: ++ case GCRY_MAC_HMAC_SHA3_256: ++ case GCRY_MAC_HMAC_SHA3_384: ++ case GCRY_MAC_HMAC_SHA3_512: ++ if (keylen >= 112) { ++ return GPG_ERR_NO_ERROR; ++ } ++ case GCRY_MAC_CMAC_AES: ++ if (keylen == 128 || keylen == 192 || keylen == 256) { ++ return GPG_ERR_NO_ERROR; ++ } ++ default: ++ return GPG_ERR_NOT_SUPPORTED; ++ } ++} + + /* This is a test on whether the library is in the error or + operational state. */ +diff --git a/src/g10lib.h b/src/g10lib.h +index 9fc868b..92c24a5 100644 +--- a/src/g10lib.h ++++ b/src/g10lib.h +@@ -488,7 +488,9 @@ void _gcry_fips_signal_error (const char *srcfile, + #endif + + int _gcry_fips_indicator_cipher (va_list arg_ptr); ++int _gcry_fips_indicator_hash (va_list arg_ptr); + int _gcry_fips_indicator_kdf (va_list arg_ptr); ++int _gcry_fips_indicator_mac (va_list arg_ptr); + int _gcry_fips_indicator_pk (va_list arg_ptr); + + int _gcry_fips_is_operational (void); +diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in +index 7704d17..344f879 100644 +--- a/src/gcrypt.h.in ++++ b/src/gcrypt.h.in +@@ -337,7 +337,9 @@ enum gcry_ctl_cmds + GCRYCTL_SET_ALLOW_WEAK_KEY = 79, + GCRYCTL_FIPS_SERVICE_INDICATOR_CIPHER = 81, + GCRYCTL_FIPS_SERVICE_INDICATOR_KDF = 82, +- GCRYCTL_FIPS_SERVICE_INDICATOR_PK = 83 ++ GCRYCTL_FIPS_SERVICE_INDICATOR_PK = 83, ++ GCRYCTL_FIPS_SERVICE_INDICATOR_HASH = 84, ++ GCRYCTL_FIPS_SERVICE_INDICATOR_MAC = 85 + }; + + /* Perform various operations defined by CMD. */ +diff --git a/src/global.c b/src/global.c +index c01b424..03756ea 100644 +--- a/src/global.c ++++ b/src/global.c +@@ -762,12 +762,24 @@ _gcry_vcontrol (enum gcry_ctl_cmds cmd, va_list arg_ptr) + rc = _gcry_fips_indicator_cipher (arg_ptr); + break; + ++ case GCRYCTL_FIPS_SERVICE_INDICATOR_HASH: ++ /* Get FIPS Service Indicator for a given HASH. Returns GPG_ERR_NO_ERROR ++ * if algorithm is allowed or GPG_ERR_NOT_SUPPORTED otherwise */ ++ rc = _gcry_fips_indicator_hash (arg_ptr); ++ break; ++ + case GCRYCTL_FIPS_SERVICE_INDICATOR_KDF: + /* Get FIPS Service Indicator for a given KDF. Returns GPG_ERR_NO_ERROR + * if algorithm is allowed or GPG_ERR_NOT_SUPPORTED otherwise */ + rc = _gcry_fips_indicator_kdf (arg_ptr); + break; + ++ case GCRYCTL_FIPS_SERVICE_INDICATOR_MAC: ++ /* Get FIPS Service Indicator for a given HMAC. Returns GPG_ERR_NO_ERROR ++ * if algorithm is allowed or GPG_ERR_NOT_SUPPORTED otherwise */ ++ rc = _gcry_fips_indicator_mac (arg_ptr); ++ break; ++ + case GCRYCTL_FIPS_SERVICE_INDICATOR_PK: + /* Get FIPS Service Indicator for a given asymmetric algorithm. For + * GCRY_PK_RSA, an additional parameter for the operation mode is diff --git a/random.conf b/random.conf index 5ccb076..378ba78 100644 --- a/random.conf +++ b/random.conf @@ -6,4 +6,4 @@ # only-urandom # Disable the use of the jitter based entropy generator. -disable-jent +# disable-jent