summaryrefslogtreecommitdiffstats
path: root/contrib/ipfilter/arc4random.c
diff options
context:
space:
mode:
authorngie <ngie@FreeBSD.org>2015-10-05 03:26:51 +0000
committerngie <ngie@FreeBSD.org>2015-10-05 03:26:51 +0000
commite1dd16d965b177f109afb771e59432e36f335d0a (patch)
tree15db092a5401cf329f1bff9d3bf700d1fde0f121 /contrib/ipfilter/arc4random.c
parent115d008392113efc6f844baa7cc407e9eaae63db (diff)
downloadFreeBSD-src-e1dd16d965b177f109afb771e59432e36f335d0a.zip
FreeBSD-src-e1dd16d965b177f109afb771e59432e36f335d0a.tar.gz
Revert r288682
I meant to do this on ^/user/ngie/more-tests Pointyhat to: ngie (use svn info next time...)
Diffstat (limited to 'contrib/ipfilter/arc4random.c')
-rw-r--r--contrib/ipfilter/arc4random.c277
1 files changed, 277 insertions, 0 deletions
diff --git a/contrib/ipfilter/arc4random.c b/contrib/ipfilter/arc4random.c
new file mode 100644
index 0000000..04b0797
--- /dev/null
+++ b/contrib/ipfilter/arc4random.c
@@ -0,0 +1,277 @@
+/*-
+ * THE BEER-WARE LICENSE
+ *
+ * <dan@FreeBSD.ORG> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you
+ * think this stuff is worth it, you can buy me a beer in return.
+ *
+ * Dan Moschuk
+ */
+#if !defined(SOLARIS2) && !defined(__osf__)
+# include <sys/cdefs.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/param.h>
+#ifdef __FreeBSD__
+# include <sys/kernel.h>
+#endif
+#if !defined(__osf__)
+# include <sys/random.h>
+#endif
+#ifdef __FreeBSD__
+# include <sys/libkern.h>
+#endif
+#include <sys/lock.h>
+#ifndef __osf__
+# include <sys/mutex.h>
+#endif
+#include <sys/time.h>
+
+#if defined(SOLARIS2) && (SOLARIS2 < 9)
+# include <netinet/in_systm.h>
+#endif
+#include <sys/socket.h>
+#include <net/if.h>
+#ifdef __osf__
+# include <net/route.h>
+#endif
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include "netinet/ip_compat.h"
+#ifdef HAS_SYS_MD5_H
+# include <sys/md5.h>
+#else
+# include "md5.h"
+#endif
+
+#ifdef NEED_LOCAL_RAND
+#if !defined(__GNUC__)
+# define __inline
+#endif
+
+#define ARC4_RESEED_BYTES 65536
+#define ARC4_RESEED_SECONDS 300
+#define ARC4_KEYBYTES (256 / 8)
+
+static u_int8_t arc4_i, arc4_j;
+static int arc4_numruns = 0;
+static u_int8_t arc4_sbox[256];
+static time_t arc4_t_reseed;
+static ipfmutex_t arc4_mtx;
+static MD5_CTX md5ctx;
+
+static u_int8_t arc4_randbyte(void);
+static int ipf_read_random(void *dest, int length);
+
+static __inline void
+arc4_swap(u_int8_t *a, u_int8_t *b)
+{
+ u_int8_t c;
+
+ c = *a;
+ *a = *b;
+ *b = c;
+}
+
+/*
+ * Stir our S-box.
+ */
+static void
+arc4_randomstir (void)
+{
+ u_int8_t key[256];
+ int r, n;
+ struct timeval tv_now;
+
+ /*
+ * XXX read_random() returns unsafe numbers if the entropy
+ * device is not loaded -- MarkM.
+ */
+ r = ipf_read_random(key, ARC4_KEYBYTES);
+ GETKTIME(&tv_now);
+ MUTEX_ENTER(&arc4_mtx);
+ /* If r == 0 || -1, just use what was on the stack. */
+ if (r > 0) {
+ for (n = r; n < sizeof(key); n++)
+ key[n] = key[n % r];
+ }
+
+ for (n = 0; n < 256; n++) {
+ arc4_j = (arc4_j + arc4_sbox[n] + key[n]) % 256;
+ arc4_swap(&arc4_sbox[n], &arc4_sbox[arc4_j]);
+ }
+
+ /* Reset for next reseed cycle. */
+ arc4_t_reseed = tv_now.tv_sec + ARC4_RESEED_SECONDS;
+ arc4_numruns = 0;
+
+ /*
+ * Throw away the first N words of output, as suggested in the
+ * paper "Weaknesses in the Key Scheduling Algorithm of RC4"
+ * by Fluher, Mantin, and Shamir. (N = 256 in our case.)
+ */
+ for (n = 0; n < 256*4; n++)
+ arc4_randbyte();
+ MUTEX_EXIT(&arc4_mtx);
+}
+
+/*
+ * Initialize our S-box to its beginning defaults.
+ */
+static void
+arc4_init(void)
+{
+ int n;
+
+ MD5Init(&md5ctx);
+
+ MUTEX_INIT(&arc4_mtx, "arc4_mtx");
+ arc4_i = arc4_j = 0;
+ for (n = 0; n < 256; n++)
+ arc4_sbox[n] = (u_int8_t) n;
+
+ arc4_t_reseed = 0;
+}
+
+
+/*
+ * Generate a random byte.
+ */
+static u_int8_t
+arc4_randbyte(void)
+{
+ u_int8_t arc4_t;
+
+ arc4_i = (arc4_i + 1) % 256;
+ arc4_j = (arc4_j + arc4_sbox[arc4_i]) % 256;
+
+ arc4_swap(&arc4_sbox[arc4_i], &arc4_sbox[arc4_j]);
+
+ arc4_t = (arc4_sbox[arc4_i] + arc4_sbox[arc4_j]) % 256;
+ return arc4_sbox[arc4_t];
+}
+
+/*
+ * MPSAFE
+ */
+void
+arc4rand(void *ptr, u_int len, int reseed)
+{
+ u_int8_t *p;
+ struct timeval tv;
+
+ GETKTIME(&tv);
+ if (reseed ||
+ (arc4_numruns > ARC4_RESEED_BYTES) ||
+ (tv.tv_sec > arc4_t_reseed))
+ arc4_randomstir();
+
+ MUTEX_ENTER(&arc4_mtx);
+ arc4_numruns += len;
+ p = ptr;
+ while (len--)
+ *p++ = arc4_randbyte();
+ MUTEX_EXIT(&arc4_mtx);
+}
+
+uint32_t
+ipf_random(void)
+{
+ uint32_t ret;
+
+ arc4rand(&ret, sizeof ret, 0);
+ return ret;
+}
+
+
+static u_char pot[ARC4_RESEED_BYTES];
+static u_char *pothead = pot, *pottail = pot;
+static int inpot = 0;
+
+/*
+ * This is not very strong, and this is understood, but the aim isn't to
+ * be cryptographically strong - it is just to make up something that is
+ * pseudo random.
+ */
+void
+ipf_rand_push(void *src, int length)
+{
+ static int arc4_inited = 0;
+ u_char *nsrc;
+ int mylen;
+
+ if (arc4_inited == 0) {
+ arc4_init();
+ arc4_inited = 1;
+ }
+
+ if (length < 64) {
+ MD5Update(&md5ctx, src, length);
+ return;
+ }
+
+ nsrc = src;
+ mylen = length;
+
+#if defined(_SYS_MD5_H) && defined(SOLARIS2)
+# define buf buf_un.buf8
+#endif
+ MUTEX_ENTER(&arc4_mtx);
+ while ((mylen > 64) && (sizeof(pot) - inpot > sizeof(md5ctx.buf))) {
+ MD5Update(&md5ctx, nsrc, 64);
+ mylen -= 64;
+ nsrc += 64;
+ if (pottail + sizeof(md5ctx.buf) > pot + sizeof(pot)) {
+ int left, numbytes;
+
+ numbytes = pot + sizeof(pot) - pottail;
+ bcopy(md5ctx.buf, pottail, numbytes);
+ left = sizeof(md5ctx.buf) - numbytes;
+ pottail = pot;
+ bcopy(md5ctx.buf + sizeof(md5ctx.buf) - left,
+ pottail, left);
+ pottail += left;
+ } else {
+ bcopy(md5ctx.buf, pottail, sizeof(md5ctx.buf));
+ pottail += sizeof(md5ctx.buf);
+ }
+ inpot += 64;
+ }
+ MUTEX_EXIT(&arc4_mtx);
+#if defined(_SYS_MD5_H) && defined(SOLARIS2)
+# undef buf
+#endif
+}
+
+
+static int
+ipf_read_random(void *dest, int length)
+{
+ if (length > inpot)
+ return 0;
+
+ MUTEX_ENTER(&arc4_mtx);
+ if (pothead + length > pot + sizeof(pot)) {
+ int left, numbytes;
+
+ left = length;
+ numbytes = pot + sizeof(pot) - pothead;
+ bcopy(pothead, dest, numbytes);
+ left -= numbytes;
+ pothead = pot;
+ bcopy(pothead, dest + length - left, left);
+ pothead += left;
+ } else {
+ bcopy(pothead, dest, length);
+ pothead += length;
+ }
+ inpot -= length;
+ if (inpot == 0)
+ pothead = pottail = pot;
+ MUTEX_EXIT(&arc4_mtx);
+
+ return length;
+}
+
+#endif /* NEED_LOCAL_RAND */
OpenPOWER on IntegriCloud