ntp_crypto_rnd.c revision 293896
1/*
2 * Crypto-quality random number functions
3 *
4 * Author: Harlan Stenn, 2014
5 *
6 * This file is Copyright (c) 2014 by Network Time Foundation.
7 * BSD terms apply: see the file COPYRIGHT in the distribution root for details.
8 */
9
10#include "config.h"
11#include <sys/types.h>
12#ifdef HAVE_UNISTD_H
13# include <unistd.h>
14#endif
15#include <stdio.h>
16
17#include <l_stdlib.h>
18#include <ntp_random.h>
19#include "safecast.h"
20
21#ifdef USE_OPENSSL_CRYPTO_RAND
22#include <openssl/err.h>
23#include <openssl/rand.h>
24
25int crypto_rand_init = 0;
26#else
27
28# ifndef HAVE_ARC4RANDOM_BUF
29static void
30arc4random_buf(void *buf, size_t nbytes);
31
32void
33evutil_secure_rng_get_bytes(void *buf, size_t nbytes);
34
35static void
36arc4random_buf(void *buf, size_t nbytes)
37{
38	evutil_secure_rng_get_bytes(buf, nbytes);
39	return;
40}
41# endif
42#endif
43
44/*
45 * As of late 2014, here's how we plan to provide cryptographic-quality
46 * random numbers:
47 *
48 * - If we are building with OpenSSL, use RAND_poll() and RAND_bytes().
49 * - Otherwise, use arc4random().
50 *
51 * Use of arc4random() can be forced using configure --disable-openssl-random
52 *
53 * We can count on arc4random existing, thru the OS or thru libevent.
54 * The quality of arc4random depends on the implementor.
55 *
56 * RAND_poll() doesn't show up until XXX.  If it's not present, we
57 * need to either provide our own or use arc4random().
58 */
59
60/*
61 * ntp_crypto_srandom:
62 *
63 * Initialize the random number generator, if needed by the underlying
64 * crypto random number generation mechanism.
65 */
66
67void
68ntp_crypto_srandom(
69	void
70	)
71{
72#ifdef USE_OPENSSL_CRYPTO_RAND
73	if (!crypto_rand_init) {
74		RAND_poll();
75		crypto_rand_init = 1;
76	}
77#else
78	/* No initialization needed for arc4random() */
79#endif
80}
81
82
83/*
84 * ntp_crypto_random_buf:
85 *
86 * Returns 0 on success, -1 on error.
87 */
88int
89ntp_crypto_random_buf(
90	void *buf,
91	size_t nbytes
92	)
93{
94#ifdef USE_OPENSSL_CRYPTO_RAND
95	int rc;
96
97	rc = RAND_bytes(buf, size2int_chk(nbytes));
98	if (1 != rc) {
99		unsigned long err;
100		char *err_str;
101
102		err = ERR_get_error();
103		err_str = ERR_error_string(err, NULL);
104		/* XXX: Log the error */
105		(void)&err_str;
106
107		return -1;
108	}
109	return 0;
110#else
111	arc4random_buf(buf, nbytes);
112	return 0;
113#endif
114}
115