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