1254219Scy/*- 2254219Scy * THE BEER-WARE LICENSE 3254219Scy * 4254219Scy * <dan@FreeBSD.ORG> wrote this file. As long as you retain this notice you 5254219Scy * can do whatever you want with this stuff. If we meet some day, and you 6254219Scy * think this stuff is worth it, you can buy me a beer in return. 7254219Scy * 8254219Scy * Dan Moschuk 9254219Scy */ 10254219Scy#if !defined(SOLARIS2) && !defined(__osf__) 11254219Scy# include <sys/cdefs.h> 12254219Scy#endif 13254219Scy 14254219Scy#include <sys/types.h> 15254219Scy#include <sys/param.h> 16254219Scy#ifdef __FreeBSD__ 17254219Scy# include <sys/kernel.h> 18254219Scy#endif 19254219Scy#if !defined(__osf__) 20254219Scy# include <sys/random.h> 21254219Scy#endif 22254219Scy#ifdef __FreeBSD__ 23254219Scy# include <sys/libkern.h> 24254219Scy#endif 25254219Scy#include <sys/lock.h> 26254219Scy#ifndef __osf__ 27254219Scy# include <sys/mutex.h> 28254219Scy#endif 29254219Scy#include <sys/time.h> 30254219Scy 31254219Scy#if defined(SOLARIS2) && (SOLARIS2 < 9) 32254219Scy# include <netinet/in_systm.h> 33254219Scy#endif 34254219Scy#include <sys/socket.h> 35254219Scy#include <net/if.h> 36254219Scy#ifdef __osf__ 37254219Scy# include <net/route.h> 38254219Scy#endif 39254219Scy#include <netinet/in.h> 40254219Scy#include <netinet/ip.h> 41254219Scy#include "netinet/ip_compat.h" 42254219Scy#ifdef HAS_SYS_MD5_H 43254219Scy# include <sys/md5.h> 44254219Scy#else 45254219Scy# include "md5.h" 46254219Scy#endif 47254219Scy 48254219Scy#ifdef NEED_LOCAL_RAND 49254219Scy#if !defined(__GNUC__) 50254219Scy# define __inline 51254219Scy#endif 52254219Scy 53254219Scy#define ARC4_RESEED_BYTES 65536 54254219Scy#define ARC4_RESEED_SECONDS 300 55254219Scy#define ARC4_KEYBYTES (256 / 8) 56254219Scy 57254219Scystatic u_int8_t arc4_i, arc4_j; 58254219Scystatic int arc4_numruns = 0; 59254219Scystatic u_int8_t arc4_sbox[256]; 60254219Scystatic time_t arc4_t_reseed; 61254219Scystatic ipfmutex_t arc4_mtx; 62254219Scystatic MD5_CTX md5ctx; 63254219Scy 64254219Scystatic u_int8_t arc4_randbyte(void); 65254219Scystatic int ipf_read_random(void *dest, int length); 66254219Scy 67254219Scystatic __inline void 68254219Scyarc4_swap(u_int8_t *a, u_int8_t *b) 69254219Scy{ 70254219Scy u_int8_t c; 71254219Scy 72254219Scy c = *a; 73254219Scy *a = *b; 74254219Scy *b = c; 75254219Scy} 76254219Scy 77254219Scy/* 78254219Scy * Stir our S-box. 79254219Scy */ 80254219Scystatic void 81254219Scyarc4_randomstir (void) 82254219Scy{ 83254219Scy u_int8_t key[256]; 84254219Scy int r, n; 85254219Scy struct timeval tv_now; 86254219Scy 87254219Scy /* 88254219Scy * XXX read_random() returns unsafe numbers if the entropy 89254219Scy * device is not loaded -- MarkM. 90254219Scy */ 91254219Scy r = ipf_read_random(key, ARC4_KEYBYTES); 92254219Scy GETKTIME(&tv_now); 93254219Scy MUTEX_ENTER(&arc4_mtx); 94254219Scy /* If r == 0 || -1, just use what was on the stack. */ 95254219Scy if (r > 0) { 96254219Scy for (n = r; n < sizeof(key); n++) 97254219Scy key[n] = key[n % r]; 98254219Scy } 99254219Scy 100254219Scy for (n = 0; n < 256; n++) { 101254219Scy arc4_j = (arc4_j + arc4_sbox[n] + key[n]) % 256; 102254219Scy arc4_swap(&arc4_sbox[n], &arc4_sbox[arc4_j]); 103254219Scy } 104254219Scy 105254219Scy /* Reset for next reseed cycle. */ 106254219Scy arc4_t_reseed = tv_now.tv_sec + ARC4_RESEED_SECONDS; 107254219Scy arc4_numruns = 0; 108254219Scy 109254219Scy /* 110254219Scy * Throw away the first N words of output, as suggested in the 111254219Scy * paper "Weaknesses in the Key Scheduling Algorithm of RC4" 112322012Scy * by Fluher, Mantin, and Shamir. (N = 768 in our case.) 113254219Scy */ 114322012Scy for (n = 0; n < 768*4; n++) 115254219Scy arc4_randbyte(); 116254219Scy MUTEX_EXIT(&arc4_mtx); 117254219Scy} 118254219Scy 119254219Scy/* 120254219Scy * Initialize our S-box to its beginning defaults. 121254219Scy */ 122254219Scystatic void 123254219Scyarc4_init(void) 124254219Scy{ 125254219Scy int n; 126254219Scy 127254219Scy MD5Init(&md5ctx); 128254219Scy 129254219Scy MUTEX_INIT(&arc4_mtx, "arc4_mtx"); 130254219Scy arc4_i = arc4_j = 0; 131254219Scy for (n = 0; n < 256; n++) 132254219Scy arc4_sbox[n] = (u_int8_t) n; 133254219Scy 134254219Scy arc4_t_reseed = 0; 135254219Scy} 136254219Scy 137254219Scy 138254219Scy/* 139254219Scy * Generate a random byte. 140254219Scy */ 141254219Scystatic u_int8_t 142254219Scyarc4_randbyte(void) 143254219Scy{ 144254219Scy u_int8_t arc4_t; 145254219Scy 146254219Scy arc4_i = (arc4_i + 1) % 256; 147254219Scy arc4_j = (arc4_j + arc4_sbox[arc4_i]) % 256; 148254219Scy 149254219Scy arc4_swap(&arc4_sbox[arc4_i], &arc4_sbox[arc4_j]); 150254219Scy 151254219Scy arc4_t = (arc4_sbox[arc4_i] + arc4_sbox[arc4_j]) % 256; 152254219Scy return arc4_sbox[arc4_t]; 153254219Scy} 154254219Scy 155254219Scy/* 156254219Scy * MPSAFE 157254219Scy */ 158254219Scyvoid 159254219Scyarc4rand(void *ptr, u_int len, int reseed) 160254219Scy{ 161254219Scy u_int8_t *p; 162254219Scy struct timeval tv; 163254219Scy 164254219Scy GETKTIME(&tv); 165254219Scy if (reseed || 166254219Scy (arc4_numruns > ARC4_RESEED_BYTES) || 167254219Scy (tv.tv_sec > arc4_t_reseed)) 168254219Scy arc4_randomstir(); 169254219Scy 170254219Scy MUTEX_ENTER(&arc4_mtx); 171254219Scy arc4_numruns += len; 172254219Scy p = ptr; 173254219Scy while (len--) 174254219Scy *p++ = arc4_randbyte(); 175254219Scy MUTEX_EXIT(&arc4_mtx); 176254219Scy} 177254219Scy 178254219Scyuint32_t 179254219Scyipf_random(void) 180254219Scy{ 181254219Scy uint32_t ret; 182254219Scy 183254219Scy arc4rand(&ret, sizeof ret, 0); 184254219Scy return ret; 185254219Scy} 186254219Scy 187254219Scy 188254219Scystatic u_char pot[ARC4_RESEED_BYTES]; 189254219Scystatic u_char *pothead = pot, *pottail = pot; 190254219Scystatic int inpot = 0; 191254219Scy 192254219Scy/* 193254219Scy * This is not very strong, and this is understood, but the aim isn't to 194254219Scy * be cryptographically strong - it is just to make up something that is 195254219Scy * pseudo random. 196254219Scy */ 197254219Scyvoid 198254219Scyipf_rand_push(void *src, int length) 199254219Scy{ 200254219Scy static int arc4_inited = 0; 201254219Scy u_char *nsrc; 202254219Scy int mylen; 203254219Scy 204254219Scy if (arc4_inited == 0) { 205254219Scy arc4_init(); 206254219Scy arc4_inited = 1; 207254219Scy } 208254219Scy 209254219Scy if (length < 64) { 210254219Scy MD5Update(&md5ctx, src, length); 211254219Scy return; 212254219Scy } 213254219Scy 214254219Scy nsrc = src; 215254219Scy mylen = length; 216254219Scy 217254219Scy#if defined(_SYS_MD5_H) && defined(SOLARIS2) 218254219Scy# define buf buf_un.buf8 219254219Scy#endif 220254219Scy MUTEX_ENTER(&arc4_mtx); 221254219Scy while ((mylen > 64) && (sizeof(pot) - inpot > sizeof(md5ctx.buf))) { 222254219Scy MD5Update(&md5ctx, nsrc, 64); 223254219Scy mylen -= 64; 224254219Scy nsrc += 64; 225254219Scy if (pottail + sizeof(md5ctx.buf) > pot + sizeof(pot)) { 226254219Scy int left, numbytes; 227254219Scy 228254219Scy numbytes = pot + sizeof(pot) - pottail; 229254219Scy bcopy(md5ctx.buf, pottail, numbytes); 230254219Scy left = sizeof(md5ctx.buf) - numbytes; 231254219Scy pottail = pot; 232254219Scy bcopy(md5ctx.buf + sizeof(md5ctx.buf) - left, 233254219Scy pottail, left); 234254219Scy pottail += left; 235254219Scy } else { 236254219Scy bcopy(md5ctx.buf, pottail, sizeof(md5ctx.buf)); 237254219Scy pottail += sizeof(md5ctx.buf); 238254219Scy } 239254219Scy inpot += 64; 240254219Scy } 241254219Scy MUTEX_EXIT(&arc4_mtx); 242254219Scy#if defined(_SYS_MD5_H) && defined(SOLARIS2) 243254219Scy# undef buf 244254219Scy#endif 245254219Scy} 246254219Scy 247254219Scy 248254219Scystatic int 249254219Scyipf_read_random(void *dest, int length) 250254219Scy{ 251254219Scy if (length > inpot) 252254219Scy return 0; 253254219Scy 254254219Scy MUTEX_ENTER(&arc4_mtx); 255254219Scy if (pothead + length > pot + sizeof(pot)) { 256254219Scy int left, numbytes; 257254219Scy 258254219Scy left = length; 259254219Scy numbytes = pot + sizeof(pot) - pothead; 260254219Scy bcopy(pothead, dest, numbytes); 261254219Scy left -= numbytes; 262254219Scy pothead = pot; 263254219Scy bcopy(pothead, dest + length - left, left); 264254219Scy pothead += left; 265254219Scy } else { 266254219Scy bcopy(pothead, dest, length); 267254219Scy pothead += length; 268254219Scy } 269254219Scy inpot -= length; 270254219Scy if (inpot == 0) 271254219Scy pothead = pottail = pot; 272254219Scy MUTEX_EXIT(&arc4_mtx); 273254219Scy 274254219Scy return length; 275254219Scy} 276254219Scy 277254219Scy#endif /* NEED_LOCAL_RAND */ 278