1 |
/***************************************************************************** |
---|
2 |
* randm.c - Random number generator program file. |
---|
3 |
* |
---|
4 |
* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. |
---|
5 |
* Copyright (c) 1998 by Global Election Systems Inc. |
---|
6 |
* |
---|
7 |
* The authors hereby grant permission to use, copy, modify, distribute, |
---|
8 |
* and license this software and its documentation for any purpose, provided |
---|
9 |
* that existing copyright notices are retained in all copies and that this |
---|
10 |
* notice and the following disclaimer are included verbatim in any |
---|
11 |
* distributions. No written agreement, license, or royalty fee is required |
---|
12 |
* for any of the authorized uses. |
---|
13 |
* |
---|
14 |
* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR |
---|
15 |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
---|
16 |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
---|
17 |
* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
---|
18 |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
---|
19 |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
---|
20 |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
---|
21 |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
---|
22 |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
---|
23 |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
---|
24 |
* |
---|
25 |
****************************************************************************** |
---|
26 |
* REVISION HISTORY |
---|
27 |
* |
---|
28 |
* 03-01-01 Marc Boucher <marc@mbsi.ca> |
---|
29 |
* Ported to lwIP. |
---|
30 |
* 98-06-03 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc. |
---|
31 |
* Extracted from avos. |
---|
32 |
*****************************************************************************/ |
---|
33 |
|
---|
34 |
#include "ppp.h" |
---|
35 |
#if PPP_SUPPORT > 0 |
---|
36 |
#include "md5.h" |
---|
37 |
#include "randm.h" |
---|
38 |
|
---|
39 |
#include "pppdebug.h" |
---|
40 |
|
---|
41 |
|
---|
42 |
#if MD5_SUPPORT>0 /* this module depends on MD5 */ |
---|
43 |
#define RANDPOOLSZ 16 /* Bytes stored in the pool of randomness. */ |
---|
44 |
|
---|
45 |
/*****************************/ |
---|
46 |
/*** LOCAL DATA STRUCTURES ***/ |
---|
47 |
/*****************************/ |
---|
48 |
static char randPool[RANDPOOLSZ]; /* Pool of randomness. */ |
---|
49 |
static long randCount = 0; /* Pseudo-random incrementer */ |
---|
50 |
|
---|
51 |
|
---|
52 |
/***********************************/ |
---|
53 |
/*** PUBLIC FUNCTION DEFINITIONS ***/ |
---|
54 |
/***********************************/ |
---|
55 |
/* |
---|
56 |
* Initialize the random number generator. |
---|
57 |
* |
---|
58 |
* Since this is to be called on power up, we don't have much |
---|
59 |
* system randomess to work with. Here all we use is the |
---|
60 |
* real-time clock. We'll accumulate more randomness as soon |
---|
61 |
* as things start happening. |
---|
62 |
*/ |
---|
63 |
void avRandomInit() |
---|
64 |
{ |
---|
65 |
avChurnRand(NULL, 0); |
---|
66 |
} |
---|
67 |
|
---|
68 |
/* |
---|
69 |
* Churn the randomness pool on a random event. Call this early and often |
---|
70 |
* on random and semi-random system events to build randomness in time for |
---|
71 |
* usage. For randomly timed events, pass a null pointer and a zero length |
---|
72 |
* and this will use the system timer and other sources to add randomness. |
---|
73 |
* If new random data is available, pass a pointer to that and it will be |
---|
74 |
* included. |
---|
75 |
* |
---|
76 |
* Ref: Applied Cryptography 2nd Ed. by Bruce Schneier p. 427 |
---|
77 |
*/ |
---|
78 |
void avChurnRand(char *randData, u32_t randLen) |
---|
79 |
{ |
---|
80 |
MD5_CTX md5; |
---|
81 |
|
---|
82 |
/* ppp_trace(LOG_INFO, "churnRand: %u@%P\n", randLen, randData); */ |
---|
83 |
MD5Init(&md5); |
---|
84 |
MD5Update(&md5, (u_char *)randPool, sizeof(randPool)); |
---|
85 |
if (randData) |
---|
86 |
MD5Update(&md5, (u_char *)randData, randLen); |
---|
87 |
else { |
---|
88 |
struct { |
---|
89 |
/* INCLUDE fields for any system sources of randomness */ |
---|
90 |
char foobar; |
---|
91 |
} sysData; |
---|
92 |
|
---|
93 |
/* Load sysData fields here. */ |
---|
94 |
; |
---|
95 |
MD5Update(&md5, (u_char *)&sysData, sizeof(sysData)); |
---|
96 |
} |
---|
97 |
MD5Final((u_char *)randPool, &md5); |
---|
98 |
/* ppp_trace(LOG_INFO, "churnRand: -> 0\n"); */ |
---|
99 |
} |
---|
100 |
|
---|
101 |
/* |
---|
102 |
* Use the random pool to generate random data. This degrades to pseudo |
---|
103 |
* random when used faster than randomness is supplied using churnRand(). |
---|
104 |
* Note: It's important that there be sufficient randomness in randPool |
---|
105 |
* before this is called for otherwise the range of the result may be |
---|
106 |
* narrow enough to make a search feasible. |
---|
107 |
* |
---|
108 |
* Ref: Applied Cryptography 2nd Ed. by Bruce Schneier p. 427 |
---|
109 |
* |
---|
110 |
* XXX Why does he not just call churnRand() for each block? Probably |
---|
111 |
* so that you don't ever publish the seed which could possibly help |
---|
112 |
* predict future values. |
---|
113 |
* XXX Why don't we preserve md5 between blocks and just update it with |
---|
114 |
* randCount each time? Probably there is a weakness but I wish that |
---|
115 |
* it was documented. |
---|
116 |
*/ |
---|
117 |
void avGenRand(char *buf, u32_t bufLen) |
---|
118 |
{ |
---|
119 |
MD5_CTX md5; |
---|
120 |
u_char tmp[16]; |
---|
121 |
u32_t n; |
---|
122 |
|
---|
123 |
while (bufLen > 0) { |
---|
124 |
n = LWIP_MIN(bufLen, RANDPOOLSZ); |
---|
125 |
MD5Init(&md5); |
---|
126 |
MD5Update(&md5, (u_char *)randPool, sizeof(randPool)); |
---|
127 |
MD5Update(&md5, (u_char *)&randCount, sizeof(randCount)); |
---|
128 |
MD5Final(tmp, &md5); |
---|
129 |
randCount++; |
---|
130 |
memcpy(buf, tmp, n); |
---|
131 |
buf += n; |
---|
132 |
bufLen -= n; |
---|
133 |
} |
---|
134 |
} |
---|
135 |
|
---|
136 |
/* |
---|
137 |
* Return a new random number. |
---|
138 |
*/ |
---|
139 |
u32_t avRandom() |
---|
140 |
{ |
---|
141 |
u32_t newRand; |
---|
142 |
|
---|
143 |
avGenRand((char *)&newRand, sizeof(newRand)); |
---|
144 |
|
---|
145 |
return newRand; |
---|
146 |
} |
---|
147 |
|
---|
148 |
#else /* MD5_SUPPORT */ |
---|
149 |
|
---|
150 |
|
---|
151 |
/*****************************/ |
---|
152 |
/*** LOCAL DATA STRUCTURES ***/ |
---|
153 |
/*****************************/ |
---|
154 |
static int avRandomized = 0; /* Set when truely randomized. */ |
---|
155 |
static u32_t avRandomSeed = 0; /* Seed used for random number generation. */ |
---|
156 |
|
---|
157 |
|
---|
158 |
/***********************************/ |
---|
159 |
/*** PUBLIC FUNCTION DEFINITIONS ***/ |
---|
160 |
/***********************************/ |
---|
161 |
/* |
---|
162 |
* Initialize the random number generator. |
---|
163 |
* |
---|
164 |
* Here we attempt to compute a random number seed but even if |
---|
165 |
* it isn't random, we'll randomize it later. |
---|
166 |
* |
---|
167 |
* The current method uses the fields from the real time clock, |
---|
168 |
* the idle process counter, the millisecond counter, and the |
---|
169 |
* hardware timer tick counter. When this is invoked |
---|
170 |
* in startup(), then the idle counter and timer values may |
---|
171 |
* repeat after each boot and the real time clock may not be |
---|
172 |
* operational. Thus we call it again on the first random |
---|
173 |
* event. |
---|
174 |
*/ |
---|
175 |
void avRandomInit() |
---|
176 |
{ |
---|
177 |
#if 0 |
---|
178 |
/* Get a pointer into the last 4 bytes of clockBuf. */ |
---|
179 |
u32_t *lptr1 = (u32_t *)((char *)&clockBuf[3]); |
---|
180 |
|
---|
181 |
/* |
---|
182 |
* Initialize our seed using the real-time clock, the idle |
---|
183 |
* counter, the millisecond timer, and the hardware timer |
---|
184 |
* tick counter. The real-time clock and the hardware |
---|
185 |
* tick counter are the best sources of randomness but |
---|
186 |
* since the tick counter is only 16 bit (and truncated |
---|
187 |
* at that), the idle counter and millisecond timer |
---|
188 |
* (which may be small values) are added to help |
---|
189 |
* randomize the lower 16 bits of the seed. |
---|
190 |
*/ |
---|
191 |
readClk(); |
---|
192 |
avRandomSeed += *(u32_t *)clockBuf + *lptr1 + OSIdleCtr |
---|
193 |
+ ppp_mtime() + ((u32_t)TM1 << 16) + TM1; |
---|
194 |
#else |
---|
195 |
avRandomSeed += sys_jiffies(); /* XXX */ |
---|
196 |
#endif |
---|
197 |
|
---|
198 |
/* Initialize the Borland random number generator. */ |
---|
199 |
srand((unsigned)avRandomSeed); |
---|
200 |
} |
---|
201 |
|
---|
202 |
/* |
---|
203 |
* Randomize our random seed value. Here we use the fact that |
---|
204 |
* this function is called at *truely random* times by the polling |
---|
205 |
* and network functions. Here we only get 16 bits of new random |
---|
206 |
* value but we use the previous value to randomize the other 16 |
---|
207 |
* bits. |
---|
208 |
*/ |
---|
209 |
void avRandomize(void) |
---|
210 |
{ |
---|
211 |
static u32_t last_jiffies; |
---|
212 |
|
---|
213 |
if (!avRandomized) { |
---|
214 |
avRandomized = !0; |
---|
215 |
avRandomInit(); |
---|
216 |
/* The initialization function also updates the seed. */ |
---|
217 |
} else { |
---|
218 |
/* avRandomSeed += (avRandomSeed << 16) + TM1; */ |
---|
219 |
avRandomSeed += (sys_jiffies() - last_jiffies); /* XXX */ |
---|
220 |
} |
---|
221 |
last_jiffies = sys_jiffies(); |
---|
222 |
} |
---|
223 |
|
---|
224 |
/* |
---|
225 |
* Return a new random number. |
---|
226 |
* Here we use the Borland rand() function to supply a pseudo random |
---|
227 |
* number which we make truely random by combining it with our own |
---|
228 |
* seed which is randomized by truely random events. |
---|
229 |
* Thus the numbers will be truely random unless there have been no |
---|
230 |
* operator or network events in which case it will be pseudo random |
---|
231 |
* seeded by the real time clock. |
---|
232 |
*/ |
---|
233 |
u32_t avRandom() |
---|
234 |
{ |
---|
235 |
return ((((u32_t)rand() << 16) + rand()) + avRandomSeed); |
---|
236 |
} |
---|
237 |
|
---|
238 |
|
---|
239 |
|
---|
240 |
#endif /* MD5_SUPPORT */ |
---|
241 |
#endif /* PPP_SUPPORT */ |
---|
242 |
|
---|