aboutsummaryrefslogtreecommitdiffstats
path: root/lib/random32.c
diff options
context:
space:
mode:
authorDaniel Borkmann <dborkman@redhat.com>2013-11-11 06:20:36 -0500
committerDavid S. Miller <davem@davemloft.net>2013-11-11 14:32:15 -0500
commita98814cef87946d2708812ad9f8b1e03b8366b6f (patch)
tree1ea8dde97b7a7e806280d4e464513c2f3205a80c /lib/random32.c
parent38e9efcdb33270b4da72143d8e7ca4dcf7f0989b (diff)
random32: upgrade taus88 generator to taus113 from errata paper
Since we use prandom*() functions quite often in networking code i.e. in UDP port selection, netfilter code, etc, upgrade the PRNG from Pierre L'Ecuyer's original paper "Maximally Equidistributed Combined Tausworthe Generators", Mathematics of Computation, 65, 213 (1996), 203--213 to the version published in his errata paper [1]. The Tausworthe generator is a maximally-equidistributed generator, that is fast and has good statistical properties [1]. The version presented there upgrades the 3 state LFSR to a 4 state LFSR with increased periodicity from about 2^88 to 2^113. The algorithm is presented in [1] by the very same author who also designed the original algorithm in [2]. Also, by increasing the state, we make it a bit harder for attackers to "guess" the PRNGs internal state. See also discussion in [3]. Now, as we use this sort of weak initialization discussed in [3] only between core_initcall() until late_initcall() time [*] for prandom32*() users, namely in prandom_init(), it is less relevant from late_initcall() onwards as we overwrite seeds through prandom_reseed() anyways with a seed source of higher entropy, that is, get_random_bytes(). In other words, a exhaustive keysearch of 96 bit would be needed. Now, with the help of this patch, this state-search increases further to 128 bit. Initialization needs to make sure that s1 > 1, s2 > 7, s3 > 15, s4 > 127. taus88 and taus113 algorithm is also part of GSL. I added a test case in the next patch to verify internal behaviour of this patch with GSL and ran tests with the dieharder 3.31.1 RNG test suite: $ dieharder -g 052 -a -m 10 -s 1 -S 4137730333 #taus88 $ dieharder -g 054 -a -m 10 -s 1 -S 4137730333 #taus113 With this seed configuration, in order to compare both, we get the following differences: algorithm taus88 taus113 rands/second [**] 1.61e+08 1.37e+08 sts_serial(4, 1st run) WEAK PASSED sts_serial(9, 2nd run) WEAK PASSED rgb_lagged_sum(31) WEAK PASSED We took out diehard_sums test as according to the authors it is considered broken and unusable [4]. Despite that and the slight decrease in performance (which is acceptable), taus113 here passes all 113 tests (only rgb_minimum_distance_5 in WEAK, the rest PASSED). In general, taus/taus113 is considered "very good" by the authors of dieharder [5]. The papers [1][2] states a single warm-up step is sufficient by running quicktaus once on each state to ensure proper initialization of ~s_{0}: Our selection of (s) according to Table 1 of [1] row 1 holds the condition L - k <= r - s, that is, (32 32 32 32) - (31 29 28 25) <= (25 27 15 22) - (18 2 7 13) with r = k - q and q = (6 2 13 3) as also stated by the paper. So according to [2] we are safe with one round of quicktaus for initialization. However we decided to include the warm-up phase of the PRNG as done in GSL in every case as a safety net. We also use the warm up phase to make the output of the RNG easier to verify by the GSL output. In prandom_init(), we also mix random_get_entropy() into it, just like drivers/char/random.c does it, jiffies ^ random_get_entropy(). random-get_entropy() is get_cycles(). xor is entropy preserving so it is fine if it is not implemented by some architectures. Note, this PRNG is *not* used for cryptography in the kernel, but rather as a fast PRNG for various randomizations i.e. in the networking code, or elsewhere for debugging purposes, for example. [*]: In order to generate some "sort of pseduo-randomness", since get_random_bytes() is not yet available for us, we use jiffies and initialize states s1 - s3 with a simple linear congruential generator (LCG), that is x <- x * 69069; and derive s2, s3, from the 32bit initialization from s1. So the above quote from [3] accounts only for the time from core to late initcall, not afterwards. [**] Single threaded run on MacBook Air w/ Intel Core i5-3317U [1] http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme2.ps [2] http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme.ps [3] http://thread.gmane.org/gmane.comp.encryption.general/12103/ [4] http://code.google.com/p/dieharder/source/browse/trunk/libdieharder/diehard_sums.c?spec=svn490&r=490#20 [5] http://www.phy.duke.edu/~rgb/General/dieharder.php Joint work with Hannes Frederic Sowa. Cc: Florian Weimer <fweimer@redhat.com> Cc: Theodore Ts'o <tytso@mit.edu> Signed-off-by: Daniel Borkmann <dborkman@redhat.com> Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'lib/random32.c')
-rw-r--r--lib/random32.c80
1 files changed, 46 insertions, 34 deletions
diff --git a/lib/random32.c b/lib/random32.c
index 9f2f2fb03dfe..27adb753180f 100644
--- a/lib/random32.c
+++ b/lib/random32.c
@@ -2,19 +2,19 @@
2 This is a maximally equidistributed combined Tausworthe generator 2 This is a maximally equidistributed combined Tausworthe generator
3 based on code from GNU Scientific Library 1.5 (30 Jun 2004) 3 based on code from GNU Scientific Library 1.5 (30 Jun 2004)
4 4
5 x_n = (s1_n ^ s2_n ^ s3_n) 5 lfsr113 version:
6 6
7 s1_{n+1} = (((s1_n & 4294967294) <<12) ^ (((s1_n <<13) ^ s1_n) >>19)) 7 x_n = (s1_n ^ s2_n ^ s3_n ^ s4_n)
8 s2_{n+1} = (((s2_n & 4294967288) << 4) ^ (((s2_n << 2) ^ s2_n) >>25))
9 s3_{n+1} = (((s3_n & 4294967280) <<17) ^ (((s3_n << 3) ^ s3_n) >>11))
10 8
11 The period of this generator is about 2^88. 9 s1_{n+1} = (((s1_n & 4294967294) << 18) ^ (((s1_n << 6) ^ s1_n) >> 13))
10 s2_{n+1} = (((s2_n & 4294967288) << 2) ^ (((s2_n << 2) ^ s2_n) >> 27))
11 s3_{n+1} = (((s3_n & 4294967280) << 7) ^ (((s3_n << 13) ^ s3_n) >> 21))
12 s4_{n+1} = (((s4_n & 4294967168) << 13) ^ (((s4_n << 3) ^ s4_n) >> 12))
12 13
13 From: P. L'Ecuyer, "Maximally Equidistributed Combined Tausworthe 14 The period of this generator is about 2^113 (see erratum paper).
14 Generators", Mathematics of Computation, 65, 213 (1996), 203--213.
15
16 This is available on the net from L'Ecuyer's home page,
17 15
16 From: P. L'Ecuyer, "Maximally Equidistributed Combined Tausworthe
17 Generators", Mathematics of Computation, 65, 213 (1996), 203--213:
18 http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme.ps 18 http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme.ps
19 ftp://ftp.iro.umontreal.ca/pub/simulation/lecuyer/papers/tausme.ps 19 ftp://ftp.iro.umontreal.ca/pub/simulation/lecuyer/papers/tausme.ps
20 20
@@ -29,7 +29,7 @@
29 that paper.) 29 that paper.)
30 30
31 This affects the seeding procedure by imposing the requirement 31 This affects the seeding procedure by imposing the requirement
32 s1 > 1, s2 > 7, s3 > 15. 32 s1 > 1, s2 > 7, s3 > 15, s4 > 127.
33 33
34*/ 34*/
35 35
@@ -52,11 +52,12 @@ u32 prandom_u32_state(struct rnd_state *state)
52{ 52{
53#define TAUSWORTHE(s,a,b,c,d) ((s&c)<<d) ^ (((s <<a) ^ s)>>b) 53#define TAUSWORTHE(s,a,b,c,d) ((s&c)<<d) ^ (((s <<a) ^ s)>>b)
54 54
55 state->s1 = TAUSWORTHE(state->s1, 13, 19, 4294967294UL, 12); 55 state->s1 = TAUSWORTHE(state->s1, 6U, 13U, 4294967294U, 18U);
56 state->s2 = TAUSWORTHE(state->s2, 2, 25, 4294967288UL, 4); 56 state->s2 = TAUSWORTHE(state->s2, 2U, 27U, 4294967288U, 2U);
57 state->s3 = TAUSWORTHE(state->s3, 3, 11, 4294967280UL, 17); 57 state->s3 = TAUSWORTHE(state->s3, 13U, 21U, 4294967280U, 7U);
58 state->s4 = TAUSWORTHE(state->s4, 3U, 12U, 4294967168U, 13U);
58 59
59 return (state->s1 ^ state->s2 ^ state->s3); 60 return (state->s1 ^ state->s2 ^ state->s3 ^ state->s4);
60} 61}
61EXPORT_SYMBOL(prandom_u32_state); 62EXPORT_SYMBOL(prandom_u32_state);
62 63
@@ -126,6 +127,21 @@ void prandom_bytes(void *buf, int bytes)
126} 127}
127EXPORT_SYMBOL(prandom_bytes); 128EXPORT_SYMBOL(prandom_bytes);
128 129
130static void prandom_warmup(struct rnd_state *state)
131{
132 /* Calling RNG ten times to satify recurrence condition */
133 prandom_u32_state(state);
134 prandom_u32_state(state);
135 prandom_u32_state(state);
136 prandom_u32_state(state);
137 prandom_u32_state(state);
138 prandom_u32_state(state);
139 prandom_u32_state(state);
140 prandom_u32_state(state);
141 prandom_u32_state(state);
142 prandom_u32_state(state);
143}
144
129/** 145/**
130 * prandom_seed - add entropy to pseudo random number generator 146 * prandom_seed - add entropy to pseudo random number generator
131 * @seed: seed value 147 * @seed: seed value
@@ -141,8 +157,9 @@ void prandom_seed(u32 entropy)
141 */ 157 */
142 for_each_possible_cpu (i) { 158 for_each_possible_cpu (i) {
143 struct rnd_state *state = &per_cpu(net_rand_state, i); 159 struct rnd_state *state = &per_cpu(net_rand_state, i);
144 state->s1 = __seed(state->s1 ^ entropy, 2); 160
145 prandom_u32_state(state); 161 state->s1 = __seed(state->s1 ^ entropy, 2U);
162 prandom_warmup(state);
146 } 163 }
147} 164}
148EXPORT_SYMBOL(prandom_seed); 165EXPORT_SYMBOL(prandom_seed);
@@ -158,18 +175,13 @@ static int __init prandom_init(void)
158 for_each_possible_cpu(i) { 175 for_each_possible_cpu(i) {
159 struct rnd_state *state = &per_cpu(net_rand_state,i); 176 struct rnd_state *state = &per_cpu(net_rand_state,i);
160 177
161#define LCG(x) ((x) * 69069) /* super-duper LCG */ 178#define LCG(x) ((x) * 69069U) /* super-duper LCG */
162 state->s1 = __seed(LCG(i + jiffies), 2); 179 state->s1 = __seed(LCG((i + jiffies) ^ random_get_entropy()), 2U);
163 state->s2 = __seed(LCG(state->s1), 8); 180 state->s2 = __seed(LCG(state->s1), 8U);
164 state->s3 = __seed(LCG(state->s2), 16); 181 state->s3 = __seed(LCG(state->s2), 16U);
165 182 state->s4 = __seed(LCG(state->s3), 128U);
166 /* "warm it up" */ 183
167 prandom_u32_state(state); 184 prandom_warmup(state);
168 prandom_u32_state(state);
169 prandom_u32_state(state);
170 prandom_u32_state(state);
171 prandom_u32_state(state);
172 prandom_u32_state(state);
173 } 185 }
174 return 0; 186 return 0;
175} 187}
@@ -215,15 +227,15 @@ static void __prandom_reseed(bool late)
215 227
216 for_each_possible_cpu(i) { 228 for_each_possible_cpu(i) {
217 struct rnd_state *state = &per_cpu(net_rand_state,i); 229 struct rnd_state *state = &per_cpu(net_rand_state,i);
218 u32 seeds[3]; 230 u32 seeds[4];
219 231
220 get_random_bytes(&seeds, sizeof(seeds)); 232 get_random_bytes(&seeds, sizeof(seeds));
221 state->s1 = __seed(seeds[0], 2); 233 state->s1 = __seed(seeds[0], 2U);
222 state->s2 = __seed(seeds[1], 8); 234 state->s2 = __seed(seeds[1], 8U);
223 state->s3 = __seed(seeds[2], 16); 235 state->s3 = __seed(seeds[2], 16U);
236 state->s4 = __seed(seeds[3], 128U);
224 237
225 /* mix it in */ 238 prandom_warmup(state);
226 prandom_u32_state(state);
227 } 239 }
228out: 240out:
229 spin_unlock_irqrestore(&lock, flags); 241 spin_unlock_irqrestore(&lock, flags);