X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=lib%2Fsilccrypt%2Fsilcrng.c;h=ab680bf04c929389a8d38ed558d1c92c6bfede9c;hb=e7b6c157b80152bf9fb9266e6bdd93f9fb0db776;hp=02fbbfa97fdb0ba78059b1981cf008bdcc7a6f74;hpb=e2c551b9693b6d42e5997b9df416a17fb94c1ccb;p=silc.git diff --git a/lib/silccrypt/silcrng.c b/lib/silccrypt/silcrng.c index 02fbbfa9..ab680bf0 100644 --- a/lib/silccrypt/silcrng.c +++ b/lib/silccrypt/silcrng.c @@ -1,10 +1,10 @@ /* - silcrng.c + silcrng.c Author: Pekka Riikonen - Copyright (C) 1997 - 2002 Pekka Riikonen + Copyright (C) 1997 - 2007 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 @@ -21,11 +21,11 @@ * Created: Sun Mar 9 00:09:18 1997 * * 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. + * 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" +#include "silc.h" #ifndef WIN32 #ifdef HAVE_GETSID @@ -44,7 +44,7 @@ extern pid_t getpgid (pid_t __pid); #define SILC_RNG_STATE_NUM 4 /* Byte size of the random data pool. */ -#define SILC_RNG_POOLSIZE 1024 +#define SILC_RNG_POOLSIZE (20 * 48) static SilcUInt32 silc_rng_get_position(SilcRng rng); static void silc_rng_stir_pool(SilcRng rng); @@ -54,7 +54,7 @@ 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. This object is used by the random number generator to provide @@ -81,8 +81,8 @@ typedef struct SilcRngStateContext { struct SilcRngStateContext *next; } *SilcRngState; -/* - SILC Random Number Generator object. +/* + SILC Random Number Generator object. This object holds random pool which is used to generate the random numbers used by various routines needing cryptographically strong @@ -179,7 +179,7 @@ void silc_rng_free(SilcRng rng) } } -/* Initializes random number generator by getting noise from environment. +/* Initializes random number generator by getting noise from environment. The environmental noise is our so called seed. One should not call this function more than once. */ @@ -200,7 +200,7 @@ void silc_rng_init(SilcRng rng) first = rng->state; for (i = SILC_RNG_STATE_NUM - 1; i >= 1; i--) { next = silc_calloc(1, sizeof(*rng->state)); - next->low = + next->low = (i * (sizeof(rng->pool) / SILC_RNG_STATE_NUM)); next->pos = (i * (sizeof(rng->pool) / SILC_RNG_STATE_NUM)) + 8; @@ -229,7 +229,10 @@ static void silc_rng_get_soft_noise(SilcRng rng) struct tms ptime; #endif SilcUInt32 pos; - +#ifdef HAVE_GETRUSAGE + struct rusage r; +#endif + pos = silc_rng_get_position(rng); silc_rng_xor(rng, clock(), 0); @@ -240,14 +243,17 @@ static void silc_rng_get_soft_noise(SilcRng rng) silc_rng_xor(rng, getpgid(getpid()) << 8, 2); silc_rng_xor(rng, getpgid(getpid()) << 8, 3); #endif +#ifdef HAVE_GETGID silc_rng_xor(rng, getgid(), 4); #endif +#endif #ifdef HAVE_GETPGRP silc_rng_xor(rng, getpgrp(), 5); #endif #ifdef HAVE_GETSID silc_rng_xor(rng, getsid(getpid()) << 16, 6); #endif +#ifndef SILC_SYMBIAN 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), pos++); @@ -259,6 +265,7 @@ static void silc_rng_get_soft_noise(SilcRng rng) 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_SYMBIAN */ #endif silc_rng_xor(rng, clock() << 4, pos++); #ifndef SILC_WIN32 @@ -271,12 +278,39 @@ static void silc_rng_get_soft_noise(SilcRng rng) #ifdef HAVE_SETSID silc_rng_xor(rng, getsid(getpid()) << 16, pos++); #endif +#ifndef SILC_SYMBIAN silc_rng_xor(rng, times(&ptime), pos++); silc_rng_xor(rng, ptime.tms_utime, pos++); +#endif /* SILC_SYMBIAN */ #ifdef HAVE_GETPGRP silc_rng_xor(rng, getpgrp(), pos++); #endif #endif +#ifdef HAVE_GETRUSAGE + getrusage(RUSAGE_SELF, &r); + silc_rng_xor(rng, (r.ru_utime.tv_sec + r.ru_utime.tv_usec), pos++); + silc_rng_xor(rng, (r.ru_utime.tv_sec ^ r.ru_utime.tv_usec), pos++); + silc_rng_xor(rng, (r.ru_stime.tv_sec + r.ru_stime.tv_usec), pos++); + silc_rng_xor(rng, (r.ru_stime.tv_sec ^ r.ru_stime.tv_usec), pos++); +#ifndef SILC_SYMBIAN + silc_rng_xor(rng, (r.ru_maxrss + r.ru_ixrss), pos++); + silc_rng_xor(rng, (r.ru_maxrss ^ r.ru_ixrss), pos++); + silc_rng_xor(rng, (r.ru_idrss + r.ru_idrss), pos++); + silc_rng_xor(rng, (r.ru_idrss ^ r.ru_idrss), pos++); + silc_rng_xor(rng, (r.ru_idrss << 16), pos++); + silc_rng_xor(rng, (r.ru_minflt + r.ru_majflt), pos++); + silc_rng_xor(rng, (r.ru_minflt ^ r.ru_majflt), pos++); + silc_rng_xor(rng, (r.ru_nswap + r.ru_oublock + r.ru_inblock), pos++); + silc_rng_xor(rng, (r.ru_nswap << 8), pos++); + silc_rng_xor(rng, (r.ru_inblock + r.ru_oublock), pos++); + silc_rng_xor(rng, (r.ru_inblock ^ r.ru_oublock), pos++); + silc_rng_xor(rng, (r.ru_msgsnd ^ r.ru_msgrcv), pos++); + silc_rng_xor(rng, (r.ru_nsignals + r.ru_msgsnd + r.ru_msgrcv), pos++); + silc_rng_xor(rng, (r.ru_nsignals << 16), pos++); + silc_rng_xor(rng, (r.ru_nvcsw + r.ru_nivcsw), pos++); + silc_rng_xor(rng, (r.ru_nvcsw ^ r.ru_nivcsw), pos++); +#endif /* SILC_SYMBIAN */ +#endif /* HAVE_GETRUSAGE */ #ifdef SILC_RNG_DEBUG SILC_LOG_HEXDUMP(("pool"), rng->pool, sizeof(rng->pool)); @@ -290,6 +324,10 @@ static void silc_rng_get_soft_noise(SilcRng rng) static void silc_rng_get_medium_noise(SilcRng rng) { + /* If getrusage is available, there is no need for shell commands */ +#ifdef HAVE_GETRUSAGE + return; +#endif 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"); @@ -305,10 +343,10 @@ static void silc_rng_get_medium_noise(SilcRng rng) static void silc_rng_get_hard_noise(SilcRng rng) { -#ifndef SILC_WIN32 +#if defined(SILC_UNIX) unsigned char buf[32]; int fd, len, i; - + /* Get noise from /dev/[u]random if available */ fd = open(rng->devrandom, O_RDONLY); if (fd < 0) @@ -337,37 +375,36 @@ static void silc_rng_get_hard_noise(SilcRng rng) static void silc_rng_exec_command(SilcRng rng, char *command) { -#ifndef SILC_WIN32 +#if defined(SILC_UNIX) unsigned char buf[1024]; FILE *fd; int i; int c; - + /* Open process */ fd = popen(command, "r"); if (!fd) return; - + /* Get data as much as we can get into the buffer */ for (i = 0; i < sizeof(buf); i++) { c = fgetc(fd); - if (c == EOF) { - if (!i) - return; - break; - } + if (c == EOF) + break; buf[i] = c; } - + pclose(fd); - - /* Add the buffer into random pool */ - silc_rng_add_noise(rng, buf, i); - memset(buf, 0, sizeof(buf)); + + if (i != 0) { + /* Add the buffer into random pool */ + silc_rng_add_noise(rng, buf, i); + memset(buf, 0, sizeof(buf)); + } #endif } -/* This function adds the contents of the buffer as noise into random +/* 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, SilcUInt32 len) @@ -391,42 +428,79 @@ void silc_rng_add_noise(SilcRng rng, unsigned char *buffer, SilcUInt32 len) static void silc_rng_xor(SilcRng rng, SilcUInt32 val, unsigned int pos) { - assert(rng != NULL); - rng->pool[pos] ^= val + val; + SilcUInt32 tmp; + + SILC_GET32_MSB(tmp, &rng->pool[pos]); + val ^= tmp + val; + SILC_PUT32_MSB(val, &rng->pool[pos]); } -/* This function stirs the random pool by encrypting buffer in CFB +/* This function stirs the random pool by encrypting buffer in CFB (cipher feedback) mode with SHA1 algorithm. */ static void silc_rng_stir_pool(SilcRng rng) { int i; - SilcUInt32 iv[5]; + SilcUInt32 iv[5], tmp; /* Get the IV */ - memcpy(iv, &rng->pool[16], sizeof(iv)); + SILC_GET32_MSB(iv[0], &rng->pool[16 ]); + SILC_GET32_MSB(iv[1], &rng->pool[16 + 4]); + SILC_GET32_MSB(iv[2], &rng->pool[16 + 8]); + SILC_GET32_MSB(iv[3], &rng->pool[16 + 12]); + SILC_GET32_MSB(iv[4], &rng->pool[16 + 16]); /* First CFB pass */ - for (i = 0; i < SILC_RNG_POOLSIZE; i += 5) { + for (i = 0; i < SILC_RNG_POOLSIZE; i += 20) { silc_hash_transform(rng->sha1, iv, rng->key); - iv[0] = rng->pool[i] ^= iv[0]; - iv[1] = rng->pool[i + 1] ^= iv[1]; - iv[2] = rng->pool[i + 2] ^= iv[2]; - iv[3] = rng->pool[i + 3] ^= iv[3]; - iv[4] = rng->pool[i + 4] ^= iv[4]; + + SILC_GET32_MSB(tmp, &rng->pool[i]); + iv[0] ^= tmp; + SILC_PUT32_MSB(iv[0], &rng->pool[i]); + + SILC_GET32_MSB(tmp, &rng->pool[i + 4]); + iv[1] ^= tmp; + SILC_PUT32_MSB(iv[1], &rng->pool[i + 4]); + + SILC_GET32_MSB(tmp, &rng->pool[i + 8]); + iv[2] ^= tmp; + SILC_PUT32_MSB(iv[2], &rng->pool[i + 8]); + + SILC_GET32_MSB(tmp, &rng->pool[i + 12]); + iv[3] ^= tmp; + SILC_PUT32_MSB(iv[3], &rng->pool[i + 12]); + + SILC_GET32_MSB(tmp, &rng->pool[i + 16]); + iv[4] ^= tmp; + SILC_PUT32_MSB(iv[4], &rng->pool[i + 16]); } /* Get new key */ memcpy(rng->key, &rng->pool[silc_rng_get_position(rng)], sizeof(rng->key)); /* Second CFB pass */ - for (i = 0; i < SILC_RNG_POOLSIZE; i += 5) { + for (i = 0; i < SILC_RNG_POOLSIZE; i += 20) { silc_hash_transform(rng->sha1, iv, rng->key); - iv[0] = rng->pool[i] ^= iv[0]; - iv[1] = rng->pool[i + 1] ^= iv[1]; - iv[2] = rng->pool[i + 2] ^= iv[2]; - iv[3] = rng->pool[i + 3] ^= iv[3]; - iv[4] = rng->pool[i + 4] ^= iv[4]; + + SILC_GET32_MSB(tmp, &rng->pool[i]); + iv[0] ^= tmp; + SILC_PUT32_MSB(iv[0], &rng->pool[i]); + + SILC_GET32_MSB(tmp, &rng->pool[i + 4]); + iv[1] ^= tmp; + SILC_PUT32_MSB(iv[1], &rng->pool[i + 4]); + + SILC_GET32_MSB(tmp, &rng->pool[i + 8]); + iv[2] ^= tmp; + SILC_PUT32_MSB(iv[2], &rng->pool[i + 8]); + + SILC_GET32_MSB(tmp, &rng->pool[i + 12]); + iv[3] ^= tmp; + SILC_PUT32_MSB(iv[3], &rng->pool[i + 12]); + + SILC_GET32_MSB(tmp, &rng->pool[i + 16]); + iv[4] ^= tmp; + SILC_PUT32_MSB(iv[4], &rng->pool[i + 16]); } memset(iv, 0, sizeof(iv)); @@ -447,7 +521,7 @@ static SilcUInt32 silc_rng_get_position(SilcRng rng) rng->state->pos = rng->state->low; #ifdef SILC_RNG_DEBUG - fprintf(stderr, "state: %p: low: %lu, pos: %lu\n", + fprintf(stderr, "state: %p: low: %lu, pos: %lu\n", rng->state, rng->state->low, rng->state->pos); #endif @@ -460,6 +534,8 @@ static SilcUInt32 silc_rng_get_position(SilcRng rng) SilcUInt8 silc_rng_get_byte(SilcRng rng) { + SilcUInt8 byte; + rng->threshold++; /* Get more soft noise after 64 bits threshold */ @@ -472,7 +548,8 @@ SilcUInt8 silc_rng_get_byte(SilcRng rng) silc_rng_get_hard_noise(rng); } - return rng->pool[silc_rng_get_position(rng)]; + do byte = rng->pool[silc_rng_get_position(rng)]; while (byte == 0x00); + return byte; } /* Return random byte as fast as possible. Reads from /dev/urandom if @@ -480,12 +557,12 @@ SilcUInt8 silc_rng_get_byte(SilcRng rng) SilcUInt8 silc_rng_get_byte_fast(SilcRng rng) { -#ifndef SILC_WIN32 +#if defined(SILC_UNIX) unsigned char buf[1]; if (rng->fd_devurandom == -1) { rng->fd_devurandom = open("/dev/urandom", O_RDONLY); - if (rng < 0) + if (rng->fd_devurandom < 0) return silc_rng_get_byte(rng); fcntl(rng->fd_devurandom, F_SETFL, O_NONBLOCK); } @@ -493,7 +570,7 @@ SilcUInt8 silc_rng_get_byte_fast(SilcRng rng) if (read(rng->fd_devurandom, buf, sizeof(buf)) < 0) return silc_rng_get_byte(rng); - return buf[0]; + return buf[0] != 0x00 ? buf[0] : silc_rng_get_byte(rng); #else return silc_rng_get_byte(rng); #endif @@ -518,7 +595,7 @@ SilcUInt16 silc_rng_get_rn16(SilcRng rng) SilcUInt32 silc_rng_get_rn32(SilcRng rng) { unsigned char rn[4]; - SilcUInt16 num; + SilcUInt32 num; rn[0] = silc_rng_get_byte(rng); rn[1] = silc_rng_get_byte(rng); @@ -529,7 +606,7 @@ SilcUInt32 silc_rng_get_rn32(SilcRng rng) return num; } -/* Returns random number string. Returned string is in HEX format. */ +/* Returns non-zero random number string. Returned string is in HEX format. */ unsigned char *silc_rng_get_rn_string(SilcRng rng, SilcUInt32 len) { @@ -544,19 +621,20 @@ unsigned char *silc_rng_get_rn_string(SilcRng rng, SilcUInt32 len) return string; } -/* Returns random number binary data. */ +/* Returns non-zero random number binary data. */ -unsigned char *silc_rng_get_rn_data(SilcRng rng, SilcUInt32 len) +SilcBool silc_rng_get_rn_data(SilcRng rng, SilcUInt32 len, unsigned char *buf, + SilcUInt32 buf_size) { int i; - unsigned char *data; - data = silc_calloc(len + 1, sizeof(*data)); + if (len > buf_size) + return FALSE; for (i = 0; i < len; i++) - data[i] = silc_rng_get_byte(rng); + buf[i] = silc_rng_get_byte(rng); - return data; + return TRUE; } /* Global RNG. This is global RNG that application can initialize so @@ -569,19 +647,22 @@ 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). */ -bool silc_rng_global_init(SilcRng rng) +SilcBool silc_rng_global_init(SilcRng rng) { - if (rng) + if (rng) { global_rng = rng; - else - global_rng = silc_rng_alloc(); + return TRUE; + } + + global_rng = silc_rng_alloc(); + silc_rng_init(global_rng); return TRUE; } /* Uninitialize global RNG */ -bool silc_rng_global_uninit(void) +SilcBool silc_rng_global_uninit(void) { if (global_rng) { silc_rng_free(global_rng); @@ -621,9 +702,11 @@ unsigned char *silc_rng_global_get_rn_string(SilcUInt32 len) return global_rng ? silc_rng_get_rn_string(global_rng, len) : NULL; } -unsigned char *silc_rng_global_get_rn_data(SilcUInt32 len) +SilcBool silc_rng_global_get_rn_data(SilcRng rng, SilcUInt32 len, + unsigned char *buf, SilcUInt32 buf_size) { - return global_rng ? silc_rng_get_rn_data(global_rng, len) : NULL; + return global_rng ? silc_rng_get_rn_data(global_rng, len, buf, + buf_size) : FALSE; } void silc_rng_global_add_noise(unsigned char *buffer, SilcUInt32 len)