Symbian compilation fixes.
[silc.git] / lib / silccrypt / silcrng.c
1 /*
2
3   silcrng.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2003 Pekka Riikonen
8
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; version 2 of the License.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18 */
19 /* $Id$ */
20 /*
21  * Created: Sun Mar  9 00:09:18 1997
22  *
23  * The original RNG was based on Secure Shell's random number generator
24  * by Tatu Ylönen and was used as reference when programming this RNG.
25  * This RNG has been rewritten twice since the creation.
26  */
27
28 #include "silc.h"
29
30 #ifndef WIN32
31 #ifdef HAVE_GETSID
32 extern pid_t getsid (pid_t __pid);
33 #endif
34
35 #ifdef HAVE_GETPGID
36 extern pid_t getpgid (pid_t __pid);
37 #endif
38 #endif
39
40 #undef SILC_RNG_DEBUG
41 /*#define SILC_RNG_DEBUG*/
42
43 /* Number of states to fetch data from pool. */
44 #define SILC_RNG_STATE_NUM 4
45
46 /* Byte size of the random data pool. */
47 #define SILC_RNG_POOLSIZE (20 * 48)
48
49 static SilcUInt32 silc_rng_get_position(SilcRng rng);
50 static void silc_rng_stir_pool(SilcRng rng);
51 static void silc_rng_xor(SilcRng rng, SilcUInt32 val, unsigned int pos);
52 static void silc_rng_exec_command(SilcRng rng, char *command);
53 static void silc_rng_get_hard_noise(SilcRng rng);
54 static void silc_rng_get_medium_noise(SilcRng rng);
55 static void silc_rng_get_soft_noise(SilcRng rng);
56
57 /*
58    SILC SilcRng State context.
59
60    This object is used by the random number generator to provide
61    variable points where the actual random number is fetched from
62    the random pool. This provides that the data is not fetched always
63    from the same point of the pool. Short description of the fields
64    following.
65
66    SilcUInt32 low
67    SilcUInt32 pos
68
69        The index for the random pool buffer. Lowest and current
70        positions.
71
72    SilcRngStateContext *next
73
74        Pointer to the next state. If this is the last state this
75        will point to the first state thus providing circular list.
76
77 */
78 typedef struct SilcRngStateContext {
79   SilcUInt32 low;
80   SilcUInt32 pos;
81   struct SilcRngStateContext *next;
82 } *SilcRngState;
83
84 /*
85    SILC Random Number Generator object.
86
87    This object holds random pool which is used to generate the random
88    numbers used by various routines needing cryptographically strong
89    random numbers. Following short descriptions of the fields.
90
91    unsigned char pool[]
92
93        The random pool. This buffer holds the random data. This is
94        frequently stirred thus providing ever changing randomnes.
95
96    unsigned char key[64]
97
98        Key used in stirring the random pool. The pool is encrypted
99        with SHA1 hash function in CFB (Cipher Feedback) mode.
100
101    SilcSilcRngState state
102
103        State object that is used to get the next position for the
104        random pool. This position is used to fetch data from pool
105        or to save the data to the pool. The state changes everytime
106        SilcRng is used.
107
108    SilcHash sha1
109
110        Hash object (SHA1) used to make the CFB encryption to the
111        random pool. This is allocated when RNG object is allocated and
112        free'd when RNG object is free'd.
113
114    SilcUInt8 threshold
115
116        Threshold to indicate when it is required to acquire more
117        noise from the environment.  More soft noise is acquired after
118        64 bits of output and hard noise every 160 bits of output.
119
120 */
121 struct SilcRngStruct {
122   unsigned char pool[SILC_RNG_POOLSIZE];
123   unsigned char key[64];
124   SilcRngState state;
125   SilcHash sha1;
126   SilcUInt8 threshold;
127   char *devrandom;
128   int fd_devurandom;
129 };
130
131 /* Allocates new RNG object. */
132
133 SilcRng silc_rng_alloc(void)
134 {
135   SilcRng new;
136
137   SILC_LOG_DEBUG(("Allocating new RNG object"));
138
139   new = silc_calloc(1, sizeof(*new));
140   new->fd_devurandom = -1;
141
142   memset(new->pool, 0, sizeof(new->pool));
143   memset(new->key, 0, sizeof(new->key));
144   new->state = NULL;
145   if (!silc_hash_alloc("sha1", &new->sha1)) {
146     silc_free(new);
147     SILC_LOG_ERROR(("Could not allocate sha1 hash, probably not registered"));
148     return NULL;
149   }
150
151   new->devrandom = strdup("/dev/random");
152
153   return new;
154 }
155
156 /* Free's RNG object. */
157
158 void silc_rng_free(SilcRng rng)
159 {
160   if (rng) {
161     SilcRngState t, n;
162
163     memset(rng->pool, 0, sizeof(rng->pool));
164     memset(rng->key, 0, sizeof(rng->key));
165     silc_hash_free(rng->sha1);
166     silc_free(rng->devrandom);
167
168     if (rng->fd_devurandom != -1)
169       close(rng->fd_devurandom);
170
171     for (t = rng->state->next; t != rng->state; ) {
172       n = t->next;
173       silc_free(t);
174       t = n;
175     }
176     silc_free(rng->state);
177
178     silc_free(rng);
179   }
180 }
181
182 /* Initializes random number generator by getting noise from environment.
183    The environmental noise is our so called seed. One should not call
184    this function more than once. */
185
186 void silc_rng_init(SilcRng rng)
187 {
188   int i;
189   SilcRngState first, next;
190
191   assert(rng != NULL);
192
193   SILC_LOG_DEBUG(("Initializing RNG object"));
194
195   /* Initialize the states for the RNG. */
196   rng->state = silc_calloc(1, sizeof(*rng->state));
197   rng->state->low = 0;
198   rng->state->pos = 8;
199   rng->state->next = NULL;
200   first = rng->state;
201   for (i = SILC_RNG_STATE_NUM - 1; i >= 1; i--) {
202     next = silc_calloc(1, sizeof(*rng->state));
203     next->low =
204       (i * (sizeof(rng->pool) / SILC_RNG_STATE_NUM));
205     next->pos =
206       (i * (sizeof(rng->pool) / SILC_RNG_STATE_NUM)) + 8;
207     next->next = rng->state;
208     rng->state = next;
209   }
210   first->next = next;
211   rng->state = first;
212
213   memset(rng->pool, 0, sizeof(rng->pool));
214
215   /* Get noise from various environmental sources */
216   silc_rng_get_soft_noise(rng);
217   silc_rng_get_medium_noise(rng);
218   silc_rng_get_hard_noise(rng);
219   silc_rng_get_soft_noise(rng);
220   silc_free(rng->devrandom);
221   rng->devrandom = strdup("/dev/urandom");
222 }
223
224 /* This function gets 'soft' noise from environment. */
225
226 static void silc_rng_get_soft_noise(SilcRng rng)
227 {
228 #ifndef SILC_WIN32
229   struct tms ptime;
230 #endif
231   SilcUInt32 pos;
232 #ifdef HAVE_GETRUSAGE
233   struct rusage r;
234 #endif
235
236   pos = silc_rng_get_position(rng);
237
238   silc_rng_xor(rng, clock(), 0);
239 #ifndef SILC_WIN32
240 #ifdef HAVE_GETPID
241   silc_rng_xor(rng, getpid(), 1);
242 #ifdef HAVE_GETPGID
243   silc_rng_xor(rng, getpgid(getpid()) << 8, 2);
244   silc_rng_xor(rng, getpgid(getpid()) << 8, 3);
245 #endif
246   silc_rng_xor(rng, getgid(), 4);
247 #endif
248 #ifdef HAVE_GETPGRP
249   silc_rng_xor(rng, getpgrp(), 5);
250 #endif
251 #ifdef HAVE_GETSID
252   silc_rng_xor(rng, getsid(getpid()) << 16, 6);
253 #endif
254   silc_rng_xor(rng, times(&ptime), 7);
255   silc_rng_xor(rng, ptime.tms_utime, 8);
256   silc_rng_xor(rng, (ptime.tms_utime + ptime.tms_stime), pos++);
257   silc_rng_xor(rng, (ptime.tms_stime + ptime.tms_cutime), pos++);
258   silc_rng_xor(rng, (ptime.tms_utime + ptime.tms_stime), pos++);
259   silc_rng_xor(rng, (ptime.tms_cutime ^ ptime.tms_stime), pos++);
260   silc_rng_xor(rng, (ptime.tms_cutime ^ ptime.tms_cstime), pos++);
261   silc_rng_xor(rng, (ptime.tms_utime ^ ptime.tms_stime), pos++);
262   silc_rng_xor(rng, (ptime.tms_stime ^ ptime.tms_cutime), pos++);
263   silc_rng_xor(rng, (ptime.tms_cutime + ptime.tms_stime), pos++);
264   silc_rng_xor(rng, (ptime.tms_stime << 8), pos++);
265 #endif
266   silc_rng_xor(rng, clock() << 4, pos++);
267 #ifndef SILC_WIN32
268 #ifdef HAVE_GETPGID
269   silc_rng_xor(rng, getpgid(getpid()) << 8, pos++);
270 #endif
271 #ifdef HAVE_GETPGRP
272   silc_rng_xor(rng, getpgrp(), pos++);
273 #endif
274 #ifdef HAVE_SETSID
275   silc_rng_xor(rng, getsid(getpid()) << 16, pos++);
276 #endif
277   silc_rng_xor(rng, times(&ptime), pos++);
278   silc_rng_xor(rng, ptime.tms_utime, pos++);
279 #ifdef HAVE_GETPGRP
280   silc_rng_xor(rng, getpgrp(), pos++);
281 #endif
282 #endif
283 #ifdef HAVE_GETRUSAGE
284   getrusage(RUSAGE_SELF, &r);
285   silc_rng_xor(rng, (r.ru_utime.tv_sec + r.ru_utime.tv_usec), pos++);
286   silc_rng_xor(rng, (r.ru_utime.tv_sec ^ r.ru_utime.tv_usec), pos++);
287   silc_rng_xor(rng, (r.ru_stime.tv_sec + r.ru_stime.tv_usec), pos++);
288   silc_rng_xor(rng, (r.ru_stime.tv_sec ^ r.ru_stime.tv_usec), pos++);
289 #ifndef SILC_SYMBIAN
290   silc_rng_xor(rng, (r.ru_maxrss + r.ru_ixrss), pos++);
291   silc_rng_xor(rng, (r.ru_maxrss ^ r.ru_ixrss), pos++);
292   silc_rng_xor(rng, (r.ru_idrss + r.ru_idrss), pos++);
293   silc_rng_xor(rng, (r.ru_idrss ^ r.ru_idrss), pos++);
294   silc_rng_xor(rng, (r.ru_idrss << 16), pos++);
295   silc_rng_xor(rng, (r.ru_minflt + r.ru_majflt), pos++);
296   silc_rng_xor(rng, (r.ru_minflt ^ r.ru_majflt), pos++);
297   silc_rng_xor(rng, (r.ru_nswap + r.ru_oublock + r.ru_inblock), pos++);
298   silc_rng_xor(rng, (r.ru_nswap << 8), pos++);
299   silc_rng_xor(rng, (r.ru_inblock + r.ru_oublock), pos++);
300   silc_rng_xor(rng, (r.ru_inblock ^ r.ru_oublock), pos++);
301   silc_rng_xor(rng, (r.ru_msgsnd ^ r.ru_msgrcv), pos++);
302   silc_rng_xor(rng, (r.ru_nsignals + r.ru_msgsnd + r.ru_msgrcv), pos++);
303   silc_rng_xor(rng, (r.ru_nsignals << 16), pos++);
304   silc_rng_xor(rng, (r.ru_nvcsw + r.ru_nivcsw), pos++);
305   silc_rng_xor(rng, (r.ru_nvcsw ^ r.ru_nivcsw), pos++);
306 #endif /* SILC_SYMBIAN */
307 #endif /* HAVE_GETRUSAGE */
308   
309 #ifdef SILC_RNG_DEBUG
310   SILC_LOG_HEXDUMP(("pool"), rng->pool, sizeof(rng->pool));
311 #endif
312
313   /* Stir random pool */
314   silc_rng_stir_pool(rng);
315 }
316
317 /* This function gets noise from different commands */
318
319 static void silc_rng_get_medium_noise(SilcRng rng)
320 {
321   /* If getrusage is available, there is no need for shell commands */
322 #ifdef HAVE_GETRUSAGE
323   return;
324 #endif
325   silc_rng_exec_command(rng, "ps -leaww 2> /dev/null");
326   silc_rng_exec_command(rng, "ls -afiln ~ 2> /dev/null");
327   silc_rng_exec_command(rng, "ls -afiln /proc 2> /dev/null");
328   silc_rng_exec_command(rng, "ps -axww 2> /dev/null");
329
330 #ifdef SILC_RNG_DEBUG
331   SILC_LOG_HEXDUMP(("pool"), rng->pool, sizeof(rng->pool));
332 #endif
333 }
334
335 /* This function gets 'hard' noise from environment. This tries to
336    get the noise from /dev/random if available. */
337
338 static void silc_rng_get_hard_noise(SilcRng rng)
339 {
340 #if defined(SILC_UNIX)
341   unsigned char buf[32];
342   int fd, len, i;
343
344   /* Get noise from /dev/[u]random if available */
345   fd = open(rng->devrandom, O_RDONLY);
346   if (fd < 0)
347     return;
348
349   fcntl(fd, F_SETFL, O_NONBLOCK);
350
351   for (i = 0; i < 2; i++) {
352     len = read(fd, buf, sizeof(buf));
353     if (len <= 0)
354       goto out;
355     silc_rng_add_noise(rng, buf, len);
356   }
357
358 #ifdef SILC_RNG_DEBUG
359   SILC_LOG_HEXDUMP(("pool"), rng->pool, sizeof(rng->pool));
360 #endif
361
362  out:
363   close(fd);
364   memset(buf, 0, sizeof(buf));
365 #endif
366 }
367
368 /* Execs command and gets noise from its output */
369
370 static void silc_rng_exec_command(SilcRng rng, char *command)
371 {
372 #if defined(SILC_UNIX)
373   unsigned char buf[1024];
374   FILE *fd;
375   int i;
376   int c;
377
378   /* Open process */
379   fd = popen(command, "r");
380   if (!fd)
381     return;
382
383   /* Get data as much as we can get into the buffer */
384   for (i = 0; i < sizeof(buf); i++) {
385     c = fgetc(fd);
386     if (c == EOF)
387       break;
388     buf[i] = c;
389   }
390
391   pclose(fd);
392
393   if (i != 0) {
394     /* Add the buffer into random pool */
395     silc_rng_add_noise(rng, buf, i);
396     memset(buf, 0, sizeof(buf));
397   }
398 #endif
399 }
400
401 /* This function adds the contents of the buffer as noise into random
402    pool. After adding the noise the pool is stirred. */
403
404 void silc_rng_add_noise(SilcRng rng, unsigned char *buffer, SilcUInt32 len)
405 {
406   SilcUInt32 i, pos;
407
408   pos = silc_rng_get_position(rng);
409
410   /* Add the buffer one by one into the pool */
411   for(i = 0; i < len; i++, buffer++) {
412     if(pos >= SILC_RNG_POOLSIZE)
413       break;
414     rng->pool[pos++] ^= *buffer;
415   }
416
417   /* Stir random pool */
418   silc_rng_stir_pool(rng);
419 }
420
421 /* XOR's data into the pool */
422
423 static void silc_rng_xor(SilcRng rng, SilcUInt32 val, unsigned int pos)
424 {
425   SilcUInt32 tmp;
426
427   SILC_GET32_MSB(tmp, &rng->pool[pos]);
428   val ^= tmp + val;
429   SILC_PUT32_MSB(val, &rng->pool[pos]);
430 }
431
432 /* This function stirs the random pool by encrypting buffer in CFB
433    (cipher feedback) mode with SHA1 algorithm. */
434
435 static void silc_rng_stir_pool(SilcRng rng)
436 {
437   int i;
438   SilcUInt32 iv[5], tmp;
439
440   /* Get the IV */
441   SILC_GET32_MSB(iv[0], &rng->pool[16     ]);
442   SILC_GET32_MSB(iv[1], &rng->pool[16 +  4]);
443   SILC_GET32_MSB(iv[2], &rng->pool[16 +  8]);
444   SILC_GET32_MSB(iv[3], &rng->pool[16 + 12]);
445   SILC_GET32_MSB(iv[4], &rng->pool[16 + 16]);
446
447   /* First CFB pass */
448   for (i = 0; i < SILC_RNG_POOLSIZE; i += 20) {
449     silc_hash_transform(rng->sha1, iv, rng->key);
450
451     SILC_GET32_MSB(tmp, &rng->pool[i]);
452     iv[0] ^= tmp;
453     SILC_PUT32_MSB(iv[0], &rng->pool[i]);
454
455     SILC_GET32_MSB(tmp, &rng->pool[i + 4]);
456     iv[1] ^= tmp;
457     SILC_PUT32_MSB(iv[1], &rng->pool[i + 4]);
458
459     SILC_GET32_MSB(tmp, &rng->pool[i + 8]);
460     iv[2] ^= tmp;
461     SILC_PUT32_MSB(iv[2], &rng->pool[i + 8]);
462
463     SILC_GET32_MSB(tmp, &rng->pool[i + 12]);
464     iv[3] ^= tmp;
465     SILC_PUT32_MSB(iv[3], &rng->pool[i + 12]);
466
467     SILC_GET32_MSB(tmp, &rng->pool[i + 16]);
468     iv[4] ^= tmp;
469     SILC_PUT32_MSB(iv[4], &rng->pool[i + 16]);
470   }
471
472   /* Get new key */
473   memcpy(rng->key, &rng->pool[silc_rng_get_position(rng)], sizeof(rng->key));
474
475   /* Second CFB pass */
476   for (i = 0; i < SILC_RNG_POOLSIZE; i += 20) {
477     silc_hash_transform(rng->sha1, iv, rng->key);
478
479     SILC_GET32_MSB(tmp, &rng->pool[i]);
480     iv[0] ^= tmp;
481     SILC_PUT32_MSB(iv[0], &rng->pool[i]);
482
483     SILC_GET32_MSB(tmp, &rng->pool[i + 4]);
484     iv[1] ^= tmp;
485     SILC_PUT32_MSB(iv[1], &rng->pool[i + 4]);
486
487     SILC_GET32_MSB(tmp, &rng->pool[i + 8]);
488     iv[2] ^= tmp;
489     SILC_PUT32_MSB(iv[2], &rng->pool[i + 8]);
490
491     SILC_GET32_MSB(tmp, &rng->pool[i + 12]);
492     iv[3] ^= tmp;
493     SILC_PUT32_MSB(iv[3], &rng->pool[i + 12]);
494
495     SILC_GET32_MSB(tmp, &rng->pool[i + 16]);
496     iv[4] ^= tmp;
497     SILC_PUT32_MSB(iv[4], &rng->pool[i + 16]);
498   }
499
500   memset(iv, 0, sizeof(iv));
501 }
502
503 /* Returns next position where data is fetched from the pool or
504    put to the pool. */
505
506 static SilcUInt32 silc_rng_get_position(SilcRng rng)
507 {
508   SilcRngState next;
509   SilcUInt32 pos;
510
511   next = rng->state->next;
512
513   pos = rng->state->pos++;
514   if ((next->low != 0 && pos >= next->low) || (pos >= SILC_RNG_POOLSIZE))
515     rng->state->pos = rng->state->low;
516
517 #ifdef SILC_RNG_DEBUG
518     fprintf(stderr, "state: %p: low: %lu, pos: %lu\n",
519             rng->state, rng->state->low, rng->state->pos);
520 #endif
521
522   rng->state = next;
523
524   return pos;
525 }
526
527 /* Returns random byte. */
528
529 SilcUInt8 silc_rng_get_byte(SilcRng rng)
530 {
531   SilcUInt8 byte;
532
533   rng->threshold++;
534
535   /* Get more soft noise after 64 bits threshold */
536   if (rng->threshold >= 8)
537     silc_rng_get_soft_noise(rng);
538
539   /* Get hard noise after 160 bits threshold, zero the threshold. */
540   if (rng->threshold >= 20) {
541     rng->threshold = 0;
542     silc_rng_get_hard_noise(rng);
543   }
544
545   do byte = rng->pool[silc_rng_get_position(rng)]; while (byte == 0x00);
546   return byte;
547 }
548
549 /* Return random byte as fast as possible. Reads from /dev/urandom if
550    available. If not then return from normal RNG (not so fast). */
551
552 SilcUInt8 silc_rng_get_byte_fast(SilcRng rng)
553 {
554 #if defined(SILC_UNIX)
555   unsigned char buf[1];
556
557   if (rng->fd_devurandom == -1) {
558     rng->fd_devurandom = open("/dev/urandom", O_RDONLY);
559     if (rng->fd_devurandom < 0)
560       return silc_rng_get_byte(rng);
561     fcntl(rng->fd_devurandom, F_SETFL, O_NONBLOCK);
562   }
563
564   if (read(rng->fd_devurandom, buf, sizeof(buf)) < 0)
565     return silc_rng_get_byte(rng);
566
567   return buf[0] != 0x00 ? buf[0] : silc_rng_get_byte(rng);
568 #else
569   return silc_rng_get_byte(rng);
570 #endif
571 }
572
573 /* Returns 16 bit random number */
574
575 SilcUInt16 silc_rng_get_rn16(SilcRng rng)
576 {
577   unsigned char rn[2];
578   SilcUInt16 num;
579
580   rn[0] = silc_rng_get_byte(rng);
581   rn[1] = silc_rng_get_byte(rng);
582   SILC_GET16_MSB(num, rn);
583
584   return num;
585 }
586
587 /* Returns 32 bit random number */
588
589 SilcUInt32 silc_rng_get_rn32(SilcRng rng)
590 {
591   unsigned char rn[4];
592   SilcUInt32 num;
593
594   rn[0] = silc_rng_get_byte(rng);
595   rn[1] = silc_rng_get_byte(rng);
596   rn[2] = silc_rng_get_byte(rng);
597   rn[3] = silc_rng_get_byte(rng);
598   SILC_GET32_MSB(num, rn);
599
600   return num;
601 }
602
603 /* Returns non-zero random number string. Returned string is in HEX format. */
604
605 unsigned char *silc_rng_get_rn_string(SilcRng rng, SilcUInt32 len)
606 {
607   int i;
608   unsigned char *string;
609
610   string = silc_calloc((len * 2 + 1), sizeof(unsigned char));
611
612   for (i = 0; i < len; i++)
613     sprintf(string + 2 * i, "%02x", silc_rng_get_byte(rng));
614
615   return string;
616 }
617
618 /* Returns non-zero random number binary data. */
619
620 unsigned char *silc_rng_get_rn_data(SilcRng rng, SilcUInt32 len)
621 {
622   int i;
623   unsigned char *data;
624
625   data = silc_calloc(len + 1, sizeof(*data));
626
627   for (i = 0; i < len; i++)
628     data[i] = silc_rng_get_byte(rng);
629
630   return data;
631 }
632
633 /* Global RNG. This is global RNG that application can initialize so
634    that any part of code anywhere can use RNG without having to allocate
635    new RNG object everytime.  If this is not initialized then these routines
636    will fail.  Note: currently in SILC applications always initialize this. */
637
638 SilcRng global_rng = NULL;
639
640 /* Initialize global RNG. If `rng' is provided it is set as the global
641    RNG object (it can be allocated by the application for example). */
642
643 SilcBool silc_rng_global_init(SilcRng rng)
644 {
645   if (rng) {
646     global_rng = rng;
647     return TRUE;
648   }
649
650   global_rng = silc_rng_alloc();
651   silc_rng_init(global_rng);
652
653   return TRUE;
654 }
655
656 /* Uninitialize global RNG */
657
658 SilcBool silc_rng_global_uninit(void)
659 {
660   if (global_rng) {
661     silc_rng_free(global_rng);
662     global_rng = NULL;
663   }
664
665   return TRUE;
666 }
667
668 /* These are analogous to the functions above. */
669
670 SilcUInt8 silc_rng_global_get_byte(void)
671 {
672   return global_rng ? silc_rng_get_byte(global_rng) : 0;
673 }
674
675 /* Return random byte as fast as possible. Reads from /dev/urandom if
676    available. If not then return from normal RNG (not so fast). */
677
678 SilcUInt8 silc_rng_global_get_byte_fast(void)
679 {
680   return global_rng ? silc_rng_get_byte_fast(global_rng) : 0;
681 }
682
683 SilcUInt16 silc_rng_global_get_rn16(void)
684 {
685   return global_rng ? silc_rng_get_rn16(global_rng) : 0;
686 }
687
688 SilcUInt32 silc_rng_global_get_rn32(void)
689 {
690   return global_rng ? silc_rng_get_rn32(global_rng) : 0;
691 }
692
693 unsigned char *silc_rng_global_get_rn_string(SilcUInt32 len)
694 {
695   return global_rng ? silc_rng_get_rn_string(global_rng, len) : NULL;
696 }
697
698 unsigned char *silc_rng_global_get_rn_data(SilcUInt32 len)
699 {
700   return global_rng ? silc_rng_get_rn_data(global_rng, len) : NULL;
701 }
702
703 void silc_rng_global_add_noise(unsigned char *buffer, SilcUInt32 len)
704 {
705   if (global_rng)
706     silc_rng_add_noise(global_rng, buffer, len);
707 }