X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=lib%2Fsilccrypt%2Fsilcrng.c;h=e9fe1c81ffe3d596b1572aeafa355104f388a2dc;hb=017dec75a98209fbef49eb496c2269b0c49e736d;hp=df7282dc3e1ca72ee0921af9362ace075ba7473e;hpb=fc45634d85fcdbc50e9db4f26cd90dbaffeadeb1;p=silc.git diff --git a/lib/silccrypt/silcrng.c b/lib/silccrypt/silcrng.c index df7282dc..e9fe1c81 100644 --- a/lib/silccrypt/silcrng.c +++ b/lib/silccrypt/silcrng.c @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 1997 - 2000 Pekka Riikonen + Copyright (C) 1997 - 2001 Pekka Riikonen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,32 +17,33 @@ GNU General Public License for more details. */ +/* $Id$ */ /* * Created: Sun Mar 9 00:09:18 1997 * - * This RNG is based on Secure Shell's random number generator. - */ -/* XXX: Some operations block resulting slow initialization. - * XXX: I have some pending changes to make this better. */ -/* - * $Id$ - * $Log$ - * Revision 1.3 2000/07/10 05:36:14 priikone - * Added silc_rng_get_rng_data to get variable length binary data. - * - * Revision 1.2 2000/07/05 06:08:43 priikone - * Global cosmetic change. - * - * Revision 1.1.1.1 2000/06/27 11:36:55 priikone - * Imported from internal CVS/Added Log headers. - * - * + * The original RNG was based on Secure Shell's random number generator + * by Tatu Ylönen and was used as reference when programming this RNG. + * This RNG has been rewritten twice since the creation. */ #include "silcincludes.h" #undef SILC_RNG_DEBUG -/* #define SILC_RNG_DEBUG */ +/*#define SILC_RNG_DEBUG*/ + +/* Number of states to fetch data from pool. */ +#define SILC_RNG_STATE_NUM 4 + +/* Byte size of the random data pool. */ +#define SILC_RNG_POOLSIZE 1024 + +static uint32 silc_rng_get_position(SilcRng rng); +static void silc_rng_stir_pool(SilcRng rng); +static void silc_rng_xor(SilcRng rng, uint32 val, unsigned int pos); +static void silc_rng_exec_command(SilcRng rng, char *command); +static void silc_rng_get_hard_noise(SilcRng rng); +static void silc_rng_get_medium_noise(SilcRng rng); +static void silc_rng_get_soft_noise(SilcRng rng); /* SILC SilcRng State context. @@ -53,8 +54,8 @@ from the same point of the pool. Short description of the fields following. - unsigned int low - unsigned int pos + uint32 low + uint32 pos The index for the random pool buffer. Lowest and current positions. @@ -66,8 +67,8 @@ */ typedef struct SilcRngStateContext { - unsigned int low; - unsigned int pos; + uint32 low; + uint32 pos; struct SilcRngStateContext *next; } *SilcRngState; @@ -101,12 +102,19 @@ typedef struct SilcRngStateContext { random pool. This is allocated when RNG object is allocated and free'd when RNG object is free'd. + uint8 threshhold + + Threshhold to indicate when it is required to acquire more + noise from the environment. More soft noise is acquired after + 64 bits of output and hard noise every 160 bits of output. + */ typedef struct SilcRngObjectStruct { unsigned char pool[SILC_RNG_POOLSIZE]; unsigned char key[64]; SilcRngState state; SilcHash sha1; + uint8 threshhold; } SilcRngObject; /* Allocates new RNG object. */ @@ -164,10 +172,6 @@ void silc_rng_init(SilcRng rng) (i * (sizeof(rng->pool) / SILC_RNG_STATE_NUM)); next->pos = (i * (sizeof(rng->pool) / SILC_RNG_STATE_NUM)) + 8; -#if 0 - next->pos = sizeof(rng->pool) - - ((i * (sizeof(rng->pool) / SILC_RNG_STATE_NUM))) + 8; -#endif next->next = rng->state; rng->state = next; } @@ -180,39 +184,69 @@ void silc_rng_init(SilcRng rng) silc_rng_get_soft_noise(rng); silc_rng_get_medium_noise(rng); silc_rng_get_hard_noise(rng); + silc_rng_get_soft_noise(rng); } /* This function gets 'soft' noise from environment. */ -void silc_rng_get_soft_noise(SilcRng rng) +static void silc_rng_get_soft_noise(SilcRng rng) { +#ifndef SILC_WIN32 struct tms ptime; +#endif + uint32 pos; + pos = silc_rng_get_position(rng); + silc_rng_xor(rng, clock(), 0); +#ifndef SILC_WIN32 +#ifdef HAVE_GETPID silc_rng_xor(rng, getpid(), 1); - silc_rng_xor(rng, getpgid(getpid() << 8), 2); - silc_rng_xor(rng, getpgid(getpid() << 8), 3); +#ifdef HAVE_GETPGID + silc_rng_xor(rng, getpgid(getpid()) << 8, 2); + silc_rng_xor(rng, getpgid(getpid()) << 8, 3); +#endif silc_rng_xor(rng, getgid(), 4); +#endif +#ifdef HAVE_GETPGRP silc_rng_xor(rng, getpgrp(), 5); - silc_rng_xor(rng, getsid(getpid() << 16), 6); +#endif +#ifdef HAVE_GETSID + silc_rng_xor(rng, getsid(getpid()) << 16, 6); +#endif silc_rng_xor(rng, times(&ptime), 7); silc_rng_xor(rng, ptime.tms_utime, 8); - silc_rng_xor(rng, (ptime.tms_utime + ptime.tms_stime), 9); - silc_rng_xor(rng, (ptime.tms_stime + ptime.tms_cutime), 10); - silc_rng_xor(rng, (ptime.tms_utime + ptime.tms_stime), 11); - silc_rng_xor(rng, (ptime.tms_cutime ^ ptime.tms_stime), 12); - silc_rng_xor(rng, (ptime.tms_cutime ^ ptime.tms_cstime), 13); - silc_rng_xor(rng, (ptime.tms_utime ^ ptime.tms_stime), 14); - silc_rng_xor(rng, (ptime.tms_stime ^ ptime.tms_cutime), 15); - silc_rng_xor(rng, (ptime.tms_cutime + ptime.tms_stime), 16); - silc_rng_xor(rng, (ptime.tms_stime << 8), 17); - silc_rng_xor(rng, clock() << 4, 18); - silc_rng_xor(rng, getpgid(getpid() << 8), 19); - silc_rng_xor(rng, getpgrp(), 20); - silc_rng_xor(rng, getsid(getpid() << 16), 21); - silc_rng_xor(rng, times(&ptime), 22); - silc_rng_xor(rng, ptime.tms_utime, 23); - silc_rng_xor(rng, getpgrp(), 24); + silc_rng_xor(rng, (ptime.tms_utime + ptime.tms_stime), pos++); + silc_rng_xor(rng, (ptime.tms_stime + ptime.tms_cutime), pos++); + silc_rng_xor(rng, (ptime.tms_utime + ptime.tms_stime), pos++); + silc_rng_xor(rng, (ptime.tms_cutime ^ ptime.tms_stime), pos++); + silc_rng_xor(rng, (ptime.tms_cutime ^ ptime.tms_cstime), pos++); + silc_rng_xor(rng, (ptime.tms_utime ^ ptime.tms_stime), pos++); + silc_rng_xor(rng, (ptime.tms_stime ^ ptime.tms_cutime), pos++); + silc_rng_xor(rng, (ptime.tms_cutime + ptime.tms_stime), pos++); + silc_rng_xor(rng, (ptime.tms_stime << 8), pos++); +#endif + silc_rng_xor(rng, clock() << 4, pos++); +#ifndef SILC_WIN32 +#ifdef HAVE_GETPGID + silc_rng_xor(rng, getpgid(getpid()) << 8, pos++); +#endif +#ifdef HAVE_GETPGRP + silc_rng_xor(rng, getpgrp(), pos++); +#endif +#ifdef HAVE_SETSID + silc_rng_xor(rng, getsid(getpid()) << 16, pos++); +#endif + silc_rng_xor(rng, times(&ptime), pos++); + silc_rng_xor(rng, ptime.tms_utime, pos++); +#ifdef HAVE_GETPGRP + silc_rng_xor(rng, getpgrp(), pos++); +#endif +#endif + +#ifdef SILC_RNG_DEBUG + SILC_LOG_HEXDUMP(("pool"), rng->pool, sizeof(rng->pool)); +#endif /* Stir random pool */ silc_rng_stir_pool(rng); @@ -220,23 +254,24 @@ void silc_rng_get_soft_noise(SilcRng rng) /* This function gets noise from different commands */ -void silc_rng_get_medium_noise(SilcRng rng) +static void silc_rng_get_medium_noise(SilcRng rng) { - silc_rng_exec_command(rng, "ps -lefaww 2> /dev/null"); - silc_rng_exec_command(rng, "ls -afiln 2> /dev/null"); - silc_rng_exec_command(rng, "ps -asww 2> /dev/null"); + silc_rng_exec_command(rng, "ps -leaww 2> /dev/null"); + silc_rng_exec_command(rng, "ls -afiln ~ 2> /dev/null"); silc_rng_exec_command(rng, "ls -afiln /proc 2> /dev/null"); - /* - silc_rng_exec_command(rng, "ps -ef 2> /dev/null"); - silc_rng_exec_command(rng, "ls -alin /dev 2> /dev/null"); - */ + silc_rng_exec_command(rng, "ps -axww 2> /dev/null"); + +#ifdef SILC_RNG_DEBUG + SILC_LOG_HEXDUMP(("pool"), rng->pool, sizeof(rng->pool)); +#endif } /* This function gets 'hard' noise from environment. This tries to get the noise from /dev/random if available. */ -void silc_rng_get_hard_noise(SilcRng rng) +static void silc_rng_get_hard_noise(SilcRng rng) { +#ifndef SILC_WIN32 char buf[32]; int fd, len, i; @@ -247,23 +282,29 @@ void silc_rng_get_hard_noise(SilcRng rng) fcntl(fd, F_SETFL, O_NONBLOCK); - for (i = 0; i < 8; i++) { + for (i = 0; i < 2; i++) { len = read(fd, buf, sizeof(buf)); if (len <= 0) goto out; silc_rng_add_noise(rng, buf, len); } +#ifdef SILC_RNG_DEBUG + SILC_LOG_HEXDUMP(("pool"), rng->pool, sizeof(rng->pool)); +#endif + out: close(fd); memset(buf, 0, sizeof(buf)); +#endif } /* Execs command and gets noise from its output */ -void silc_rng_exec_command(SilcRng rng, char *command) +static void silc_rng_exec_command(SilcRng rng, char *command) { - char buf[2048]; +#ifndef SILC_WIN32 + char buf[1024]; FILE *fd; int i; int c; @@ -289,15 +330,15 @@ void silc_rng_exec_command(SilcRng rng, char *command) /* Add the buffer into random pool */ silc_rng_add_noise(rng, buf, strlen(buf)); memset(buf, 0, sizeof(buf)); +#endif } /* This function adds the contents of the buffer as noise into random pool. After adding the noise the pool is stirred. */ -void silc_rng_add_noise(SilcRng rng, unsigned char *buffer, - unsigned int len) +void silc_rng_add_noise(SilcRng rng, unsigned char *buffer, uint32 len) { - unsigned int i, pos; + uint32 i, pos; pos = silc_rng_get_position(rng); @@ -314,7 +355,7 @@ void silc_rng_add_noise(SilcRng rng, unsigned char *buffer, /* XOR's data into the pool */ -void silc_rng_xor(SilcRng rng, unsigned int val, unsigned int pos) +static void silc_rng_xor(SilcRng rng, uint32 val, unsigned int pos) { assert(rng != NULL); rng->pool[pos] ^= val + val; @@ -323,10 +364,10 @@ void silc_rng_xor(SilcRng rng, unsigned int val, unsigned int pos) /* This function stirs the random pool by encrypting buffer in CFB (cipher feedback) mode with SHA1 algorithm. */ -void silc_rng_stir_pool(SilcRng rng) +static void silc_rng_stir_pool(SilcRng rng) { int i; - unsigned long iv[5]; + uint32 iv[5]; /* Get the IV */ memcpy(iv, &rng->pool[SILC_RNG_POOLSIZE - 256], sizeof(iv)); @@ -360,10 +401,10 @@ void silc_rng_stir_pool(SilcRng rng) /* Returns next position where data is fetched from the pool or put to the pool. */ -unsigned int silc_rng_get_position(SilcRng rng) +static uint32 silc_rng_get_position(SilcRng rng) { SilcRngState next; - unsigned int pos; + uint32 pos; next = rng->state->next; @@ -372,7 +413,7 @@ unsigned int silc_rng_get_position(SilcRng rng) rng->state->pos = rng->state->low; #ifdef SILC_RNG_DEBUG - fprintf(stderr, "state: %p: low: %d, pos: %d\n", + fprintf(stderr, "state: %p: low: %lu, pos: %lu\n", rng->state, rng->state->low, rng->state->pos); #endif @@ -381,19 +422,31 @@ unsigned int silc_rng_get_position(SilcRng rng) return pos; } -/* returns random byte. Every two byte is from pools low or high state. */ +/* Returns random byte. */ unsigned char silc_rng_get_byte(SilcRng rng) { + rng->threshhold++; + + /* Get more soft noise after 64 bits threshhold */ + if (rng->threshhold >= 8) + silc_rng_get_soft_noise(rng); + + /* Get hard noise after 160 bits threshhold, zero the threshhold. */ + if (rng->threshhold >= 20) { + rng->threshhold = 0; + silc_rng_get_hard_noise(rng); + } + return rng->pool[silc_rng_get_position(rng)]; } /* Returns 16 bit random number */ -unsigned short silc_rng_get_rn16(SilcRng rng) +uint16 silc_rng_get_rn16(SilcRng rng) { unsigned char rn[2]; - unsigned short num; + uint16 num; rn[0] = silc_rng_get_byte(rng); rn[1] = silc_rng_get_byte(rng); @@ -404,10 +457,10 @@ unsigned short silc_rng_get_rn16(SilcRng rng) /* Returns 32 bit random number */ -unsigned int silc_rng_get_rn32(SilcRng rng) +uint32 silc_rng_get_rn32(SilcRng rng) { unsigned char rn[4]; - unsigned short num; + uint16 num; rn[0] = silc_rng_get_byte(rng); rn[1] = silc_rng_get_byte(rng); @@ -420,7 +473,7 @@ unsigned int silc_rng_get_rn32(SilcRng rng) /* Returns random number string. Returned string is in HEX format. */ -unsigned char *silc_rng_get_rn_string(SilcRng rng, unsigned int len) +unsigned char *silc_rng_get_rn_string(SilcRng rng, uint32 len) { int i; unsigned char *string; @@ -435,7 +488,7 @@ unsigned char *silc_rng_get_rn_string(SilcRng rng, unsigned int len) /* Returns random number binary data. */ -unsigned char *silc_rng_get_rn_data(SilcRng rng, unsigned int len) +unsigned char *silc_rng_get_rn_data(SilcRng rng, uint32 len) { int i; unsigned char *data; @@ -447,3 +500,68 @@ unsigned char *silc_rng_get_rn_data(SilcRng rng, unsigned int len) return data; } + +/* Global RNG. This is global RNG that application can initialize so + that any part of code anywhere can use RNG without having to allocate + new RNG object everytime. If this is not initialized then these routines + will fail. Note: currently in SILC applications always initialize this. */ + +SilcRng global_rng = NULL; + +/* Initialize global RNG. If `rng' is provided it is set as the global + RNG object (it can be allocated by the application for example). */ + +int silc_rng_global_init(SilcRng rng) +{ + if (rng) + global_rng = rng; + else + global_rng = silc_rng_alloc(); + + return TRUE; +} + +/* Uninitialize global RNG */ + +int silc_rng_global_uninit() +{ + if (global_rng) { + silc_rng_free(global_rng); + global_rng = NULL; + } + + return TRUE; +} + +/* These are analogous to the functions above. */ + +unsigned char silc_rng_global_get_byte() +{ + return global_rng ? silc_rng_get_byte(global_rng) : 0; +} + +uint16 silc_rng_global_get_rn16() +{ + return global_rng ? silc_rng_get_rn16(global_rng) : 0; +} + +uint32 silc_rng_global_get_rn32() +{ + return global_rng ? silc_rng_get_rn32(global_rng) : 0; +} + +unsigned char *silc_rng_global_get_rn_string(uint32 len) +{ + return global_rng ? silc_rng_get_rn_string(global_rng, len) : NULL; +} + +unsigned char *silc_rng_global_get_rn_data(uint32 len) +{ + return global_rng ? silc_rng_get_rn_data(global_rng, len) : NULL; +} + +void silc_rng_global_add_noise(unsigned char *buffer, uint32 len) +{ + if (global_rng) + silc_rng_add_noise(global_rng, buffer, len); +}