1 /**	$MirOS: src/lib/libdes/rnd_keys.c,v 1.2 2005/03/06 20:29:00 tg Exp $	*/
2 /*	$OpenBSD: rnd_keys.c,v 1.2 2000/03/02 00:29:48 todd Exp $	*/
3 
4 /* Copyright (C) 1993 Eric Young - see COPYING for more details */
5 #include "des_locl.h"
6 #include <sys/time.h>
7 
8 #include <unistd.h>
9 
10 #include <sys/socket.h>
11 #include <netinet/in.h>
12 #include <netdb.h>
13 
14 /*
15  * Create a sequence of random 64 bit blocks.
16  * The sequence is indexed with a long long and
17  * based on an initial des key used as a seed.
18  */
19 static des_key_schedule sequence_seed;
20 static u_int32_t sequence_index[2];
21 
22 /*
23  * In case the generator does not get inited use this for backup.
24  */
25 static int initialized;
26 static des_cblock default_seed = {0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef};
27 static void
do_initialize()28 do_initialize()
29 {
30   des_set_odd_parity(&default_seed);
31   des_set_random_generator_seed(&default_seed);
32 }
33 
34 #define zero_long_long(ll) do { ll[0] = ll[1] = 0; } while (0)
35 
36 #define incr_long_long(ll) do { if (++ll[0] == 0) ++ll[1]; } while (0)
37 
38 #define des_set_sequence_number(ll) \
39 do { \
40        memcpy((char *)sequence_index, (ll), sizeof(sequence_index)); \
41      } while (0)
42 
43 #define des_generate_random_block(ret) \
44 do { \
45        des_ecb_encrypt((des_cblock *) sequence_index, (ret), sequence_seed, DES_ENCRYPT); \
46 	 incr_long_long(sequence_index); \
47      } while (0)
48 
49 void
des_set_random_generator_seed(des_cblock * seed)50 des_set_random_generator_seed(des_cblock *seed)
51 {
52   des_key_sched(seed, sequence_seed);
53   zero_long_long(sequence_index);
54   initialized = 1;
55 }
56 
57 /*
58  * Generate a sequence of random des keys
59  * using the random block sequence, fixup
60  * parity and skip weak keys.
61  */
62 int
des_new_random_key(des_cblock * key)63 des_new_random_key(des_cblock *key)
64 {
65   if (!initialized)
66     do_initialize();
67 
68  try_again:
69   des_generate_random_block(key);
70   /* random key must have odd parity and not be weak */
71   des_set_odd_parity(key);
72   if (des_is_weak_key(key))
73     goto try_again;
74   return(0);
75 }
76 
77 /*
78  * des_init_random_number_generator:
79  *
80  *    This routine takes a secret key possibly shared by a number
81  * of servers and uses it to generate a random number stream that is
82  * not shared by any of the other servers.  It does this by using the current
83  * process id, host id, and the current time to the nearest second.  The
84  * resulting stream seed is not useful information for cracking the secret
85  * key.   Moreover, this routine keeps no copy of the secret key.
86  *
87  */
88 void
des_init_random_number_generator(des_cblock * seed)89 des_init_random_number_generator(des_cblock *seed)
90 {
91   struct timeval now;
92   static long uniq[2];
93   des_cblock new_key;
94   long gethostid(void);
95 
96   gettimeofday(&now, (struct timezone *)0);
97   if (!uniq[0])
98     {
99       struct hostent *hent;
100       char hostname[100];
101       gethostname(hostname, sizeof(hostname));
102       hent = gethostbyname(hostname);
103       if (hent != NULL)
104 	memmove(&uniq[0], hent->h_addr_list[0], sizeof(uniq[0]));
105       else
106 	uniq[0] = gethostid();
107 #ifdef MSDOS
108       uniq[1] = 1;
109 #else
110       uniq[1] = getpid();
111 #endif
112     }
113 
114   /* Pick a unique random key from the shared sequence. */
115   des_set_random_generator_seed(seed);
116   des_set_sequence_number((unsigned char *)uniq);
117   des_new_random_key(&new_key);
118 
119   /* Select a new nonshared sequence, */
120   des_set_random_generator_seed(&new_key);
121 
122   /* and use the current time to pick a key for the new sequence. */
123   des_set_sequence_number((unsigned char *)&now);
124   des_new_random_key(&new_key);
125   des_set_random_generator_seed(&new_key);
126 }
127