summaryrefslogtreecommitdiff
path: root/libtommath/bn_mp_rand.c
diff options
context:
space:
mode:
authorSteffen Jaeckel <s_jaeckel@gmx.de>2019-09-16 15:50:38 +0200
committerSteffen Jaeckel <s_jaeckel@gmx.de>2019-09-16 15:50:38 +0200
commit577b7c01fef2c4dd6ec499398e64aa2adeda7e8f (patch)
tree8d6f745fddd3a9c170f7c98603518f77b515da4f /libtommath/bn_mp_rand.c
parent663fc015dbb5b39ac6be6630a003f0530af734fb (diff)
downloaddropbear-577b7c01fef2c4dd6ec499398e64aa2adeda7e8f.tar.gz
update ltm to 1.1.0 and enable FIPS 186.4 compliant key-generation (#79)
* make key-generation compliant to FIPS 186.4 * fix includes in tommath_class.h * update fuzzcorpus instead of error-out * fixup fuzzing make-targets * update Makefile.in * apply necessary patches to ltm sources * clean-up not required ltm files * update to vanilla ltm 1.1.0 this already only contains the required files * remove set/get double
Diffstat (limited to 'libtommath/bn_mp_rand.c')
-rw-r--r--libtommath/bn_mp_rand.c246
1 files changed, 194 insertions, 52 deletions
diff --git a/libtommath/bn_mp_rand.c b/libtommath/bn_mp_rand.c
index 93e255a..06a6f93 100644
--- a/libtommath/bn_mp_rand.c
+++ b/libtommath/bn_mp_rand.c
@@ -1,4 +1,4 @@
-#include <tommath_private.h>
+#include "tommath_private.h"
#ifdef BN_MP_RAND_C
/* LibTomMath, multiple-precision integer library -- Tom St Denis
*
@@ -9,72 +9,214 @@
* Michael Fromberger but has been written from scratch with
* additional optimizations in place.
*
- * The library is free for all purposes without any express
- * guarantee it works.
- *
- * Tom St Denis, tstdenis82@gmail.com, http://libtom.org
+ * SPDX-License-Identifier: Unlicense
+ */
+
+/* First the OS-specific special cases
+ * - *BSD
+ * - Windows
*/
+#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
+#define MP_ARC4RANDOM
+#define MP_GEN_RANDOM_MAX 0xffffffffu
+#define MP_GEN_RANDOM_SHIFT 32
-#if MP_GEN_RANDOM_MAX == 0xffffffff
- #define MP_GEN_RANDOM_SHIFT 32
-#elif MP_GEN_RANDOM_MAX == 32767
- /* SHRT_MAX */
- #define MP_GEN_RANDOM_SHIFT 15
-#elif MP_GEN_RANDOM_MAX == 2147483647
- /* INT_MAX */
- #define MP_GEN_RANDOM_SHIFT 31
-#elif !defined(MP_GEN_RANDOM_SHIFT)
-#error Thou shalt define their own valid MP_GEN_RANDOM_SHIFT
+static int s_read_arc4random(mp_digit *p)
+{
+ mp_digit d = 0, msk = 0;
+ do {
+ d <<= MP_GEN_RANDOM_SHIFT;
+ d |= ((mp_digit) arc4random());
+ msk <<= MP_GEN_RANDOM_SHIFT;
+ msk |= (MP_MASK & MP_GEN_RANDOM_MAX);
+ } while ((MP_MASK & msk) != MP_MASK);
+ *p = d;
+ return MP_OKAY;
+}
#endif
-/* makes a pseudo-random int of a given size */
-static mp_digit s_gen_random(void)
+#if defined(_WIN32) || defined(_WIN32_WCE)
+#define MP_WIN_CSP
+
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0400
+#endif
+#ifdef _WIN32_WCE
+#define UNDER_CE
+#define ARM
+#endif
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <wincrypt.h>
+
+static HCRYPTPROV hProv = 0;
+
+static void s_cleanup_win_csp(void)
{
- mp_digit d = 0, msk = 0;
- do {
- d <<= MP_GEN_RANDOM_SHIFT;
- d |= ((mp_digit) MP_GEN_RANDOM());
- msk <<= MP_GEN_RANDOM_SHIFT;
- msk |= (MP_MASK & MP_GEN_RANDOM_MAX);
- } while ((MP_MASK & msk) != MP_MASK);
- d &= MP_MASK;
- return d;
+ CryptReleaseContext(hProv, 0);
+ hProv = 0;
}
-int
-mp_rand (mp_int * a, int digits)
+static int s_read_win_csp(mp_digit *p)
{
- int res;
- mp_digit d;
+ int ret = -1;
+ if (hProv == 0) {
+ if (!CryptAcquireContext(&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL,
+ (CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET)) &&
+ !CryptAcquireContext(&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL,
+ CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET | CRYPT_NEWKEYSET)) {
+ hProv = 0;
+ return ret;
+ }
+ atexit(s_cleanup_win_csp);
+ }
+ if (CryptGenRandom(hProv, sizeof(*p), (void *)p) == TRUE) {
+ ret = MP_OKAY;
+ }
+ return ret;
+}
+#endif /* WIN32 */
- mp_zero (a);
- if (digits <= 0) {
- return MP_OKAY;
- }
+#if !defined(MP_WIN_CSP) && defined(__linux__) && defined(__GLIBC_PREREQ)
+#if __GLIBC_PREREQ(2, 25)
+#define MP_GETRANDOM
+#include <sys/random.h>
+#include <errno.h>
- /* first place a random non-zero digit */
- do {
- d = s_gen_random();
- } while (d == 0);
+static int s_read_getrandom(mp_digit *p)
+{
+ int ret;
+ do {
+ ret = getrandom(p, sizeof(*p), 0);
+ } while ((ret == -1) && (errno == EINTR));
+ if (ret == sizeof(*p)) return MP_OKAY;
+ return -1;
+}
+#endif
+#endif
- if ((res = mp_add_d (a, d, a)) != MP_OKAY) {
- return res;
- }
+/* We assume all platforms besides windows provide "/dev/urandom".
+ * In case yours doesn't, define MP_NO_DEV_URANDOM at compile-time.
+ */
+#if !defined(MP_WIN_CSP) && !defined(MP_NO_DEV_URANDOM)
+#ifndef MP_DEV_URANDOM
+#define MP_DEV_URANDOM "/dev/urandom"
+#endif
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
- while (--digits > 0) {
- if ((res = mp_lshd (a, 1)) != MP_OKAY) {
- return res;
- }
+static int s_read_dev_urandom(mp_digit *p)
+{
+ ssize_t r;
+ int fd;
+ do {
+ fd = open(MP_DEV_URANDOM, O_RDONLY);
+ } while ((fd == -1) && (errno == EINTR));
+ if (fd == -1) return -1;
+ do {
+ r = read(fd, p, sizeof(*p));
+ } while ((r == -1) && (errno == EINTR));
+ close(fd);
+ if (r != sizeof(*p)) return -1;
+ return MP_OKAY;
+}
+#endif
- if ((res = mp_add_d (a, s_gen_random(), a)) != MP_OKAY) {
+#if defined(MP_PRNG_ENABLE_LTM_RNG)
+unsigned long (*ltm_rng)(unsigned char *out, unsigned long outlen, void (*callback)(void));
+void (*ltm_rng_callback)(void);
+
+static int s_read_ltm_rng(mp_digit *p)
+{
+ unsigned long ret;
+ if (ltm_rng == NULL) return -1;
+ ret = ltm_rng((void *)p, sizeof(*p), ltm_rng_callback);
+ if (ret != sizeof(*p)) return -1;
+ return MP_OKAY;
+}
+#endif
+
+static int s_rand_digit(mp_digit *p)
+{
+ int ret = -1;
+
+#if defined(MP_ARC4RANDOM)
+ ret = s_read_arc4random(p);
+ if (ret == MP_OKAY) return ret;
+#endif
+
+#if defined(MP_WIN_CSP)
+ ret = s_read_win_csp(p);
+ if (ret == MP_OKAY) return ret;
+#else
+
+#if defined(MP_GETRANDOM)
+ ret = s_read_getrandom(p);
+ if (ret == MP_OKAY) return ret;
+#endif
+#if defined(MP_DEV_URANDOM)
+ ret = s_read_dev_urandom(p);
+ if (ret == MP_OKAY) return ret;
+#endif
+
+#endif /* MP_WIN_CSP */
+
+#if defined(MP_PRNG_ENABLE_LTM_RNG)
+ ret = s_read_ltm_rng(p);
+ if (ret == MP_OKAY) return ret;
+#endif
+
+ return ret;
+}
+
+/* makes a pseudo-random int of a given size */
+int mp_rand_digit(mp_digit *r)
+{
+ int ret = s_rand_digit(r);
+ *r &= MP_MASK;
+ return ret;
+}
+
+int mp_rand(mp_int *a, int digits)
+{
+ int res;
+ mp_digit d;
+
+ mp_zero(a);
+ if (digits <= 0) {
+ return MP_OKAY;
+ }
+
+ /* first place a random non-zero digit */
+ do {
+ if (mp_rand_digit(&d) != MP_OKAY) {
+ return MP_VAL;
+ }
+ } while (d == 0u);
+
+ if ((res = mp_add_d(a, d, a)) != MP_OKAY) {
return res;
- }
- }
+ }
+
+ while (--digits > 0) {
+ if ((res = mp_lshd(a, 1)) != MP_OKAY) {
+ return res;
+ }
+
+ if (mp_rand_digit(&d) != MP_OKAY) {
+ return MP_VAL;
+ }
+ if ((res = mp_add_d(a, d, a)) != MP_OKAY) {
+ return res;
+ }
+ }
- return MP_OKAY;
+ return MP_OKAY;
}
#endif
-/* ref: $Format:%D$ */
-/* git commit: $Format:%H$ */
-/* commit time: $Format:%ai$ */
+/* ref: HEAD -> master, tag: v1.1.0 */
+/* git commit: 08549ad6bc8b0cede0b357a9c341c5c6473a9c55 */
+/* commit time: 2019-01-28 20:32:32 +0100 */