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 28d201fe46SDaniel Eischen #include "namespace.h" 2983a03b38SAndrey A. Chernov #include <stdlib.h> 3083a03b38SAndrey A. Chernov #include <fcntl.h> 3183a03b38SAndrey A. Chernov #include <unistd.h> 3283a03b38SAndrey A. Chernov #include <sys/types.h> 3383a03b38SAndrey A. Chernov #include <sys/time.h> 34d201fe46SDaniel Eischen #include "un-namespace.h" 3583a03b38SAndrey A. Chernov 3683a03b38SAndrey A. Chernov struct arc4_stream { 3783a03b38SAndrey A. Chernov u_int8_t i; 3883a03b38SAndrey A. Chernov u_int8_t j; 3983a03b38SAndrey A. Chernov u_int8_t s[256]; 4083a03b38SAndrey A. Chernov }; 4183a03b38SAndrey A. Chernov 4283a03b38SAndrey A. Chernov static int rs_initialized; 4383a03b38SAndrey A. Chernov static struct arc4_stream rs; 4483a03b38SAndrey A. Chernov 4583a03b38SAndrey A. Chernov static inline void 4683a03b38SAndrey A. Chernov arc4_init(as) 4783a03b38SAndrey A. Chernov struct arc4_stream *as; 4883a03b38SAndrey A. Chernov { 4983a03b38SAndrey A. Chernov int n; 5083a03b38SAndrey A. Chernov 5183a03b38SAndrey A. Chernov for (n = 0; n < 256; n++) 5283a03b38SAndrey A. Chernov as->s[n] = n; 5383a03b38SAndrey A. Chernov as->i = 0; 5483a03b38SAndrey A. Chernov as->j = 0; 5583a03b38SAndrey A. Chernov } 5683a03b38SAndrey A. Chernov 5783a03b38SAndrey A. Chernov static inline void 5883a03b38SAndrey A. Chernov arc4_addrandom(as, dat, datlen) 5983a03b38SAndrey A. Chernov struct arc4_stream *as; 6083a03b38SAndrey A. Chernov u_char *dat; 6183a03b38SAndrey A. Chernov int datlen; 6283a03b38SAndrey A. Chernov { 6383a03b38SAndrey A. Chernov int n; 6483a03b38SAndrey A. Chernov u_int8_t si; 6583a03b38SAndrey A. Chernov 6683a03b38SAndrey A. Chernov as->i--; 6783a03b38SAndrey A. Chernov for (n = 0; n < 256; n++) { 6883a03b38SAndrey A. Chernov as->i = (as->i + 1); 6983a03b38SAndrey A. Chernov si = as->s[as->i]; 7083a03b38SAndrey A. Chernov as->j = (as->j + si + dat[n % datlen]); 7183a03b38SAndrey A. Chernov as->s[as->i] = as->s[as->j]; 7283a03b38SAndrey A. Chernov as->s[as->j] = si; 7383a03b38SAndrey A. Chernov } 7483a03b38SAndrey A. Chernov } 7583a03b38SAndrey A. Chernov 7683a03b38SAndrey A. Chernov static void 7783a03b38SAndrey A. Chernov arc4_stir(as) 7883a03b38SAndrey A. Chernov struct arc4_stream *as; 7983a03b38SAndrey A. Chernov { 8083a03b38SAndrey A. Chernov int fd; 8183a03b38SAndrey A. Chernov struct { 8283a03b38SAndrey A. Chernov struct timeval tv; 8383a03b38SAndrey A. Chernov pid_t pid; 8483a03b38SAndrey A. Chernov u_int8_t rnd[128 - sizeof(struct timeval) - sizeof(pid_t)]; 8583a03b38SAndrey A. Chernov } rdat; 8683a03b38SAndrey A. Chernov 8783a03b38SAndrey A. Chernov gettimeofday(&rdat.tv, NULL); 8883a03b38SAndrey A. Chernov rdat.pid = getpid(); 899233c4d9SJason Evans fd = _open("/dev/urandom", O_RDONLY, 0); 9083a03b38SAndrey A. Chernov if (fd >= 0) { 919233c4d9SJason Evans (void) _read(fd, rdat.rnd, sizeof(rdat.rnd)); 929233c4d9SJason Evans _close(fd); 9383a03b38SAndrey A. Chernov } 9483a03b38SAndrey A. Chernov /* fd < 0? Ah, what the heck. We'll just take whatever was on the 9583a03b38SAndrey A. Chernov * stack... */ 9683a03b38SAndrey A. Chernov 9783a03b38SAndrey A. Chernov arc4_addrandom(as, (void *) &rdat, sizeof(rdat)); 9883a03b38SAndrey A. Chernov } 9983a03b38SAndrey A. Chernov 10083a03b38SAndrey A. Chernov static inline u_int8_t 10183a03b38SAndrey A. Chernov arc4_getbyte(as) 10283a03b38SAndrey A. Chernov struct arc4_stream *as; 10383a03b38SAndrey A. Chernov { 10483a03b38SAndrey A. Chernov u_int8_t si, sj; 10583a03b38SAndrey A. Chernov 10683a03b38SAndrey A. Chernov as->i = (as->i + 1); 10783a03b38SAndrey A. Chernov si = as->s[as->i]; 10883a03b38SAndrey A. Chernov as->j = (as->j + si); 10983a03b38SAndrey A. Chernov sj = as->s[as->j]; 11083a03b38SAndrey A. Chernov as->s[as->i] = sj; 11183a03b38SAndrey A. Chernov as->s[as->j] = si; 11283a03b38SAndrey A. Chernov return (as->s[(si + sj) & 0xff]); 11383a03b38SAndrey A. Chernov } 11483a03b38SAndrey A. Chernov 11583a03b38SAndrey A. Chernov static inline u_int32_t 11683a03b38SAndrey A. Chernov arc4_getword(as) 11783a03b38SAndrey A. Chernov struct arc4_stream *as; 11883a03b38SAndrey A. Chernov { 11983a03b38SAndrey A. Chernov u_int32_t val; 12083a03b38SAndrey A. Chernov val = arc4_getbyte(as) << 24; 12183a03b38SAndrey A. Chernov val |= arc4_getbyte(as) << 16; 12283a03b38SAndrey A. Chernov val |= arc4_getbyte(as) << 8; 12383a03b38SAndrey A. Chernov val |= arc4_getbyte(as); 12483a03b38SAndrey A. Chernov return val; 12583a03b38SAndrey A. Chernov } 12683a03b38SAndrey A. Chernov 12783a03b38SAndrey A. Chernov void 12883a03b38SAndrey A. Chernov arc4random_stir() 12983a03b38SAndrey A. Chernov { 13083a03b38SAndrey A. Chernov if (!rs_initialized) { 13183a03b38SAndrey A. Chernov arc4_init(&rs); 13283a03b38SAndrey A. Chernov rs_initialized = 1; 13383a03b38SAndrey A. Chernov } 13483a03b38SAndrey A. Chernov arc4_stir(&rs); 13583a03b38SAndrey A. Chernov } 13683a03b38SAndrey A. Chernov 13783a03b38SAndrey A. Chernov void 13883a03b38SAndrey A. Chernov arc4random_addrandom(dat, datlen) 13983a03b38SAndrey A. Chernov u_char *dat; 14083a03b38SAndrey A. Chernov int datlen; 14183a03b38SAndrey A. Chernov { 14283a03b38SAndrey A. Chernov if (!rs_initialized) 14383a03b38SAndrey A. Chernov arc4random_stir(); 14483a03b38SAndrey A. Chernov arc4_addrandom(&rs, dat, datlen); 14583a03b38SAndrey A. Chernov } 14683a03b38SAndrey A. Chernov 14783a03b38SAndrey A. Chernov u_int32_t 14883a03b38SAndrey A. Chernov arc4random() 14983a03b38SAndrey A. Chernov { 15083a03b38SAndrey A. Chernov if (!rs_initialized) 15183a03b38SAndrey A. Chernov arc4random_stir(); 15283a03b38SAndrey A. Chernov return arc4_getword(&rs); 15383a03b38SAndrey A. Chernov } 15483a03b38SAndrey A. Chernov 15583a03b38SAndrey A. Chernov #if 0 15683a03b38SAndrey A. Chernov /*-------- Test code for i386 --------*/ 15783a03b38SAndrey A. Chernov #include <stdio.h> 15883a03b38SAndrey A. Chernov #include <machine/pctr.h> 15983a03b38SAndrey A. Chernov int 16083a03b38SAndrey A. Chernov main(int argc, char **argv) 16183a03b38SAndrey A. Chernov { 16283a03b38SAndrey A. Chernov const int iter = 1000000; 16383a03b38SAndrey A. Chernov int i; 16483a03b38SAndrey A. Chernov pctrval v; 16583a03b38SAndrey A. Chernov 16683a03b38SAndrey A. Chernov v = rdtsc(); 16783a03b38SAndrey A. Chernov for (i = 0; i < iter; i++) 16883a03b38SAndrey A. Chernov arc4random(); 16983a03b38SAndrey A. Chernov v = rdtsc() - v; 17083a03b38SAndrey A. Chernov v /= iter; 17183a03b38SAndrey A. Chernov 17283a03b38SAndrey A. Chernov printf("%qd cycles\n", v); 17383a03b38SAndrey A. Chernov } 17483a03b38SAndrey A. Chernov #endif 175