1 /* 2 * Non-physical true random number generator based on timing jitter. 3 * 4 * Copyright Stephan Mueller <smueller@chronox.de>, 2014 5 * Copyright Petr Štetiar <ynezz@true.cz>, 2019 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 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 18 * written permission. 19 * 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.) 25 * 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 37 * DAMAGE. 38 */ 39 40 #include <stdio.h> 41 #include <stdlib.h> 42 #include <unistd.h> 43 44 #include <sys/ioctl.h> 45 #include <linux/random.h> 46 47 #include <libubox/uloop.h> 48 49 #include "log.h" 50 #include "jitterentropy.h" 51 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))) 59 60 #ifdef URNGD_DEBUG 61 unsigned int debug; 62 #endif 63 64 struct urngd { 65 struct uloop_fd rnd_fd; 66 struct rand_data *ec; 67 struct rand_pool_info *rpi; 68 }; 69 70 static struct urngd urngd_service; 71 72 static inline void memset_secure(void *s, int c, size_t n) 73 { 74 memset(s, c, n); 75 __asm__ __volatile__("" : : "r" (s) : "memory"); 76 } 77 78 static size_t write_entropy(struct urngd *u, char *buf, size_t len, 79 size_t entropy_bytes) 80 { 81 int ret; 82 size_t written = 0; 83 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); 88 memset(buf, 0, len); 89 90 ret = ioctl(u->rnd_fd.fd, RNDADDENTROPY, u->rpi); 91 if (0 > ret) { 92 ERROR("error injecting entropy: %s\n", strerror(errno)); 93 } else { 94 DEBUG(1, "injected %zub (%zub of entropy)\n", len, entropy_bytes); 95 written = len; 96 } 97 98 u->rpi->entropy_count = 0; 99 u->rpi->buf_size = 0; 100 memset(u->rpi->buf, 0, len); 101 102 return written; 103 } 104 105 static size_t gather_entropy(struct urngd *u) 106 { 107 size_t ret = 0; 108 char buf[(ENTROPYBYTES * OVERSAMPLINGFACTOR)]; 109 110 if (jent_read_entropy(u->ec, buf, sizeof(buf)) < 0) { 111 ERROR("cannot read entropy\n"); 112 return 0; 113 } 114 115 ret = write_entropy(u, buf, sizeof(buf), ENTROPYBYTES); 116 if (sizeof(buf) != ret) { 117 ERROR("injected %zub of entropy, less then %zub expected\n", 118 ret, sizeof(buf)); 119 } else { 120 ret = sizeof(buf); 121 } 122 123 memset_secure(buf, 0, sizeof(buf)); 124 DEBUG(2, DEV_RANDOM " fed with %zub of entropy\n", ret); 125 126 return ret; 127 } 128 129 static void low_entropy_cb(struct uloop_fd *ufd, unsigned int events) 130 { 131 struct urngd *u = container_of(ufd, struct urngd, rnd_fd); 132 133 DEBUG(2, DEV_RANDOM " signals low entropy\n"); 134 gather_entropy(u); 135 } 136 137 static void urngd_done(struct urngd *u) 138 { 139 if (u->ec) { 140 jent_entropy_collector_free(u->ec); 141 u->ec = NULL; 142 } 143 144 if (u->rpi) { 145 memset(u->rpi, 0, ENTROPYPOOLBYTES); 146 free(u->rpi); 147 u->rpi = NULL; 148 } 149 150 if (u->rnd_fd.fd) { 151 close(u->rnd_fd.fd); 152 u->rnd_fd.fd = 0; 153 } 154 } 155 156 static bool urngd_init(struct urngd *u) 157 { 158 int ret = jent_entropy_init(); 159 if (ret) { 160 ERROR("jent-rng init failed, err: %d\n", ret); 161 return false; 162 } 163 164 u->ec = jent_entropy_collector_alloc(1, 0); 165 if (!u->ec) { 166 ERROR("jent-rng alloc failed\n"); 167 return false; 168 } 169 170 u->rpi = malloc(ENTROPYPOOLBYTES); 171 if (!u->rpi) { 172 ERROR("rand pool alloc failed\n"); 173 return false; 174 } 175 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\n", strerror(errno)); 180 return false; 181 } 182 183 uloop_fd_add(&u->rnd_fd, ULOOP_WRITE); 184 185 return true; 186 } 187 188 static int usage(const char *prog) 189 { 190 fprintf(stderr, "Usage: %s [options]\n" 191 "Options:\n" 192 #ifdef URNGD_DEBUG 193 " -d <level> Enable debug messages\n" 194 #endif 195 " -S Print messages to stdout\n" 196 "\n", prog); 197 return 1; 198 } 199 200 int main(int argc, char **argv) 201 { 202 int ch; 203 int ulog_channels = ULOG_KMSG; 204 #ifdef URNGD_DEBUG 205 char *dbglvl = getenv("DBGLVL"); 206 207 if (dbglvl) { 208 debug = atoi(dbglvl); 209 unsetenv("DBGLVL"); 210 } 211 #endif 212 213 while ((ch = getopt(argc, argv, "d:S")) != -1) { 214 switch (ch) { 215 #ifdef URNGD_DEBUG 216 case 'd': 217 debug = atoi(optarg); 218 break; 219 #endif 220 case 'S': 221 ulog_channels = ULOG_STDIO; 222 break; 223 default: 224 return usage(argv[0]); 225 } 226 } 227 228 ulog_open(ulog_channels, LOG_DAEMON, "urngd"); 229 230 uloop_init(); 231 if (!urngd_init(&urngd_service)) { 232 uloop_done(); 233 return -1; 234 } 235 236 LOG("v%s started.\n", URNGD_VERSION); 237 238 gather_entropy(&urngd_service); 239 240 uloop_run(); 241 uloop_done(); 242 243 urngd_done(&urngd_service); 244 245 return 0; 246 } 247
This page was automatically generated by LXR 0.3.1. • OpenWrt