1 /*
2  ---------------------------------------------------------------------------
3  Copyright (c) 2002, Dr Brian Gladman <                 >, Worcester, UK.
4  All rights reserved.
5 
6  LICENSE TERMS
7 
8  The free distribution and use of this software in both source and binary
9  form is allowed (with or without changes) provided that:
10 
11    1. distributions of this source code include the above copyright
12       notice, this list of conditions and the following disclaimer;
13 
14    2. distributions in binary form include the above copyright
15       notice, this list of conditions and the following disclaimer
16       in the documentation and/or other associated materials;
17 
18    3. the copyright holder's name is not used to endorse products
19       built using this software without specific written permission.
20 
21  ALTERNATIVELY, provided that this notice is retained in full, this product
22  may be distributed under the terms of the GNU General Public License (GPL),
23  in which case the provisions of the GPL apply INSTEAD OF those given above.
24 
25  DISCLAIMER
26 
27  This software is provided 'as is' with no explicit or implied warranties
28  in respect of its properties, including, but not limited to, correctness
29  and/or fitness for purpose.
30  ---------------------------------------------------------------------------
31  Issue Date: 24/01/2003
32 
33  This file implements a random data pool based on the use of an external
34  entropy function.  It is based on the ideas advocated by Peter Gutmann in
35  his work on pseudo random sequence generators.  It is not a 'paranoid'
36  random sequence generator and no attempt is made to protect the pool
37  from prying eyes either by memory locking or by techniques to obscure
38  its location in memory.
39 */
40 
41 #include <memory.h>
42 #include "prng.h"
43 
44 /* mix a random data pool using the SHA1 compression function (as   */
45 /* suggested by Peter Gutmann in his paper on random pools)         */
46 
prng_mix(unsigned char buf[])47 static void prng_mix(unsigned char buf[])
48 {   unsigned int    i, len;
49     sha1_ctx        ctx[1];
50 
51     /*lint -e{663}  unusual array to pointer conversion */
52     for(i = 0; i < PRNG_POOL_SIZE; i += SHA1_DIGEST_SIZE)
53     {
54         /* copy digest size pool block into SHA1 hash block */
55         memcpy(ctx->hash, buf + (i ? i : PRNG_POOL_SIZE)
56                             - SHA1_DIGEST_SIZE, SHA1_DIGEST_SIZE);
57 
58         /* copy data from pool into the SHA1 data buffer    */
59         len = PRNG_POOL_SIZE - i;
60         memcpy(ctx->wbuf, buf + i, (len > SHA1_BLOCK_SIZE ? SHA1_BLOCK_SIZE : len));
61 
62         if(len < SHA1_BLOCK_SIZE)
63             memcpy(((char*)ctx->wbuf) + len, buf, SHA1_BLOCK_SIZE - len);
64 
65         /* compress using the SHA1 compression function     */
66         sha1_compile(ctx);
67 
68         /* put digest size block back into the random pool  */
69         memcpy(buf + i, ctx->hash, SHA1_DIGEST_SIZE);
70     }
71 }
72 
73 /* refresh the output buffer and update the random pool by adding   */
74 /* entropy and remixing                                             */
75 
update_pool(prng_ctx ctx[1])76 static void update_pool(prng_ctx ctx[1])
77 {   unsigned int    i = 0;
78 
79     /* transfer random pool data to the output buffer   */
80     memcpy(ctx->obuf, ctx->rbuf, PRNG_POOL_SIZE);
81 
82     /* enter entropy data into the pool */
83     while(i < PRNG_POOL_SIZE)
84         i += ctx->entropy(ctx->rbuf + i, PRNG_POOL_SIZE - i);
85 
86     /* invert and xor the original pool data into the pool  */
87     for(i = 0; i < PRNG_POOL_SIZE; ++i)
88         ctx->rbuf[i] ^= ~ctx->obuf[i];
89 
90     /* mix the pool and the output buffer   */
91     prng_mix(ctx->rbuf);
92     prng_mix(ctx->obuf);
93 }
94 
prng_init(prng_entropy_fn fun,prng_ctx ctx[1])95 void prng_init(prng_entropy_fn fun, prng_ctx ctx[1])
96 {   int i;
97 
98     /* clear the buffers and the counter in the context     */
99     memset(ctx, 0, sizeof(prng_ctx));
100 
101     /* set the pointer to the entropy collection function   */
102     ctx->entropy = fun;
103 
104     /* initialise the random data pool                      */
105     update_pool(ctx);
106 
107     /* mix the pool a minimum number of times               */
108     for(i = 0; i < PRNG_MIN_MIX; ++i)
109         prng_mix(ctx->rbuf);
110 
111     /* update the pool to prime the pool output buffer      */
112     update_pool(ctx);
113 }
114 
115 /* provide random bytes from the random data pool   */
116 
prng_rand(unsigned char data[],unsigned int data_len,prng_ctx ctx[1])117 void prng_rand(unsigned char data[], unsigned int data_len, prng_ctx ctx[1])
118 {   unsigned char   *rp = data;
119     unsigned int    len, pos = ctx->pos;
120 
121     while(data_len)
122     {
123         /* transfer 'data_len' bytes (or the number of bytes remaining  */
124         /* the pool output buffer if less) into the output              */
125         len = (data_len < PRNG_POOL_SIZE - pos ? data_len : PRNG_POOL_SIZE - pos);
126         memcpy(rp, ctx->obuf + pos, len);
127         rp += len;          /* update ouput buffer position pointer     */
128         pos += len;         /* update pool output buffer pointer        */
129         data_len -= len;    /* update the remaining data count          */
130 
131         /* refresh the random pool if necessary */
132         if(pos == PRNG_POOL_SIZE)
133         {
134             update_pool(ctx); pos = 0;
135         }
136     }
137 
138     ctx->pos = pos;
139 }
140 
prng_end(prng_ctx ctx[1])141 void prng_end(prng_ctx ctx[1])
142 {
143     /* ensure the data in the context is destroyed  */
144     memset(ctx, 0, sizeof(prng_ctx));
145 }
146 
147