Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
186 changes: 164 additions & 22 deletions bn_mp_rand.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,34 +13,171 @@
* guarantee it works.
*/

#if defined(MP_8BIT) || defined(MP_16BIT)
#define MP_GEN_RANDOM_SHIFT DIGIT_BIT
#else
#if MP_GEN_RANDOM_MAX == 0xffffffffu
#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
#endif
#endif
/* 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

/* makes a pseudo-random int of a given size */
static mp_digit s_gen_random(void)
static int s_read_arc4random(mp_digit* p)
{
mp_digit d = 0, msk = 0;
do {
d <<= MP_GEN_RANDOM_SHIFT;
d |= ((mp_digit) MP_GEN_RANDOM());
d |= ((mp_digit) arc4random());
msk <<= MP_GEN_RANDOM_SHIFT;
msk |= (MP_MASK & MP_GEN_RANDOM_MAX);
} while ((MP_MASK & msk) != MP_MASK);
d &= MP_MASK;
return d;
*p = d;
return MP_OKAY;
}
#endif

#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)
{
CryptReleaseContext(hProv, 0);
hProv = 0;
}

static int s_read_win_csp(mp_digit* p)
{
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 */

#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>

static int s_read_getrandom(mp_digit* p)
{
int ret;
do {
ret = getrandom(p, sizeof(*p), 0);
} while((ret == -1) && (errno == EINTR));
Copy link

@sebastianas sebastianas Apr 14, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-   return ret;
+   if (ret == sizeof(*p))
+          return MP_OKAY;
+   return -1;

otherwise you do this and fallback to /dev/urandom because getrandom returns the number of random bytes.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

if (ret == sizeof(*p)) return MP_OKAY;
return -1;
}
#endif
#endif

/* 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>

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 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 */
static int s_gen_random(mp_digit *r)
{
int ret = s_rand_digit(r);
*r &= MP_MASK;
return ret;
}

int mp_rand(mp_int *a, int digits)
Expand All @@ -55,7 +192,9 @@ int mp_rand(mp_int *a, int digits)

/* first place a random non-zero digit */
do {
d = s_gen_random();
if (s_gen_random(&d) != MP_OKAY) {
return MP_VAL;
}
} while (d == 0u);

if ((res = mp_add_d(a, d, a)) != MP_OKAY) {
Expand All @@ -67,7 +206,10 @@ int mp_rand(mp_int *a, int digits)
return res;
}

if ((res = mp_add_d(a, s_gen_random(), a)) != MP_OKAY) {
if (s_gen_random(&d) != MP_OKAY) {
return MP_VAL;
}
if ((res = mp_add_d(a, d, a)) != MP_OKAY) {
return res;
}
}
Expand Down
20 changes: 8 additions & 12 deletions tommath.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,18 +100,6 @@ typedef uint_least32_t mp_min_u32;
typedef mp_digit mp_min_u32;
#endif

/* use arc4random on platforms that support it */
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
# define MP_GEN_RANDOM() arc4random()
# define MP_GEN_RANDOM_MAX 0xffffffffu
#endif

/* use rand() as fall-back if there's no better rand function */
#ifndef MP_GEN_RANDOM
# define MP_GEN_RANDOM() rand()
# define MP_GEN_RANDOM_MAX RAND_MAX
#endif

#define MP_DIGIT_BIT DIGIT_BIT
#define MP_MASK ((((mp_digit)1)<<((mp_digit)DIGIT_BIT))-((mp_digit)1))
#define MP_DIGIT_MAX MP_MASK
Expand Down Expand Up @@ -287,6 +275,14 @@ int mp_cnt_lsb(const mp_int *a);
/* makes a pseudo-random int of a given size */
int mp_rand(mp_int *a, int digits);

#ifdef MP_PRNG_ENABLE_LTM_RNG
/* as last resort we will fall back to libtomcrypt's rng_get_bytes()
* in case you don't use libtomcrypt or use it w/o rng_get_bytes()
* you have to implement it somewhere else, as it's required */
extern unsigned long (*ltm_rng)(unsigned char *out, unsigned long outlen, void (*callback)(void));
extern void (*ltm_rng_callback)(void);
#endif

/* ---> binary operations <--- */
/* c = a XOR b */
int mp_xor(const mp_int *a, const mp_int *b, mp_int *c);
Expand Down