Mercurial > hg > dhcpcd
changeset 1471:f571f1664c02 draft
Import cut down arc4ramdom.c from OpenBSD for better randomness.
Partially addresses #183.
| author | Roy Marples <roy@marples.name> |
|---|---|
| date | Wed, 13 Jan 2010 23:44:14 +0000 |
| parents | 15fc071ce025 |
| children | f26dd0e4f778 |
| files | compat/arc4random.c compat/arc4random.h |
| diffstat | 2 files changed, 143 insertions(+), 34 deletions(-) [+] |
line wrap: on
line diff
--- a/compat/arc4random.c Wed Dec 23 08:22:32 2009 +0000 +++ b/compat/arc4random.c Wed Jan 13 23:44:14 2010 +0000 @@ -1,51 +1,158 @@ -/* - * dhcpcd - DHCP client daemon - * Copyright (c) 2006-2009 Roy Marples <roy@marples.name> - * All rights reserved +/* + * Arc4 random number generator for OpenBSD. + * Copyright 1996 David Mazieres <dm@lcs.mit.edu>. + * + * Modification and redistribution in source and binary forms is + * permitted provided that due credit is given to the author and the + * OpenBSD project by leaving this copyright notice intact. + */ - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. +/* + * This code is derived from section 17.1 of Applied Cryptography, + * second edition, which describes a stream cipher allegedly + * compatible with RSA Labs "RC4" cipher (the actual description of + * which is a trade secret). The same algorithm is used as a stream + * cipher called "arcfour" in Tatu Ylonen's ssh package. * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * Here the stream cipher has been modified always to include the time + * when initializing the state. That makes it impossible to + * regenerate the same random sequence twice, so this can't be used + * for encryption, but will generate good random numbers. + * + * RC4 is a registered trademark of RSA Laboratories. */ +#include <sys/time.h> + #include <fcntl.h> #include <stdint.h> #include <stdlib.h> -#include <time.h> #include <unistd.h> #include "arc4random.h" -uint32_t arc4random(void) +struct arc4_stream { + uint8_t i; + uint8_t j; + uint8_t s[256]; +}; + +static int rs_initialized; +static struct arc4_stream rs; +static int arc4_count; + +static void +arc4_init(struct arc4_stream *as) +{ + int n; + + for (n = 0; n < 256; n++) + as->s[n] = n; + as->i = 0; + as->j = 0; +} + +static void +arc4_addrandom(struct arc4_stream *as, unsigned char *dat, int datlen) +{ + int n; + uint8_t si; + + as->i--; + for (n = 0; n < 256; n++) { + as->i = (as->i + 1); + si = as->s[as->i]; + as->j = (as->j + si + dat[n % datlen]); + as->s[as->i] = as->s[as->j]; + as->s[as->j] = si; + } + as->j = as->i; +} + +static uint8_t +arc4_getbyte(struct arc4_stream *as) +{ + uint8_t si, sj; + + as->i = (as->i + 1); + si = as->s[as->i]; + as->j = (as->j + si); + sj = as->s[as->j]; + as->s[as->i] = sj; + as->s[as->j] = si; + return (as->s[(si + sj) & 0xff]); +} + +static uint32_t +arc4_getword(struct arc4_stream *as) +{ + uint32_t val; + + val = arc4_getbyte(as) << 24; + val |= arc4_getbyte(as) << 16; + val |= arc4_getbyte(as) << 8; + val |= arc4_getbyte(as); + return val; +} + +static void +arc4_stir(struct arc4_stream *as) { int fd; - static unsigned long seed; + struct { + struct timeval tv; + unsigned int rnd[(128 - sizeof(struct timeval)) / + sizeof(unsigned int)]; + } rdat; + int n; - if (seed == 0) { - fd = open("/dev/urandom", 0); - if (fd == -1 || read(fd, &seed, sizeof(seed)) == -1) - seed = time(0); - if (fd >= 0) - close(fd); - srandom(seed); + gettimeofday(&rdat.tv, NULL); + fd = open("/dev/urandom", O_RDONLY); + if (fd != -1) { + n = read(fd, rdat.rnd, sizeof(rdat.rnd)); + close(fd); } - return (uint32_t)random(); + /* fd < 0? Ah, what the heck. We'll just take + * whatever was on the stack... */ + arc4_addrandom(as, (void *) &rdat, sizeof(rdat)); + + /* + * Throw away the first N words of output, as suggested in the + * paper "Weaknesses in the Key Scheduling Algorithm of RC4" + * by Fluher, Mantin, and Shamir. (N = 256 in our case.) + */ + for (n = 0; n < 256 * 4; n++) + arc4_getbyte(as); + arc4_count = 1600000; } + +void +arc4random_stir() +{ + + if (!rs_initialized) { + arc4_init(&rs); + rs_initialized = 1; + } + arc4_stir(&rs); +} + +void +arc4random_addrandom(unsigned char *dat, int datlen) +{ + + if (!rs_initialized) + arc4random_stir(); + arc4_addrandom(&rs, dat, datlen); +} + +uint32_t +arc4random() +{ + + arc4_count -= 4; + if (!rs_initialized || arc4_count <= 0) + arc4random_stir(); + return arc4_getword(&rs); +}
