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 /src/lib/libc | |
| 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@
Diffstat (limited to 'src/lib/libc')
| -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 | ||
