arc4random.c revision 56698
150476Speter/* $FreeBSD: head/lib/libc/gen/arc4random.c 56698 2000-01-27 23:07:25Z jasone $ */ 226628Sache 326628Sache/* 426628Sache * Arc4 random number generator for OpenBSD. 526628Sache * Copyright 1996 David Mazieres <dm@lcs.mit.edu>. 626628Sache * 726628Sache * Modification and redistribution in source and binary forms is 826628Sache * permitted provided that due credit is given to the author and the 926628Sache * OpenBSD project (for instance by leaving this copyright notice 1026628Sache * intact). 1126628Sache */ 1226628Sache 1326628Sache/* 1426628Sache * This code is derived from section 17.1 of Applied Cryptography, 1526628Sache * second edition, which describes a stream cipher allegedly 1626628Sache * compatible with RSA Labs "RC4" cipher (the actual description of 1726628Sache * which is a trade secret). The same algorithm is used as a stream 1826628Sache * cipher called "arcfour" in Tatu Ylonen's ssh package. 1926628Sache * 2026628Sache * Here the stream cipher has been modified always to include the time 2126628Sache * when initializing the state. That makes it impossible to 2226628Sache * regenerate the same random sequence twice, so this can't be used 2326628Sache * for encryption, but will generate good random numbers. 2426628Sache * 2526628Sache * RC4 is a registered trademark of RSA Laboratories. 2626628Sache */ 2726628Sache 2826628Sache#include <stdlib.h> 2926628Sache#include <fcntl.h> 3026628Sache#include <unistd.h> 3126628Sache#include <sys/types.h> 3226628Sache#include <sys/time.h> 3326628Sache 3426628Sachestruct arc4_stream { 3526628Sache u_int8_t i; 3626628Sache u_int8_t j; 3726628Sache u_int8_t s[256]; 3826628Sache}; 3926628Sache 4026628Sachestatic int rs_initialized; 4126628Sachestatic struct arc4_stream rs; 4226628Sache 4326628Sachestatic inline void 4426628Sachearc4_init(as) 4526628Sache struct arc4_stream *as; 4626628Sache{ 4726628Sache int n; 4826628Sache 4926628Sache for (n = 0; n < 256; n++) 5026628Sache as->s[n] = n; 5126628Sache as->i = 0; 5226628Sache as->j = 0; 5326628Sache} 5426628Sache 5526628Sachestatic inline void 5626628Sachearc4_addrandom(as, dat, datlen) 5726628Sache struct arc4_stream *as; 5826628Sache u_char *dat; 5926628Sache int datlen; 6026628Sache{ 6126628Sache int n; 6226628Sache u_int8_t si; 6326628Sache 6426628Sache as->i--; 6526628Sache for (n = 0; n < 256; n++) { 6626628Sache as->i = (as->i + 1); 6726628Sache si = as->s[as->i]; 6826628Sache as->j = (as->j + si + dat[n % datlen]); 6926628Sache as->s[as->i] = as->s[as->j]; 7026628Sache as->s[as->j] = si; 7126628Sache } 7226628Sache} 7326628Sache 7426628Sachestatic void 7526628Sachearc4_stir(as) 7626628Sache struct arc4_stream *as; 7726628Sache{ 7826628Sache int fd; 7926628Sache struct { 8026628Sache struct timeval tv; 8126628Sache pid_t pid; 8226628Sache u_int8_t rnd[128 - sizeof(struct timeval) - sizeof(pid_t)]; 8326628Sache } rdat; 8426628Sache 8526628Sache gettimeofday(&rdat.tv, NULL); 8626628Sache rdat.pid = getpid(); 8756698Sjasone fd = _open("/dev/urandom", O_RDONLY, 0); 8826628Sache if (fd >= 0) { 8956698Sjasone (void) _read(fd, rdat.rnd, sizeof(rdat.rnd)); 9056698Sjasone _close(fd); 9126628Sache } 9226628Sache /* fd < 0? Ah, what the heck. We'll just take whatever was on the 9326628Sache * stack... */ 9426628Sache 9526628Sache arc4_addrandom(as, (void *) &rdat, sizeof(rdat)); 9626628Sache} 9726628Sache 9826628Sachestatic inline u_int8_t 9926628Sachearc4_getbyte(as) 10026628Sache struct arc4_stream *as; 10126628Sache{ 10226628Sache u_int8_t si, sj; 10326628Sache 10426628Sache as->i = (as->i + 1); 10526628Sache si = as->s[as->i]; 10626628Sache as->j = (as->j + si); 10726628Sache sj = as->s[as->j]; 10826628Sache as->s[as->i] = sj; 10926628Sache as->s[as->j] = si; 11026628Sache return (as->s[(si + sj) & 0xff]); 11126628Sache} 11226628Sache 11326628Sachestatic inline u_int32_t 11426628Sachearc4_getword(as) 11526628Sache struct arc4_stream *as; 11626628Sache{ 11726628Sache u_int32_t val; 11826628Sache val = arc4_getbyte(as) << 24; 11926628Sache val |= arc4_getbyte(as) << 16; 12026628Sache val |= arc4_getbyte(as) << 8; 12126628Sache val |= arc4_getbyte(as); 12226628Sache return val; 12326628Sache} 12426628Sache 12526628Sachevoid 12626628Sachearc4random_stir() 12726628Sache{ 12826628Sache if (!rs_initialized) { 12926628Sache arc4_init(&rs); 13026628Sache rs_initialized = 1; 13126628Sache } 13226628Sache arc4_stir(&rs); 13326628Sache} 13426628Sache 13526628Sachevoid 13626628Sachearc4random_addrandom(dat, datlen) 13726628Sache u_char *dat; 13826628Sache int datlen; 13926628Sache{ 14026628Sache if (!rs_initialized) 14126628Sache arc4random_stir(); 14226628Sache arc4_addrandom(&rs, dat, datlen); 14326628Sache} 14426628Sache 14526628Sacheu_int32_t 14626628Sachearc4random() 14726628Sache{ 14826628Sache if (!rs_initialized) 14926628Sache arc4random_stir(); 15026628Sache return arc4_getword(&rs); 15126628Sache} 15226628Sache 15326628Sache#if 0 15426628Sache/*-------- Test code for i386 --------*/ 15526628Sache#include <stdio.h> 15626628Sache#include <machine/pctr.h> 15726628Sacheint 15826628Sachemain(int argc, char **argv) 15926628Sache{ 16026628Sache const int iter = 1000000; 16126628Sache int i; 16226628Sache pctrval v; 16326628Sache 16426628Sache v = rdtsc(); 16526628Sache for (i = 0; i < iter; i++) 16626628Sache arc4random(); 16726628Sache v = rdtsc() - v; 16826628Sache v /= iter; 16926628Sache 17026628Sache printf("%qd cycles\n", v); 17126628Sache} 17226628Sache#endif 173