main()1 /*
2 * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska H�gskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by the Kungliga Tekniska
20 * H�gskolan and its contributors.
21 *
22 * 4. Neither the name of the Institute nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 */
38
39 #ifdef HAVE_CONFIG_H
40 #include "config.h"
41
42 RCSID("$Id: rnd_keys.c,v 1.2 2001/12/04 02:06:31 rjs3 Exp $");
43 #endif
44
45 #include <des.h>
46 #include <des_locl.h>
47 #ifdef KRB5
48 #include <krb5-types.h>
49 #elif defined(KRB4)
50 #include <ktypes.h>
51 #endif
52
53 #include <string.h>
54
55 #ifdef TIME_WITH_SYS_TIME
56 #include <sys/time.h>
57 #include <time.h>
58 #elif defined(HAVE_SYS_TIME_H)
59 #include <sys/time.h>
60 #else
61 #include <time.h>
62 #endif
63
64 #ifdef HAVE_SYS_TYPES_H
65 #include <sys/types.h>
66 #endif
67
68 #ifdef HAVE_UNISTD_H
69 #include <unistd.h>
70 #endif
71 #ifdef HAVE_IO_H
72 #include <io.h>
73 #endif
74
75 #ifdef HAVE_SIGNAL_H
76 #include <signal.h>
77 #endif
78 #ifdef HAVE_FCNTL_H
79 #include <fcntl.h>
80 #endif
81
82 #ifdef HAVE_WINSOCK_H
83 #include <winsock.h>
84 #endif
85
86 /*
87 * Generate "random" data by checksumming a file.
88 *
89 * Returns -1 if there were any problems with permissions or I/O
90 * errors.
91 */
92 static
93 int
94 sumFile (const char *name, int len, void *res)
95 {
96 u_int32_t sum[2];
97 u_int32_t buf[1024*2];
98 int fd, i;
99
100 fd = open (name, 0);
101 if (fd < 0)
102 return -1;
103
104 while (len > 0)
105 {
106 int n = read(fd, buf, sizeof(buf));
107 if (n < 0)
108 {
109 close(fd);
110 return n;
111 }
112 for (i = 0; i < (n/sizeof(buf[0])); i++)
113 {
114 sum[0] += buf[i];
115 i++;
116 sum[1] += buf[i];
117 }
118 len -= n;
119 }
120 close (fd);
121 memcpy (res, &sum, sizeof(sum));
122 return 0;
123 }
124
125 #if 0
126 static
127 int
128 md5sumFile (const char *name, int len, int32_t sum[4])
129 {
130 int32_t buf[1024*2];
131 int fd, cnt;
132 struct md5 md5;
133
134 fd = open (name, 0);
135 if (fd < 0)
136 return -1;
137
138 md5_init(&md5);
139 while (len > 0)
140 {
141 int n = read(fd, buf, sizeof(buf));
142 if (n < 0)
143 {
144 close(fd);
145 return n;
146 }
147 md5_update(&md5, buf, n);
148 len -= n;
149 }
150 md5_finito(&md5, (unsigned char *)sum);
151 close (fd);
152 return 0;
153 }
154 #endif
155
156 /*
157 * Create a sequence of random 64 bit blocks.
158 * The sequence is indexed with a long long and
159 * based on an initial des key used as a seed.
160 */
161 static des_key_schedule sequence_seed;
162 static u_int32_t sequence_index[2];
163
164 /*
165 * Random number generator based on ideas from truerand in cryptolib
166 * as described on page 424 in Applied Cryptography 2 ed. by Bruce
167 * Schneier.
168 */
169
170 static volatile int counter;
171 static volatile unsigned char *gdata; /* Global data */
172 static volatile int igdata; /* Index into global data */
173 static int gsize;
174
175 #if !defined(WIN32) && !defined(__EMX__) && !defined(__OS2__) && !defined(__CYGWIN32__)
176 /* Visual C++ 4.0 (Windows95/NT) */
177
178 static
179 RETSIGTYPE
180 sigALRM(int sig)
181 {
182 if (igdata < gsize)
183 gdata[igdata++] ^= counter & 0xff;
184
185 #ifndef HAVE_SIGACTION
186 signal(SIGALRM, sigALRM); /* Reinstall SysV signal handler */
187 #endif
188 SIGRETURN(0);
189 }
190
191 #endif
192
193 #if !defined(HAVE_RANDOM) && defined(HAVE_RAND)
194 #ifndef srandom
195 #define srandom srand
196 #endif
197 #ifndef random
198 #define random rand
199 #endif
200 #endif
201
202 static void
203 des_not_rand_data(unsigned char *data, int size)
204 {
205 int i;
206
207 srandom (time (NULL));
208
209 for(i = 0; i < size; ++i)
210 data[i] ^= random() % 0x100;
211 }
212
213 #if !defined(WIN32) && !defined(__EMX__) && !defined(__OS2__) && !defined(__CYGWIN32__)
214
215 #ifndef HAVE_SETITIMER
216 static void
217 pacemaker(struct timeval *tv)
218 {
219 fd_set fds;
220 pid_t pid;
221 pid = getppid();
222 while(1){
223 FD_ZERO(&fds);
224 FD_SET(0, &fds);
225 select(1, &fds, NULL, NULL, tv);
226 kill(pid, SIGALRM);
227 }
228 }
229 #endif
230
231 /*
232 * Generate size bytes of "random" data using timed interrupts.
233 * It takes about 40ms/byte random data.
234 * It's not neccessary to be root to run it.
235 */
236 void
237 des_rand_data(unsigned char *data, int size)
238 {
239 struct itimerval tv, otv;
240 #ifdef HAVE_SIGACTION
241 struct sigaction sa, osa;
242 #else
243 RETSIGTYPE (*osa)(int);
244 #endif
245 int i, j;
246 #ifndef HAVE_SETITIMER
247 pid_t pid;
248 #endif
249 char *rnd_devices[] = {"/dev/random",
250 "/dev/srandom",
251 "/dev/urandom",
252 NULL};
253 char **p;
254
255 for(p = rnd_devices; *p; p++) {
256 int fd = open(*p, O_RDONLY | O_NDELAY);
257
258 if(fd >= 0 && read(fd, data, size) == size) {
259 close(fd);
260 return;
261 }
262 close(fd);
263 }
264
265 /* Paranoia? Initialize data from /dev/mem if we can read it. */
266 if (size >= 8)
267 sumFile("/dev/mem", (1024*1024*2), data);
268
269 gdata = data;
270 gsize = size;
271 igdata = 0;
272
273 #ifdef HAVE_SIGACTION
274 /* Setup signal handler */
275 sa.sa_handler = sigALRM;
276 sa.sa_flags = 0;
277 sigemptyset(&sa.sa_mask);
278 sigaction(SIGALRM, &sa, &osa);
279 #else
280 osa = signal(SIGALRM, sigALRM);
281 #endif
282
283 /* Start timer */
284 tv.it_value.tv_sec = 0;
285 tv.it_value.tv_usec = 10 * 1000; /* 10 ms */
286 tv.it_interval = tv.it_value;
287 #ifdef HAVE_SETITIMER
288 setitimer(ITIMER_REAL, &tv, &otv);
289 #else
290 pid = fork();
291 if(pid == -1){
292 des_not_rand_data(data, size);
293 return;
294 }
295 if(pid == 0)
296 pacemaker(&tv.it_interval);
297 #endif
298
299 for(i = 0; i < 4; i++) {
300 for (igdata = 0; igdata < size;) /* igdata++ in sigALRM */
301 counter++;
302 for (j = 0; j < size; j++) /* Only use 2 bits each lap */
303 gdata[j] = (gdata[j]>>2) | (gdata[j]<<6);
304 }
305 #ifdef HAVE_SETITIMER
306 setitimer(ITIMER_REAL, &otv, 0);
307 #else
308 kill(pid, SIGKILL);
309 waitpid(pid, NULL, 0);
310 #endif
311 #ifdef HAVE_SIGACTION
312 sigaction(SIGALRM, &osa, 0);
313 #else
314 signal(SIGALRM, osa != SIG_ERR ? osa : SIG_DFL);
315 #endif
316 }
317 #else
318 void
319 des_rand_data(unsigned char *p, int s)
320 {
321 des_not_rand_data (p, s);
322 }
323 #endif
324
325 void
326 des_generate_random_block(des_cblock *block)
327 {
328 des_rand_data((unsigned char *)block, sizeof(*block));
329 }
330
331 /*
332 * Generate a "random" DES key.
333 */
334 void
335 des_rand_data_key(des_cblock *key)
336 {
337 unsigned char data[8];
338 des_key_schedule sched;
339 do {
340 des_rand_data(data, sizeof(data));
341 des_rand_data((unsigned char*)key, sizeof(des_cblock));
342 des_set_odd_parity(key);
343 des_key_sched(key, sched);
344 des_ecb_encrypt(&data, key, sched, DES_ENCRYPT);
345 memset(&data, 0, sizeof(data));
346 memset(&sched, 0, sizeof(sched));
347 des_set_odd_parity(key);
348 } while(des_is_weak_key(key));
349 }
350
351 /*
352 * Generate "random" data by checksumming /dev/mem
353 *
354 * It's neccessary to be root to run it. Returns -1 if there were any
355 * problems with permissions.
356 */
357 int
358 des_mem_rand8(unsigned char *data)
359 {
360 return 1;
361 }
362
363 /*
364 * In case the generator does not get initialized use this as fallback.
365 */
366 static int initialized;
367
368 static void
369 do_initialize(void)
370 {
371 des_cblock default_seed;
372 do {
373 des_generate_random_block(&default_seed);
374 des_set_odd_parity(&default_seed);
375 } while (des_is_weak_key(&default_seed));
376 des_init_random_number_generator(&default_seed);
377 }
378
379 #define zero_long_long(ll) do { ll[0] = ll[1] = 0; } while (0)
380
381 #define incr_long_long(ll) do { if (++ll[0] == 0) ++ll[1]; } while (0)
382
383 #define set_sequence_number(ll) \
384 memcpy((char *)sequence_index, (ll), sizeof(sequence_index));
385
386 /*
387 * Set the sequnce number to this value (a long long).
388 */
389 void
390 des_set_sequence_number(unsigned char *ll)
391 {
392 set_sequence_number(ll);
393 }
394
395 /*
396 * Set the generator seed and reset the sequence number to 0.
397 */
398 void
399 des_set_random_generator_seed(des_cblock *seed)
400 {
401 des_key_sched(seed, sequence_seed);
402 zero_long_long(sequence_index);
403 initialized = 1;
404 }
405
406 /*
407 * Generate a sequence of random des keys
408 * using the random block sequence, fixup
409 * parity and skip weak keys.
410 */
411 int
412 des_new_random_key(des_cblock *key)
413 {
414 if (!initialized)
415 do_initialize();
416
417 do {
418 des_ecb_encrypt((des_cblock *) sequence_index,
419 key,
420 sequence_seed,
421 DES_ENCRYPT);
422 incr_long_long(sequence_index);
423 /* random key must have odd parity and not be weak */
424 des_set_odd_parity(key);
425 } while (des_is_weak_key(key));
426 return(0);
427 }
428
429 /*
430 * des_init_random_number_generator:
431 *
432 * Initialize the sequence of random 64 bit blocks. The input seed
433 * can be a secret key since it should be well hidden and is also not
434 * kept.
435 *
436 */
437 void
438 des_init_random_number_generator(des_cblock *seed)
439 {
440 struct timeval now;
441 des_cblock uniq;
442 des_cblock new_key;
443
444 gettimeofday(&now, (struct timezone *)0);
445 des_generate_random_block(&uniq);
446
447 /* Pick a unique random key from the shared sequence. */
448 des_set_random_generator_seed(seed);
449 set_sequence_number((unsigned char *)&uniq);
450 des_new_random_key(&new_key);
451
452 /* Select a new nonshared sequence, */
453 des_set_random_generator_seed(&new_key);
454
455 /* and use the current time to pick a key for the new sequence. */
456 set_sequence_number((unsigned char *)&now);
457 des_new_random_key(&new_key);
458 des_set_random_generator_seed(&new_key);
459 }
460
461 /* This is for backwards compatibility. */
462 void
463 des_random_key(des_cblock ret)
464 {
465 des_new_random_key((des_cblock *)ret);
466 }
467
468 #ifdef TESTRUN
469 int
470 main()
471 {
472 unsigned char data[8];
473 int i;
474
475 while (1)
476 {
477 if (sumFile("/dev/mem", (1024*1024*8), data) != 0)
478 { perror("sumFile"); exit(1); }
479 for (i = 0; i < 8; i++)
480 printf("%02x", data[i]);
481 printf("\n");
482 }
483 }
484 #endif
485
486 #ifdef TESTRUN2
487 int
488 main()
489 {
490 des_cblock data;
491 int i;
492
493 while (1)
494 {
495 do_initialize();
496 des_random_key(data);
497 for (i = 0; i < 8; i++)
498 printf("%02x", data[i]);
499 printf("\n");
500 }
501 }
502 #endif
503