Subject: Re: kernel ip_randomid() and libc randomid(3) still "broken"
To: None <jonathan@DSG.Stanford.EDU>
From: Jun-ichiro itojun Hagino <itojun@itojun.org>
List: tech-net
Date: 11/26/2003 04:17:42
--NextPart-20031126041623-0813301
Content-Type: Text/Plain; charset=us-ascii

> 	ip_randomid() and friends are all corrected.  they have the desired
> 	property of having certain amount of gap between appearance of the
> 	same output.  now, could I make RANDOM_IP_ID default to 1 so that it
> 	will be compiled in always (less #define is always better)?
> 	we have ip_do_randomid variable so people can enable/disable it as they
> 	wish.

	btw here's the analysis code i used today.  this is openbsd
	ip_random.c with some mods.  "ru_seed2 + ru_x" is suggested by provos
	and has the non-repeating property.  the commit i made was the removal
	of ru_seed2.

itojun

--NextPart-20031126041623-0813301
Content-Type: Text/Plain; charset=us-ascii
Content-Disposition: attachment; filename="1"

# This is a shell archive.  Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file".  Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
#	Makefile
#	ip_id.c
#
echo x - Makefile
sed 's/^X//' >Makefile << 'END-of-Makefile'
XPROG=	ip_id
X
Xtest1:
X	./ip_id 0 | sort -n | tee out | head
Xtest2:
X	./ip_id 1 | sort -n | tee out | head
Xtest3:
X	./ip_id 2 | sort -n | tee out | head
X
XNOMAN=	yes
X
X.include <bsd.prog.mk>
END-of-Makefile
echo x - ip_id.c
sed 's/^X//' >ip_id.c << 'END-of-ip_id.c'
X/* $OpenBSD: ip_id.c,v 1.7 2003/09/21 04:06:39 itojun Exp $ */
X
X/*
X * Copyright 1998 Niels Provos <provos@citi.umich.edu>
X * All rights reserved.
X *
X * Theo de Raadt <deraadt@openbsd.org> came up with the idea of using
X * such a mathematical system to generate more random (yet non-repeating)
X * ids to solve the resolver/named problem.  But Niels designed the
X * actual system based on the constraints.
X *
X * Redistribution and use in source and binary forms, with or without
X * modification, are permitted provided that the following conditions
X * are met:
X * 1. Redistributions of source code must retain the above copyright
X *    notice, this list of conditions and the following disclaimer.
X * 2. Redistributions in binary form must reproduce the above copyright
X *    notice, this list of conditions and the following disclaimer in the
X *    documentation and/or other materials provided with the distribution.
X * 3. All advertising materials mentioning features or use of this software
X *    must display the following acknowledgement:
X *      This product includes software developed by Niels Provos.
X * 4. The name of the author may not be used to endorse or promote products
X *    derived from this software without specific prior written permission.
X *
X * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
X * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
X * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
X * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
X * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
X * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
X * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
X * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
X * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
X */
X
X/*
X * seed = random 15bit
X * n = prime, g0 = generator to n,
X * j = random so that gcd(j,n-1) == 1
X * g = g0^j mod n will be a generator again.
X *
X * X[0] = random seed.
X * X[n] = a*X[n-1]+b mod m is a Linear Congruential Generator
X * with a = 7^(even random) mod m,
X *      b = random with gcd(b,m) == 1
X *      m = 31104 and a maximal period of m-1.
X *
X * The transaction id is determined by:
X * id[n] = seed xor (g^X[n] mod n)
X *
X * Effectivly the id is restricted to the lower 15 bits, thus
X * yielding two different cycles by toggling the msb on and off.
X * This avoids reuse issues caused by reseeding.
X */
X
X#include <sys/param.h>
X#if 0
X#include <sys/kernel.h>
X#include <dev/rndvar.h>
X#else
X#include <sys/time.h>
X#include <stdio.h>
X#include <stdlib.h>
X#include <string.h>
X#endif
X
X#define RU_OUT  180		/* Time after wich will be reseeded */
X#define RU_MAX	30000		/* Uniq cycle, avoid blackjack prediction */
X#define RU_GEN	2		/* Starting generator */
X#define RU_N	32749		/* RU_N-1 = 2*2*3*2729 */
X#define RU_AGEN	7		/* determine ru_a as RU_AGEN^(2*rand) */
X#define RU_M	31104		/* RU_M = 2^7*3^5 - don't change */
X
X#define PFAC_N 3
Xconst static u_int16_t pfacts[PFAC_N] = {
X	2,
X	3,
X	2729
X};
X
Xstatic u_int16_t ru_x;
Xstatic u_int16_t ru_seed, ru_seed2;
Xstatic u_int16_t ru_a, ru_b;
Xstatic u_int16_t ru_g;
Xstatic u_int16_t ru_counter = 0;
Xstatic u_int16_t ru_msb = 0;
Xstatic long ru_reseed;
Xstatic u_int32_t tmp;		/* Storage for unused random */
X
Xstatic u_int16_t pmod(u_int16_t, u_int16_t, u_int16_t);
Xstatic void ip_initid(void);
Xu_int16_t ip_randomid(void);
X
Xint seed2 = 1;
X
X/*
X * Do a fast modular exponation, returned value will be in the range
X * of 0 - (mod-1)
X */
X
Xstatic u_int16_t
Xpmod(u_int16_t gen, u_int16_t expo, u_int16_t mod)
X{
X	u_int16_t s, t, u;
X
X	s = 1;
X	t = gen;
X	u = expo;
X
X	while (u) {
X		if (u & 1)
X			s = (s*t) % mod;
X		u >>= 1;
X		t = (t*t) % mod;
X	}
X	return (s);
X}
X
X/*
X * Initalizes the seed and chooses a suitable generator. Also toggles
X * the msb flag. The msb flag is used to generate two distinct
X * cycles of random numbers and thus avoiding reuse of ids.
X *
X * This function is called from id_randomid() when needed, an
X * application does not have to worry about it.
X */
Xstatic void
Xip_initid(void)
X{
X	u_int16_t j, i;
X	int noprime = 1;
X	struct timeval time;
X
X	ru_x = ((tmp = arc4random()) & 0xFFFF) % RU_M;
X
X	/* 15 bits of random seed */
X	ru_seed = (tmp >> 16) & 0x7FFF;
X	ru_seed2 = arc4random() & 0x7FFF;
X
X	/* Determine the LCG we use */
X	ru_b = ((tmp = arc4random()) & 0xfffe) | 1;
X	ru_a = pmod(RU_AGEN, (tmp >> 16) & 0xfffe, RU_M);
X	while (ru_b % 3 == 0)
X		ru_b += 2;
X
X	j = (tmp = arc4random()) % RU_N;
X	tmp = tmp >> 16;
X
X	/*
X	 * Do a fast gcd(j,RU_N-1), so we can find a j with
X	 * gcd(j, RU_N-1) == 1, giving a new generator for
X	 * RU_GEN^j mod RU_N
X	 */
X
X	while (noprime) {
X		for (i = 0; i < PFAC_N; i++)
X			if (j % pfacts[i] == 0)
X				break;
X
X		if (i >= PFAC_N)
X			noprime = 0;
X		else
X			j = (j+1) % RU_N;
X	}
X
X	ru_g = pmod(RU_GEN,j,RU_N);
X	ru_counter = 0;
X
X	gettimeofday(&time, NULL);
X	ru_reseed = time.tv_sec + RU_OUT;
X	ru_msb = ru_msb == 0x8000 ? 0 : 0x8000;
X}
X
Xu_int16_t
Xip_randomid(void)
X{
X	int i, n;
X	struct timeval time;
X
X	gettimeofday(&time, NULL);
X	if (ru_counter >= RU_MAX || time.tv_sec > ru_reseed)
X		ip_initid();
X
X	if (!tmp)
X		tmp = arc4random();
X
X	/* Skip a random number of ids */
X	n = tmp & 0x3; tmp = tmp >> 2;
X	if (ru_counter + n >= RU_MAX)
X		ip_initid();
X
X	for (i = 0; i <= n; i++)
X		/* Linear Congruential Generator */
X		ru_x = (ru_a * ru_x + ru_b) % RU_M;
X
X	ru_counter += i;
X
X	switch (seed2) {
X	default:
X		return (ru_seed ^ pmod(ru_g, ru_seed2 ^ ru_x, RU_N)) | ru_msb;
X	case 1:
X		return (ru_seed ^ pmod(ru_g, ru_x, RU_N)) | ru_msb;
X	case 2:
X		return (ru_seed ^ pmod(ru_g, ru_seed2 + ru_x, RU_N)) | ru_msb;
X	}
X}
X
Xlong lastseen[65536];
X
Xint
Xmain(int argc, char **argv)
X{
X	long i, iter;
X	u_int16_t x;
X
X	if (argc != 2)
X		seed2 = 1;
X	else
X		seed2 = atoi(argv[1]);
X	iter = 100000;
X	for (i = 0; i < iter; i++) {
X		x = ip_randomid();
X		if (lastseen[x])
X			printf("%ld gap for value %04x (last %ld, now %ld)\n",
X			    i - lastseen[x], x, lastseen[x], i);
X		lastseen[x] = i;
X	}
X}
END-of-ip_id.c
exit


--NextPart-20031126041623-0813301--