diff options
author | Ben Laurie <ben@apache.org> | 2003-11-03 13:25:01 +0000 |
---|---|---|
committer | Ben Laurie <ben@apache.org> | 2003-11-03 13:25:01 +0000 |
commit | 2f0be761a3f6e953fe182290cb5d2130d813fbdc (patch) | |
tree | c536774cf3cb5165af68bf77cbb9be38bb1bf388 /random/unix/apr_random.c | |
parent | 1d2c775d4940ea5ab992682d1ed5ca16b889a4a4 (diff) | |
download | apr-2f0be761a3f6e953fe182290cb5d2130d813fbdc.tar.gz |
Start of new PRNG.
git-svn-id: https://svn.apache.org/repos/asf/apr/apr/trunk@64712 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'random/unix/apr_random.c')
-rw-r--r-- | random/unix/apr_random.c | 294 |
1 files changed, 294 insertions, 0 deletions
diff --git a/random/unix/apr_random.c b/random/unix/apr_random.c new file mode 100644 index 000000000..d62177b10 --- /dev/null +++ b/random/unix/apr_random.c @@ -0,0 +1,294 @@ +/* ==================================================================== + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2003 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Apache" and "Apache Software Foundation" must + * not be used to endorse or promote products derived from this + * software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * nor may "Apache" appear in their name, without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + */ +/* + * See the paper "???" by Ben Laurie for an explanation of this PRNG. + */ + +#include "apr.h" +#include "apr_pools.h" +#include "apr_random.h" +#include <assert.h> + +#define min(a,b) ((a) < (b) ? (a) : (b)) + +#define APR_RANDOM_DEFAULT_POOLS 32 +#define APR_RANDOM_DEFAULT_REHASH_SIZE 1024 +#define APR_RANDOM_DEFAULT_RESEED_SIZE 32 +#define APR_RANDOM_DEFAULT_HASH_SECRET_SIZE 32 +#define APR_RANDOM_DEFAULT_G_FOR_INSECURE 32 +#define APR_RANDOM_DEFAULT_G_FOR_SECURE 320 + +typedef struct apr_random_pool_t + { + unsigned char *pool; + int bytes; + int pool_size; + } apr_random_pool_t; + +#define hash_init(h) (h)->init(h) +#define hash_add(h,b,n) (h)->add(h,b,n) +#define hash_finish(h,r) (h)->finish(h,r) + +#define hash(h,r,b,n) hash_init(h),hash_add(h,b,n),hash_finish(h,r) + +#define crypt_setkey(c,k) (c)->set_key((c)->data,k) +#define crypt_crypt(c,out,in) (c)->crypt((c)->date,out,in) + +struct apr_random_t + { + apr_pool_t *apr_pool; + apr_crypto_hash_t *pool_hash; + unsigned int npools; + apr_random_pool_t *pools; + unsigned int next_pool; + unsigned int generation; + apr_size_t rehash_size; + apr_size_t reseed_size; + apr_crypto_hash_t *key_hash; +#define K_size(g) ((g)->key_hash->size) + apr_crypto_hash_t *prng_hash; +#define B_size(g) ((g)->prng_hash->size) + unsigned char *H; + unsigned char *H_waiting; +#define H_size(g) (B_size(g)+K_size(g)) + unsigned char *randomness; + apr_size_t random_bytes; + unsigned int g_for_insecure; + unsigned int g_for_secure; + unsigned int secure_base; + unsigned char insecure_started:1; + unsigned char secure_started:1; + }; + +void apr_random_init(apr_random_t *g,apr_pool_t *p, + apr_crypto_hash_t *pool_hash,apr_crypto_hash_t *key_hash, + apr_crypto_hash_t *prng_hash) + { + int n; + + g->apr_pool=p; + g->pool_hash=pool_hash; + g->key_hash=key_hash; + g->prng_hash=prng_hash; + g->npools=APR_RANDOM_DEFAULT_POOLS; + g->pools=apr_palloc(p,g->npools*sizeof *g->pools); + for(n=0 ; n < g->npools ; ++n) + { + g->pools[n].bytes=g->pools[n].pool_size=0; + g->pools[n].pool=NULL; + } + g->next_pool=0; + g->generation=0; + g->rehash_size=APR_RANDOM_DEFAULT_REHASH_SIZE; + /* Ensure that the rehash size is twice the size of the pool hasher */ + g->rehash_size=((g->rehash_size+2*g->pool_hash->size-1)/g->pool_hash->size + /2)*g->pool_hash->size*2; + g->reseed_size=APR_RANDOM_DEFAULT_RESEED_SIZE; + g->prng_hash=prng_hash; + g->H=apr_palloc(p,H_size(g)); + g->H_waiting=apr_palloc(p,H_size(g)); + g->randomness=apr_palloc(p,B_size(g)); + g->random_bytes=0; + + g->g_for_insecure=APR_RANDOM_DEFAULT_G_FOR_INSECURE; + g->secure_base=0; + g->g_for_secure=APR_RANDOM_DEFAULT_G_FOR_SECURE; + g->secure_started=g->insecure_started=0; + } + +apr_random_t *apr_random_standard_new(apr_pool_t *p) + { + apr_random_t *r=apr_palloc(p,sizeof *r); + + apr_random_init(r,p,apr_crypto_sha256_new(p),apr_crypto_sha256_new(p), + apr_crypto_sha256_new(p)); + return r; + } + +static void rekey(apr_random_t *g) + { + int n; + unsigned char *H=(g->insecure_started && !g->secure_started) ? g->H_waiting + : g->H; + + hash_init(g->key_hash); + hash_add(g->key_hash,H,H_size(g)); + for(n=0 ; n < g->npools && (n == 0 || g->generation&(1 << (n-1))) + ; ++n) + { + hash_add(g->key_hash,g->pools[n].pool,g->pools[n].bytes); + g->pools[n].bytes=0; + } + hash_finish(g->key_hash,H+B_size(g)); + ++g->generation; + if(!g->insecure_started && g->generation > g->g_for_insecure) + { + g->insecure_started=1; + if(!g->secure_started) + { + memcpy(g->H_waiting,g->H,H_size(g)); + g->secure_base=g->generation; + } + } + if(!g->secure_started && g->generation > g->secure_base+g->g_for_secure) + { + g->secure_started=1; + memcpy(g->H,g->H_waiting,H_size(g)); + } + } + +void apr_random_add_entropy(apr_random_t *g,const void *entropy_, + apr_size_t bytes) + { + int n; + const unsigned char *entropy=entropy_; + + for(n=0 ; n < bytes ; ++n) + { + apr_random_pool_t *p=&g->pools[g->next_pool]; + + if(++g->next_pool == g->npools) + g->next_pool=0; + + if(p->pool_size < p->bytes+1) + { + unsigned char *np=apr_palloc(g->apr_pool,(p->bytes+1)*2); + + memcpy(np,p->pool,p->bytes); + p->pool=np; + p->pool_size=(p->bytes+1)*2; + } + p->pool[p->bytes++]=entropy[n]; + + if(p->bytes == g->rehash_size) + { + int r; + + for(r=0 ; r < p->bytes/2 ; r+=g->pool_hash->size) + hash(g->pool_hash,p->pool+r,p->pool+r*2,g->pool_hash->size*2); + p->bytes/=2; + } + assert(p->bytes < g->rehash_size); + } + + if(g->pools[0].bytes >= g->reseed_size) + rekey(g); + } + +// This will give g->B_size bytes of randomness +static void apr_random_block(apr_random_t *g,unsigned char *random) + { + // FIXME: in principle, these are different hashes + hash(g->prng_hash,g->H,g->H,H_size(g)); + hash(g->prng_hash,random,g->H,B_size(g)); + } + +static void apr_random_bytes(apr_random_t *g,unsigned char *random, + apr_size_t bytes) + { + apr_size_t n; + + for(n=0 ; n < bytes ; ) + { + int l; + + if(g->random_bytes == 0) + { + apr_random_block(g,g->randomness); + g->random_bytes=B_size(g); + } + l=min(bytes-n,g->random_bytes); + memcpy(&random[n],g->randomness+B_size(g)-g->random_bytes,l); + g->random_bytes-=l; + n+=l; + } + } + +apr_status_t apr_random_secure_bytes(apr_random_t *g,void *random, + apr_size_t bytes) + { + if(!g->secure_started) + return APR_ENOTENOUGHENTROPY; + apr_random_bytes(g,random,bytes); + return APR_SUCCESS; + } + +apr_status_t apr_random_insecure_bytes(apr_random_t *g,void *random, + apr_size_t bytes) + { + if(!g->insecure_started) + return APR_ENOTENOUGHENTROPY; + apr_random_bytes(g,random,bytes); + return APR_SUCCESS; + } + +void apr_random_barrier(apr_random_t *g) + { + g->secure_started=0; + g->secure_base=g->generation; + } + +apr_status_t apr_random_secure_ready(apr_random_t *r) + { + if(!r->secure_started) + return APR_ENOTENOUGHENTROPY; + return APR_SUCCESS; + } + +apr_status_t apr_random_insecure_ready(apr_random_t *r) + { + if(!r->insecure_started) + return APR_ENOTENOUGHENTROPY; + return APR_SUCCESS; + } |