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