3 * $Id: rand.c,v 1.2 1997/08/07 09:47:07 mdw Exp $
5 * Random number generation
10 /*----- Licencing notice --------------------------------------------------*
12 * This file is part of Become.
14 * Become is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
19 * Become is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with `become'; if not, write to the Free Software Foundation,
26 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29 /*----- Revision history --------------------------------------------------*
32 * Revision 1.2 1997/08/07 09:47:07 mdw
33 * Fix address of the FSF.
35 * Revision 1.1 1997/08/07 09:46:05 mdw
36 * New source file added to maintain a randomness pool.
40 /*----- Header files ------------------------------------------------------*/
42 /* --- ANSI headers --- */
51 /* --- Local headers --- */
61 /*----- Magic numbers -----------------------------------------------------*/
63 #define rand__seedBits 512 /* Number of random seed bits */
65 /*----- Persistant state --------------------------------------------------*/
67 static unsigned char rand__pool
[rand__seedBits
/ 8]; /* Entropy pool */
68 static size_t rand__i
= 0; /* Index into entropy pool */
69 static size_t rand__r
= 0; /* Rotation to apply to next byte */
71 /*----- Main code ---------------------------------------------------------*/
73 /* --- @rand_read@ --- *
75 * Arguments: @FILE *fp@ = pointer to file to read from
79 * Use: Reads a random number seed from the stream.
82 void rand_read(FILE *fp
)
84 tx_getBits(rand__pool
, rand__seedBits
, fp
);
87 T( traceblk(TRACE_RAND
, "rand: loaded randomness pool",
88 rand__pool
, sizeof(rand__pool
)); )
91 /* --- @rand_write@ --- *
93 * Arguments: @FILE *fp@ = pointer to file to write on
97 * Use: Writes a random number seed back to the stream.
100 void rand_write(FILE *fp
)
103 tx_putBits(rand__pool
, rand__seedBits
, fp
);
106 /* --- @rand_clear@ --- *
112 * Use: Clears the random number pool.
115 void rand_clear(void)
117 memset(rand__pool
, 0, sizeof(rand__pool
));
118 T( trace(TRACE_RAND
, "rand: cleared randomness pool"); )
123 /* --- @rand_encrypt@ --- *
125 * Arguments: @icrypt_job *j@ = pointer to an encryption job to apply
129 * Use: Encrypts the randomness pool with a given key. This should
130 * be done before use, in case the pool gets compromised.
133 void rand_encrypt(icrypt_job
*j
)
135 icrypt_encrypt(j
, rand__pool
, rand__pool
, sizeof(rand__pool
));
138 T( traceblk(TRACE_RAND
, "encrypted randomness pool",
139 rand__pool
, sizeof(rand__pool
)); )
142 /* --- @rand_add@ --- *
144 * Arguments: @const void *p@ = pointer to some data
145 * @size_t sz@ = size of the data in bytes
149 * Use: Adds entropy to the pool.
152 void rand_add(const void *p
, size_t sz
)
156 * Entropy is inserted byte-by-byte. The method used is derived from
157 * Linux's `drivers/char/random.c', which is in turn appears to be inspired
160 * Imagine the randomness pool as 8 parallel shift registers. To insert
161 * a byte into the pool, XOR it with bytes picked according to a primitive
162 * polynomial mod 2, and rotate one place to the left. (The rotation is
163 * from SHA-1; it introduces some interaction between the registers.)
167 const unsigned char *cp
= p
;
168 size_t mask
= (rand__seedBits
/ 8) - 1;
172 /* --- Ensure the polynomial is valid --- *
174 * The current polynomal is %$x^{64} + x^4 + x^3 + x + 1$% (picked from
175 * Schneier's excellent book). If the pool size changes, though, I'll
176 * need another polynomial.
179 #if rand__seedBits / 8 != 64
180 # error Change the polynomal in rand_add
183 T( traceblk(TRACE_RAND
, "rand: incoming entropy", p
, sz
); )
185 /* --- Add values to the entropy pool --- */
190 x
= ((x
<< r
) | (x
>> (8 - r
)));
191 x
^= (rand__pool
[i
] ^
192 rand__pool
[(i
+ 1) & mask
] ^
193 rand__pool
[(i
+ 3) & mask
] ^
194 rand__pool
[(i
+ 4) & mask
]);
195 rand__pool
[i
] = ((x
<< 1) | (x
>> 7)) & 0xffu
;
201 /* --- Update the global counters --- */
206 T( traceblk(TRACE_RAND
, "rand: added some entropy",
207 rand__pool
, sizeof(rand__pool
)); )
210 /* --- @rand_extract@ --- *
212 * Arguments: @unsigned char *b@ = pointer to output buffer
213 * @size_t sz@ = number of bytes wanted
217 * Use: Produces a number of random bytes.
220 void rand_extract(unsigned char *b
, size_t sz
)
224 * Hash the buffer with a secure hash (or, in this case, with MD5 and hope
225 * for the best...). If this gives us enough bytes, fill the output
226 * buffer; otherwise copy the whole hash out. The contribute the hash back
227 * into the randomness pool with @rand_add@ to provide some feedback.
229 * The secure hash gives us good mixing over the whole of the randomness
230 * pool, and attempts to ensure that an attacker receiving our random
231 * numbers can't predict any numbers we don't actually give him.
235 unsigned char mdbuf
[MD5_HASHSIZE
];
238 T( trace(TRACE_RAND
, "rand: extracting entropy"); )
241 c
= (sz
>= sizeof(mdbuf
)) ?
sizeof(mdbuf
) : sz
;
243 md5_buffer(&md
, rand__pool
, sizeof(rand__pool
));
244 md5_final(&md
, mdbuf
);
249 burn(mdbuf
); burn(md
);
251 T( trace(TRACE_RAND
, "rand: finished extracting entropy"); )
254 /* --- @rand_churn@ --- *
260 * Use: Churns the randomness pool completely. The pool is replaced
261 * by repeated MD5-ings of itself.
264 void rand_churn(void)
267 unsigned char mdbuf
[MD5_HASHSIZE
];
268 size_t sz
= sizeof(rand__pool
);
271 T( trace(TRACE_RAND
, "rand: churning pool"); )
277 c
= (sz
>= sizeof(mdbuf
)) ?
sizeof(mdbuf
) : sz
;
279 md5_buffer(&md
, rand__pool
, sizeof(rand__pool
));
280 md5_final(&md
, mdbuf
);
288 burn(mdbuf
); burn(md
);
290 T( trace(TRACE_RAND
, "rand: finished churning pool"); )
293 /*----- That's all, folks -------------------------------------------------*/