diff options
author | djm <> | 2008-04-13 00:28:35 +0000 |
---|---|---|
committer | djm <> | 2008-04-13 00:28:35 +0000 |
commit | 5e750bd35f84420b17ed5842c8d69e716d485360 (patch) | |
tree | 62e3eeaaed04c399a4ee40b21abf4ad3f648fed4 | |
parent | 3e091e5f9bb5ae7fbc3f63db4474a599ad3fe529 (diff) | |
download | openbsd-5e750bd35f84420b17ed5842c8d69e716d485360.tar.gz openbsd-5e750bd35f84420b17ed5842c8d69e716d485360.tar.bz2 openbsd-5e750bd35f84420b17ed5842c8d69e716d485360.zip |
Improve the libc DNS resolver ID generation algorithm to be more
resistant to prediction atacks by wrapping the existing LCG in a
random permutation generator based on a Luby-Rackoff block cipher.
lots of discussion and final ok deraadt@
-rw-r--r-- | src/lib/libc/net/res_random.c | 122 |
1 files changed, 79 insertions, 43 deletions
diff --git a/src/lib/libc/net/res_random.c b/src/lib/libc/net/res_random.c index 4dc1d33462..f0beb7a573 100644 --- a/src/lib/libc/net/res_random.c +++ b/src/lib/libc/net/res_random.c | |||
@@ -1,7 +1,8 @@ | |||
1 | /* $OpenBSD: res_random.c,v 1.16 2005/03/25 13:24:12 otto Exp $ */ | 1 | /* $OpenBSD: res_random.c,v 1.17 2008/04/13 00:28:35 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright 1997 Niels Provos <provos@physnet.uni-hamburg.de> | 4 | * Copyright 1997 Niels Provos <provos@physnet.uni-hamburg.de> |
5 | * Copyright 2008 Damien Miller <djm@openbsd.org> | ||
5 | * All rights reserved. | 6 | * All rights reserved. |
6 | * | 7 | * |
7 | * Theo de Raadt <deraadt@openbsd.org> came up with the idea of using | 8 | * Theo de Raadt <deraadt@openbsd.org> came up with the idea of using |
@@ -9,6 +10,11 @@ | |||
9 | * ids to solve the resolver/named problem. But Niels designed the | 10 | * ids to solve the resolver/named problem. But Niels designed the |
10 | * actual system based on the constraints. | 11 | * actual system based on the constraints. |
11 | * | 12 | * |
13 | * Later modified by Damien Miller to wrap the LCG output in a 15-bit | ||
14 | * permutation generator based on a Luby-Rackoff block cipher. This | ||
15 | * ensures the output is non-repeating and preserves the MSB twiddle | ||
16 | * trick, but makes it more resistant to LCG prediction. | ||
17 | * | ||
12 | * Redistribution and use in source and binary forms, with or without | 18 | * Redistribution and use in source and binary forms, with or without |
13 | * modification, are permitted provided that the following conditions | 19 | * modification, are permitted provided that the following conditions |
14 | * are met: | 20 | * are met: |
@@ -49,9 +55,8 @@ | |||
49 | * yielding two different cycles by toggling the msb on and off. | 55 | * yielding two different cycles by toggling the msb on and off. |
50 | * This avoids reuse issues caused by reseeding. | 56 | * This avoids reuse issues caused by reseeding. |
51 | * | 57 | * |
52 | * The 16 bit space is very small and brute force attempts are | 58 | * The output of this generator is then randomly permuted though a |
53 | * entirly feasible, we skip a random number of transaction ids | 59 | * custom 15 bit Luby-Rackoff block cipher. |
54 | * so that an attacker will not get sequential ids. | ||
55 | */ | 60 | */ |
56 | 61 | ||
57 | #include <sys/types.h> | 62 | #include <sys/types.h> |
@@ -63,12 +68,21 @@ | |||
63 | #include <stdlib.h> | 68 | #include <stdlib.h> |
64 | #include <string.h> | 69 | #include <string.h> |
65 | 70 | ||
66 | #define RU_OUT 180 /* Time after wich will be reseeded */ | 71 | #define RU_OUT 180 /* Time after wich will be reseeded */ |
67 | #define RU_MAX 30000 /* Uniq cycle, avoid blackjack prediction */ | 72 | #define RU_MAX 30000 /* Uniq cycle, avoid blackjack prediction */ |
68 | #define RU_GEN 2 /* Starting generator */ | 73 | #define RU_GEN 2 /* Starting generator */ |
69 | #define RU_N 32749 /* RU_N-1 = 2*2*3*2729 */ | 74 | #define RU_N 32749 /* RU_N-1 = 2*2*3*2729 */ |
70 | #define RU_AGEN 7 /* determine ru_a as RU_AGEN^(2*rand) */ | 75 | #define RU_AGEN 7 /* determine ru_a as RU_AGEN^(2*rand) */ |
71 | #define RU_M 31104 /* RU_M = 2^7*3^5 - don't change */ | 76 | #define RU_M 31104 /* RU_M = 2^7*3^5 - don't change */ |
77 | #define RU_ROUNDS 11 /* Number of rounds for permute (odd) */ | ||
78 | |||
79 | struct prf_ctx { | ||
80 | /* PRF lookup table for odd rounds (7 bits input to 8 bits output) */ | ||
81 | u_char prf7[(RU_ROUNDS / 2) * (1 << 7)]; | ||
82 | |||
83 | /* PRF lookup table for even rounds (8 bits input to 7 bits output) */ | ||
84 | u_char prf8[((RU_ROUNDS + 1) / 2) * (1 << 8)]; | ||
85 | }; | ||
72 | 86 | ||
73 | #define PFAC_N 3 | 87 | #define PFAC_N 3 |
74 | const static u_int16_t pfacts[PFAC_N] = { | 88 | const static u_int16_t pfacts[PFAC_N] = { |
@@ -83,9 +97,8 @@ static u_int16_t ru_a, ru_b; | |||
83 | static u_int16_t ru_g; | 97 | static u_int16_t ru_g; |
84 | static u_int16_t ru_counter = 0; | 98 | static u_int16_t ru_counter = 0; |
85 | static u_int16_t ru_msb = 0; | 99 | static u_int16_t ru_msb = 0; |
100 | static struct prf_ctx *ru_prf = NULL; | ||
86 | static long ru_reseed; | 101 | static long ru_reseed; |
87 | static u_int32_t tmp; /* Storage for unused random */ | ||
88 | static struct timeval tv; | ||
89 | 102 | ||
90 | static u_int16_t pmod(u_int16_t, u_int16_t, u_int16_t); | 103 | static u_int16_t pmod(u_int16_t, u_int16_t, u_int16_t); |
91 | static void res_initid(void); | 104 | static void res_initid(void); |
@@ -94,7 +107,6 @@ static void res_initid(void); | |||
94 | * Do a fast modular exponation, returned value will be in the range | 107 | * Do a fast modular exponation, returned value will be in the range |
95 | * of 0 - (mod-1) | 108 | * of 0 - (mod-1) |
96 | */ | 109 | */ |
97 | |||
98 | static u_int16_t | 110 | static u_int16_t |
99 | pmod(u_int16_t gen, u_int16_t exp, u_int16_t mod) | 111 | pmod(u_int16_t gen, u_int16_t exp, u_int16_t mod) |
100 | { | 112 | { |
@@ -113,6 +125,39 @@ pmod(u_int16_t gen, u_int16_t exp, u_int16_t mod) | |||
113 | return (s); | 125 | return (s); |
114 | } | 126 | } |
115 | 127 | ||
128 | /* | ||
129 | * 15-bit permutation based on Luby-Rackoff block cipher | ||
130 | */ | ||
131 | u_int | ||
132 | permute15(u_int in) | ||
133 | { | ||
134 | int i; | ||
135 | u_int left, right, tmp; | ||
136 | |||
137 | if (ru_prf == NULL) | ||
138 | return in; | ||
139 | |||
140 | left = (in >> 8) & 0x7f; | ||
141 | right = in & 0xff; | ||
142 | |||
143 | /* | ||
144 | * Each round swaps the width of left and right. Even rounds have | ||
145 | * a 7-bit left, odd rounds have an 8-bit left. Since this uses an | ||
146 | * odd number of rounds, left is always 8 bits wide at the end. | ||
147 | */ | ||
148 | for (i = 0; i < RU_ROUNDS; i++) { | ||
149 | if ((i & 1) == 0) | ||
150 | tmp = ru_prf->prf8[(i << (8 - 1)) | right] & 0x7f; | ||
151 | else | ||
152 | tmp = ru_prf->prf7[((i - 1) << (7 - 1)) | right]; | ||
153 | tmp ^= left; | ||
154 | left = right; | ||
155 | right = tmp; | ||
156 | } | ||
157 | |||
158 | return (right << 8) | left; | ||
159 | } | ||
160 | |||
116 | /* | 161 | /* |
117 | * Initializes the seed and chooses a suitable generator. Also toggles | 162 | * Initializes the seed and chooses a suitable generator. Also toggles |
118 | * the msb flag. The msb flag is used to generate two distinct | 163 | * the msb flag. The msb flag is used to generate two distinct |
@@ -125,27 +170,25 @@ static void | |||
125 | res_initid(void) | 170 | res_initid(void) |
126 | { | 171 | { |
127 | u_int16_t j, i; | 172 | u_int16_t j, i; |
173 | u_int32_t tmp; | ||
128 | int noprime = 1; | 174 | int noprime = 1; |
175 | struct timeval tv; | ||
129 | 176 | ||
130 | tmp = arc4random(); | 177 | ru_x = arc4random_uniform(RU_M); |
131 | ru_x = (tmp & 0xFFFF) % RU_M; | ||
132 | 178 | ||
133 | /* 15 bits of random seed */ | 179 | /* 15 bits of random seed */ |
134 | ru_seed = (tmp >> 16) & 0x7FFF; | ||
135 | tmp = arc4random(); | 180 | tmp = arc4random(); |
181 | ru_seed = (tmp >> 16) & 0x7FFF; | ||
136 | ru_seed2 = tmp & 0x7FFF; | 182 | ru_seed2 = tmp & 0x7FFF; |
137 | 183 | ||
138 | tmp = arc4random(); | ||
139 | |||
140 | /* Determine the LCG we use */ | 184 | /* Determine the LCG we use */ |
185 | tmp = arc4random(); | ||
141 | ru_b = (tmp & 0xfffe) | 1; | 186 | ru_b = (tmp & 0xfffe) | 1; |
142 | ru_a = pmod(RU_AGEN, (tmp >> 16) & 0xfffe, RU_M); | 187 | ru_a = pmod(RU_AGEN, (tmp >> 16) & 0xfffe, RU_M); |
143 | while (ru_b % 3 == 0) | 188 | while (ru_b % 3 == 0) |
144 | ru_b += 2; | 189 | ru_b += 2; |
145 | 190 | ||
146 | tmp = arc4random(); | 191 | j = arc4random_uniform(RU_N); |
147 | j = tmp % RU_N; | ||
148 | tmp = tmp >> 16; | ||
149 | 192 | ||
150 | /* | 193 | /* |
151 | * Do a fast gcd(j,RU_N-1), so we can find a j with | 194 | * Do a fast gcd(j,RU_N-1), so we can find a j with |
@@ -167,6 +210,12 @@ res_initid(void) | |||
167 | ru_g = pmod(RU_GEN, j, RU_N); | 210 | ru_g = pmod(RU_GEN, j, RU_N); |
168 | ru_counter = 0; | 211 | ru_counter = 0; |
169 | 212 | ||
213 | /* Initialise PRF for Luby-Rackoff permutation */ | ||
214 | if (ru_prf == NULL) | ||
215 | ru_prf = malloc(sizeof(*ru_prf)); | ||
216 | if (ru_prf != NULL) | ||
217 | arc4random_buf(ru_prf, sizeof(*ru_prf)); | ||
218 | |||
170 | gettimeofday(&tv, NULL); | 219 | gettimeofday(&tv, NULL); |
171 | ru_reseed = tv.tv_sec + RU_OUT; | 220 | ru_reseed = tv.tv_sec + RU_OUT; |
172 | ru_msb = ru_msb == 0x8000 ? 0 : 0x8000; | 221 | ru_msb = ru_msb == 0x8000 ? 0 : 0x8000; |
@@ -175,35 +224,21 @@ res_initid(void) | |||
175 | u_int | 224 | u_int |
176 | res_randomid(void) | 225 | res_randomid(void) |
177 | { | 226 | { |
178 | int i, n; | 227 | struct timeval tv; |
179 | 228 | ||
180 | gettimeofday(&tv, NULL); | 229 | gettimeofday(&tv, NULL); |
181 | if (ru_counter >= RU_MAX || tv.tv_sec > ru_reseed) | 230 | if (ru_counter >= RU_MAX || tv.tv_sec > ru_reseed) |
182 | res_initid(); | 231 | res_initid(); |
183 | 232 | ||
184 | #if 0 | 233 | /* Linear Congruential Generator */ |
185 | if (!tmp) | 234 | ru_x = (ru_a * ru_x + ru_b) % RU_M; |
186 | tmp = arc4random(); | 235 | ru_counter++; |
187 | |||
188 | /* Skip a random number of ids */ | ||
189 | n = tmp & 0x7; tmp = tmp >> 3; | ||
190 | if (ru_counter + n >= RU_MAX) | ||
191 | res_initid(); | ||
192 | #else | ||
193 | n = 0; | ||
194 | #endif | ||
195 | |||
196 | for (i = 0; i <= n; i++) | ||
197 | /* Linear Congruential Generator */ | ||
198 | ru_x = (ru_a * ru_x + ru_b) % RU_M; | ||
199 | |||
200 | ru_counter += i; | ||
201 | 236 | ||
202 | return (ru_seed ^ pmod(ru_g, ru_seed2 + ru_x, RU_N)) | ru_msb; | 237 | return permute15(ru_seed ^ pmod(ru_g, ru_seed2 + ru_x, RU_N)) | ru_msb; |
203 | } | 238 | } |
204 | 239 | ||
205 | #if 0 | 240 | #if 0 |
206 | void | 241 | int |
207 | main(int argc, char **argv) | 242 | main(int argc, char **argv) |
208 | { | 243 | { |
209 | int i, n; | 244 | int i, n; |
@@ -218,11 +253,12 @@ main(int argc, char **argv) | |||
218 | printf("Ru_A: %u\n", ru_a); | 253 | printf("Ru_A: %u\n", ru_a); |
219 | printf("Ru_B: %u\n", ru_b); | 254 | printf("Ru_B: %u\n", ru_b); |
220 | 255 | ||
221 | n = atoi(argv[1]); | 256 | n = argc > 1 ? atoi(argv[1]) : 60001; |
222 | for (i=0;i<n;i++) { | 257 | for (i=0;i<n;i++) { |
223 | wert = res_randomid(); | 258 | wert = res_randomid(); |
224 | printf("%06d\n", wert); | 259 | printf("%u\n", wert); |
225 | } | 260 | } |
261 | return 0; | ||
226 | } | 262 | } |
227 | #endif | 263 | #endif |
228 | 264 | ||