xref: /openbsd-src/lib/libc/net/res_random.c (revision 98fa2d1286822c83f69beb18ce7fc5ca14177fc3)
1 /* $OpenBSD: res_random.c,v 1.1 1997/04/13 21:30:47 provos Exp $ */
2 
3 /*
4  * Copyright 1997 Niels Provos <provos@physnet.uni-hamburg.de>
5  * All rights reserved.
6  *
7  * Theo de Raadt <deraadt@openbsd.org> came up with the idea of using
8  * such a mathematical system to generate more random (yet non-repeating)
9  * ids to solve the resolver/named problem.  But Niels designed the
10  * actual system based on the constraints.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  * 3. All advertising materials mentioning features or use of this software
21  *    must display the following acknowledgement:
22  *      This product includes software developed by Niels Provos.
23  * 4. The name of the author may not be used to endorse or promote products
24  *    derived from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
27  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
28  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
29  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
30  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
31  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
35  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36  */
37 
38 /*
39  * seed = random 15bit
40  * n = prime, g0 = generator to n,
41  * j = random so that gcd(j,n-1) == 1
42  * g = g0^j mod n will be a generator again.
43  *
44  * X[0] = random seed.
45  * X[n] = a*X[n-1]+b mod m is a Linear Congruential Generator
46  * with a = 625, b = 6571, m = 31104 and a maximal period of m-1.
47  *
48  * The transaction id is determined by:
49  * id[n] = seed xor (g^X[n] mod n)
50  *
51  * Effectivly the id is restricted to the lower 15 bits, thus
52  * yielding two different cycles by toggling the msb on and off.
53  * This avoids reuse issues caused by reseeding.
54  */
55 
56 #include <sys/types.h>
57 #include <netinet/in.h>
58 #include <sys/time.h>
59 #include <resolv.h>
60 
61 #include <unistd.h>
62 #include <stdlib.h>
63 #include <string.h>
64 
65 #define RU_MAX	20000		/* Uniq cycle, avoid blackjack prediction */
66 #define RU_GEN	2		/* Starting generator */
67 #define RU_N	32749		/* RU_N-1 = 2*2*3*2729 */
68 #define RU_A	625
69 #define RU_B	6571
70 #define RU_M	31104
71 
72 #define PFAC_N 3
73 const static u_int16_t pfacts[PFAC_N] = {
74 	2,
75 	3,
76 	2729
77 };
78 
79 static u_int16_t ru_x;
80 static u_int16_t ru_seed;
81 static u_int16_t ru_g;
82 static u_int16_t ru_counter = 0;
83 static u_int16_t ru_msb = 0;
84 
85 static u_int32_t pmod __P((u_int32_t, u_int32_t, u_int32_t));
86 static void res_initid __P((void));
87 
88 /*
89  * Do a fast modular exponation, returned value will be in the range
90  * of 0 - (mod-1)
91  */
92 
93 static u_int32_t
94 pmod(gen, exp, mod)
95 	u_int32_t gen, exp, mod;
96 {
97 	u_int32_t s, t, u;
98 
99 	s = 1;
100 	t = gen;
101 	u = exp;
102 
103 	while (u) {
104 		if (u & 1)
105 			s = (s*t) % mod;
106 		u >>= 1;
107 		t = (t*t) % mod;
108 	}
109 	return (s);
110 }
111 
112 /*
113  * Initalizes the seed and choosed a suitable generator. Also toggles
114  * the msb flag. The msb flag is used to generate two distinct
115  * cycles of random numbers and thus avoiding reuse of ids.
116  *
117  * This function is called from res_randomid() when needed, an
118  * application does not have to worry about it.
119  */
120 static void
121 res_initid()
122 {
123 	u_int16_t j, i;
124 	u_int32_t tmp;
125 	int noprime = 1;
126 
127 	tmp = arc4random();
128 	ru_x = (tmp & 0xFFFF) % RU_M;
129 
130 	/* 15 bits of random seed */
131 	ru_seed = (tmp >> 16) & 0x7FFF;
132 
133 	j = arc4random() % RU_N;
134 
135 	/*
136 	 * Do a fast gcd(j,RU_N-1), so we can find a j with
137 	 * gcd(j, RU_N-1) == 1, giving a new generator for
138 	 * RU_GEN^j mod RU_N
139 	 */
140 
141 	while (noprime) {
142 		for (i=0; i<PFAC_N; i++)
143 			if (j%pfacts[i] == 0)
144 				break;
145 
146 		if (i>=PFAC_N)
147 			noprime = 0;
148 		else
149 			j = (j+1) % RU_N;
150 	}
151 
152 	ru_g = pmod(RU_GEN,j,RU_N);
153 	ru_counter = 0;
154 
155 	ru_msb = ru_msb == 0x8000 ? 0 : 0x8000;
156 }
157 
158 u_int
159 res_randomid()
160 {
161 	if (ru_counter % RU_MAX == 0)
162 		res_initid();
163 
164 	ru_counter++;
165 
166 	/* Linear Congruential Generator */
167 	ru_x = (RU_A*ru_x + RU_B) % RU_M;
168 
169 	return (ru_seed ^ pmod(ru_g,ru_x,RU_N)) | ru_msb;
170 }
171 
172 #if 0
173 void
174 main(int argc, char **argv)
175 {
176 	int i, n;
177 	u_int16_t wert;
178 
179 	res_initid();
180 
181 	printf("Generator: %d\n", ru_g);
182 	printf("Seed: %d\n", ru_seed);
183 	printf("Ru_X: %d\n", ru_x);
184 
185 	n = atoi(argv[1]);
186 	for (i=0;i<n;i++) {
187 		wert = res_randomid();
188 		printf("%06d\n", wert);
189 	}
190 }
191 #endif
192 
193