From 0f7d882bb7661f9601f3843b0e393b6155cd9571 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Mon, 21 Jul 2014 15:31:01 -0700 Subject: [PATCH] Switch to OpenBSD res_random. Change-Id: Ia971d647832893e9bb4601697132a105524d2f96 --- libc/Android.mk | 8 +- libc/dns/resolv/res_init.c | 41 --- .../lib/libc/net/res_random.c | 275 ++++++++++++++++++ 3 files changed, 282 insertions(+), 42 deletions(-) create mode 100644 libc/upstream-openbsd/lib/libc/net/res_random.c diff --git a/libc/Android.mk b/libc/Android.mk index 0adaff7d5..2d87ebb2e 100644 --- a/libc/Android.mk +++ b/libc/Android.mk @@ -636,7 +636,13 @@ LOCAL_SRC_FILES := \ upstream-netbsd/lib/libc/isc/ev_streams.c \ upstream-netbsd/lib/libc/isc/ev_timers.c \ -LOCAL_CFLAGS := \ +# We use the OpenBSD res_random. +LOCAL_CFLAGS += \ + -Dres_randomid=__res_randomid +LOCAL_SRC_FILES += \ + upstream-openbsd/lib/libc/net/res_random.c \ + +LOCAL_CFLAGS += \ $(libc_common_cflags) \ -DANDROID_CHANGES \ -DINET6 \ diff --git a/libc/dns/resolv/res_init.c b/libc/dns/resolv/res_init.c index f1cbed8ac..ab5db1323 100644 --- a/libc/dns/resolv/res_init.c +++ b/libc/dns/resolv/res_init.c @@ -616,47 +616,6 @@ net_mask(struct in_addr in) /*!< XXX - should really use system's version of thi } #endif -#ifdef ANDROID_CHANGES -static int -real_randomid(u_int *random_value) { - /* open the nonblocking random device, returning -1 on failure */ - int random_device = open("/dev/urandom", O_RDONLY | O_CLOEXEC); - if (random_device < 0) { - return -1; - } - - /* read from the random device, returning -1 on failure (or too many retries)*/ - for (u_int retry = 5; retry > 0; retry--) { - int retval = read(random_device, random_value, sizeof(u_int)); - if (retval == sizeof(u_int)) { - *random_value &= 0xffff; - close(random_device); - return 0; - } else if ((retval < 0) && (errno != EINTR)) { - break; - } - } - - close(random_device); - return -1; -} -#endif /* ANDROID_CHANGES */ - -u_int -res_randomid(void) { -#ifdef ANDROID_CHANGES - int status = 0; - u_int output = 0; - status = real_randomid(&output); - if (status != -1) { - return output; - } -#endif /* ANDROID_CHANGES */ - struct timeval now; - gettimeofday(&now, NULL); - return (0xffff & (now.tv_sec ^ now.tv_usec ^ getpid())); -} - /*% * This routine is for closing the socket if a virtual circuit is used and * the program wants to close it. This provides support for endhostent() diff --git a/libc/upstream-openbsd/lib/libc/net/res_random.c b/libc/upstream-openbsd/lib/libc/net/res_random.c new file mode 100644 index 000000000..f28692f7c --- /dev/null +++ b/libc/upstream-openbsd/lib/libc/net/res_random.c @@ -0,0 +1,275 @@ +/* $OpenBSD: res_random.c,v 1.21 2014/07/20 04:22:34 guenther Exp $ */ + +/* + * Copyright 1997 Niels Provos + * Copyright 2008 Damien Miller + * All rights reserved. + * + * Theo de Raadt came up with the idea of using + * such a mathematical system to generate more random (yet non-repeating) + * ids to solve the resolver/named problem. But Niels designed the + * actual system based on the constraints. + * + * Later modified by Damien Miller to wrap the LCG output in a 15-bit + * permutation generator based on a Luby-Rackoff block cipher. This + * ensures the output is non-repeating and preserves the MSB twiddle + * trick, but makes it more resistant to LCG prediction. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * seed = random 15bit + * n = prime, g0 = generator to n, + * j = random so that gcd(j,n-1) == 1 + * g = g0^j mod n will be a generator again. + * + * X[0] = random seed. + * X[n] = a*X[n-1]+b mod m is a Linear Congruential Generator + * with a = 7^(even random) mod m, + * b = random with gcd(b,m) == 1 + * m = 31104 and a maximal period of m-1. + * + * The transaction id is determined by: + * id[n] = seed xor (g^X[n] mod n) + * + * Effectivly the id is restricted to the lower 15 bits, thus + * yielding two different cycles by toggling the msb on and off. + * This avoids reuse issues caused by reseeding. + * + * The output of this generator is then randomly permuted though a + * custom 15 bit Luby-Rackoff block cipher. + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include "thread_private.h" + +#define RU_OUT 180 /* Time after wich will be reseeded */ +#define RU_MAX 30000 /* Uniq cycle, avoid blackjack prediction */ +#define RU_GEN 2 /* Starting generator */ +#define RU_N 32749 /* RU_N-1 = 2*2*3*2729 */ +#define RU_AGEN 7 /* determine ru_a as RU_AGEN^(2*rand) */ +#define RU_M 31104 /* RU_M = 2^7*3^5 - don't change */ +#define RU_ROUNDS 11 /* Number of rounds for permute (odd) */ + +struct prf_ctx { + /* PRF lookup table for odd rounds (7 bits input to 8 bits output) */ + u_char prf7[(RU_ROUNDS / 2) * (1 << 7)]; + + /* PRF lookup table for even rounds (8 bits input to 7 bits output) */ + u_char prf8[((RU_ROUNDS + 1) / 2) * (1 << 8)]; +}; + +#define PFAC_N 3 +static const u_int16_t pfacts[PFAC_N] = { + 2, + 3, + 2729 +}; + +static u_int16_t ru_x; +static u_int16_t ru_seed, ru_seed2; +static u_int16_t ru_a, ru_b; +static u_int16_t ru_g; +static u_int16_t ru_counter = 0; +static u_int16_t ru_msb = 0; +static struct prf_ctx *ru_prf = NULL; +static time_t ru_reseed; + +static u_int16_t pmod(u_int16_t, u_int16_t, u_int16_t); +static void res_initid(void); + +/* + * Do a fast modular exponation, returned value will be in the range + * of 0 - (mod-1) + */ +static u_int16_t +pmod(u_int16_t gen, u_int16_t exp, u_int16_t mod) +{ + u_int16_t s, t, u; + + s = 1; + t = gen; + u = exp; + + while (u) { + if (u & 1) + s = (s * t) % mod; + u >>= 1; + t = (t * t) % mod; + } + return (s); +} + +/* + * 15-bit permutation based on Luby-Rackoff block cipher + */ +static u_int +permute15(u_int in) +{ + int i; + u_int left, right, tmp; + + if (ru_prf == NULL) + return in; + + left = (in >> 8) & 0x7f; + right = in & 0xff; + + /* + * Each round swaps the width of left and right. Even rounds have + * a 7-bit left, odd rounds have an 8-bit left. Since this uses an + * odd number of rounds, left is always 8 bits wide at the end. + */ + for (i = 0; i < RU_ROUNDS; i++) { + if ((i & 1) == 0) + tmp = ru_prf->prf8[(i << (8 - 1)) | right] & 0x7f; + else + tmp = ru_prf->prf7[((i - 1) << (7 - 1)) | right]; + tmp ^= left; + left = right; + right = tmp; + } + + return (right << 8) | left; +} + +/* + * Initializes the seed and chooses a suitable generator. Also toggles + * the msb flag. The msb flag is used to generate two distinct + * cycles of random numbers and thus avoiding reuse of ids. + * + * This function is called from res_randomid() when needed, an + * application does not have to worry about it. + */ +static void +res_initid(void) +{ + u_int16_t j, i; + u_int32_t tmp; + int noprime = 1; + struct timespec ts; + + ru_x = arc4random_uniform(RU_M); + + /* 15 bits of random seed */ + tmp = arc4random(); + ru_seed = (tmp >> 16) & 0x7FFF; + ru_seed2 = tmp & 0x7FFF; + + /* Determine the LCG we use */ + tmp = arc4random(); + ru_b = (tmp & 0xfffe) | 1; + ru_a = pmod(RU_AGEN, (tmp >> 16) & 0xfffe, RU_M); + while (ru_b % 3 == 0) + ru_b += 2; + + j = arc4random_uniform(RU_N); + + /* + * Do a fast gcd(j,RU_N-1), so we can find a j with + * gcd(j, RU_N-1) == 1, giving a new generator for + * RU_GEN^j mod RU_N + */ + + while (noprime) { + for (i = 0; i < PFAC_N; i++) + if (j % pfacts[i] == 0) + break; + + if (i >= PFAC_N) + noprime = 0; + else + j = (j + 1) % RU_N; + } + + ru_g = pmod(RU_GEN, j, RU_N); + ru_counter = 0; + + /* Initialise PRF for Luby-Rackoff permutation */ + if (ru_prf == NULL) + ru_prf = malloc(sizeof(*ru_prf)); + if (ru_prf != NULL) + arc4random_buf(ru_prf, sizeof(*ru_prf)); + + clock_gettime(CLOCK_MONOTONIC, &ts); + ru_reseed = ts.tv_sec + RU_OUT; + ru_msb = ru_msb == 0x8000 ? 0 : 0x8000; +} + +u_int +res_randomid(void) +{ + struct timespec ts; + u_int r; + _THREAD_PRIVATE_MUTEX(random); + + clock_gettime(CLOCK_MONOTONIC, &ts); + + _THREAD_PRIVATE_MUTEX_LOCK(random); + + if (ru_counter >= RU_MAX || ts.tv_sec > ru_reseed) + res_initid(); + + /* Linear Congruential Generator */ + ru_x = (ru_a * ru_x + ru_b) % RU_M; + ru_counter++; + + r = permute15(ru_seed ^ pmod(ru_g, ru_seed2 + ru_x, RU_N)) | ru_msb; + + _THREAD_PRIVATE_MUTEX_UNLOCK(random); + + return (r); +} + +#if 0 +int +main(int argc, char **argv) +{ + int i, n; + u_int16_t wert; + + res_initid(); + + printf("Generator: %u\n", ru_g); + printf("Seed: %u\n", ru_seed); + printf("Reseed at %ld\n", ru_reseed); + printf("Ru_X: %u\n", ru_x); + printf("Ru_A: %u\n", ru_a); + printf("Ru_B: %u\n", ru_b); + + n = argc > 1 ? atoi(argv[1]) : 60001; + for (i=0;i