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