17c478bd9Sstevel@tonic-gate /* 2*a0b85df4Sstevel * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 3*a0b85df4Sstevel * Use is subject to license terms. 47c478bd9Sstevel@tonic-gate */ 5*a0b85df4Sstevel 6*a0b85df4Sstevel #pragma ident "%Z%%M% %I% %E% SMI" 7*a0b85df4Sstevel 87c478bd9Sstevel@tonic-gate /* $OpenBSD: arc4random.c,v 1.6 2001/06/05 05:05:38 pvalchev Exp $ */ 97c478bd9Sstevel@tonic-gate 107c478bd9Sstevel@tonic-gate /* 117c478bd9Sstevel@tonic-gate * Arc4 random number generator for OpenBSD. 127c478bd9Sstevel@tonic-gate * Copyright 1996 David Mazieres <dm@lcs.mit.edu>. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * Modification and redistribution in source and binary forms is 157c478bd9Sstevel@tonic-gate * permitted provided that due credit is given to the author and the 167c478bd9Sstevel@tonic-gate * OpenBSD project by leaving this copyright notice intact. 177c478bd9Sstevel@tonic-gate */ 187c478bd9Sstevel@tonic-gate 197c478bd9Sstevel@tonic-gate /* 207c478bd9Sstevel@tonic-gate * This code is derived from section 17.1 of Applied Cryptography, 217c478bd9Sstevel@tonic-gate * second edition, which describes a stream cipher allegedly 227c478bd9Sstevel@tonic-gate * compatible with RSA Labs "RC4" cipher (the actual description of 237c478bd9Sstevel@tonic-gate * which is a trade secret). The same algorithm is used as a stream 247c478bd9Sstevel@tonic-gate * cipher called "arcfour" in Tatu Ylonen's ssh package. 257c478bd9Sstevel@tonic-gate * 267c478bd9Sstevel@tonic-gate * Here the stream cipher has been modified always to include the time 277c478bd9Sstevel@tonic-gate * when initializing the state. That makes it impossible to 287c478bd9Sstevel@tonic-gate * regenerate the same random sequence twice, so this can't be used 297c478bd9Sstevel@tonic-gate * for encryption, but will generate good random numbers. 307c478bd9Sstevel@tonic-gate * 317c478bd9Sstevel@tonic-gate * RC4 is a registered trademark of RSA Laboratories. 327c478bd9Sstevel@tonic-gate */ 337c478bd9Sstevel@tonic-gate 347c478bd9Sstevel@tonic-gate #include <fcntl.h> 357c478bd9Sstevel@tonic-gate #include <stdlib.h> 367c478bd9Sstevel@tonic-gate #include <unistd.h> 377c478bd9Sstevel@tonic-gate #include <sys/types.h> 387c478bd9Sstevel@tonic-gate #include <sys/param.h> 397c478bd9Sstevel@tonic-gate #include <sys/time.h> 407c478bd9Sstevel@tonic-gate 417c478bd9Sstevel@tonic-gate #ifdef __GNUC__ 427c478bd9Sstevel@tonic-gate #define inline __inline 437c478bd9Sstevel@tonic-gate #else /* !__GNUC__ */ 447c478bd9Sstevel@tonic-gate #define inline 457c478bd9Sstevel@tonic-gate #endif /* !__GNUC__ */ 467c478bd9Sstevel@tonic-gate 477c478bd9Sstevel@tonic-gate struct arc4_stream { 487c478bd9Sstevel@tonic-gate uint8_t i; 497c478bd9Sstevel@tonic-gate uint8_t j; 507c478bd9Sstevel@tonic-gate uint8_t s[256]; 517c478bd9Sstevel@tonic-gate }; 527c478bd9Sstevel@tonic-gate 537c478bd9Sstevel@tonic-gate int rs_initialized; 547c478bd9Sstevel@tonic-gate static struct arc4_stream rs; 557c478bd9Sstevel@tonic-gate 567c478bd9Sstevel@tonic-gate static inline void 577c478bd9Sstevel@tonic-gate arc4_init(as) 587c478bd9Sstevel@tonic-gate struct arc4_stream *as; 597c478bd9Sstevel@tonic-gate { 607c478bd9Sstevel@tonic-gate int n; 617c478bd9Sstevel@tonic-gate 627c478bd9Sstevel@tonic-gate for (n = 0; n < 256; n++) 637c478bd9Sstevel@tonic-gate as->s[n] = n; 647c478bd9Sstevel@tonic-gate as->i = 0; 657c478bd9Sstevel@tonic-gate as->j = 0; 667c478bd9Sstevel@tonic-gate } 677c478bd9Sstevel@tonic-gate 687c478bd9Sstevel@tonic-gate static inline void 697c478bd9Sstevel@tonic-gate arc4_addrandom(as, dat, datlen) 707c478bd9Sstevel@tonic-gate struct arc4_stream *as; 717c478bd9Sstevel@tonic-gate u_char *dat; 727c478bd9Sstevel@tonic-gate size_t datlen; 737c478bd9Sstevel@tonic-gate { 747c478bd9Sstevel@tonic-gate int n; 757c478bd9Sstevel@tonic-gate uint8_t si; 767c478bd9Sstevel@tonic-gate 777c478bd9Sstevel@tonic-gate as->i--; 787c478bd9Sstevel@tonic-gate for (n = 0; n < 256; n++) { 797c478bd9Sstevel@tonic-gate as->i = (as->i + 1); 807c478bd9Sstevel@tonic-gate si = as->s[as->i]; 817c478bd9Sstevel@tonic-gate as->j = (as->j + si + dat[n % datlen]); 827c478bd9Sstevel@tonic-gate as->s[as->i] = as->s[as->j]; 837c478bd9Sstevel@tonic-gate as->s[as->j] = si; 847c478bd9Sstevel@tonic-gate } 857c478bd9Sstevel@tonic-gate as->j = as->i; 867c478bd9Sstevel@tonic-gate } 877c478bd9Sstevel@tonic-gate 887c478bd9Sstevel@tonic-gate static void 897c478bd9Sstevel@tonic-gate arc4_stir(as) 907c478bd9Sstevel@tonic-gate struct arc4_stream *as; 917c478bd9Sstevel@tonic-gate { 927c478bd9Sstevel@tonic-gate int fd; 937c478bd9Sstevel@tonic-gate struct { 947c478bd9Sstevel@tonic-gate struct timeval tv; 957c478bd9Sstevel@tonic-gate uint rnd[(128 - sizeof(struct timeval)) / sizeof(uint)]; 967c478bd9Sstevel@tonic-gate } rdat; 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate (void) gettimeofday(&rdat.tv, NULL); 997c478bd9Sstevel@tonic-gate fd = open("/dev/urandom", O_RDONLY); 1007c478bd9Sstevel@tonic-gate if (fd != -1) { 1017c478bd9Sstevel@tonic-gate (void) read(fd, rdat.rnd, sizeof(rdat.rnd)); 1027c478bd9Sstevel@tonic-gate (void) close(fd); 1037c478bd9Sstevel@tonic-gate } 1047c478bd9Sstevel@tonic-gate /* fd < 0 ? Ah, what the heck. We'll just take 1057c478bd9Sstevel@tonic-gate * whatever was on the stack... */ 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate arc4_addrandom(as, (void *) &rdat, sizeof(rdat)); 1087c478bd9Sstevel@tonic-gate } 1097c478bd9Sstevel@tonic-gate 1107c478bd9Sstevel@tonic-gate static inline uint8_t 1117c478bd9Sstevel@tonic-gate arc4_getbyte(as) 1127c478bd9Sstevel@tonic-gate struct arc4_stream *as; 1137c478bd9Sstevel@tonic-gate { 1147c478bd9Sstevel@tonic-gate uint8_t si, sj; 1157c478bd9Sstevel@tonic-gate 1167c478bd9Sstevel@tonic-gate as->i = (as->i + 1); 1177c478bd9Sstevel@tonic-gate si = as->s[as->i]; 1187c478bd9Sstevel@tonic-gate as->j = (as->j + si); 1197c478bd9Sstevel@tonic-gate sj = as->s[as->j]; 1207c478bd9Sstevel@tonic-gate as->s[as->i] = sj; 1217c478bd9Sstevel@tonic-gate as->s[as->j] = si; 1227c478bd9Sstevel@tonic-gate return (as->s[(si + sj) & 0xff]); 1237c478bd9Sstevel@tonic-gate } 1247c478bd9Sstevel@tonic-gate 1257c478bd9Sstevel@tonic-gate static inline uint32_t 1267c478bd9Sstevel@tonic-gate arc4_getword(as) 1277c478bd9Sstevel@tonic-gate struct arc4_stream *as; 1287c478bd9Sstevel@tonic-gate { 1297c478bd9Sstevel@tonic-gate uint32_t val; 1307c478bd9Sstevel@tonic-gate val = arc4_getbyte(as) << 24; 1317c478bd9Sstevel@tonic-gate val |= arc4_getbyte(as) << 16; 1327c478bd9Sstevel@tonic-gate val |= arc4_getbyte(as) << 8; 1337c478bd9Sstevel@tonic-gate val |= arc4_getbyte(as); 1347c478bd9Sstevel@tonic-gate return val; 1357c478bd9Sstevel@tonic-gate } 1367c478bd9Sstevel@tonic-gate 1377c478bd9Sstevel@tonic-gate void 1387c478bd9Sstevel@tonic-gate arc4random_stir() 1397c478bd9Sstevel@tonic-gate { 1407c478bd9Sstevel@tonic-gate if (!rs_initialized) { 1417c478bd9Sstevel@tonic-gate arc4_init(&rs); 1427c478bd9Sstevel@tonic-gate rs_initialized = 1; 1437c478bd9Sstevel@tonic-gate } 1447c478bd9Sstevel@tonic-gate arc4_stir(&rs); 1457c478bd9Sstevel@tonic-gate } 1467c478bd9Sstevel@tonic-gate 1477c478bd9Sstevel@tonic-gate void 1487c478bd9Sstevel@tonic-gate arc4random_addrandom(dat, datlen) 1497c478bd9Sstevel@tonic-gate u_char *dat; 1507c478bd9Sstevel@tonic-gate size_t datlen; 1517c478bd9Sstevel@tonic-gate { 1527c478bd9Sstevel@tonic-gate if (!rs_initialized) 1537c478bd9Sstevel@tonic-gate arc4random_stir(); 1547c478bd9Sstevel@tonic-gate arc4_addrandom(&rs, dat, datlen); 1557c478bd9Sstevel@tonic-gate } 1567c478bd9Sstevel@tonic-gate 1577c478bd9Sstevel@tonic-gate uint32_t 1587c478bd9Sstevel@tonic-gate arc4random() 1597c478bd9Sstevel@tonic-gate { 1607c478bd9Sstevel@tonic-gate if (!rs_initialized) 1617c478bd9Sstevel@tonic-gate arc4random_stir(); 1627c478bd9Sstevel@tonic-gate return arc4_getword(&rs); 1637c478bd9Sstevel@tonic-gate } 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate #if 0 1667c478bd9Sstevel@tonic-gate /*-------- Test code for i386 --------*/ 1677c478bd9Sstevel@tonic-gate #include <stdio.h> 1687c478bd9Sstevel@tonic-gate #include <machine/pctr.h> 1697c478bd9Sstevel@tonic-gate int 1707c478bd9Sstevel@tonic-gate main(int argc, char **argv) 1717c478bd9Sstevel@tonic-gate { 1727c478bd9Sstevel@tonic-gate const int iter = 1000000; 1737c478bd9Sstevel@tonic-gate int i; 1747c478bd9Sstevel@tonic-gate pctrval v; 1757c478bd9Sstevel@tonic-gate 1767c478bd9Sstevel@tonic-gate v = rdtsc(); 1777c478bd9Sstevel@tonic-gate for (i = 0; i < iter; i++) 1787c478bd9Sstevel@tonic-gate arc4random(); 1797c478bd9Sstevel@tonic-gate v = rdtsc() - v; 1807c478bd9Sstevel@tonic-gate v /= iter; 1817c478bd9Sstevel@tonic-gate 1827c478bd9Sstevel@tonic-gate printf("%qd cycles\n", v); 1837c478bd9Sstevel@tonic-gate } 1847c478bd9Sstevel@tonic-gate #endif 185