5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 1997 - 2000 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
22 * Created: Sun Mar 9 00:09:18 1997
24 * This RNG is based on Secure Shell's random number generator.
26 /* XXX: Some operations block resulting slow initialization.
27 * XXX: I have some pending changes to make this better. */
29 #include "silcincludes.h"
32 /* #define SILC_RNG_DEBUG */
35 SILC SilcRng State context.
37 This object is used by the random number generator to provide
38 variable points where the actual random number is fetched from
39 the random pool. This provides that the data is not fetched always
40 from the same point of the pool. Short description of the fields
46 The index for the random pool buffer. Lowest and current
49 SilcRngStateContext *next
51 Pointer to the next state. If this is the last state this
52 will point to the first state thus providing circular list.
55 typedef struct SilcRngStateContext {
58 struct SilcRngStateContext *next;
62 SILC Random Number Generator object.
64 This object holds random pool which is used to generate the random
65 numbers used by various routines needing cryptographically strong
66 random numbers. Following short descriptions of the fields.
70 The random pool. This buffer holds the random data. This is
71 frequently stirred thus providing ever changing randomnes.
75 Key used in stirring the random pool. The pool is encrypted
76 with SHA1 hash function in CFB (Cipher Feedback) mode.
78 SilcSilcRngState state
80 State object that is used to get the next position for the
81 random pool. This position is used to fetch data from pool
82 or to save the data to the pool. The state changes everytime
87 Hash object (SHA1) used to make the CFB encryption to the
88 random pool. This is allocated when RNG object is allocated and
89 free'd when RNG object is free'd.
92 typedef struct SilcRngObjectStruct {
93 unsigned char pool[SILC_RNG_POOLSIZE];
94 unsigned char key[64];
99 /* Allocates new RNG object. */
101 SilcRng silc_rng_alloc()
105 SILC_LOG_DEBUG(("Allocating new RNG object"));
107 new = silc_calloc(1, sizeof(*new));
109 memset(new->pool, 0, sizeof(new->pool));
110 memset(new->key, 0, sizeof(new->key));
112 silc_hash_alloc("sha1", &new->sha1);
117 /* Free's RNG object. */
119 void silc_rng_free(SilcRng rng)
122 memset(rng->pool, 0, sizeof(rng->pool));
123 memset(rng->key, 0, sizeof(rng->key));
124 silc_free(rng->sha1);
129 /* Initializes random number generator by getting noise from environment.
130 The environmental noise is our so called seed. One should not call
131 this function more than once. */
133 void silc_rng_init(SilcRng rng)
136 SilcRngState first, next;
140 SILC_LOG_DEBUG(("Initializing RNG object"));
142 /* Initialize the states for the RNG. */
143 rng->state = silc_calloc(1, sizeof(*rng->state));
146 rng->state->next = NULL;
148 for (i = SILC_RNG_STATE_NUM - 1; i >= 1; i--) {
149 next = silc_calloc(1, sizeof(*rng->state));
151 (i * (sizeof(rng->pool) / SILC_RNG_STATE_NUM));
153 (i * (sizeof(rng->pool) / SILC_RNG_STATE_NUM)) + 8;
154 next->next = rng->state;
160 memset(rng->pool, 0, sizeof(rng->pool));
162 /* Get noise from various environmental sources */
163 silc_rng_get_soft_noise(rng);
164 silc_rng_get_medium_noise(rng);
165 silc_rng_get_hard_noise(rng);
168 /* This function gets 'soft' noise from environment. */
170 void silc_rng_get_soft_noise(SilcRng rng)
174 silc_rng_xor(rng, clock(), 0);
175 silc_rng_xor(rng, getpid(), 1);
176 silc_rng_xor(rng, getpgid(getpid() << 8), 2);
177 silc_rng_xor(rng, getpgid(getpid() << 8), 3);
178 silc_rng_xor(rng, getgid(), 4);
179 silc_rng_xor(rng, getpgrp(), 5);
180 silc_rng_xor(rng, getsid(getpid() << 16), 6);
181 silc_rng_xor(rng, times(&ptime), 7);
182 silc_rng_xor(rng, ptime.tms_utime, 8);
183 silc_rng_xor(rng, (ptime.tms_utime + ptime.tms_stime), 9);
184 silc_rng_xor(rng, (ptime.tms_stime + ptime.tms_cutime), 10);
185 silc_rng_xor(rng, (ptime.tms_utime + ptime.tms_stime), 11);
186 silc_rng_xor(rng, (ptime.tms_cutime ^ ptime.tms_stime), 12);
187 silc_rng_xor(rng, (ptime.tms_cutime ^ ptime.tms_cstime), 13);
188 silc_rng_xor(rng, (ptime.tms_utime ^ ptime.tms_stime), 14);
189 silc_rng_xor(rng, (ptime.tms_stime ^ ptime.tms_cutime), 15);
190 silc_rng_xor(rng, (ptime.tms_cutime + ptime.tms_stime), 16);
191 silc_rng_xor(rng, (ptime.tms_stime << 8), 17);
192 silc_rng_xor(rng, clock() << 4, 18);
193 silc_rng_xor(rng, getpgid(getpid() << 8), 19);
194 silc_rng_xor(rng, getpgrp(), 20);
195 silc_rng_xor(rng, getsid(getpid() << 16), 21);
196 silc_rng_xor(rng, times(&ptime), 22);
197 silc_rng_xor(rng, ptime.tms_utime, 23);
198 silc_rng_xor(rng, getpgrp(), 24);
200 /* Stir random pool */
201 silc_rng_stir_pool(rng);
204 /* This function gets noise from different commands */
206 void silc_rng_get_medium_noise(SilcRng rng)
208 silc_rng_exec_command(rng, "ps -lefaww 2> /dev/null");
209 silc_rng_exec_command(rng, "ls -afiln 2> /dev/null");
210 silc_rng_exec_command(rng, "ps -asww 2> /dev/null");
211 silc_rng_exec_command(rng, "ls -afiln /proc 2> /dev/null");
213 silc_rng_exec_command(rng, "ps -ef 2> /dev/null");
214 silc_rng_exec_command(rng, "ls -alin /dev 2> /dev/null");
218 /* This function gets 'hard' noise from environment. This tries to
219 get the noise from /dev/random if available. */
221 void silc_rng_get_hard_noise(SilcRng rng)
226 /* Get noise from /dev/random if available */
227 fd = open("/dev/random", O_RDONLY);
231 fcntl(fd, F_SETFL, O_NONBLOCK);
233 for (i = 0; i < 8; i++) {
234 len = read(fd, buf, sizeof(buf));
237 silc_rng_add_noise(rng, buf, len);
242 memset(buf, 0, sizeof(buf));
245 /* Execs command and gets noise from its output */
247 void silc_rng_exec_command(SilcRng rng, char *command)
255 fd = popen(command, "r");
259 /* Get data as much as we can get into the buffer */
260 for (i = 0; i < sizeof(buf); i++) {
272 /* Add the buffer into random pool */
273 silc_rng_add_noise(rng, buf, strlen(buf));
274 memset(buf, 0, sizeof(buf));
277 /* This function adds the contents of the buffer as noise into random
278 pool. After adding the noise the pool is stirred. */
280 void silc_rng_add_noise(SilcRng rng, unsigned char *buffer,
285 pos = silc_rng_get_position(rng);
287 /* Add the buffer one by one into the pool */
288 for(i = 0; i < len; i++, buffer++) {
289 if(pos >= SILC_RNG_POOLSIZE)
291 rng->pool[pos++] ^= *buffer;
294 /* Stir random pool */
295 silc_rng_stir_pool(rng);
298 /* XOR's data into the pool */
300 void silc_rng_xor(SilcRng rng, unsigned int val, unsigned int pos)
303 rng->pool[pos] ^= val + val;
306 /* This function stirs the random pool by encrypting buffer in CFB
307 (cipher feedback) mode with SHA1 algorithm. */
309 void silc_rng_stir_pool(SilcRng rng)
315 memcpy(iv, &rng->pool[SILC_RNG_POOLSIZE - 256], sizeof(iv));
318 for (i = 0; i < SILC_RNG_POOLSIZE; i += 5) {
319 rng->sha1->hash->transform(iv, rng->key);
320 iv[0] = rng->pool[i] ^= iv[0];
321 iv[1] = rng->pool[i + 1] ^= iv[1];
322 iv[2] = rng->pool[i + 2] ^= iv[2];
323 iv[3] = rng->pool[i + 3] ^= iv[3];
324 iv[4] = rng->pool[i + 4] ^= iv[4];
328 memcpy(rng->key, &rng->pool[silc_rng_get_position(rng)], sizeof(rng->key));
330 /* Second CFB pass */
331 for (i = 0; i < SILC_RNG_POOLSIZE; i += 5) {
332 rng->sha1->hash->transform(iv, rng->key);
333 iv[0] = rng->pool[i] ^= iv[0];
334 iv[1] = rng->pool[i + 1] ^= iv[1];
335 iv[2] = rng->pool[i + 2] ^= iv[2];
336 iv[3] = rng->pool[i + 3] ^= iv[3];
337 iv[4] = rng->pool[i + 4] ^= iv[4];
340 memset(iv, 0, sizeof(iv));
343 /* Returns next position where data is fetched from the pool or
346 unsigned int silc_rng_get_position(SilcRng rng)
351 next = rng->state->next;
353 pos = rng->state->pos++;
354 if ((next->low != 0 && pos >= next->low) || (pos >= SILC_RNG_POOLSIZE))
355 rng->state->pos = rng->state->low;
357 #ifdef SILC_RNG_DEBUG
358 fprintf(stderr, "state: %p: low: %d, pos: %d\n",
359 rng->state, rng->state->low, rng->state->pos);
367 /* returns random byte. Every two byte is from pools low or high state. */
369 unsigned char silc_rng_get_byte(SilcRng rng)
371 return rng->pool[silc_rng_get_position(rng)];
374 /* Returns 16 bit random number */
376 unsigned short silc_rng_get_rn16(SilcRng rng)
381 rn[0] = silc_rng_get_byte(rng);
382 rn[1] = silc_rng_get_byte(rng);
383 SILC_GET16_MSB(num, rn);
388 /* Returns 32 bit random number */
390 unsigned int silc_rng_get_rn32(SilcRng rng)
395 rn[0] = silc_rng_get_byte(rng);
396 rn[1] = silc_rng_get_byte(rng);
397 rn[2] = silc_rng_get_byte(rng);
398 rn[3] = silc_rng_get_byte(rng);
399 SILC_GET32_MSB(num, rn);
404 /* Returns random number string. Returned string is in HEX format. */
406 unsigned char *silc_rng_get_rn_string(SilcRng rng, unsigned int len)
409 unsigned char *string;
411 string = silc_calloc((len * 2 + 1), sizeof(unsigned char));
413 for (i = 0; i < len; i++)
414 sprintf(string + 2 * i, "%02x", silc_rng_get_byte(rng));
419 /* Returns random number binary data. */
421 unsigned char *silc_rng_get_rn_data(SilcRng rng, unsigned int len)
426 data = silc_calloc(len + 1, sizeof(*data));
428 for (i = 0; i < len; i++)
429 data[i] = silc_rng_get_byte(rng);