| /* | |
| * 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. | |
| */ | |
| /* | |
| * 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. | |
| * | |
| * 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 <unistd.h> | |
| #include "arc4random.h" | |
| 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; | |
| struct { | |
| struct timeval tv; | |
| unsigned int rnd[(128 - sizeof(struct timeval)) / | |
| sizeof(unsigned int)]; | |
| } rdat; | |
| int n; | |
| gettimeofday(&rdat.tv, NULL); | |
| fd = open("/dev/urandom", O_RDONLY); | |
| if (fd != -1) { | |
| n = read(fd, rdat.rnd, sizeof(rdat.rnd)); | |
| close(fd); | |
| } | |
| /* 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); | |
| } |