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--