michael@0: /* michael@0: * rand_source.c michael@0: * michael@0: * implements a random source based on /dev/random michael@0: * michael@0: * David A. McGrew michael@0: * Cisco Systems, Inc. michael@0: */ michael@0: /* michael@0: * michael@0: * Copyright(c) 2001-2006 Cisco Systems, Inc. michael@0: * All rights reserved. michael@0: * michael@0: * Redistribution and use in source and binary forms, with or without michael@0: * modification, are permitted provided that the following conditions michael@0: * are met: michael@0: * michael@0: * Redistributions of source code must retain the above copyright michael@0: * notice, this list of conditions and the following disclaimer. michael@0: * michael@0: * Redistributions in binary form must reproduce the above michael@0: * copyright notice, this list of conditions and the following michael@0: * disclaimer in the documentation and/or other materials provided michael@0: * with the distribution. michael@0: * michael@0: * Neither the name of the Cisco Systems, Inc. nor the names of its michael@0: * contributors may be used to endorse or promote products derived michael@0: * from this software without specific prior written permission. michael@0: * michael@0: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS michael@0: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT michael@0: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS michael@0: * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE michael@0: * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, michael@0: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES michael@0: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR michael@0: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) michael@0: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, michael@0: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) michael@0: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED michael@0: * OF THE POSSIBILITY OF SUCH DAMAGE. michael@0: * michael@0: */ michael@0: michael@0: #include "config.h" michael@0: michael@0: #ifdef DEV_URANDOM michael@0: # include /* for open() */ michael@0: # include /* for close() */ michael@0: #elif defined(HAVE_RAND_S) michael@0: # define _CRT_RAND_S michael@0: # include michael@0: #else michael@0: # include michael@0: #endif michael@0: michael@0: #include "rand_source.h" michael@0: michael@0: michael@0: /* michael@0: * global dev_rand_fdes is file descriptor for /dev/random michael@0: * michael@0: * This variable is also used to indicate that the random source has michael@0: * been initialized. When this variable is set to the value of the michael@0: * #define RAND_SOURCE_NOT_READY, it indicates that the random source michael@0: * is not ready to be used. The value of the #define michael@0: * RAND_SOURCE_READY is for use whenever that variable is used as an michael@0: * indicator of the state of the random source, but not as a file michael@0: * descriptor. michael@0: */ michael@0: michael@0: #define RAND_SOURCE_NOT_READY (-1) michael@0: #define RAND_SOURCE_READY (17) michael@0: michael@0: static int dev_random_fdes = RAND_SOURCE_NOT_READY; michael@0: michael@0: michael@0: err_status_t michael@0: rand_source_init(void) { michael@0: if (dev_random_fdes >= 0) { michael@0: /* already open */ michael@0: return err_status_ok; michael@0: } michael@0: #ifdef DEV_URANDOM michael@0: /* open random source for reading */ michael@0: dev_random_fdes = open(DEV_URANDOM, O_RDONLY); michael@0: if (dev_random_fdes < 0) michael@0: return err_status_init_fail; michael@0: #elif defined(HAVE_RAND_S) michael@0: dev_random_fdes = RAND_SOURCE_READY; michael@0: #else michael@0: /* no random source available; let the user know */ michael@0: fprintf(stderr, "WARNING: no real random source present!\n"); michael@0: dev_random_fdes = RAND_SOURCE_READY; michael@0: #endif michael@0: return err_status_ok; michael@0: } michael@0: michael@0: err_status_t michael@0: rand_source_get_octet_string(void *dest, uint32_t len) { michael@0: michael@0: /* michael@0: * read len octets from /dev/random to dest, and michael@0: * check return value to make sure enough octets were michael@0: * written michael@0: */ michael@0: #ifdef DEV_URANDOM michael@0: uint8_t *dst = (uint8_t *)dest; michael@0: while (len) michael@0: { michael@0: ssize_t num_read = read(dev_random_fdes, dst, len); michael@0: if (num_read <= 0 || num_read > len) michael@0: return err_status_fail; michael@0: len -= num_read; michael@0: dst += num_read; michael@0: } michael@0: #elif defined(HAVE_RAND_S) michael@0: uint8_t *dst = (uint8_t *)dest; michael@0: while (len) michael@0: { michael@0: unsigned int val; michael@0: errno_t err = rand_s(&val); michael@0: michael@0: if (err != 0) michael@0: return err_status_fail; michael@0: michael@0: *dst++ = val & 0xff; michael@0: len--; michael@0: } michael@0: #else michael@0: /* Generic C-library (rand()) version */ michael@0: /* This is a random source of last resort */ michael@0: uint8_t *dst = (uint8_t *)dest; michael@0: while (len) michael@0: { michael@0: int val = rand(); michael@0: /* rand() returns 0-32767 (ugh) */ michael@0: /* Is this a good enough way to get random bytes? michael@0: It is if it passes FIPS-140... */ michael@0: *dst++ = val & 0xff; michael@0: len--; michael@0: } michael@0: #endif michael@0: return err_status_ok; michael@0: } michael@0: michael@0: err_status_t michael@0: rand_source_deinit(void) { michael@0: if (dev_random_fdes < 0) michael@0: return err_status_dealloc_fail; /* well, we haven't really failed, * michael@0: * but there is something wrong */ michael@0: #ifdef DEV_URANDOM michael@0: close(dev_random_fdes); michael@0: #endif michael@0: dev_random_fdes = RAND_SOURCE_NOT_READY; michael@0: michael@0: return err_status_ok; michael@0: }