|
|
1.1.1.2 root 1: /*
2: * True random number computation and storage
3: *
4: * (c) Copyright 1990-1994 by Philip Zimmermann. All rights reserved.
5: * The author assumes no liability for damages resulting from the use
6: * of this software, even if the damage results from defects in this
7: * software. No warranty is expressed or implied.
8: *
9: * Note that while most PGP source modules bear Philip Zimmermann's
10: * copyright notice, many of them have been revised or entirely written
11: * by contributors who frequently failed to put their names in their
12: * code. Code that has been incorporated into PGP from other authors
13: * was either originally published in the public domain or is used with
14: * permission from the various authors.
15: *
16: * PGP is available for free to the public under certain restrictions.
17: * See the PGP User's Guide (included in the release package) for
18: * important information about licensing, patent restrictions on
19: * certain algorithms, trademarks, copyrights, and export controls.
20: *
21: * Written by Colin Plumb.
22: */
23: #include <stdlib.h>
24: #include <string.h>
25:
26: #include "randpool.h"
27: #include "usuals.h"
28: #include "md5.h"
29:
30: /* The pool must be a multiple of the 16-byte (128-bit) MD5 block size */
31: #define RANDPOOLWORDS ((RANDPOOLBITS+127 & ~127) >> 5)
32: #if RANDPOOLWORDS <= 16
1.1.1.3 ! root 33: /* #error is not portable, this has the same effect */
! 34: #include "Random pool too small - please increase RANDPOOLBITS in randpool.h"
1.1.1.2 root 35: #endif
36:
37: /* Must be word-aligned, so make it words. Cast to bytes as needed. */
38: static word32 randPool[RANDPOOLWORDS]; /* Random pool */
39: static unsigned randPoolGetPos = sizeof(randPool); /* Position to get from */
40: static unsigned randPoolAddPos = 0; /* Position to add to */
41:
42: static void
43: xorbytes(byte *dest, byte const *src, unsigned len)
44: {
45: while (len--)
1.1.1.3 ! root 46: *dest++ ^= *src++;
1.1.1.2 root 47: }
48:
49: /*
50: * Destroys already-used random numbers. Ensures no sensitive data
51: * remains in memory that can be recovered later. This is also
52: * called to "stir in" newly acquired environmental noise bits before
53: * removing any random bytes.
54: *
55: * The transformation is carried out by "encrypting" the data in CFB
56: * mode with MD5 as the block cipher. Then, to make certain the stirring
57: * operation is strictly one-way, we destroy the key, getting 64 bytes
58: * from the beginning of the pool and using them to reinitialize the
59: * key. These bytes are not returned by randPoolGetBytes().
60: *
61: * The stirring operation is done twice, to ensure that each bit in the
62: * pool depends on each bit of entropy XORed in after each call to
63: * randPoolStir().
64: *
65: * To make this useful for pseudo-random (that is, repeatable) operations,
66: * the MD5 transformation is always done with a consistent byte order.
67: * MD5Transform itself works with 32-bit words, not bytes, so the pool,
68: * usually an array of bytes, is transformed into an array of 32-bit words,
69: * taking each group of 4 bytes in big-endian order. At the end of the
70: * stirring, the transformation is reversed.
71: */
72: void
73: randPoolStir(void)
74: {
75: int i;
76: byte *p;
77: word32 t;
78: word32 iv[4];
79: static word32 randPoolKey[16] = {0};
80:
81: /* Convert to word32s for stirring operation */
82: p = (byte *)randPool;
83: for (i = 0; i < RANDPOOLWORDS; i++) {
84: t = (word32)((unsigned)p[3]<<8 | p[2]) << 16 |
85: (unsigned)p[1]<<8 | p[0];
86: randPool[i] = t;
87: p += 4;
88: }
89:
90: /* Start IV from last block of randPool */
91: memcpy(iv, randPool+RANDPOOLWORDS-4, sizeof(iv));
92:
93: /* First CFB pass */
94: for (i = 0; i < RANDPOOLWORDS; i += 4) {
95: MD5Transform(iv, randPoolKey);
96: iv[0] = randPool[i ] ^= iv[0];
97: iv[1] = randPool[i+1] ^= iv[1];
98: iv[2] = randPool[i+2] ^= iv[2];
99: iv[3] = randPool[i+3] ^= iv[3];
100: }
101:
102: /* Get new key */
103: memcpy(randPoolKey, randPool, sizeof(randPoolKey));
104:
105: /* Second CFB pass */
106: for (i = 0; i < RANDPOOLWORDS; i += 4) {
107: MD5Transform(iv, randPoolKey);
108: iv[0] = randPool[i ] ^= iv[0];
109: iv[1] = randPool[i+1] ^= iv[1];
110: iv[2] = randPool[i+2] ^= iv[2];
111: iv[3] = randPool[i+3] ^= iv[3];
112: }
113:
114: /* Get new key */
115: memcpy(randPoolKey, randPool, sizeof(randPoolKey));
116:
117: /* Wipe iv from memory */
118: memset(iv, 0, sizeof(iv));
119:
120: /* Convert randPool back to bytes for further use */
121: p = (byte *)randPool;
122: for (i = 0; i < RANDPOOLWORDS; i++) {
123: t = randPool[i];
124: p[0] = t>>24;
125: p[1] = t>>16;
126: p[2] = t>>8;
127: p[3] = t;
128: p += 4;
129: }
130:
131: /* Set up pointers for future addition or removal of random bytes */
132: randPoolAddPos = 0;
133: randPoolGetPos = sizeof(randPoolKey);
134: }
135:
136: /*
137: * Make a deposit of information (entropy) into the pool. The bits
138: * deposited need not have any particular distribution; the stirring
139: * operation transformes them to uniformly-distributed bits.
140: */
141: void
142: randPoolAddBytes(byte const *buf, unsigned len)
143: {
144: unsigned t;
145:
146: while (len > (t = sizeof(randPool) - randPoolAddPos)) {
147: xorbytes((byte *)randPool+randPoolAddPos, buf, t);
148: buf += t;
149: len -= t;
150: randPoolStir();
151: }
152:
153: if (len) {
154: xorbytes((byte *)randPool+randPoolAddPos, buf, len);
155: randPoolAddPos += len;
156: randPoolGetPos = sizeof(randPool); /* Force stir on get */
157: }
158: }
159:
160: /*
161: * Withdraw some bits from the pool. Regardless of the distribution of the
162: * input bits, the bits returned are uniformly distributed, although they
163: * cannot, of course, contain more Shannon entropy than the input bits.
164: */
165: void
166: randPoolGetBytes(byte *buf, unsigned len)
167: {
168: unsigned t;
169:
170: while (len > (t = sizeof(randPool) - randPoolGetPos)) {
171: memcpy(buf, (byte *)randPool+randPoolGetPos, t);
172: buf += t;
173: len -= t;
174: randPoolStir();
175: }
176:
177: if (len) {
178: memcpy(buf, (byte *)randPool+randPoolGetPos, len);
179: randPoolGetPos += len;
180: }
181: }
182:
183: byte
184: randPoolGetByte(void)
185: {
186: if (randPoolGetPos == sizeof(randPool))
187: randPoolStir();
188:
189: return (((byte *)randPool)[randPoolGetPos++]);
190: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.