From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S268752AbUIXNuV (ORCPT ); Fri, 24 Sep 2004 09:50:21 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S268755AbUIXNuU (ORCPT ); Fri, 24 Sep 2004 09:50:20 -0400 Received: from 104.engsoc.carleton.ca ([134.117.69.104]:33464 "EHLO certainkey.com") by vger.kernel.org with ESMTP id S268752AbUIXNp3 (ORCPT ); Fri, 24 Sep 2004 09:45:29 -0400 Date: Fri, 24 Sep 2004 09:44:57 -0400 From: Jean-Luc Cooke To: "Theodore Ts'o" , linux-kernel@vger.kernel.org Subject: Re: [PROPOSAL/PATCH] Fortuna PRNG in /dev/random Message-ID: <20040924134457.GQ28317@certainkey.com> References: <20040923234340.GF28317@certainkey.com> <20040924043851.GA3611@thunk.org> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="qLni7iB6Dl8qUSwk" Content-Disposition: inline Content-Transfer-Encoding: 8bit In-Reply-To: <20040924043851.GA3611@thunk.org> User-Agent: Mutt/1.5.6+20040722i Sender: linux-kernel-owner@vger.kernel.org X-Mailing-List: linux-kernel@vger.kernel.org --qLni7iB6Dl8qUSwk Content-Type: text/plain; charset=us-ascii Content-Disposition: inline On Fri, Sep 24, 2004 at 12:38:51AM -0400, Theodore Ts'o wrote: > I'm also a bit concerned about how much time AES takes over the > cut-down MD4, as this may affect networking benchmarks. (And we don't > need super-strength crypto here.) Oh, openssl speed md4 aes shows: type 16 bytes 64 bytes 256 bytes 1024 bytes 8192 bytes md4 10708.72k 38240.96k 111170.47k 215872.85k 296828.93k aes-128 cbc 32121.81k 32678.31k 33119.49k 33221.29k 33210.59k aes-192 cbc 27915.92k 27868.52k 28418.08k 28677.12k 28721.15k aes-256 cbc 24599.57k 25142.38k 25381.80k 25474.88k 25392.46k Since we're using small blocks. Attached is the patch with the problems Ted pointed out. JLC --qLni7iB6Dl8qUSwk Content-Type: text/plain; charset=unknown-8bit Content-Disposition: attachment; filename="fortuna-2.6.8.1.patch" Content-Transfer-Encoding: 8bit diff -uNr linux-2.6.8.1-orig/include/linux/sysctl.h linux-2.6.8.1-fortuna/include/linux/sysctl.h --- linux-2.6.8.1-orig/include/linux/sysctl.h 2004-08-14 12:55:33.000000000 +0200 +++ linux-2.6.8.1-fortuna/include/linux/sysctl.h 2004-09-13 18:55:43.000000000 +0200 @@ -198,7 +198,8 @@ RANDOM_READ_THRESH=3, RANDOM_WRITE_THRESH=4, RANDOM_BOOT_ID=5, - RANDOM_UUID=6 + RANDOM_UUID=6, + RANDOM_DERIVE_SEED=7 }; /* /proc/sys/kernel/pty */ --- linux-2.6.8.1/drivers/char/random.c 2004-09-24 08:32:30.222610504 -0400 +++ linux-2.6.8.1-rand2/drivers/char/random.c 2004-09-24 09:31:30.251444320 -0400 @@ -2,9 +2,11 @@ * random.c -- A strong random number generator * * Version 1.89, last modified 19-Sep-99 + * Version 2.01, last modified 24-Sep-2004 * * Copyright Theodore Ts'o, 1994, 1995, 1996, 1997, 1998, 1999. All * rights reserved. + * Copyright Jean-Luc Cooke, 2004. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -40,61 +42,157 @@ */ /* - * (now, with legal B.S. out of the way.....) - * - * This routine gathers environmental noise from device drivers, etc., - * and returns good random numbers, suitable for cryptographic use. - * Besides the obvious cryptographic uses, these numbers are also good - * for seeding TCP sequence numbers, and other places where it is - * desirable to have numbers which are not only random, but hard to - * predict by an attacker. - * - * Theory of operation - * =================== - * - * Computers are very predictable devices. Hence it is extremely hard - * to produce truly random numbers on a computer --- as opposed to - * pseudo-random numbers, which can easily generated by using a - * algorithm. Unfortunately, it is very easy for attackers to guess - * the sequence of pseudo-random number generators, and for some - * applications this is not acceptable. So instead, we must try to - * gather "environmental noise" from the computer's environment, which - * must be hard for outside attackers to observe, and use that to - * generate random numbers. In a Unix environment, this is best done - * from inside the kernel. - * - * Sources of randomness from the environment include inter-keyboard - * timings, inter-interrupt timings from some interrupts, and other - * events which are both (a) non-deterministic and (b) hard for an - * outside observer to measure. Randomness from these sources are - * added to an "entropy pool", which is mixed using a CRC-like function. - * This is not cryptographically strong, but it is adequate assuming - * the randomness is not chosen maliciously, and it is fast enough that - * the overhead of doing it on every interrupt is very reasonable. - * As random bytes are mixed into the entropy pool, the routines keep - * an *estimate* of how many bits of randomness have been stored into - * the random number generator's internal state. - * - * When random bytes are desired, they are obtained by taking the SHA - * hash of the contents of the "entropy pool". The SHA hash avoids - * exposing the internal state of the entropy pool. It is believed to - * be computationally infeasible to derive any useful information - * about the input of SHA from its output. Even if it is possible to - * analyze SHA in some clever way, as long as the amount of data - * returned from the generator is less than the inherent entropy in - * the pool, the output data is totally unpredictable. For this - * reason, the routine decreases its internal estimate of how many - * bits of "true randomness" are contained in the entropy pool as it - * outputs random numbers. - * - * If this estimate goes to zero, the routine can still generate - * random numbers; however, an attacker may (at least in theory) be - * able to infer the future output of the generator from prior - * outputs. This requires successful cryptanalysis of SHA, which is - * not believed to be feasible, but there is a remote possibility. - * Nonetheless, these numbers should be useful for the vast majority - * of purposes. - * + * The entire PRNG used in this file was replaced using a variant of the Fortuna + * PRNG described in Practical Cryptography by Ferguson and Schnier. + * + * The changes to their design include: + * - feeding the output of each pool back into their input to carry entropy + * forward (avoids pool overflow attacks like + * "dd if=/dev/zero of=/dev/random" + * + * Also, the entropy estimator was removed since it is not needed for + * cryptographically secure random data and such constructions are + * historically prone to attack + * [read Practical Cryptography]. + * + * The Fortuna PRNG as described in Practical Cryptography is implemented here. + * + * Pseudo-code follows. + * +create_entropy_pool(r) + - create an entropy pool in "r" + + r.pool0_len = 0; + r.reseed_count = 0; + r.derive_count = 0; + r.digestsize = // digest size for our hash + r.blocksize = // block size for our cipher + r.keysize = // key size for our cipher + for (i=0; i<32; i++) { + crypto_digest_init(r.pool[i]); + } + memset(r.key, 0, r.keysize); + crypto_cipher_setkey(r.cipher, r.key, r.keysize); + +add_entropy_words(r, in, nwords) + - mix 32bit word array "in" which is "nwords" long into pool "r" + + crypto_digest_update(r.pool[i], in, nwords*sizeof(in[0])); + if (r.pool_index == 0) + r.pool0_len += nwords*sizeof(in[0]); + r.pool_index = r.pool_index + 1 mod (2number of pools - 1) + +random_reseed(r) + - reseed the key from the pooling system + + r.reseed_count++; + + crypto_digest_init(hash); + crypto_digest_update(hash, r.key, r.keysize); + + for (i=0; i<32; i++) { + if (2i is a factor of r.reseed_count) { + crypto_digest_final(r.pool[i], tmp); + crypto_digest_init(r.poo[i]); + crypto_digest_update(hash, tmp, r.digestsize); + + // jlcooke: small change from Ferguson + crypto_digest_update(r.pool[i], tmp, r.digestsize); + } + } + + crypto_digest_final(hash, tmp); + crypto_cipher_setkey(r.cipher, tmp, r.keysize); + r.ctrValue = r.ctrValue + 1 mod (2number of pools - 1) + +extract_entropy(r, buf, nbytes, flags) + - fill byte array "buf" with "nbytes" of random data from entropy pool "r" + + random_reseed(r); + r.pool0_len = 0; + + while (nbytes > 0) { + crypto_cipher_encrypt(r.cipher, tmp, r.ctrValue, r.blocksize); + r.ctrValue++; // modulo 2r.blocksize/8 + + // + // Copy r.blocksize of tmp to the user + // Unless nbytes is less than r.blocksize, in which case only copy nbytes + // + + nbytes -= r.blocksize; + } + + // generate a new key + crypto_cipher_encrypt(r.cipher, r.key, r.ctrValue, r.blocksize); + crypto_cipher_setkey(r.cipher, r.key, r.keysize); + +derive_pool(r, buf) + - Fill "buf" with the output from a 1-way transformation of all 32-pools + + memset(tmp, 0, r.digestsize); + r.pool0_len = 0; + + for (i=0; i<32; i++) { + crypto_digest_init(hash); + + crypto_digest_update(hash, tmp, r.digestsize); + + crypto_digest_final(r.pool[i], tmp); + crypto_digest_init(r.pool[i]); + crypto_digest_update(hash, tmp, r.digestsize); + + crypto_digest_update(hash, r.derive_count, sizeof(r.derive_count)); + + crypto_digest_final(hash, tmp); + + // Replace all 0x00 in "tmp" with "0x01" because the API to return a byte + // array does not exist. Only a "return string" API is provided. This + // reduces the effective entropy of the output by 0.39%. + // + + memcpy(&buf[i*r.digestsize], tmp, r.digestsize); + r.derive_count++; + } + * + * Draft Security Statement/Analysis (Jean-Luc Cooke ) + * + * The Fortuna PRNG is resilliant to all known and preventable PRNG attacks. + * Proof of strength to these attacks can be done by reduction to the security + * of the underlying cryptographic primitives. + * * H = HASH(M) + * + M={0,1}^Mlen 0 <= Mlen < infinity + * + H={0,1}^Hlen 256 <= Hlen + * * C = ENCRYPT(K,M) + * + K={0,1}^Klen 256 <= Klen + * + M={0,1}^Mlen Mlen = 128 + * + C={0,1}^Clen Clen = 128 + * + * - Invertability of the output function + * The state of the output function Output[i] = ENCRYPT(KEY, CTR++) is + * {KEY,CTR} To recover the state {KEY,CTR} the attacker must be able to + * mount a known-plaintext or a known-ciphertext attack on the block cipher + * C=ENCRYPT(K,M) with N blocks. + * N = ReseedIntervalInSeconds * OutputRateInBytesPerSecond / BytesPerBlock + * AES256 in CTR is secure from known-plaintext/ciphertext key recovery + * attacks with N < 2^128 + * However, After 2^64 blocks (2^71 bits) an attacker would have a 0.5 chance + * to guessing the next 128bit output. N <<< 2^64 + * + * - Invertability of the pool mixing function + * The pool mixing function H' = HASH(H' || M) is said to be non-inveretable + * if H=HASH(MSG) is invertable. + * There have been no invertability discoveries in SHA-256. + * + * - Manipulating pool mixing + * An attack who has access to one or all of the entropy event sources may + * be able to input mallicious event data to alter any one of the pool states + * into a degenerate state. This requires that the underlying H=HASH(MSG) + * function is suseptible to a 1st pre-image attack. SHA-256 has no such + * known attacks. + */ + +/* * Exported interfaces ---- output * =============================== * @@ -107,17 +205,13 @@ * and place it in the requested buffer. * * The two other interfaces are two character devices /dev/random and - * /dev/urandom. /dev/random is suitable for use when very high - * quality randomness is desired (for example, for key generation or - * one-time pads), as it will only return a maximum of the number of - * bits of randomness (as estimated by the random number generator) - * contained in the entropy pool. - * - * The /dev/urandom device does not have this limit, and will return - * as many bytes as are requested. As more and more random bytes are - * requested without giving time for the entropy pool to recharge, - * this will result in random numbers that are merely cryptographically - * strong. For many applications, however, this is acceptable. + * /dev/urandom. They are synonymous with eachother for legacy reasons + * + * Both the devices will return as many bytes as are requested. As more + * and more random bytes are requested without giving time for the entropy + * pool to recharge, this will result in random numbers that are merely + * cryptographically strong. For many applications, however, this is + * acceptable. * * Exported interfaces ---- input * ============================== @@ -160,32 +254,28 @@ * following lines an appropriate script which is run during the boot * sequence: * - * echo "Initializing random number generator..." - * random_seed=/var/run/random-seed - * # Carry a random seed from start-up to start-up - * # Load and then save the whole entropy pool - * if [ -f $random_seed ]; then - * cat $random_seed >/dev/urandom - * else - * touch $random_seed - * fi - * chmod 600 $random_seed - * poolfile=/proc/sys/kernel/random/poolsize - * [ -r $poolfile ] && bytes=`cat $poolfile` || bytes=512 - * dd if=/dev/urandom of=$random_seed count=1 bs=$bytes + * echo "Initializing random number generator..." + * random_seed=/var/run/random-seed + * # Carry a random seed from start-up to start-up + * # Load and then save the whole entropy pool + * if [ -f $random_seed ]; then + * cat $random_seed >/dev/urandom + * else + * touch $random_seed + * fi + * chmod 600 $random_seed + * dd if=/proc/sys/kernel/random/derive_seed of=$random_seed * * and the following lines in an appropriate script which is run as * the system is shutdown: * - * # Carry a random seed from shut-down to start-up - * # Save the whole entropy pool - * echo "Saving random seed..." - * random_seed=/var/run/random-seed - * touch $random_seed - * chmod 600 $random_seed - * poolfile=/proc/sys/kernel/random/poolsize - * [ -r $poolfile ] && bytes=`cat $poolfile` || bytes=512 - * dd if=/dev/urandom of=$random_seed count=1 bs=$bytes + * # Carry a random seed from shut-down to start-up + * # Save the whole entropy pool + * echo "Saving random seed..." + * random_seed=/var/run/random-seed + * touch $random_seed + * chmod 600 $random_seed + * dd if=/proc/sys/kernel/random/derive_seed of=$random_seed * * For example, on most modern systems using the System V init * scripts, such code fragments would be found in @@ -215,22 +305,11 @@ * Acknowledgements: * ================= * - * Ideas for constructing this random number generator were derived - * from Pretty Good Privacy's random number generator, and from private - * discussions with Phil Karn. Colin Plumb provided a faster random - * number generator, which speed up the mixing function of the entropy - * pool, taken from PGPfone. Dale Worley has also contributed many - * useful ideas and suggestions to improve this driver. + * The design for this RNG come from Fortuna as explined above. + * Cryptographic implementations are used from the CryptoAPI. * * Any flaws in the design are solely my responsibility, and should - * not be attributed to the Phil, Colin, or any of authors of PGP. - * - * The code for SHA transform was taken from Peter Gutmann's - * implementation, which has been placed in the public domain. - * The code for MD5 transform was taken from Colin Plumb's - * implementation, which has been placed in the public domain. - * The MD5 cryptographic checksum was devised by Ronald Rivest, and is - * documented in RFC 1321, "The MD5 Message Digest Algorithm". + * not be attributed to the Ted, Phil, Colin, or any of authors of PGP. * * Further background information on this topic may be obtained from * RFC 1750, "Randomness Recommendations for Security", by Donald @@ -254,137 +333,43 @@ #include #include #include +#include +#include <../crypto/internal.h> +#include #include #include #include #include -/* - * Configuration information - */ -#define DEFAULT_POOL_SIZE 512 -#define SECONDARY_POOL_SIZE 128 -#define BATCH_ENTROPY_SIZE 256 -#define USE_SHA - -/* - * The minimum number of bits of entropy before we wake up a read on - * /dev/random. Should be enough to do a significant reseed. - */ -static int random_read_wakeup_thresh = 64; - -/* - * If the entropy count falls under this number of bits, then we - * should wake up processes which are selecting or polling on write - * access to /dev/random. - */ -static int random_write_wakeup_thresh = 128; - -/* - * When the input pool goes over trickle_thresh, start dropping most - * samples to avoid wasting CPU time and reduce lock contention. - */ - -static int trickle_thresh = DEFAULT_POOL_SIZE * 7; - -static DEFINE_PER_CPU(int, trickle_count) = 0; +#if 0 + #define DEBUG_PRINTK printk +#else + #define DEBUG_PRINTK debug_printk +static inline void debug_printk(const char *a, ...) {} +#endif /* - * A pool of size .poolwords is stirred with a primitive polynomial - * of degree .poolwords over GF(2). The taps for various sizes are - * defined below. They are chosen to be evenly spaced (minimum RMS - * distance from evenly spaced; the numbers in the comments are a - * scaled squared error sum) except for the last tap, which is 1 to - * get the twisting happening as fast as possible. + * Configuration information */ -static struct poolinfo { - int poolwords; - int tap1, tap2, tap3, tap4, tap5; -} poolinfo_table[] = { - /* x^2048 + x^1638 + x^1231 + x^819 + x^411 + x + 1 -- 115 */ - { 2048, 1638, 1231, 819, 411, 1 }, - - /* x^1024 + x^817 + x^615 + x^412 + x^204 + x + 1 -- 290 */ - { 1024, 817, 615, 412, 204, 1 }, -#if 0 /* Alternate polynomial */ - /* x^1024 + x^819 + x^616 + x^410 + x^207 + x^2 + 1 -- 115 */ - { 1024, 819, 616, 410, 207, 2 }, -#endif - - /* x^512 + x^411 + x^308 + x^208 + x^104 + x + 1 -- 225 */ - { 512, 411, 308, 208, 104, 1 }, -#if 0 /* Alternates */ - /* x^512 + x^409 + x^307 + x^206 + x^102 + x^2 + 1 -- 95 */ - { 512, 409, 307, 206, 102, 2 }, - /* x^512 + x^409 + x^309 + x^205 + x^103 + x^2 + 1 -- 95 */ - { 512, 409, 309, 205, 103, 2 }, -#endif - - /* x^256 + x^205 + x^155 + x^101 + x^52 + x + 1 -- 125 */ - { 256, 205, 155, 101, 52, 1 }, - - /* x^128 + x^103 + x^76 + x^51 +x^25 + x + 1 -- 105 */ - { 128, 103, 76, 51, 25, 1 }, -#if 0 /* Alternate polynomial */ - /* x^128 + x^103 + x^78 + x^51 + x^27 + x^2 + 1 -- 70 */ - { 128, 103, 78, 51, 27, 2 }, -#endif - - /* x^64 + x^52 + x^39 + x^26 + x^14 + x + 1 -- 15 */ - { 64, 52, 39, 26, 14, 1 }, - - /* x^32 + x^26 + x^20 + x^14 + x^7 + x + 1 -- 15 */ - { 32, 26, 20, 14, 7, 1 }, - - { 0, 0, 0, 0, 0, 0 }, -}; - -#define POOLBITS poolwords*32 -#define POOLBYTES poolwords*4 +#define BATCH_ENTROPY_SIZE 512 /* how many events do we buffer? BATCH_ENTROPY_SIZE/2 == how many we need before batch-submitting them */ +#define RANDOM_RESEED_INTERVAL 600 /* reseed the PRNG output state every 5mins */ +#define RANDOM_DEFAULT_CIPHER_ALGO "aes" +#define RANDOM_DEFAULT_DIGEST_ALGO "sha256" + +#define DEFAULT_POOL_NUMBER 5 /* 2^{5} = 32 pools */ +#define MAXIMUM_POOL_NUMBER DEFAULT_POOL_NUMBER +#define MINIMUM_POOL_NUMBER 2 /* 2^{2} = 4 pools */ +#define USE_SHA256 +#define RANDOM_MAX_DIGEST_SIZE 64 /* SHA512/WHIRLPOOL have 64bytes == 512 bits */ +#define RANDOM_MAX_BLOCK_SIZE 16 /* AES256 has 16byte blocks == 128 bits */ +#define RANDOM_MAX_KEY_SIZE 32 /* AES256 has 32byte keys == 256 bits */ +#define USE_AES256 /* - * For the purposes of better mixing, we use the CRC-32 polynomial as - * well to make a twisted Generalized Feedback Shift Reigster - * - * (See M. Matsumoto & Y. Kurita, 1992. Twisted GFSR generators. ACM - * Transactions on Modeling and Computer Simulation 2(3):179-194. - * Also see M. Matsumoto & Y. Kurita, 1994. Twisted GFSR generators - * II. ACM Transactions on Mdeling and Computer Simulation 4:254-266) - * - * Thanks to Colin Plumb for suggesting this. - * - * We have not analyzed the resultant polynomial to prove it primitive; - * in fact it almost certainly isn't. Nonetheless, the irreducible factors - * of a random large-degree polynomial over GF(2) are more than large enough - * that periodicity is not a concern. - * - * The input hash is much less sensitive than the output hash. All - * that we want of it is that it be a good non-cryptographic hash; - * i.e. it not produce collisions when fed "random" data of the sort - * we expect to see. As long as the pool state differs for different - * inputs, we have preserved the input entropy and done a good job. - * The fact that an intelligent attacker can construct inputs that - * will produce controlled alterations to the pool's state is not - * important because we don't consider such inputs to contribute any - * randomness. The only property we need with respect to them is that - * the attacker can't increase his/her knowledge of the pool's state. - * Since all additions are reversible (knowing the final state and the - * input, you can reconstruct the initial state), if an attacker has - * any uncertainty about the initial state, he/she can only shuffle - * that uncertainty about, but never cause any collisions (which would - * decrease the uncertainty). - * - * The chosen system lets the state of the pool be (essentially) the input - * modulo the generator polymnomial. Now, for random primitive polynomials, - * this is a universal class of hash functions, meaning that the chance - * of a collision is limited by the attacker's knowledge of the generator - * polynomail, so if it is chosen at random, an attacker can never force - * a collision. Here, we use a fixed polynomial, but we *can* assume that - * ###--> it is unknown to the processes generating the input entropy. <-### - * Because of this important property, this is a good, collision-resistant - * hash; hash collisions will occur no more often than chance. + * Throttle mouse/keyboard/disk/interrupt entropy input to only add after this many jiffies/rdtsc counts */ +#define RANDOM_INPUT_THROTTLE 1000 /* * Linux 2.2 compatibility @@ -399,8 +384,10 @@ /* * Static global variables */ +static int random_entropy_count; // jlc & cam have been together for 5 and 2/3 years as of the time this was written; +static int random_read_wakeup_thresh = 0; // ignored now. +static int random_write_wakeup_thresh = 0; // ignored now. static struct entropy_store *random_state; /* The default global store */ -static struct entropy_store *sec_random_state; /* secondary store */ static DECLARE_WAIT_QUEUE_HEAD(random_read_wait); static DECLARE_WAIT_QUEUE_HEAD(random_write_wait); @@ -411,71 +398,6 @@ static void sysctl_init_random(struct entropy_store *random_state); #endif -/***************************************************************** - * - * Utility functions, with some ASM defined functions for speed - * purposes - * - *****************************************************************/ - -/* - * Unfortunately, while the GCC optimizer for the i386 understands how - * to optimize a static rotate left of x bits, it doesn't know how to - * deal with a variable rotate of x bits. So we use a bit of asm magic. - */ -#if (!defined (__i386__)) -static inline __u32 rotate_left(int i, __u32 word) -{ - return (word << i) | (word >> (32 - i)); - -} -#else -static inline __u32 rotate_left(int i, __u32 word) -{ - __asm__("roll %%cl,%0" - :"=r" (word) - :"0" (word),"c" (i)); - return word; -} -#endif - -/* - * More asm magic.... - * - * For entropy estimation, we need to do an integral base 2 - * logarithm. - * - * Note the "12bits" suffix - this is used for numbers between - * 0 and 4095 only. This allows a few shortcuts. - */ -#if 0 /* Slow but clear version */ -static inline __u32 int_ln_12bits(__u32 word) -{ - __u32 nbits = 0; - - while (word >>= 1) - nbits++; - return nbits; -} -#else /* Faster (more clever) version, courtesy Colin Plumb */ -static inline __u32 int_ln_12bits(__u32 word) -{ - /* Smear msbit right to make an n-bit mask */ - word |= word >> 8; - word |= word >> 4; - word |= word >> 2; - word |= word >> 1; - /* Remove one bit to make this a logarithm */ - word >>= 1; - /* Count the bits set in the word */ - word -= (word >> 1) & 0x555; - word = (word & 0x333) + ((word >> 2) & 0x333); - word += (word >> 4); - word += (word >> 8); - return word & 15; -} -#endif - #if 0 #define DEBUG_ENT(fmt, arg...) printk(KERN_DEBUG "random: " fmt, ## arg) #else @@ -490,15 +412,28 @@ **********************************************************************/ struct entropy_store { - /* mostly-read data: */ - struct poolinfo poolinfo; - __u32 *pool; + const char *digestAlgo; + unsigned int digestsize; + struct crypto_tfm *pools[1<words */ - /* The pool size must be a multiple of 16 32-bit words */ - poolwords = ((poolwords + 15) / 16) * 16; - - for (p = poolinfo_table; p->poolwords; p++) { - if (poolwords == p->poolwords) - break; - } - if (p->poolwords == 0) - return -EINVAL; + pool_number = pool_number_arg; + if (pool_number < MINIMUM_POOL_NUMBER) + pool_number = MINIMUM_POOL_NUMBER; r = kmalloc(sizeof(struct entropy_store), GFP_KERNEL); - if (!r) + if (!r) { return -ENOMEM; + } memset (r, 0, sizeof(struct entropy_store)); - r->poolinfo = *p; + r->pool_number = pool_number; + r->digestAlgo = RANDOM_DEFAULT_DIGEST_ALGO; - r->pool = kmalloc(POOLBYTES, GFP_KERNEL); - if (!r->pool) { - kfree(r); - return -ENOMEM; +DEBUG_PRINTK("create_entropy_store() pools=%u index=%u\n", 1<pool_index); + for (i=0; i<(1<pool_index); + r->pools[i] = crypto_alloc_tfm(r->digestAlgo, 0); + if (r->pools[i] == NULL) { + for (j=0; jpools[j] != NULL) { + kfree(r->pools[j]); + } + } + kfree(r); + return -ENOMEM; + } + crypto_digest_init( r->pools[i] ); } - memset(r->pool, 0, POOLBYTES); r->lock = SPIN_LOCK_UNLOCKED; *ret_bucket = r; - return 0; -} -/* Clear the entropy pool and associated counters. */ -static void clear_entropy_store(struct entropy_store *r) -{ - r->add_ptr = 0; - r->entropy_count = 0; - r->input_rotate = 0; - memset(r->pool, 0, r->poolinfo.POOLBYTES); -} -#ifdef CONFIG_SYSCTL -static void free_entropy_store(struct entropy_store *r) -{ - if (r->pool) - kfree(r->pool); - kfree(r); -} -#endif -/* - * This function adds a byte into the entropy "pool". It does not - * update the entropy estimate. The caller should call - * credit_entropy_store if this is appropriate. - * - * The pool is stirred with a primitive polynomial of the appropriate - * degree, and then twisted. We twist by three bits at a time because - * it's cheap to do so and helps slightly in the expected case where - * the entropy is concentrated in the low-order bits. - */ -static void add_entropy_words(struct entropy_store *r, const __u32 *in, - int nwords) -{ - static __u32 const twist_table[8] = { - 0, 0x3b6e20c8, 0x76dc4190, 0x4db26158, - 0xedb88320, 0xd6d6a3e8, 0x9b64c2b0, 0xa00ae278 }; - unsigned long i, add_ptr, tap1, tap2, tap3, tap4, tap5; - int new_rotate, input_rotate; - int wordmask = r->poolinfo.poolwords - 1; - __u32 w, next_w; - unsigned long flags; + r->cipherAlgo = RANDOM_DEFAULT_CIPHER_ALGO; + if ((r->cipher=crypto_alloc_tfm(r->cipherAlgo, 0)) == NULL) { + return -ENOMEM; + } - /* Taps are constant, so we can load them without holding r->lock. */ - tap1 = r->poolinfo.tap1; - tap2 = r->poolinfo.tap2; - tap3 = r->poolinfo.tap3; - tap4 = r->poolinfo.tap4; - tap5 = r->poolinfo.tap5; - next_w = *in++; + /* If the HASH's output is greater then the cipher's keysize, truncate + * to the cipher's keysize */ + keysize = crypto_tfm_alg_max_keysize(r->cipher); + r->digestsize = crypto_tfm_alg_digestsize(r->pools[0]); + r->blocksize = crypto_tfm_alg_blocksize(r->cipher); - spin_lock_irqsave(&r->lock, flags); - prefetch_range(r->pool, wordmask); - input_rotate = r->input_rotate; - add_ptr = r->add_ptr; - - while (nwords--) { - w = rotate_left(input_rotate, next_w); - if (nwords > 0) - next_w = *in++; - i = add_ptr = (add_ptr - 1) & wordmask; - /* - * Normally, we add 7 bits of rotation to the pool. - * At the beginning of the pool, add an extra 7 bits - * rotation, so that successive passes spread the - * input bits across the pool evenly. - */ - new_rotate = input_rotate + 14; - if (i) - new_rotate = input_rotate + 7; - input_rotate = new_rotate & 31; - - /* XOR in the various taps */ - w ^= r->pool[(i + tap1) & wordmask]; - w ^= r->pool[(i + tap2) & wordmask]; - w ^= r->pool[(i + tap3) & wordmask]; - w ^= r->pool[(i + tap4) & wordmask]; - w ^= r->pool[(i + tap5) & wordmask]; - w ^= r->pool[i]; - r->pool[i] = (w >> 3) ^ twist_table[w & 7]; + r->keysize = (keysize < r->digestsize) ? keysize : r->digestsize; + + if (crypto_cipher_setkey(r->cipher, r->key, r->keysize)) { + return -EINVAL; } - r->input_rotate = input_rotate; - r->add_ptr = add_ptr; + /* digest used duing random-reseed() */ + if ((r->reseedHash=crypto_alloc_tfm(r->digestAlgo, 0)) == NULL) { + return -ENOMEM; + } + /* cipher used for network randomness, init to key={zerovector} + * for now */ + if ((r->networkCipher=crypto_alloc_tfm(r->cipherAlgo, 0)) == NULL) { + return -ENOMEM; + } - spin_unlock_irqrestore(&r->lock, flags); + return 0; } /* - * Credit (or debit) the entropy store with n bits of entropy + * This function adds a byte into the entropy "pool". */ -static void credit_entropy_store(struct entropy_store *r, int nbits) +static void add_entropy_words(struct entropy_store *r, const __u32 *in, + int nwords) { unsigned long flags; + struct scatterlist sg[1]; + static unsigned int totalBytes=0; + + if (r == NULL) { + return; + } spin_lock_irqsave(&r->lock, flags); - if (r->entropy_count + nbits < 0) { - DEBUG_ENT("negative entropy/overflow (%d+%d)\n", - r->entropy_count, nbits); - r->entropy_count = 0; - } else if (r->entropy_count + nbits > r->poolinfo.POOLBITS) { - r->entropy_count = r->poolinfo.POOLBITS; - } else { - r->entropy_count += nbits; - if (nbits) - DEBUG_ENT("%04d %04d : added %d bits to %s\n", - random_state->entropy_count, - sec_random_state->entropy_count, - nbits, - r == sec_random_state ? "secondary" : - r == random_state ? "primary" : "unknown"); + totalBytes += nwords * sizeof(__u32); + r->pools_bytes[r->pool_index] += nwords * sizeof(__u32); + + sg[0].page = virt_to_page(in); + sg[0].offset = offset_in_page(in); + sg[0].length = nwords*sizeof(__u32); + crypto_digest_update(r->pools[r->pool_index], sg, 1); + + if (r->pool_index == 0) { + r->pool0_len += nwords*sizeof(__u32); } + /* idx = (idx + 1) mod ( (2^N)-1 ) */ + r->pool_index = (r->pool_index + 1) & ((1<pool_number)-1); + spin_unlock_irqrestore(&r->lock, flags); +DEBUG_PRINTK("0 add_entropy_words() nwords=%u pool[i].bytes=%u total=%u\n", + nwords, r->pools_bytes[r->pool_index], totalBytes); } /********************************************************************** @@ -668,10 +559,10 @@ }; static struct sample *batch_entropy_pool, *batch_entropy_copy; -static int batch_head, batch_tail; +static int batch_head, batch_tail; static spinlock_t batch_lock = SPIN_LOCK_UNLOCKED; -static int batch_max; +static int batch_max; static void batch_entropy_process(void *private_); static DECLARE_WORK(batch_work, batch_entropy_process, NULL); @@ -703,19 +594,20 @@ int new; unsigned long flags; - if (!batch_max) + if (!batch_max) { return; + } spin_lock_irqsave(&batch_lock, flags); batch_entropy_pool[batch_head].data[0] = a; batch_entropy_pool[batch_head].data[1] = b; - batch_entropy_pool[batch_head].credit = num; + batch_entropy_pool[batch_head].credit = 0; if (((batch_head - batch_tail) & (batch_max-1)) >= (batch_max / 2)) { /* - * Schedule it for the next timer tick: - */ + * Schedule it for the next timer tick: + */ schedule_delayed_work(&batch_work, 1); } @@ -733,13 +625,11 @@ /* * Flush out the accumulated entropy operations, adding entropy to the passed - * store (normally random_state). If that store has enough entropy, alternate - * between randomizing the data of the primary and secondary stores. + * store (normally random_state). */ static void batch_entropy_process(void *private_) { - struct entropy_store *r = (struct entropy_store *) private_, *p; - int max_entropy = r->poolinfo.POOLBITS; + struct entropy_store *r = (struct entropy_store *) private_; unsigned head, tail; /* Mixing into the pool is expensive, so copy over the batch @@ -750,7 +640,7 @@ spin_lock_irq(&batch_lock); memcpy(batch_entropy_copy, batch_entropy_pool, - batch_max*sizeof(struct sample)); + batch_max*sizeof(struct sample)); head = batch_head; tail = batch_tail; @@ -758,61 +648,30 @@ spin_unlock_irq(&batch_lock); - p = r; while (head != tail) { - if (r->entropy_count >= max_entropy) { - r = (r == sec_random_state) ? random_state : - sec_random_state; - max_entropy = r->poolinfo.POOLBITS; - } add_entropy_words(r, batch_entropy_copy[tail].data, 2); - credit_entropy_store(r, batch_entropy_copy[tail].credit); tail = (tail+1) & (batch_max-1); } - if (p->entropy_count >= random_read_wakeup_thresh) - wake_up_interruptible(&random_read_wait); } + /********************************************************************* * * Entropy input management * *********************************************************************/ -/* There is one of these per entropy source */ -struct timer_rand_state { - __u32 last_time; - __s32 last_delta,last_delta2; - int dont_count_entropy:1; -}; - -static struct timer_rand_state keyboard_timer_state; -static struct timer_rand_state mouse_timer_state; -static struct timer_rand_state extract_timer_state; -static struct timer_rand_state *irq_timer_state[NR_IRQS]; - /* * This function adds entropy to the entropy "pool" by using timing - * delays. It uses the timer_rand_state structure to make an estimate - * of how many bits of entropy this call has added to the pool. + * delays. * * The number "num" is also added to the pool - it should somehow describe - * the type of event which just happened. This is currently 0-255 for - * keyboard scan codes, and 256 upwards for interrupts. - * On the i386, this is assumed to be at most 16 bits, and the high bits - * are used for a high-resolution timer. - * + * the type of event which just happened. */ -static void add_timer_randomness(struct timer_rand_state *state, unsigned num) +static void add_timer_randomness(unsigned num) { - __u32 time; - __s32 delta, delta2, delta3; - int entropy = 0; - - /* if over the trickle threshold, use only 1 in 4096 samples */ - if ( random_state->entropy_count > trickle_thresh && - (__get_cpu_var(trickle_count)++ & 0xfff)) - return; + static __u32 lasttime=0; + __u32 time; #if defined (__i386__) || defined (__x86_64__) if (cpu_has_tsc) { @@ -822,480 +681,57 @@ } else { time = jiffies; } -#elif defined (__sparc_v9__) - unsigned long tick = tick_ops->get_tick(); - - time = (unsigned int) tick; - num ^= (tick >> 32UL); #else time = jiffies; #endif - /* - * Calculate number of bits of randomness we probably added. - * We take into account the first, second and third-order deltas - * in order to make our estimate. - */ - if (!state->dont_count_entropy) { - delta = time - state->last_time; - state->last_time = time; - - delta2 = delta - state->last_delta; - state->last_delta = delta; - - delta3 = delta2 - state->last_delta2; - state->last_delta2 = delta2; - - if (delta < 0) - delta = -delta; - if (delta2 < 0) - delta2 = -delta2; - if (delta3 < 0) - delta3 = -delta3; - if (delta > delta2) - delta = delta2; - if (delta > delta3) - delta = delta3; - - /* - * delta is now minimum absolute delta. - * Round down by 1 bit on general principles, - * and limit entropy entimate to 12 bits. - */ - delta >>= 1; - delta &= (1 << 12) - 1; - - entropy = int_ln_12bits(delta); + /* Throttle our input to add_entropy_words() */ + if ((time-lasttime) < RANDOM_INPUT_THROTTLE) { + return; } - batch_entropy_store(num, time, entropy); + lasttime = time; + + batch_entropy_store(num, time, 0); } void add_keyboard_randomness(unsigned char scancode) { - static unsigned char last_scancode; - /* ignore autorepeat (multiple key down w/o key up) */ - if (scancode != last_scancode) { - last_scancode = scancode; - add_timer_randomness(&keyboard_timer_state, scancode); - } + /* jlcooke: we don't care about auto-repeats, + * they can't hurt us anymore */ + add_timer_randomness(scancode); } EXPORT_SYMBOL(add_keyboard_randomness); void add_mouse_randomness(__u32 mouse_data) { - add_timer_randomness(&mouse_timer_state, mouse_data); + add_timer_randomness(mouse_data); } EXPORT_SYMBOL(add_mouse_randomness); void add_interrupt_randomness(int irq) { - if (irq >= NR_IRQS || irq_timer_state[irq] == 0) + if (irq >= NR_IRQS) return; - add_timer_randomness(irq_timer_state[irq], 0x100+irq); + /* jlcooke: no need to add 0x100 ... not random! :P */ + add_timer_randomness(irq); } EXPORT_SYMBOL(add_interrupt_randomness); void add_disk_randomness(struct gendisk *disk) { - if (!disk || !disk->random) + if (!disk) return; - /* first major is 1, so we get >= 0x200 here */ - add_timer_randomness(disk->random, 0x100+MKDEV(disk->major, disk->first_minor)); + + /* jlcooke: no need to add 0x100 ... not random! :P */ + add_timer_randomness(MKDEV(disk->major, disk->first_minor)); } EXPORT_SYMBOL(add_disk_randomness); -/****************************************************************** - * - * Hash function definition - * - *******************************************************************/ - -/* - * This chunk of code defines a function - * void HASH_TRANSFORM(__u32 digest[HASH_BUFFER_SIZE + HASH_EXTRA_SIZE], - * __u32 const data[16]) - * - * The function hashes the input data to produce a digest in the first - * HASH_BUFFER_SIZE words of the digest[] array, and uses HASH_EXTRA_SIZE - * more words for internal purposes. (This buffer is exported so the - * caller can wipe it once rather than this code doing it each call, - * and tacking it onto the end of the digest[] array is the quick and - * dirty way of doing it.) - * - * It so happens that MD5 and SHA share most of the initial vector - * used to initialize the digest[] array before the first call: - * 1) 0x67452301 - * 2) 0xefcdab89 - * 3) 0x98badcfe - * 4) 0x10325476 - * 5) 0xc3d2e1f0 (SHA only) - * - * For /dev/random purposes, the length of the data being hashed is - * fixed in length, so appending a bit count in the usual way is not - * cryptographically necessary. - */ - -#ifdef USE_SHA - -#define HASH_BUFFER_SIZE 5 -#define HASH_EXTRA_SIZE 80 -#define HASH_TRANSFORM SHATransform - -/* Various size/speed tradeoffs are available. Choose 0..3. */ -#define SHA_CODE_SIZE 0 - -/* - * SHA transform algorithm, taken from code written by Peter Gutmann, - * and placed in the public domain. - */ - -/* The SHA f()-functions. */ - -#define f1(x,y,z) ( z ^ (x & (y^z)) ) /* Rounds 0-19: x ? y : z */ -#define f2(x,y,z) (x ^ y ^ z) /* Rounds 20-39: XOR */ -#define f3(x,y,z) ( (x & y) + (z & (x ^ y)) ) /* Rounds 40-59: majority */ -#define f4(x,y,z) (x ^ y ^ z) /* Rounds 60-79: XOR */ - -/* The SHA Mysterious Constants */ - -#define K1 0x5A827999L /* Rounds 0-19: sqrt(2) * 2^30 */ -#define K2 0x6ED9EBA1L /* Rounds 20-39: sqrt(3) * 2^30 */ -#define K3 0x8F1BBCDCL /* Rounds 40-59: sqrt(5) * 2^30 */ -#define K4 0xCA62C1D6L /* Rounds 60-79: sqrt(10) * 2^30 */ - -#define ROTL(n,X) ( ( ( X ) << n ) | ( ( X ) >> ( 32 - n ) ) ) - -#define subRound(a, b, c, d, e, f, k, data) \ - ( e += ROTL( 5, a ) + f( b, c, d ) + k + data, b = ROTL( 30, b ) ) - - -static void SHATransform(__u32 digest[85], __u32 const data[16]) -{ - __u32 A, B, C, D, E; /* Local vars */ - __u32 TEMP; - int i; -#define W (digest + HASH_BUFFER_SIZE) /* Expanded data array */ - - /* - * Do the preliminary expansion of 16 to 80 words. Doing it - * out-of-line line this is faster than doing it in-line on - * register-starved machines like the x86, and not really any - * slower on real processors. - */ - memcpy(W, data, 16*sizeof(__u32)); - for (i = 0; i < 64; i++) { - TEMP = W[i] ^ W[i+2] ^ W[i+8] ^ W[i+13]; - W[i+16] = ROTL(1, TEMP); - } - - /* Set up first buffer and local data buffer */ - A = digest[ 0 ]; - B = digest[ 1 ]; - C = digest[ 2 ]; - D = digest[ 3 ]; - E = digest[ 4 ]; - - /* Heavy mangling, in 4 sub-rounds of 20 iterations each. */ -#if SHA_CODE_SIZE == 0 - /* - * Approximately 50% of the speed of the largest version, but - * takes up 1/16 the space. Saves about 6k on an i386 kernel. - */ - for (i = 0; i < 80; i++) { - if (i < 40) { - if (i < 20) - TEMP = f1(B, C, D) + K1; - else - TEMP = f2(B, C, D) + K2; - } else { - if (i < 60) - TEMP = f3(B, C, D) + K3; - else - TEMP = f4(B, C, D) + K4; - } - TEMP += ROTL(5, A) + E + W[i]; - E = D; D = C; C = ROTL(30, B); B = A; A = TEMP; - } -#elif SHA_CODE_SIZE == 1 - for (i = 0; i < 20; i++) { - TEMP = f1(B, C, D) + K1 + ROTL(5, A) + E + W[i]; - E = D; D = C; C = ROTL(30, B); B = A; A = TEMP; - } - for (; i < 40; i++) { - TEMP = f2(B, C, D) + K2 + ROTL(5, A) + E + W[i]; - E = D; D = C; C = ROTL(30, B); B = A; A = TEMP; - } - for (; i < 60; i++) { - TEMP = f3(B, C, D) + K3 + ROTL(5, A) + E + W[i]; - E = D; D = C; C = ROTL(30, B); B = A; A = TEMP; - } - for (; i < 80; i++) { - TEMP = f4(B, C, D) + K4 + ROTL(5, A) + E + W[i]; - E = D; D = C; C = ROTL(30, B); B = A; A = TEMP; - } -#elif SHA_CODE_SIZE == 2 - for (i = 0; i < 20; i += 5) { - subRound( A, B, C, D, E, f1, K1, W[ i ] ); - subRound( E, A, B, C, D, f1, K1, W[ i+1 ] ); - subRound( D, E, A, B, C, f1, K1, W[ i+2 ] ); - subRound( C, D, E, A, B, f1, K1, W[ i+3 ] ); - subRound( B, C, D, E, A, f1, K1, W[ i+4 ] ); - } - for (; i < 40; i += 5) { - subRound( A, B, C, D, E, f2, K2, W[ i ] ); - subRound( E, A, B, C, D, f2, K2, W[ i+1 ] ); - subRound( D, E, A, B, C, f2, K2, W[ i+2 ] ); - subRound( C, D, E, A, B, f2, K2, W[ i+3 ] ); - subRound( B, C, D, E, A, f2, K2, W[ i+4 ] ); - } - for (; i < 60; i += 5) { - subRound( A, B, C, D, E, f3, K3, W[ i ] ); - subRound( E, A, B, C, D, f3, K3, W[ i+1 ] ); - subRound( D, E, A, B, C, f3, K3, W[ i+2 ] ); - subRound( C, D, E, A, B, f3, K3, W[ i+3 ] ); - subRound( B, C, D, E, A, f3, K3, W[ i+4 ] ); - } - for (; i < 80; i += 5) { - subRound( A, B, C, D, E, f4, K4, W[ i ] ); - subRound( E, A, B, C, D, f4, K4, W[ i+1 ] ); - subRound( D, E, A, B, C, f4, K4, W[ i+2 ] ); - subRound( C, D, E, A, B, f4, K4, W[ i+3 ] ); - subRound( B, C, D, E, A, f4, K4, W[ i+4 ] ); - } -#elif SHA_CODE_SIZE == 3 /* Really large version */ - subRound( A, B, C, D, E, f1, K1, W[ 0 ] ); - subRound( E, A, B, C, D, f1, K1, W[ 1 ] ); - subRound( D, E, A, B, C, f1, K1, W[ 2 ] ); - subRound( C, D, E, A, B, f1, K1, W[ 3 ] ); - subRound( B, C, D, E, A, f1, K1, W[ 4 ] ); - subRound( A, B, C, D, E, f1, K1, W[ 5 ] ); - subRound( E, A, B, C, D, f1, K1, W[ 6 ] ); - subRound( D, E, A, B, C, f1, K1, W[ 7 ] ); - subRound( C, D, E, A, B, f1, K1, W[ 8 ] ); - subRound( B, C, D, E, A, f1, K1, W[ 9 ] ); - subRound( A, B, C, D, E, f1, K1, W[ 10 ] ); - subRound( E, A, B, C, D, f1, K1, W[ 11 ] ); - subRound( D, E, A, B, C, f1, K1, W[ 12 ] ); - subRound( C, D, E, A, B, f1, K1, W[ 13 ] ); - subRound( B, C, D, E, A, f1, K1, W[ 14 ] ); - subRound( A, B, C, D, E, f1, K1, W[ 15 ] ); - subRound( E, A, B, C, D, f1, K1, W[ 16 ] ); - subRound( D, E, A, B, C, f1, K1, W[ 17 ] ); - subRound( C, D, E, A, B, f1, K1, W[ 18 ] ); - subRound( B, C, D, E, A, f1, K1, W[ 19 ] ); - - subRound( A, B, C, D, E, f2, K2, W[ 20 ] ); - subRound( E, A, B, C, D, f2, K2, W[ 21 ] ); - subRound( D, E, A, B, C, f2, K2, W[ 22 ] ); - subRound( C, D, E, A, B, f2, K2, W[ 23 ] ); - subRound( B, C, D, E, A, f2, K2, W[ 24 ] ); - subRound( A, B, C, D, E, f2, K2, W[ 25 ] ); - subRound( E, A, B, C, D, f2, K2, W[ 26 ] ); - subRound( D, E, A, B, C, f2, K2, W[ 27 ] ); - subRound( C, D, E, A, B, f2, K2, W[ 28 ] ); - subRound( B, C, D, E, A, f2, K2, W[ 29 ] ); - subRound( A, B, C, D, E, f2, K2, W[ 30 ] ); - subRound( E, A, B, C, D, f2, K2, W[ 31 ] ); - subRound( D, E, A, B, C, f2, K2, W[ 32 ] ); - subRound( C, D, E, A, B, f2, K2, W[ 33 ] ); - subRound( B, C, D, E, A, f2, K2, W[ 34 ] ); - subRound( A, B, C, D, E, f2, K2, W[ 35 ] ); - subRound( E, A, B, C, D, f2, K2, W[ 36 ] ); - subRound( D, E, A, B, C, f2, K2, W[ 37 ] ); - subRound( C, D, E, A, B, f2, K2, W[ 38 ] ); - subRound( B, C, D, E, A, f2, K2, W[ 39 ] ); - - subRound( A, B, C, D, E, f3, K3, W[ 40 ] ); - subRound( E, A, B, C, D, f3, K3, W[ 41 ] ); - subRound( D, E, A, B, C, f3, K3, W[ 42 ] ); - subRound( C, D, E, A, B, f3, K3, W[ 43 ] ); - subRound( B, C, D, E, A, f3, K3, W[ 44 ] ); - subRound( A, B, C, D, E, f3, K3, W[ 45 ] ); - subRound( E, A, B, C, D, f3, K3, W[ 46 ] ); - subRound( D, E, A, B, C, f3, K3, W[ 47 ] ); - subRound( C, D, E, A, B, f3, K3, W[ 48 ] ); - subRound( B, C, D, E, A, f3, K3, W[ 49 ] ); - subRound( A, B, C, D, E, f3, K3, W[ 50 ] ); - subRound( E, A, B, C, D, f3, K3, W[ 51 ] ); - subRound( D, E, A, B, C, f3, K3, W[ 52 ] ); - subRound( C, D, E, A, B, f3, K3, W[ 53 ] ); - subRound( B, C, D, E, A, f3, K3, W[ 54 ] ); - subRound( A, B, C, D, E, f3, K3, W[ 55 ] ); - subRound( E, A, B, C, D, f3, K3, W[ 56 ] ); - subRound( D, E, A, B, C, f3, K3, W[ 57 ] ); - subRound( C, D, E, A, B, f3, K3, W[ 58 ] ); - subRound( B, C, D, E, A, f3, K3, W[ 59 ] ); - - subRound( A, B, C, D, E, f4, K4, W[ 60 ] ); - subRound( E, A, B, C, D, f4, K4, W[ 61 ] ); - subRound( D, E, A, B, C, f4, K4, W[ 62 ] ); - subRound( C, D, E, A, B, f4, K4, W[ 63 ] ); - subRound( B, C, D, E, A, f4, K4, W[ 64 ] ); - subRound( A, B, C, D, E, f4, K4, W[ 65 ] ); - subRound( E, A, B, C, D, f4, K4, W[ 66 ] ); - subRound( D, E, A, B, C, f4, K4, W[ 67 ] ); - subRound( C, D, E, A, B, f4, K4, W[ 68 ] ); - subRound( B, C, D, E, A, f4, K4, W[ 69 ] ); - subRound( A, B, C, D, E, f4, K4, W[ 70 ] ); - subRound( E, A, B, C, D, f4, K4, W[ 71 ] ); - subRound( D, E, A, B, C, f4, K4, W[ 72 ] ); - subRound( C, D, E, A, B, f4, K4, W[ 73 ] ); - subRound( B, C, D, E, A, f4, K4, W[ 74 ] ); - subRound( A, B, C, D, E, f4, K4, W[ 75 ] ); - subRound( E, A, B, C, D, f4, K4, W[ 76 ] ); - subRound( D, E, A, B, C, f4, K4, W[ 77 ] ); - subRound( C, D, E, A, B, f4, K4, W[ 78 ] ); - subRound( B, C, D, E, A, f4, K4, W[ 79 ] ); -#else -#error Illegal SHA_CODE_SIZE -#endif - - /* Build message digest */ - digest[ 0 ] += A; - digest[ 1 ] += B; - digest[ 2 ] += C; - digest[ 3 ] += D; - digest[ 4 ] += E; - - /* W is wiped by the caller */ -#undef W -} - -#undef ROTL -#undef f1 -#undef f2 -#undef f3 -#undef f4 -#undef K1 -#undef K2 -#undef K3 -#undef K4 -#undef subRound - -#else /* !USE_SHA - Use MD5 */ - -#define HASH_BUFFER_SIZE 4 -#define HASH_EXTRA_SIZE 0 -#define HASH_TRANSFORM MD5Transform - -/* - * MD5 transform algorithm, taken from code written by Colin Plumb, - * and put into the public domain - */ - -/* The four core functions - F1 is optimized somewhat */ - -/* #define F1(x, y, z) (x & y | ~x & z) */ -#define F1(x, y, z) (z ^ (x & (y ^ z))) -#define F2(x, y, z) F1(z, x, y) -#define F3(x, y, z) (x ^ y ^ z) -#define F4(x, y, z) (y ^ (x | ~z)) - -/* This is the central step in the MD5 algorithm. */ -#define MD5STEP(f, w, x, y, z, data, s) \ - ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) - -/* - * The core of the MD5 algorithm, this alters an existing MD5 hash to - * reflect the addition of 16 longwords of new data. MD5Update blocks - * the data and converts bytes into longwords for this routine. - */ -static void MD5Transform(__u32 buf[HASH_BUFFER_SIZE], __u32 const in[16]) -{ - __u32 a, b, c, d; - - a = buf[0]; - b = buf[1]; - c = buf[2]; - d = buf[3]; - - MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478, 7); - MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12); - MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17); - MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22); - MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf, 7); - MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12); - MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17); - MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22); - MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8, 7); - MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12); - MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17); - MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22); - MD5STEP(F1, a, b, c, d, in[12]+0x6b901122, 7); - MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12); - MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17); - MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22); - - MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562, 5); - MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340, 9); - MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14); - MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20); - MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d, 5); - MD5STEP(F2, d, a, b, c, in[10]+0x02441453, 9); - MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14); - MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20); - MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6, 5); - MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6, 9); - MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14); - MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20); - MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905, 5); - MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8, 9); - MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14); - MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20); - - MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942, 4); - MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11); - MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16); - MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23); - MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44, 4); - MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11); - MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16); - MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23); - MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6, 4); - MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11); - MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16); - MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23); - MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039, 4); - MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11); - MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16); - MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23); - - MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244, 6); - MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10); - MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15); - MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21); - MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3, 6); - MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10); - MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15); - MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21); - MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f, 6); - MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10); - MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15); - MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21); - MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82, 6); - MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10); - MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15); - MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21); - - buf[0] += a; - buf[1] += b; - buf[2] += c; - buf[3] += d; -} - -#undef F1 -#undef F2 -#undef F3 -#undef F4 -#undef MD5STEP - -#endif /* !USE_SHA */ - /********************************************************************* * * Entropy extraction routines @@ -1305,169 +741,145 @@ #define EXTRACT_ENTROPY_USER 1 #define EXTRACT_ENTROPY_SECONDARY 2 #define EXTRACT_ENTROPY_LIMIT 4 -#define TMP_BUF_SIZE (HASH_BUFFER_SIZE + HASH_EXTRA_SIZE) -#define SEC_XFER_SIZE (TMP_BUF_SIZE*4) +#define CRYPTO_MAX_BLOCK_SIZE 32 static ssize_t extract_entropy(struct entropy_store *r, void * buf, size_t nbytes, int flags); +static inline void increment_iv(unsigned char *IV, const unsigned int IVsize) { + unsigned int i; + for (i=0; ientropy_count < nbytes * 8 && - r->entropy_count < r->poolinfo.POOLBITS) { - int bytes = max_t(int, random_read_wakeup_thresh / 8, - min_t(int, nbytes, TMP_BUF_SIZE)); - - DEBUG_ENT("%04d %04d : going to reseed %s with %d bits " - "(%d of %d requested)\n", - random_state->entropy_count, - sec_random_state->entropy_count, - r == sec_random_state ? "secondary" : "unknown", - bytes * 8, nbytes * 8, r->entropy_count); - - bytes=extract_entropy(random_state, tmp, bytes, - EXTRACT_ENTROPY_LIMIT); - add_entropy_words(r, tmp, bytes); - credit_entropy_store(r, bytes*8); + * Fortuna's Reseed is ... + */ +static void random_reseed(struct entropy_store *r) { + struct scatterlist sg[1]; + int i; + unsigned char tmp[RANDOM_MAX_DIGEST_SIZE]; + + r->reseed_count++; + + crypto_digest_init(r->reseedHash); + + sg[0].page = virt_to_page(r->key); + sg[0].offset = offset_in_page(r->key); + sg[0].length = r->keysize; + crypto_digest_update(r->reseedHash, sg, 1); + +#define TESTBIT(VAL, N)\ + ( ((VAL) >> (N)) & 1 ) + for (i=0; i<(1<pool_number); i++) { + /* using pool[i] if r->reseed_count is divisible by 2^i + * since 2^0 == 1, we always use pool[0] + */ + if ( (i==0) || TESTBIT(r->reseed_count,i)==0 ) { + crypto_digest_final(r->pools[i], tmp); + + sg[0].page = virt_to_page(tmp); + sg[0].offset = offset_in_page(tmp); + sg[0].length = r->keysize; + crypto_digest_update(r->reseedHash, sg, 1); + + crypto_digest_init(r->pools[i]); + /* should each pool carry it's past state forward? */ + crypto_digest_update(r->pools[i], sg, 1); + } else { + /* pool N can only be used once every 2^N times */ + break; + } } +#undef TESTBIT + + crypto_digest_final(r->reseedHash, r->key); + crypto_cipher_setkey(r->cipher, r->key, r->keysize); + increment_iv(r->iv, r->blocksize); } /* * This function extracts randomness from the "entropy pool", and - * returns it in a buffer. This function computes how many remaining - * bits of entropy are left in the pool, but it does not restrict the - * number of bytes that are actually obtained. If the EXTRACT_ENTROPY_USER + * returns it in a buffer. If the EXTRACT_ENTROPY_USER * flag is given, then the buf pointer is assumed to be in user space. - * - * If the EXTRACT_ENTROPY_SECONDARY flag is given, then we are actually - * extracting entropy from the secondary pool, and can refill from the - * primary pool if needed. - * - * Note: extract_entropy() assumes that .poolwords is a multiple of 16 words. */ static ssize_t extract_entropy(struct entropy_store *r, void * buf, size_t nbytes, int flags) { ssize_t ret, i; - __u32 tmp[TMP_BUF_SIZE]; - __u32 x; + __u32 tmp[CRYPTO_MAX_BLOCK_SIZE]; unsigned long cpuflags; + struct scatterlist sgiv[1], + sgtmp[1]; - - /* Redundant, but just in case... */ - if (r->entropy_count > r->poolinfo.POOLBITS) - r->entropy_count = r->poolinfo.POOLBITS; - - if (flags & EXTRACT_ENTROPY_SECONDARY) - xfer_secondary_pool(r, nbytes, tmp); - - /* Hold lock while accounting */ + /* lock while we're reseeding */ spin_lock_irqsave(&r->lock, cpuflags); - DEBUG_ENT("%04d %04d : trying to extract %d bits from %s\n", - random_state->entropy_count, - sec_random_state->entropy_count, - nbytes * 8, - r == sec_random_state ? "secondary" : - r == random_state ? "primary" : "unknown"); - - if (flags & EXTRACT_ENTROPY_LIMIT && nbytes >= r->entropy_count / 8) - nbytes = r->entropy_count / 8; - - if (r->entropy_count / 8 >= nbytes) - r->entropy_count -= nbytes*8; - else - r->entropy_count = 0; + random_reseed(r); + r->pool0_len = 0; - if (r->entropy_count < random_write_wakeup_thresh) - wake_up_interruptible(&random_write_wait); + spin_unlock_irqrestore(&r->lock, cpuflags); - DEBUG_ENT("%04d %04d : debiting %d bits from %s%s\n", - random_state->entropy_count, - sec_random_state->entropy_count, - nbytes * 8, - r == sec_random_state ? "secondary" : - r == random_state ? "primary" : "unknown", - flags & EXTRACT_ENTROPY_LIMIT ? "" : " (unlimited)"); + /* + * don't output any data until we reseed at least once + * But this causes problems at boot-time. So weĺl assume since they + * don't wait to the PRNG to setup, they don't really new strong random + * data + */ + /* + if (r->reseed_count == 0) + return 0; + */ - spin_unlock_irqrestore(&r->lock, cpuflags); + sgiv[0].page = virt_to_page(r->iv); + sgiv[0].offset = offset_in_page(r->iv); + sgiv[0].length = r->blocksize; + sgtmp[0].page = virt_to_page(tmp); + sgtmp[0].offset = offset_in_page(tmp); + sgtmp[0].length = r->blocksize; ret = 0; while (nbytes) { - /* - * Check if we need to break out or reschedule.... - */ - if ((flags & EXTRACT_ENTROPY_USER) && need_resched()) { - if (signal_pending(current)) { - if (ret == 0) - ret = -ERESTARTSYS; - break; - } + crypto_cipher_encrypt(r->cipher, sgtmp, sgiv, r->blocksize); + increment_iv(r->iv, r->blocksize); - DEBUG_ENT("%04d %04d : extract feeling sleepy (%d bytes left)\n", - random_state->entropy_count, - sec_random_state->entropy_count, nbytes); - - schedule(); - - DEBUG_ENT("%04d %04d : extract woke up\n", - random_state->entropy_count, - sec_random_state->entropy_count); - } - - /* Hash the pool to get the output */ - tmp[0] = 0x67452301; - tmp[1] = 0xefcdab89; - tmp[2] = 0x98badcfe; - tmp[3] = 0x10325476; -#ifdef USE_SHA - tmp[4] = 0xc3d2e1f0; -#endif - /* - * As we hash the pool, we mix intermediate values of - * the hash back into the pool. This eliminates - * backtracking attacks (where the attacker knows - * the state of the pool plus the current outputs, and - * attempts to find previous ouputs), unless the hash - * function can be inverted. - */ - for (i = 0, x = 0; i < r->poolinfo.poolwords; i += 16, x+=2) { - HASH_TRANSFORM(tmp, r->pool+i); - add_entropy_words(r, &tmp[x%HASH_BUFFER_SIZE], 1); - } - - /* - * In case the hash function has some recognizable - * output pattern, we fold it in half. - */ - for (i = 0; i < HASH_BUFFER_SIZE/2; i++) - tmp[i] ^= tmp[i + (HASH_BUFFER_SIZE+1)/2]; -#if HASH_BUFFER_SIZE & 1 /* There's a middle word to deal with */ - x = tmp[HASH_BUFFER_SIZE/2]; - x ^= (x >> 16); /* Fold it in half */ - ((__u16 *)tmp)[HASH_BUFFER_SIZE-1] = (__u16)x; -#endif - /* Copy data to destination buffer */ - i = min(nbytes, HASH_BUFFER_SIZE*sizeof(__u32)/2); + i = (nbytes < 16) ? nbytes : 16; if (flags & EXTRACT_ENTROPY_USER) { i -= copy_to_user(buf, (__u8 const *)tmp, i); if (!i) { ret = -EFAULT; break; } - } else + } else { memcpy(buf, (__u8 const *)tmp, i); + } nbytes -= i; buf += i; ret += i; } + + /* generate a new key */ + /* take into account the possibility that keysize >= blocksize */ + for (i=0; i+r->blocksize<=r->keysize; i+=r->blocksize) { + sgtmp[0].page = virt_to_page( r->key+i ); + sgtmp[0].offset = offset_in_page( r->key+i ); + sgtmp[0].length = r->blocksize; + crypto_cipher_encrypt(r->cipher, sgtmp, sgiv, 1); + increment_iv(r->iv, r->blocksize); + } + sgtmp[0].page = virt_to_page( r->key+i ); + sgtmp[0].offset = offset_in_page( r->key+i ); + sgtmp[0].length = r->blocksize-i; + crypto_cipher_encrypt(r->cipher, sgtmp, sgiv, 1); + increment_iv(r->iv, r->blocksize); + + if (crypto_cipher_setkey(r->cipher, r->key, r->keysize)) { + return -EINVAL; + } /* Wipe data just returned from memory */ memset(tmp, 0, sizeof(tmp)); @@ -1482,10 +894,7 @@ */ void get_random_bytes(void *buf, int nbytes) { - if (sec_random_state) - extract_entropy(sec_random_state, (char *) buf, nbytes, - EXTRACT_ENTROPY_SECONDARY); - else if (random_state) + if (random_state) extract_entropy(random_state, (char *) buf, nbytes, 0); else printk(KERN_NOTICE "get_random_bytes called before " @@ -1500,57 +909,16 @@ * *********************************************************************/ -/* - * Initialize the random pool with standard stuff. - * - * NOTE: This is an OS-dependent function. - */ -static void init_std_data(struct entropy_store *r) -{ - struct timeval tv; - __u32 words[2]; - char *p; - int i; - - do_gettimeofday(&tv); - words[0] = tv.tv_sec; - words[1] = tv.tv_usec; - add_entropy_words(r, words, 2); - - /* - * This doesn't lock system.utsname. However, we are generating - * entropy so a race with a name set here is fine. - */ - p = (char *) &system_utsname; - for (i = sizeof(system_utsname) / sizeof(words); i; i--) { - memcpy(words, p, sizeof(words)); - add_entropy_words(r, words, sizeof(words)/4); - p += sizeof(words); - } -} - static int __init rand_initialize(void) { - int i; - - if (create_entropy_store(DEFAULT_POOL_SIZE, &random_state)) - goto err; - if (batch_entropy_init(BATCH_ENTROPY_SIZE, random_state)) - goto err; - if (create_entropy_store(SECONDARY_POOL_SIZE, &sec_random_state)) + if (create_entropy_store(DEFAULT_POOL_NUMBER, &random_state)) goto err; - clear_entropy_store(random_state); - clear_entropy_store(sec_random_state); - init_std_data(random_state); + if (batch_entropy_init(BATCH_ENTROPY_SIZE, random_state)) + goto err; + #ifdef CONFIG_SYSCTL sysctl_init_random(random_state); #endif - for (i = 0; i < NR_IRQS; i++) - irq_timer_state[i] = NULL; - memset(&keyboard_timer_state, 0, sizeof(struct timer_rand_state)); - memset(&mouse_timer_state, 0, sizeof(struct timer_rand_state)); - memset(&extract_timer_state, 0, sizeof(struct timer_rand_state)); - extract_timer_state.dont_count_entropy = 1; return 0; err: return -1; @@ -1559,139 +927,33 @@ void rand_initialize_irq(int irq) { - struct timer_rand_state *state; - - if (irq >= NR_IRQS || irq_timer_state[irq]) - return; - - /* - * If kmalloc returns null, we just won't use that entropy - * source. - */ - state = kmalloc(sizeof(struct timer_rand_state), GFP_KERNEL); - if (state) { - memset(state, 0, sizeof(struct timer_rand_state)); - irq_timer_state[irq] = state; - } + /* we don't use timers anymore, we just use the current time */ } void rand_initialize_disk(struct gendisk *disk) { - struct timer_rand_state *state; - - /* - * If kmalloc returns null, we just won't use that entropy - * source. - */ - state = kmalloc(sizeof(struct timer_rand_state), GFP_KERNEL); - if (state) { - memset(state, 0, sizeof(struct timer_rand_state)); - disk->random = state; - } -} - -static ssize_t -random_read(struct file * file, char __user * buf, size_t nbytes, loff_t *ppos) -{ - DECLARE_WAITQUEUE(wait, current); - ssize_t n, retval = 0, count = 0; - - if (nbytes == 0) - return 0; - - while (nbytes > 0) { - n = nbytes; - if (n > SEC_XFER_SIZE) - n = SEC_XFER_SIZE; - - DEBUG_ENT("%04d %04d : reading %d bits, p: %d s: %d\n", - random_state->entropy_count, - sec_random_state->entropy_count, - n*8, random_state->entropy_count, - sec_random_state->entropy_count); - - n = extract_entropy(sec_random_state, buf, n, - EXTRACT_ENTROPY_USER | - EXTRACT_ENTROPY_LIMIT | - EXTRACT_ENTROPY_SECONDARY); - - DEBUG_ENT("%04d %04d : read got %d bits (%d still needed)\n", - random_state->entropy_count, - sec_random_state->entropy_count, - n*8, (nbytes-n)*8); - - if (n == 0) { - if (file->f_flags & O_NONBLOCK) { - retval = -EAGAIN; - break; - } - if (signal_pending(current)) { - retval = -ERESTARTSYS; - break; - } - - DEBUG_ENT("%04d %04d : sleeping?\n", - random_state->entropy_count, - sec_random_state->entropy_count); - - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&random_read_wait, &wait); - - if (sec_random_state->entropy_count / 8 == 0) - schedule(); - - set_current_state(TASK_RUNNING); - remove_wait_queue(&random_read_wait, &wait); - - DEBUG_ENT("%04d %04d : waking up\n", - random_state->entropy_count, - sec_random_state->entropy_count); - - continue; - } - - if (n < 0) { - retval = n; - break; - } - count += n; - buf += n; - nbytes -= n; - break; /* This break makes the device work */ - /* like a named pipe */ - } - - /* - * If we gave the user some bytes, update the access time. - */ - if (count) - file_accessed(file); - - return (count ? count : retval); + /* we don't use timers anymore, we just use the current time */ } static ssize_t urandom_read(struct file * file, char __user * buf, size_t nbytes, loff_t *ppos) { - return extract_entropy(sec_random_state, buf, nbytes, + return extract_entropy(random_state, buf, nbytes, EXTRACT_ENTROPY_USER | EXTRACT_ENTROPY_SECONDARY); } +static ssize_t +random_read(struct file * file, char __user * buf, size_t nbytes, loff_t *ppos) +{ + return urandom_read(file, buf, nbytes, ppos); +} + static unsigned int random_poll(struct file *file, poll_table * wait) { - unsigned int mask; - - poll_wait(file, &random_read_wait, wait); - poll_wait(file, &random_write_wait, wait); - mask = 0; - if (random_state->entropy_count >= random_read_wakeup_thresh) - mask |= POLLIN | POLLRDNORM; - if (random_state->entropy_count < random_write_wakeup_thresh) - mask |= POLLOUT | POLLWRNORM; - return mask; + return POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM; } static ssize_t @@ -1701,12 +963,13 @@ int ret = 0; size_t bytes; __u32 buf[16]; - const char __user *p = buffer; + const char __user *p = buffer; size_t c = count; while (c > 0) { bytes = min(c, sizeof(buf)); +DEBUG_PRINTK("random_write() %p, %p, %u\n", &buf, p, bytes); bytes -= copy_from_user(&buf, p, bytes); if (!bytes) { ret = -EFAULT; @@ -1730,67 +993,25 @@ random_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg) { - int *tmp, size, ent_count; - int __user *p = (int __user *)arg; + int size, ent_count; + int __user *p = (int __user *) arg; int retval; - unsigned long flags; switch (cmd) { case RNDGETENTCNT: - ent_count = random_state->entropy_count; - if (put_user(ent_count, p)) + if (put_user(random_entropy_count, p)) return -EFAULT; return 0; case RNDADDTOENTCNT: - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (get_user(ent_count, p)) - return -EFAULT; - credit_entropy_store(random_state, ent_count); - /* - * Wake up waiting processes if we have enough - * entropy. - */ - if (random_state->entropy_count >= random_read_wakeup_thresh) - wake_up_interruptible(&random_read_wait); + /* entropy accounting removed. */ return 0; case RNDGETPOOL: - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (get_user(size, p) || - put_user(random_state->poolinfo.poolwords, p++)) - return -EFAULT; - if (size < 0) - return -EFAULT; - if (size > random_state->poolinfo.poolwords) - size = random_state->poolinfo.poolwords; - - /* prepare to atomically snapshot pool */ - - tmp = kmalloc(size * sizeof(__u32), GFP_KERNEL); - - if (!tmp) - return -ENOMEM; - - spin_lock_irqsave(&random_state->lock, flags); - ent_count = random_state->entropy_count; - memcpy(tmp, random_state->pool, size * sizeof(__u32)); - spin_unlock_irqrestore(&random_state->lock, flags); - - if (!copy_to_user(p, tmp, size * sizeof(__u32))) { - kfree(tmp); - return -EFAULT; - } - - kfree(tmp); - - if(put_user(ent_count, p++)) - return -EFAULT; - + /* jlcooke: never get the raw pool!!! */ return 0; case RNDADDENTROPY: if (!capable(CAP_SYS_ADMIN)) return -EPERM; + p = (int *) arg; if (get_user(ent_count, p++)) return -EFAULT; if (ent_count < 0) @@ -1801,25 +1022,12 @@ size, &file->f_pos); if (retval < 0) return retval; - credit_entropy_store(random_state, ent_count); - /* - * Wake up waiting processes if we have enough - * entropy. - */ - if (random_state->entropy_count >= random_read_wakeup_thresh) - wake_up_interruptible(&random_read_wait); return 0; case RNDZAPENTCNT: - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - random_state->entropy_count = 0; + /* entropy accounting removed. */ return 0; case RNDCLEARPOOL: - /* Clear the entropy pool and associated counters. */ - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - clear_entropy_store(random_state); - init_std_data(random_state); + /* jlcooke: this is maddness! Never clear the entropy pool */ return 0; default: return -EINVAL; @@ -1875,71 +1083,111 @@ static int min_write_thresh, max_write_thresh; static char sysctl_bootid[16]; -/* - * This function handles a request from the user to change the pool size - * of the primary entropy store. - */ -static int change_poolsize(int poolsize) -{ - struct entropy_store *new_store, *old_store; - int ret; - - if ((ret = create_entropy_store(poolsize, &new_store))) - return ret; - - add_entropy_words(new_store, random_state->pool, - random_state->poolinfo.poolwords); - credit_entropy_store(new_store, random_state->entropy_count); - - sysctl_init_random(new_store); - old_store = random_state; - random_state = batch_work.data = new_store; - free_entropy_store(old_store); - return 0; -} - static int proc_do_poolsize(ctl_table *table, int write, struct file *filp, void __user *buffer, size_t *lenp, loff_t *ppos) { - int ret; + int ret; - sysctl_poolsize = random_state->poolinfo.POOLBYTES; + if (write) { + /* you can't change the poolsize, but we'll let you think + * you can for legacy reasons. + */ + return 0; + } + sysctl_poolsize = (1<pool_number) * + random_state->pools[0]->__crt_alg->cra_ctxsize; ret = proc_dointvec(table, write, filp, buffer, lenp, ppos); - if (ret || !write || - (sysctl_poolsize == random_state->poolinfo.POOLBYTES)) - return ret; - return change_poolsize(sysctl_poolsize); + return ret; } -static int poolsize_strategy(ctl_table *table, int __user *name, int nlen, +static int poolsize_strategy(ctl_table *table, int *name, int nlen, void __user *oldval, size_t __user *oldlenp, void __user *newval, size_t newlen, void **context) { - int len; - - sysctl_poolsize = random_state->poolinfo.POOLBYTES; - - /* - * We only handle the write case, since the read case gets - * handled by the default handler (and we don't care if the - * write case happens twice; it's harmless). + /* you can't set a poolsize strtegy because it doesn't change in + * size anymore */ - if (newval && newlen) { - len = newlen; - if (len > table->maxlen) - len = table->maxlen; - if (copy_from_user(table->data, newval, len)) - return -EFAULT; + return 0; +} + +static int proc_derive_seed(ctl_table *table, int write, struct file *filp, + void __user *buffer, size_t *lenp, loff_t *ppos) +{ + static unsigned char *hextab = "0123456789abcdef"; + static unsigned int derive_count=0; + /* hex length of derived seed */ + static unsigned char buf[(1<lock, flags); + random_state->pool0_len = 0; + + memset(buf, 0, random_state->pool_number * 2*random_state->digestsize); + + /* the carry-state from pool to pool */ + memset(tmp, 0, random_state->digestsize); + + for (i=0; i<(1<pool_number); i++) { + crypto_digest_init(random_state->reseedHash); + + /* + * carry the digest from the previous output so a derive seed + * from a lightly seeded state is indistinguishavble from a + * heavily seeded one + */ + p = &tmp; + sg[0].page = virt_to_page(p); + sg[0].offset = offset_in_page(p); + sg[0].length = sizeof(tmp); + + /* finalize and digest the i-th pool */ + crypto_digest_final(random_state->pools[i], tmp); + crypto_digest_init(random_state->pools[i]); + p = &tmp; + sg[1].page = virt_to_page(p); + sg[1].offset = offset_in_page(p); + sg[1].length = sizeof(tmp); + + /* + * digest in a counter to ensure the final hash can change even if the + * message does not + */ + p = &derive_count; + sg[2].page = virt_to_page(p); + sg[2].offset = offset_in_page(p); + sg[2].length = sizeof(derive_count); + + crypto_digest_digest(random_state->reseedHash, sg, 3, tmp); + for (j=0; jdigestsize; j++) { + buf[2*(i*random_state->digestsize +j) ] = hextab[ (tmp[j] >> 4) & 0xf ]; + buf[2*(i*random_state->digestsize +j)+1] = hextab[ (tmp[j] ) & 0xf ]; + } + derive_count++; } - if (sysctl_poolsize != random_state->poolinfo.POOLBYTES) - return change_poolsize(sysctl_poolsize); + spin_unlock_irqrestore(&random_state->lock, flags); - return 0; + fake_table.data = buf; + fake_table.maxlen = (1<pool_number) * + 2*random_state->digestsize; + + ret = proc_dostring(&fake_table, write, filp, buffer, lenp, ppos); + + return ret; } + /* * These functions is used to return both the bootid UUID, and random * UUID. The difference is in whether table->data is NULL; if it is, @@ -1975,7 +1223,7 @@ return proc_dostring(&fake_table, write, filp, buffer, lenp, ppos); } -static int uuid_strategy(ctl_table *table, int __user *name, int nlen, +static int uuid_strategy(ctl_table *table, int *name, int nlen, void __user *oldval, size_t __user *oldlenp, void __user *newval, size_t newlen, void **context) { @@ -2011,38 +1259,41 @@ .procname = "poolsize", .data = &sysctl_poolsize, .maxlen = sizeof(int), + /* you can't change the poolsize, but we'll let you think you + * can for legacy reasons. + */ .mode = 0644, .proc_handler = &proc_do_poolsize, .strategy = &poolsize_strategy, }, { - .ctl_name = RANDOM_ENTROPY_COUNT, - .procname = "entropy_avail", - .maxlen = sizeof(int), - .mode = 0444, - .proc_handler = &proc_dointvec, - }, + .ctl_name = RANDOM_ENTROPY_COUNT, + .procname = "entropy_avail", + .maxlen = sizeof(int), + .mode = 0444, + .proc_handler = &proc_dointvec, + }, { - .ctl_name = RANDOM_READ_THRESH, - .procname = "read_wakeup_threshold", - .data = &random_read_wakeup_thresh, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, - .extra1 = &min_read_thresh, - .extra2 = &max_read_thresh, + .ctl_name = RANDOM_READ_THRESH, + .procname = "read_wakeup_threshold", + .data = &random_read_wakeup_thresh, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec_minmax, + .strategy = &sysctl_intvec, + .extra1 = &min_read_thresh, + .extra2 = &max_read_thresh, }, { - .ctl_name = RANDOM_WRITE_THRESH, - .procname = "write_wakeup_threshold", - .data = &random_write_wakeup_thresh, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, - .extra1 = &min_write_thresh, - .extra2 = &max_write_thresh, + .ctl_name = RANDOM_WRITE_THRESH, + .procname = "write_wakeup_threshold", + .data = &random_write_wakeup_thresh, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec_minmax, + .strategy = &sysctl_intvec, + .extra1 = &min_write_thresh, + .extra2 = &max_write_thresh, }, { .ctl_name = RANDOM_BOOT_ID, @@ -2061,15 +1312,25 @@ .proc_handler = &proc_do_uuid, .strategy = &uuid_strategy, }, + { + .ctl_name = RANDOM_DERIVE_SEED, + .procname = "derive_seed", + .maxlen = MAXIMUM_POOL_NUMBER * RANDOM_MAX_DIGEST_SIZE, + .mode = 0400, + .proc_handler = &proc_derive_seed, + }, { .ctl_name = 0 } }; -static void sysctl_init_random(struct entropy_store *random_state) +static void sysctl_init_random(struct entropy_store *r) { min_read_thresh = 8; min_write_thresh = 0; - max_read_thresh = max_write_thresh = random_state->poolinfo.POOLBITS; - random_table[1].data = &random_state->entropy_count; + random_entropy_count = + max_read_thresh = + max_write_thresh = (1<pool_number) * + r->pools[0]->__crt_alg->cra_ctxsize; + random_table[1].data = &random_entropy_count; } #endif /* CONFIG_SYSCTL */ @@ -2081,135 +1342,23 @@ /* * TCP initial sequence number picking. This uses the random number - * generator to pick an initial secret value. This value is hashed - * along with the TCP endpoint information to provide a unique - * starting point for each pair of TCP endpoints. This defeats - * attacks which rely on guessing the initial TCP sequence number. - * This algorithm was suggested by Steve Bellovin. + * generator to pick an initial secret value. This value is encrypted + * with the TCP endpoint information to provide a unique starting point + * for each pair of TCP endpoints. This defeats attacks which rely on + * guessing the initial TCP sequence number. * * Using a very strong hash was taking an appreciable amount of the total - * TCP connection establishment time, so this is a weaker hash, - * compensated for by changing the secret periodically. + * TCP connection establishment time, so this now uses AES256 + * + * openssl spped md4 aes shows aes256 is 2.5 times faster then basic md4 for + * the block sizes we're dealing with. + * type 16 bytes 64 bytes 256 bytes 1024 bytes 8192 bytes + * md4 10708.72k 38240.96k 111170.47k 215872.85k 296828.93k + * aes-128 cbc 32121.81k 32678.31k 33119.49k 33221.29k 33210.59k + * aes-192 cbc 27915.92k 27868.52k 28418.08k 28677.12k 28721.15k + * aes-256 cbc 24599.57k 25142.38k 25381.80k 25474.88k 25392.46k */ -/* F, G and H are basic MD4 functions: selection, majority, parity */ -#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) -#define G(x, y, z) (((x) & (y)) + (((x) ^ (y)) & (z))) -#define H(x, y, z) ((x) ^ (y) ^ (z)) - -/* - * The generic round function. The application is so specific that - * we don't bother protecting all the arguments with parens, as is generally - * good macro practice, in favor of extra legibility. - * Rotation is separate from addition to prevent recomputation - */ -#define ROUND(f, a, b, c, d, x, s) \ - (a += f(b, c, d) + x, a = (a << s) | (a >> (32-s))) -#define K1 0 -#define K2 013240474631UL -#define K3 015666365641UL - -/* - * Basic cut-down MD4 transform. Returns only 32 bits of result. - */ -static __u32 halfMD4Transform (__u32 const buf[4], __u32 const in[8]) -{ - __u32 a = buf[0], b = buf[1], c = buf[2], d = buf[3]; - - /* Round 1 */ - ROUND(F, a, b, c, d, in[0] + K1, 3); - ROUND(F, d, a, b, c, in[1] + K1, 7); - ROUND(F, c, d, a, b, in[2] + K1, 11); - ROUND(F, b, c, d, a, in[3] + K1, 19); - ROUND(F, a, b, c, d, in[4] + K1, 3); - ROUND(F, d, a, b, c, in[5] + K1, 7); - ROUND(F, c, d, a, b, in[6] + K1, 11); - ROUND(F, b, c, d, a, in[7] + K1, 19); - - /* Round 2 */ - ROUND(G, a, b, c, d, in[1] + K2, 3); - ROUND(G, d, a, b, c, in[3] + K2, 5); - ROUND(G, c, d, a, b, in[5] + K2, 9); - ROUND(G, b, c, d, a, in[7] + K2, 13); - ROUND(G, a, b, c, d, in[0] + K2, 3); - ROUND(G, d, a, b, c, in[2] + K2, 5); - ROUND(G, c, d, a, b, in[4] + K2, 9); - ROUND(G, b, c, d, a, in[6] + K2, 13); - - /* Round 3 */ - ROUND(H, a, b, c, d, in[3] + K3, 3); - ROUND(H, d, a, b, c, in[7] + K3, 9); - ROUND(H, c, d, a, b, in[2] + K3, 11); - ROUND(H, b, c, d, a, in[6] + K3, 15); - ROUND(H, a, b, c, d, in[1] + K3, 3); - ROUND(H, d, a, b, c, in[5] + K3, 9); - ROUND(H, c, d, a, b, in[0] + K3, 11); - ROUND(H, b, c, d, a, in[4] + K3, 15); - - return buf[1] + b; /* "most hashed" word */ - /* Alternative: return sum of all words? */ -} - -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - -static __u32 twothirdsMD4Transform (__u32 const buf[4], __u32 const in[12]) -{ - __u32 a = buf[0], b = buf[1], c = buf[2], d = buf[3]; - - /* Round 1 */ - ROUND(F, a, b, c, d, in[ 0] + K1, 3); - ROUND(F, d, a, b, c, in[ 1] + K1, 7); - ROUND(F, c, d, a, b, in[ 2] + K1, 11); - ROUND(F, b, c, d, a, in[ 3] + K1, 19); - ROUND(F, a, b, c, d, in[ 4] + K1, 3); - ROUND(F, d, a, b, c, in[ 5] + K1, 7); - ROUND(F, c, d, a, b, in[ 6] + K1, 11); - ROUND(F, b, c, d, a, in[ 7] + K1, 19); - ROUND(F, a, b, c, d, in[ 8] + K1, 3); - ROUND(F, d, a, b, c, in[ 9] + K1, 7); - ROUND(F, c, d, a, b, in[10] + K1, 11); - ROUND(F, b, c, d, a, in[11] + K1, 19); - - /* Round 2 */ - ROUND(G, a, b, c, d, in[ 1] + K2, 3); - ROUND(G, d, a, b, c, in[ 3] + K2, 5); - ROUND(G, c, d, a, b, in[ 5] + K2, 9); - ROUND(G, b, c, d, a, in[ 7] + K2, 13); - ROUND(G, a, b, c, d, in[ 9] + K2, 3); - ROUND(G, d, a, b, c, in[11] + K2, 5); - ROUND(G, c, d, a, b, in[ 0] + K2, 9); - ROUND(G, b, c, d, a, in[ 2] + K2, 13); - ROUND(G, a, b, c, d, in[ 4] + K2, 3); - ROUND(G, d, a, b, c, in[ 6] + K2, 5); - ROUND(G, c, d, a, b, in[ 8] + K2, 9); - ROUND(G, b, c, d, a, in[10] + K2, 13); - - /* Round 3 */ - ROUND(H, a, b, c, d, in[ 3] + K3, 3); - ROUND(H, d, a, b, c, in[ 7] + K3, 9); - ROUND(H, c, d, a, b, in[11] + K3, 11); - ROUND(H, b, c, d, a, in[ 2] + K3, 15); - ROUND(H, a, b, c, d, in[ 6] + K3, 3); - ROUND(H, d, a, b, c, in[10] + K3, 9); - ROUND(H, c, d, a, b, in[ 1] + K3, 11); - ROUND(H, b, c, d, a, in[ 5] + K3, 15); - ROUND(H, a, b, c, d, in[ 9] + K3, 3); - ROUND(H, d, a, b, c, in[ 0] + K3, 9); - ROUND(H, c, d, a, b, in[ 4] + K3, 11); - ROUND(H, b, c, d, a, in[ 8] + K3, 15); - - return buf[1] + b; /* "most hashed" word */ - /* Alternative: return sum of all words? */ -} -#endif - -#undef ROUND -#undef F -#undef G -#undef H -#undef K1 -#undef K2 -#undef K3 /* This should not be decreased so low that ISNs wrap too fast. */ #define REKEY_INTERVAL 300 @@ -2237,79 +1386,70 @@ #define HASH_BITS 24 #define HASH_MASK ( (1<rekey_time || (time - keyptr->rekey_time) > REKEY_INTERVAL) { - keyptr = &ip_keydata[1^(ip_cnt&1)]; - keyptr->rekey_time = time; - get_random_bytes(keyptr->secret, sizeof(keyptr->secret)); - keyptr->count = (ip_cnt&COUNT_MASK)<blocksize); + + do_gettimeofday(&tv); + if (lastRekey==0 || (tv.tv_sec - lastRekey) < REKEY_INTERVAL) { + lastRekey = tv.tv_sec; + + sgctr[0].page = virt_to_page(ctr); + sgctr[0].offset = offset_in_page(ctr); + sgctr[0].length = 16; + + if (!random_state->networkCipher_ready) { + u8 secret[32]; /* max key size? */ + get_random_bytes(secret, random_state->keysize); + crypto_cipher_setkey(random_state->networkCipher, + (const u8*)secret, + random_state->keysize); + random_state->networkCipher_ready = 1; + } + mb(); - ip_cnt++; - } - spin_unlock_bh(&ip_lock); - return keyptr; -} + } -static inline struct keydata *check_and_rekey(time_t time) -{ - struct keydata *keyptr = &ip_keydata[ip_cnt&1]; + spin_unlock_bh(&ip_lock); - rmb(); - if (!keyptr->rekey_time || (time - keyptr->rekey_time) > REKEY_INTERVAL) { - keyptr = __check_and_rekey(time); - } + sgtmp[0].page = virt_to_page(tmp); + sgtmp[0].offset = offset_in_page(tmp); + sgtmp[0].length = random_state->blocksize; + /* tmp[]/sg[0] = Enc(Sec, CTR++) */ + crypto_cipher_encrypt(random_state->networkCipher, sgtmp, sgctr, 1); + increment_iv(ctr, random_state->blocksize); - return keyptr; + /* seq# needs to be random-ish, but incresing */ + return (tmp[0] & COUNT_MASK) + (count << (32-COUNT_BITS)); } #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) __u32 secure_tcpv6_sequence_number(__u32 *saddr, __u32 *daddr, __u16 sport, __u16 dport) { - struct timeval tv; - __u32 seq; - __u32 hash[12]; - struct keydata *keyptr; - - /* The procedure is the same as for IPv4, but addresses are longer. - * Thus we must use twothirdsMD4Transform. - */ - - do_gettimeofday(&tv); /* We need the usecs below... */ - keyptr = check_and_rekey(tv.tv_sec); - - memcpy(hash, saddr, 16); - hash[4]=(sport << 16) + dport; - memcpy(&hash[5],keyptr->secret,sizeof(__u32)*7); - - seq = twothirdsMD4Transform(daddr, hash) & HASH_MASK; - seq += keyptr->count; - seq += tv.tv_usec + tv.tv_sec*1000000; - - return seq; + return network_random_read32(); } EXPORT_SYMBOL(secure_tcpv6_sequence_number); __u32 secure_ipv6_id(__u32 *daddr) { - struct keydata *keyptr; - - keyptr = check_and_rekey(get_seconds()); - - return halfMD4Transform(daddr, keyptr->secret); + return network_random_read32(); } EXPORT_SYMBOL(secure_ipv6_id); @@ -2319,75 +1459,20 @@ __u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr, __u16 sport, __u16 dport) { - struct timeval tv; - __u32 seq; - __u32 hash[4]; - struct keydata *keyptr; - - /* - * Pick a random secret every REKEY_INTERVAL seconds. - */ - do_gettimeofday(&tv); /* We need the usecs below... */ - keyptr = check_and_rekey(tv.tv_sec); - - /* - * Pick a unique starting offset for each TCP connection endpoints - * (saddr, daddr, sport, dport). - * Note that the words are placed into the starting vector, which is - * then mixed with a partial MD4 over random data. - */ - hash[0]=saddr; - hash[1]=daddr; - hash[2]=(sport << 16) + dport; - hash[3]=keyptr->secret[11]; - - seq = halfMD4Transform(hash, keyptr->secret) & HASH_MASK; - seq += keyptr->count; - /* - * As close as possible to RFC 793, which - * suggests using a 250 kHz clock. - * Further reading shows this assumes 2 Mb/s networks. - * For 10 Mb/s Ethernet, a 1 MHz clock is appropriate. - * That's funny, Linux has one built in! Use it! - * (Networks are faster now - should this be increased?) - */ - seq += tv.tv_usec + tv.tv_sec*1000000; -#if 0 - printk("init_seq(%lx, %lx, %d, %d) = %d\n", - saddr, daddr, sport, dport, seq); -#endif - return seq; + return network_random_read32(); } EXPORT_SYMBOL(secure_tcp_sequence_number); -/* The code below is shamelessly stolen from secure_tcp_sequence_number(). - * All blames to Andrey V. Savochkin . - */ __u32 secure_ip_id(__u32 daddr) { - struct keydata *keyptr; - __u32 hash[4]; - - keyptr = check_and_rekey(get_seconds()); - - /* - * Pick a unique starting offset for each IP destination. - * The dest ip address is placed in the starting vector, - * which is then hashed with random data. - */ - hash[0] = daddr; - hash[1] = keyptr->secret[9]; - hash[2] = keyptr->secret[10]; - hash[3] = keyptr->secret[11]; - - return halfMD4Transform(hash, keyptr->secret); + return network_random_read32(); } #ifdef CONFIG_SYN_COOKIES /* * Secure SYN cookie computation. This is the algorithm worked out by - * Dan Bernstein and Eric Schenk. + * Jean-Luc Cooke * * For linux I implement the 1 minute counter by looking at the jiffies clock. * The count is passed in as a parameter, so this code doesn't much care. @@ -2396,50 +1481,54 @@ #define COOKIEBITS 24 /* Upper bits store count */ #define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1) -static int syncookie_init; -static __u32 syncookie_secret[2][16-3+HASH_BUFFER_SIZE]; - __u32 secure_tcp_syn_cookie(__u32 saddr, __u32 daddr, __u16 sport, __u16 dport, __u32 sseq, __u32 count, __u32 data) { - __u32 tmp[16 + HASH_BUFFER_SIZE + HASH_EXTRA_SIZE]; - __u32 seq; - - /* - * Pick two random secrets the first time we need a cookie. - */ - if (syncookie_init == 0) { - get_random_bytes(syncookie_secret, sizeof(syncookie_secret)); - syncookie_init = 1; - } + struct scatterlist sg[1]; + __u32 tmp[4]; /* * Compute the secure sequence number. - * The output should be: - * HASH(sec1,saddr,sport,daddr,dport,sec1) + sseq + (count * 2^24) - * + (HASH(sec2,saddr,sport,daddr,dport,count,sec2) % 2^24). - * Where sseq is their sequence number and count increases every - * minute by 1. - * As an extra hack, we add a small "data" value that encodes the - * MSS into the second hash value. + * + * Output is the 32bit tag of a CBC-MAC of PT={count,0,0,0} with IV={addr,daddr,sport|dport,sseq} + * cookie = <8bit count> || truncate_24bit( Encrypt(Sec, {saddr,daddr,sport|dport,sseq}) ) + * + * DJB wrote (http://cr.yp.to/syncookies/archive) about how to do this with hash algorithms + * - we can replace two SHA1s used in the previous kernel with two AESs and make things 3x faster + * - I'd like to propose we remove the use of two whittenings with a single operation since we + * were only using addition modulo 2^32 of all these values anyways. Not to mention the hashs + * differ only in that the second processes more data... why drop the first hash? We did learn + * that addition is commutative and associative long ago. + * - by replacing two SHA1s and addition modulo 2^32 with encryption of a 32bit value using AES-CTR + * we've made it 1,000,000,000 times easier to understand what is going on. + * - Todo: we should rekey the cipher peridoically... if we do this, some packets will now fail + * our checking system... is this ok? How can we get around this? Rekey's would ideally happen + * once per minute (6 million TCP connections per minute is a unrealistic enough security margin) */ - memcpy(tmp+3, syncookie_secret[0], sizeof(syncookie_secret[0])); - tmp[0]=saddr; - tmp[1]=daddr; - tmp[2]=(sport << 16) + dport; - HASH_TRANSFORM(tmp+16, tmp); - seq = tmp[17] + sseq + (count << COOKIEBITS); - - memcpy(tmp+3, syncookie_secret[1], sizeof(syncookie_secret[1])); - tmp[0]=saddr; - tmp[1]=daddr; - tmp[2]=(sport << 16) + dport; - tmp[3] = count; /* minute counter */ - HASH_TRANSFORM(tmp+16, tmp); + tmp[0] = saddr; + tmp[1] = daddr; + tmp[2] = (sport << 16) + dport; + tmp[3] = sseq; + + sg[0].page = virt_to_page(tmp); + sg[0].offset = offset_in_page(tmp); + sg[0].length = 16; + if (!random_state->networkCipher_ready) { + u8 secret[32]; + get_random_bytes(secret, sizeof(secret)); + if (crypto_cipher_setkey(random_state->networkCipher, + secret, random_state->keysize)) { + return 0; + } + random_state->networkCipher_ready = 1; + } + /* tmp[]/sg[0] = Enc(Sec, {saddr,daddr,sport|dport,sseq}) */ + crypto_cipher_encrypt(random_state->networkCipher, sg, sg, 1); - /* Add in the second hash and the data */ - return seq + ((tmp[17] + data) & COOKIEMASK); + /* cookie = CTR encrypt of 8-bit-count and 24-bit-data */ + return tmp[0] ^ ( (count << COOKIEBITS) | + (data >> (sizeof(__u32)*8-COOKIEBITS)) ); } /* @@ -2454,32 +1543,32 @@ __u32 check_tcp_syn_cookie(__u32 cookie, __u32 saddr, __u32 daddr, __u16 sport, __u16 dport, __u32 sseq, __u32 count, __u32 maxdiff) { - __u32 tmp[16 + HASH_BUFFER_SIZE + HASH_EXTRA_SIZE]; - __u32 diff; + struct scatterlist sg[1]; + __u32 tmp[4], thiscount, diff; - if (syncookie_init == 0) + if (random_state == NULL || !random_state->networkCipher_ready) return (__u32)-1; /* Well, duh! */ - /* Strip away the layers from the cookie */ - memcpy(tmp+3, syncookie_secret[0], sizeof(syncookie_secret[0])); - tmp[0]=saddr; - tmp[1]=daddr; - tmp[2]=(sport << 16) + dport; - HASH_TRANSFORM(tmp+16, tmp); - cookie -= tmp[17] + sseq; - /* Cookie is now reduced to (count * 2^24) ^ (hash % 2^24) */ - - diff = (count - (cookie >> COOKIEBITS)) & ((__u32)-1 >> COOKIEBITS); - if (diff >= maxdiff) - return (__u32)-1; - - memcpy(tmp+3, syncookie_secret[1], sizeof(syncookie_secret[1])); tmp[0] = saddr; tmp[1] = daddr; tmp[2] = (sport << 16) + dport; - tmp[3] = count - diff; /* minute counter */ - HASH_TRANSFORM(tmp+16, tmp); + tmp[3] = sseq; + sg[0].page = virt_to_page(tmp); + sg[0].offset = offset_in_page(tmp); + sg[0].length = 16; + crypto_cipher_encrypt(random_state->networkCipher, sg, sg, 1); + + /* CTR decrypt the cookie */ + cookie ^= tmp[0]; + + /* top 8 bits are 'count' */ + thiscount = cookie >> COOKIEBITS; + + diff = count - thiscount; + if (diff >= maxdiff) + return (__u32)-1; - return (cookie - tmp[17]) & COOKIEMASK; /* Leaving the data behind */ + /* bottom 24 bits are 'data' */ + return cookie >> (sizeof(__u32)*8-COOKIEBITS); } #endif --qLni7iB6Dl8qUSwk--