2 * Non-physical true random number generator based on timing jitter.
4 * Copyright Stephan Mueller <smueller@chronox.de>, 2014
5 * Copyright Petr Štetiar <ynezz@true.cz>, 2019
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, and the entire permission notice in its entirety,
12 * including the disclaimer of warranties.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote
17 * products derived from this software without specific prior
20 * ALTERNATIVELY, this product may be distributed under the terms of
21 * the GNU General Public License, in which case the provisions of the GPL are
22 * required INSTEAD OF the above restrictions. (This clause is
23 * necessary due to a potential bad interaction between the GPL and
24 * the restrictions contained in a BSD-style copyright.)
26 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
27 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
28 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
29 * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
30 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
32 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
33 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
36 * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
44 #include <sys/ioctl.h>
45 #include <linux/random.h>
47 #include <libubox/uloop.h>
50 #include "jitterentropy.h"
52 #define ENTROPYBYTES 32
53 #define ENTROPYTHRESH 1024
54 #define OVERSAMPLINGFACTOR 2
55 #define DEV_RANDOM "/dev/random"
56 #define ENTROPYAVAIL "/proc/sys/kernel/random/entropy_avail"
57 #define ENTROPYPOOLBYTES (sizeof(struct rand_pool_info) + \
58 (ENTROPYBYTES * OVERSAMPLINGFACTOR * sizeof(char)))
65 struct uloop_fd rnd_fd
;
67 struct rand_pool_info
*rpi
;
70 static struct urngd urngd_service
;
72 static inline void memset_secure(void *s
, int c
, size_t n
)
75 __asm__
__volatile__("" : : "r" (s
) : "memory");
78 static size_t write_entropy(struct urngd
*u
, char *buf
, size_t len
,
84 /* value is in bits */
85 u
->rpi
->entropy_count
= (entropy_bytes
* 8);
86 u
->rpi
->buf_size
= len
;
87 memcpy(u
->rpi
->buf
, buf
, len
);
90 ret
= ioctl(u
->rnd_fd
.fd
, RNDADDENTROPY
, u
->rpi
);
92 ERROR("error injecting entropy: %s\n", strerror(errno
));
94 DEBUG(1, "injected %ub (%ub of entropy)\n", len
, entropy_bytes
);
98 u
->rpi
->entropy_count
= 0;
100 memset(u
->rpi
->buf
, 0, len
);
105 static size_t gather_entropy(struct urngd
*u
)
108 char buf
[(ENTROPYBYTES
* OVERSAMPLINGFACTOR
)];
110 if (jent_read_entropy(u
->ec
, buf
, sizeof(buf
)) < 0) {
111 ERROR("cannot read entropy\n");
115 ret
= write_entropy(u
, buf
, sizeof(buf
), ENTROPYBYTES
);
116 if (sizeof(buf
) != ret
) {
117 ERROR("injected %lub of entropy, less then %db expected\n",
123 memset_secure(buf
, 0, sizeof(buf
));
124 DEBUG(2, DEV_RANDOM
" fed with %lub of entropy\n", ret
);
129 static void low_entropy_cb(struct uloop_fd
*ufd
, unsigned int events
)
131 struct urngd
*u
= container_of(ufd
, struct urngd
, rnd_fd
);
133 DEBUG(2, DEV_RANDOM
" signals low entropy\n");
137 static void urngd_done(struct urngd
*u
)
140 jent_entropy_collector_free(u
->ec
);
145 memset(u
->rpi
, 0, ENTROPYPOOLBYTES
);
156 static bool urngd_init(struct urngd
*u
)
158 int ret
= jent_entropy_init();
160 ERROR("jent-rng init failed, err: %d\n", ret
);
164 u
->ec
= jent_entropy_collector_alloc(1, 0);
166 ERROR("jent-rng alloc failed\n");
170 u
->rpi
= malloc(ENTROPYPOOLBYTES
);
172 ERROR("rand pool alloc failed\n");
176 u
->rnd_fd
.cb
= low_entropy_cb
;
177 u
->rnd_fd
.fd
= open(DEV_RANDOM
, O_WRONLY
);
178 if (u
->rnd_fd
.fd
< 1) {
179 ERROR(DEV_RANDOM
" open failed: %s", strerror(errno
));
183 uloop_fd_add(&u
->rnd_fd
, ULOOP_READ
);
188 static int usage(const char *prog
)
190 fprintf(stderr
, "Usage: %s [options]\n"
193 " -d <level> Enable debug messages\n"
195 " -S Print messages to stdout\n"
200 int main(int argc
, char **argv
)
203 int ulog_channels
= ULOG_KMSG
;
205 char *dbglvl
= getenv("DBGLVL");
208 debug
= atoi(dbglvl
);
213 while ((ch
= getopt(argc
, argv
, "d:S")) != -1) {
217 debug
= atoi(optarg
);
221 ulog_channels
= ULOG_STDIO
;
224 return usage(argv
[0]);
228 if (!urngd_init(&urngd_service
))
231 ulog_open(ulog_channels
, LOG_DAEMON
, "urngd");
232 LOG("v%s started.\n", URNGD_VERSION
);
234 gather_entropy(&urngd_service
);
240 urngd_done(&urngd_service
);