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