17f3dea24SPeter Wemm /* $FreeBSD$ */ 283a03b38SAndrey A. Chernov 383a03b38SAndrey A. Chernov /* 483a03b38SAndrey A. Chernov * Arc4 random number generator for OpenBSD. 583a03b38SAndrey A. Chernov * Copyright 1996 David Mazieres <dm@lcs.mit.edu>. 683a03b38SAndrey A. Chernov * 783a03b38SAndrey A. Chernov * Modification and redistribution in source and binary forms is 883a03b38SAndrey A. Chernov * permitted provided that due credit is given to the author and the 983a03b38SAndrey A. Chernov * OpenBSD project (for instance by leaving this copyright notice 1083a03b38SAndrey A. Chernov * intact). 1183a03b38SAndrey A. Chernov */ 1283a03b38SAndrey A. Chernov 1383a03b38SAndrey A. Chernov /* 1483a03b38SAndrey A. Chernov * This code is derived from section 17.1 of Applied Cryptography, 1583a03b38SAndrey A. Chernov * second edition, which describes a stream cipher allegedly 1683a03b38SAndrey A. Chernov * compatible with RSA Labs "RC4" cipher (the actual description of 1783a03b38SAndrey A. Chernov * which is a trade secret). The same algorithm is used as a stream 1883a03b38SAndrey A. Chernov * cipher called "arcfour" in Tatu Ylonen's ssh package. 1983a03b38SAndrey A. Chernov * 2083a03b38SAndrey A. Chernov * Here the stream cipher has been modified always to include the time 2183a03b38SAndrey A. Chernov * when initializing the state. That makes it impossible to 2283a03b38SAndrey A. Chernov * regenerate the same random sequence twice, so this can't be used 2383a03b38SAndrey A. Chernov * for encryption, but will generate good random numbers. 2483a03b38SAndrey A. Chernov * 2583a03b38SAndrey A. Chernov * RC4 is a registered trademark of RSA Laboratories. 2683a03b38SAndrey A. Chernov */ 2783a03b38SAndrey A. Chernov 28333fc21eSDavid E. O'Brien #include <sys/cdefs.h> 29333fc21eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 30333fc21eSDavid E. O'Brien 31d201fe46SDaniel Eischen #include "namespace.h" 32333fc21eSDavid E. O'Brien #include <sys/types.h> 33333fc21eSDavid E. O'Brien #include <sys/time.h> 3483a03b38SAndrey A. Chernov #include <stdlib.h> 3583a03b38SAndrey A. Chernov #include <fcntl.h> 3683a03b38SAndrey A. Chernov #include <unistd.h> 37d201fe46SDaniel Eischen #include "un-namespace.h" 3883a03b38SAndrey A. Chernov 3983a03b38SAndrey A. Chernov struct arc4_stream { 4083a03b38SAndrey A. Chernov u_int8_t i; 4183a03b38SAndrey A. Chernov u_int8_t j; 4283a03b38SAndrey A. Chernov u_int8_t s[256]; 4383a03b38SAndrey A. Chernov }; 4483a03b38SAndrey A. Chernov 4583a03b38SAndrey A. Chernov static int rs_initialized; 4683a03b38SAndrey A. Chernov static struct arc4_stream rs; 4783a03b38SAndrey A. Chernov 4860ce8b0eSDavid Schultz static inline u_int8_t arc4_getbyte(struct arc4_stream *); 4960ce8b0eSDavid Schultz 5083a03b38SAndrey A. Chernov static inline void 5183a03b38SAndrey A. Chernov arc4_init(as) 5283a03b38SAndrey A. Chernov struct arc4_stream *as; 5383a03b38SAndrey A. Chernov { 5483a03b38SAndrey A. Chernov int n; 5583a03b38SAndrey A. Chernov 5683a03b38SAndrey A. Chernov for (n = 0; n < 256; n++) 5783a03b38SAndrey A. Chernov as->s[n] = n; 5883a03b38SAndrey A. Chernov as->i = 0; 5983a03b38SAndrey A. Chernov as->j = 0; 6083a03b38SAndrey A. Chernov } 6183a03b38SAndrey A. Chernov 6283a03b38SAndrey A. Chernov static inline void 6383a03b38SAndrey A. Chernov arc4_addrandom(as, dat, datlen) 6483a03b38SAndrey A. Chernov struct arc4_stream *as; 6583a03b38SAndrey A. Chernov u_char *dat; 6683a03b38SAndrey A. Chernov int datlen; 6783a03b38SAndrey A. Chernov { 6883a03b38SAndrey A. Chernov int n; 6983a03b38SAndrey A. Chernov u_int8_t si; 7083a03b38SAndrey A. Chernov 7183a03b38SAndrey A. Chernov as->i--; 7283a03b38SAndrey A. Chernov for (n = 0; n < 256; n++) { 7383a03b38SAndrey A. Chernov as->i = (as->i + 1); 7483a03b38SAndrey A. Chernov si = as->s[as->i]; 7583a03b38SAndrey A. Chernov as->j = (as->j + si + dat[n % datlen]); 7683a03b38SAndrey A. Chernov as->s[as->i] = as->s[as->j]; 7783a03b38SAndrey A. Chernov as->s[as->j] = si; 7883a03b38SAndrey A. Chernov } 7983a03b38SAndrey A. Chernov } 8083a03b38SAndrey A. Chernov 8183a03b38SAndrey A. Chernov static void 8283a03b38SAndrey A. Chernov arc4_stir(as) 8383a03b38SAndrey A. Chernov struct arc4_stream *as; 8483a03b38SAndrey A. Chernov { 8560ce8b0eSDavid Schultz int fd, n; 8683a03b38SAndrey A. Chernov struct { 8783a03b38SAndrey A. Chernov struct timeval tv; 8883a03b38SAndrey A. Chernov pid_t pid; 8983a03b38SAndrey A. Chernov u_int8_t rnd[128 - sizeof(struct timeval) - sizeof(pid_t)]; 9083a03b38SAndrey A. Chernov } rdat; 9183a03b38SAndrey A. Chernov 9283a03b38SAndrey A. Chernov gettimeofday(&rdat.tv, NULL); 9383a03b38SAndrey A. Chernov rdat.pid = getpid(); 949233c4d9SJason Evans fd = _open("/dev/urandom", O_RDONLY, 0); 9583a03b38SAndrey A. Chernov if (fd >= 0) { 969233c4d9SJason Evans (void) _read(fd, rdat.rnd, sizeof(rdat.rnd)); 979233c4d9SJason Evans _close(fd); 9883a03b38SAndrey A. Chernov } 9983a03b38SAndrey A. Chernov /* fd < 0? Ah, what the heck. We'll just take whatever was on the 10083a03b38SAndrey A. Chernov * stack... */ 10183a03b38SAndrey A. Chernov 10283a03b38SAndrey A. Chernov arc4_addrandom(as, (void *) &rdat, sizeof(rdat)); 10360ce8b0eSDavid Schultz 10460ce8b0eSDavid Schultz /* 10560ce8b0eSDavid Schultz * Throw away the first N bytes of output, as suggested in the 10660ce8b0eSDavid Schultz * paper "Weaknesses in the Key Scheduling Algorithm of RC4" 10760ce8b0eSDavid Schultz * by Fluher, Mantin, and Shamir. N=1024 is based on 10860ce8b0eSDavid Schultz * suggestions in the paper "(Not So) Random Shuffles of RC4" 10960ce8b0eSDavid Schultz * by Ilya Mironov. 11060ce8b0eSDavid Schultz */ 11160ce8b0eSDavid Schultz for (n = 0; n < 1024; n++) 11260ce8b0eSDavid Schultz arc4_getbyte(as); 11383a03b38SAndrey A. Chernov } 11483a03b38SAndrey A. Chernov 11583a03b38SAndrey A. Chernov static inline u_int8_t 11683a03b38SAndrey A. Chernov arc4_getbyte(as) 11783a03b38SAndrey A. Chernov struct arc4_stream *as; 11883a03b38SAndrey A. Chernov { 11983a03b38SAndrey A. Chernov u_int8_t si, sj; 12083a03b38SAndrey A. Chernov 12183a03b38SAndrey A. Chernov as->i = (as->i + 1); 12283a03b38SAndrey A. Chernov si = as->s[as->i]; 12383a03b38SAndrey A. Chernov as->j = (as->j + si); 12483a03b38SAndrey A. Chernov sj = as->s[as->j]; 12583a03b38SAndrey A. Chernov as->s[as->i] = sj; 12683a03b38SAndrey A. Chernov as->s[as->j] = si; 12783a03b38SAndrey A. Chernov return (as->s[(si + sj) & 0xff]); 12883a03b38SAndrey A. Chernov } 12983a03b38SAndrey A. Chernov 13083a03b38SAndrey A. Chernov static inline u_int32_t 13183a03b38SAndrey A. Chernov arc4_getword(as) 13283a03b38SAndrey A. Chernov struct arc4_stream *as; 13383a03b38SAndrey A. Chernov { 13483a03b38SAndrey A. Chernov u_int32_t val; 13583a03b38SAndrey A. Chernov val = arc4_getbyte(as) << 24; 13683a03b38SAndrey A. Chernov val |= arc4_getbyte(as) << 16; 13783a03b38SAndrey A. Chernov val |= arc4_getbyte(as) << 8; 13883a03b38SAndrey A. Chernov val |= arc4_getbyte(as); 13983a03b38SAndrey A. Chernov return val; 14083a03b38SAndrey A. Chernov } 14183a03b38SAndrey A. Chernov 14283a03b38SAndrey A. Chernov void 14383a03b38SAndrey A. Chernov arc4random_stir() 14483a03b38SAndrey A. Chernov { 14583a03b38SAndrey A. Chernov if (!rs_initialized) { 14683a03b38SAndrey A. Chernov arc4_init(&rs); 14783a03b38SAndrey A. Chernov rs_initialized = 1; 14883a03b38SAndrey A. Chernov } 14983a03b38SAndrey A. Chernov arc4_stir(&rs); 15083a03b38SAndrey A. Chernov } 15183a03b38SAndrey A. Chernov 15283a03b38SAndrey A. Chernov void 15383a03b38SAndrey A. Chernov arc4random_addrandom(dat, datlen) 15483a03b38SAndrey A. Chernov u_char *dat; 15583a03b38SAndrey A. Chernov int datlen; 15683a03b38SAndrey A. Chernov { 15783a03b38SAndrey A. Chernov if (!rs_initialized) 15883a03b38SAndrey A. Chernov arc4random_stir(); 15983a03b38SAndrey A. Chernov arc4_addrandom(&rs, dat, datlen); 16083a03b38SAndrey A. Chernov } 16183a03b38SAndrey A. Chernov 16283a03b38SAndrey A. Chernov u_int32_t 16383a03b38SAndrey A. Chernov arc4random() 16483a03b38SAndrey A. Chernov { 16583a03b38SAndrey A. Chernov if (!rs_initialized) 16683a03b38SAndrey A. Chernov arc4random_stir(); 16783a03b38SAndrey A. Chernov return arc4_getword(&rs); 16883a03b38SAndrey A. Chernov } 16983a03b38SAndrey A. Chernov 17083a03b38SAndrey A. Chernov #if 0 17183a03b38SAndrey A. Chernov /*-------- Test code for i386 --------*/ 17283a03b38SAndrey A. Chernov #include <stdio.h> 17383a03b38SAndrey A. Chernov #include <machine/pctr.h> 17483a03b38SAndrey A. Chernov int 17583a03b38SAndrey A. Chernov main(int argc, char **argv) 17683a03b38SAndrey A. Chernov { 17783a03b38SAndrey A. Chernov const int iter = 1000000; 17883a03b38SAndrey A. Chernov int i; 17983a03b38SAndrey A. Chernov pctrval v; 18083a03b38SAndrey A. Chernov 18183a03b38SAndrey A. Chernov v = rdtsc(); 18283a03b38SAndrey A. Chernov for (i = 0; i < iter; i++) 18383a03b38SAndrey A. Chernov arc4random(); 18483a03b38SAndrey A. Chernov v = rdtsc() - v; 18583a03b38SAndrey A. Chernov v /= iter; 18683a03b38SAndrey A. Chernov 18783a03b38SAndrey A. Chernov printf("%qd cycles\n", v); 18883a03b38SAndrey A. Chernov } 18983a03b38SAndrey A. Chernov #endif 190