1/* 2 * Copyright (c) 2006 - 2007 Kungliga Tekniska H��gskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 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 * 17 * 3. Neither the name of the Institute nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34#include <config.h> 35 36#include <stdio.h> 37#include <stdlib.h> 38#include <rand.h> 39#include <randi.h> 40 41#include <roken.h> 42 43#ifndef O_BINARY 44#define O_BINARY 0 45#endif 46 47/** 48 * @page page_rand RAND - random number 49 * 50 * See the library functions here: @ref hcrypto_rand 51 */ 52 53const static RAND_METHOD *selected_meth = NULL; 54static ENGINE *selected_engine = NULL; 55 56static void 57init_method(void) 58{ 59 if (selected_meth != NULL) 60 return; 61#ifdef __APPLE__ 62 selected_meth = &hc_rand_unix_method; 63#else 64 selected_meth = &hc_rand_fortuna_method; 65#endif 66} 67 68/** 69 * Seed that random number generator. Secret material can securely be 70 * feed into the function, they will never be returned. 71 * 72 * @param indata seed data 73 * @param size length seed data 74 * 75 * @ingroup hcrypto_rand 76 */ 77 78void 79RAND_seed(const void *indata, size_t size) 80{ 81 init_method(); 82 (*selected_meth->seed)(indata, size); 83} 84 85/** 86 * Get a random block from the random generator, can be used for key material. 87 * 88 * @param outdata random data 89 * @param size length random data 90 * 91 * @return 1 on success, 0 on failure. 92 * 93 * @ingroup hcrypto_rand 94 */ 95int 96RAND_bytes(void *outdata, size_t size) 97{ 98 init_method(); 99 return (*selected_meth->bytes)(outdata, size); 100} 101 102/** 103 * Reset and free memory used by the random generator. 104 * 105 * @ingroup hcrypto_rand 106 */ 107 108void 109RAND_cleanup(void) 110{ 111 const RAND_METHOD *meth = selected_meth; 112 ENGINE *engine = selected_engine; 113 114 selected_meth = NULL; 115 selected_engine = NULL; 116 117 if (meth) 118 (*meth->cleanup)(); 119 if (engine) 120 ENGINE_finish(engine); 121} 122 123/** 124 * Seed that random number generator. Secret material can securely be 125 * feed into the function, they will never be returned. 126 * 127 * @param indata the input data. 128 * @param size size of in data. 129 * @param entropi entropi in data. 130 * 131 * 132 * @ingroup hcrypto_rand 133 */ 134 135void 136RAND_add(const void *indata, size_t size, double entropi) 137{ 138 init_method(); 139 (*selected_meth->add)(indata, size, entropi); 140} 141 142/** 143 * Get a random block from the random generator, should NOT be used for key material. 144 * 145 * @param outdata random data 146 * @param size length random data 147 * 148 * @return 1 on success, 0 on failure. 149 * 150 * @ingroup hcrypto_rand 151 */ 152 153int 154RAND_pseudo_bytes(void *outdata, size_t size) 155{ 156 init_method(); 157 return (*selected_meth->pseudorand)(outdata, size); 158} 159 160/** 161 * Return status of the random generator 162 * 163 * @return 1 if the random generator can deliver random data. 164 * 165 * @ingroup hcrypto_rand 166 */ 167 168int 169RAND_status(void) 170{ 171 init_method(); 172 return (*selected_meth->status)(); 173} 174 175/** 176 * Set the default random method. 177 * 178 * @param meth set the new default method. 179 * 180 * @return 1 on success. 181 * 182 * @ingroup hcrypto_rand 183 */ 184 185int 186RAND_set_rand_method(const RAND_METHOD *meth) 187{ 188 const RAND_METHOD *old = selected_meth; 189 selected_meth = meth; 190 if (old) 191 (*old->cleanup)(); 192 if (selected_engine) { 193 ENGINE_finish(selected_engine); 194 selected_engine = NULL; 195 } 196 return 1; 197} 198 199/** 200 * Get the default random method. 201 * 202 * @ingroup hcrypto_rand 203 */ 204 205const RAND_METHOD * 206RAND_get_rand_method(void) 207{ 208 init_method(); 209 return selected_meth; 210} 211 212/** 213 * Set the default random method from engine. 214 * 215 * @param engine use engine, if NULL is passed it, old method and engine is cleared. 216 * 217 * @return 1 on success, 0 on failure. 218 * 219 * @ingroup hcrypto_rand 220 */ 221 222int 223RAND_set_rand_engine(ENGINE *engine) 224{ 225 const RAND_METHOD *meth, *old = selected_meth; 226 227 if (engine) { 228 ENGINE_up_ref(engine); 229 meth = ENGINE_get_RAND(engine); 230 if (meth == NULL) { 231 ENGINE_finish(engine); 232 return 0; 233 } 234 } else { 235 meth = NULL; 236 } 237 238 if (old) 239 (*old->cleanup)(); 240 241 if (selected_engine) 242 ENGINE_finish(selected_engine); 243 244 selected_engine = engine; 245 selected_meth = meth; 246 247 return 1; 248} 249 250#define RAND_FILE_SIZE 1024 251 252/** 253 * Load a a file and feed it into RAND_seed(). 254 * 255 * @param filename name of file to read. 256 * @param size minimum size to read. 257 * 258 * @ingroup hcrypto_rand 259 */ 260 261int 262RAND_load_file(const char *filename, size_t size) 263{ 264 unsigned char buf[128]; 265 size_t len; 266 ssize_t slen; 267 int fd; 268 269 fd = open(filename, O_RDONLY | O_BINARY, 0600); 270 if (fd < 0) 271 return 0; 272 rk_cloexec(fd); 273 len = 0; 274 while(len < size) { 275 slen = read(fd, buf, sizeof(buf)); 276 if (slen <= 0) 277 break; 278 RAND_seed(buf, slen); 279 len += slen; 280 } 281 close(fd); 282 283 return len ? 1 : 0; 284} 285 286/** 287 * Write of random numbers to a file to store for later initiation with RAND_load_file(). 288 * 289 * @param filename name of file to write. 290 * 291 * @return 1 on success and non-one on failure. 292 * @ingroup hcrypto_rand 293 */ 294 295int 296RAND_write_file(const char *filename) 297{ 298 unsigned char buf[128]; 299 size_t len; 300 int res = 0, fd; 301 302 fd = open(filename, O_WRONLY | O_CREAT | O_BINARY, 0600); 303 if (fd < 0) 304 return 0; 305 rk_cloexec(fd); 306 307 len = 0; 308 while(len < RAND_FILE_SIZE) { 309 res = RAND_bytes(buf, sizeof(buf)); 310 if (res != 1) 311 break; 312 if (write(fd, buf, sizeof(buf)) != sizeof(buf)) { 313 res = 0; 314 break; 315 } 316 len += sizeof(buf); 317 } 318 319 close(fd); 320 321 return res; 322} 323 324/** 325 * Return the default random state filename for a user to use for 326 * RAND_load_file(), and RAND_write_file(). 327 * 328 * @param filename buffer to hold file name. 329 * @param size size of buffer filename. 330 * 331 * @return the buffer filename or NULL on failure. 332 * 333 * @ingroup hcrypto_rand 334 */ 335 336const char * 337RAND_file_name(char *filename, size_t size) 338{ 339 const char *e = NULL; 340 int pathp = 0, ret; 341 342 if (!issuid()) { 343 e = getenv("RANDFILE"); 344 if (e == NULL) { 345 e = getenv("HOME"); 346 if (e) 347 pathp = 1; 348 } 349 } 350 /* 351 * Here we really want to call getpwuid(getuid()) but this will 352 * cause recursive lookups if the nss library uses 353 * gssapi/krb5/hcrypto to authenticate to the ldap servers. 354 */ 355 356 if (e == NULL) 357 return NULL; 358 359 if (pathp) 360 ret = snprintf(filename, size, "%s/.rnd", e); 361 else 362 ret = snprintf(filename, size, "%s", e); 363 364 if (ret <= 0 || ret >= size) 365 return NULL; 366 367 return filename; 368} 369