2 * Copyright 1988 by the Massachusetts Institute of Technology.
4 * For copying and distribution information, please see the file
7 * New pseudo-random key generator, using DES encryption to make the
8 * pseudo-random cycle as hard to break as DES.
10 * Written by Mark Lillibridge, MIT Project Athena
12 * Under U.S. law, this software may not be exported outside the US
13 * without license from the U.S. Commerce department.
16 #include <mit-cpyright.h>
18 #include <afsconfig.h>
19 #include <afs/param.h>
28 #include "des_internal.h"
29 #include "des_prototypes.h"
31 #ifdef AFS_PTHREAD_ENV
43 static afs_int32 des_set_sequence_number(des_cblock new_sequence_number);
44 static afs_int32 des_generate_random_block(des_cblock block);
46 #define XPRT_NEW_RND_KEY
48 static int is_inited = 0;
49 #ifdef AFS_PTHREAD_ENV
51 * This mutex protects the following global variables:
56 pthread_mutex_t des_init_mutex;
57 #define LOCK_INIT assert(pthread_mutex_lock(&des_init_mutex)==0);
58 #define UNLOCK_INIT assert(pthread_mutex_unlock(&des_init_mutex)==0);
64 * des_random_key: create a random des key
66 * You should call des_set_random_number_generater_seed at least
67 * once before this routine is called. If you haven't, I'll try
68 * to add a little randomness to the start point anyway. Yes,
69 * it recurses. Deal with it.
71 * Notes: the returned key has correct parity and is guarenteed not
72 * to be a weak des key. Des_generate_random_block is used to
73 * provide the random bits.
76 des_random_key(des_cblock key)
78 LOCK_INIT if (!is_inited) {
79 void des_init_random_number_generator();
80 des_init_random_number_generator(key);
84 des_generate_random_block(key);
85 des_fixup_key_parity(key);
86 } while (des_is_weak_key(key));
92 * des_init_random_number_generator:
94 * This routine takes a secret key possibly shared by a number
95 * of servers and uses it to generate a random number stream that is
96 * not shared by any of the other servers. It does this by using the current
97 * process id, host id, and the current time to the nearest second. The
98 * resulting stream seed is not useful information for cracking the secret
99 * key. Moreover, this routine keeps no copy of the secret key.
100 * This routine is used for example, by the kerberos server(s) with the
101 * key in question being the kerberos master key.
103 * Note: this routine calls des_set_random_generator_seed.
105 #if !defined(BSDUNIX) && !defined(AFS_SGI_ENV) && !defined(AFS_NT40_ENV) && !defined(AFS_LINUX20_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_DJGPP_ENV)
106 you lose ... (aka, you get to implement an analog of this for your system ...)
110 #include <winsock2.h>
112 #include <afs/afsutil.h>
114 #include <sys/time.h>
119 des_init_random_number_generator(des_cblock key)
121 struct { /* This must be 64 bits exactly */
122 afs_int32 process_id;
125 struct timeval time; /* this must also be 64 bits exactly */
130 * use a host id and process id in generating the seed to ensure
131 * that different servers have different streams:
133 #if !defined(AFS_HPUX_ENV) && !defined(AFS_NT40_ENV) && !defined(AFS_DJGPP_ENV)
134 seed.host_id = gethostid();
136 seed.process_id = getpid();
139 * Generate a tempory value that depends on the key, host_id, and
140 * process_id such that it gives no useful information about the key:
142 des_set_random_generator_seed(key);
143 des_set_sequence_number((unsigned char *)&seed);
144 des_random_key(new_key);
147 * use it to select a random stream:
149 des_set_random_generator_seed(new_key);
152 * use a time stamp to ensure that a server started later does not reuse
155 gettimeofday(&time, NULL);
156 des_set_sequence_number((unsigned char *)&time);
159 * use the time stamp finally to select the final seed using the
160 * current random number stream:
162 des_random_key(new_key);
163 des_set_random_generator_seed(new_key);
166 #endif /* ifdef BSDUNIX */
169 * This module implements a random number generator faculty such that the next
170 * number in any random number stream is very hard to predict without knowing
171 * the seed for that stream even given the preceeding random numbers.
175 * The secret des key schedule for the current stream of random numbers:
180 } random_sequence_key;
183 * The sequence # in the current stream of random numbers:
185 static unsigned char sequence_number[8];
187 #ifdef AFS_PTHREAD_ENV
189 * This mutex protects the following global variables:
190 * random_sequence_key
195 pthread_mutex_t des_random_mutex;
196 #define LOCK_RANDOM assert(pthread_mutex_lock(&des_random_mutex)==0);
197 #define UNLOCK_RANDOM assert(pthread_mutex_unlock(&des_random_mutex)==0);
200 #define UNLOCK_RANDOM
204 * des_set_random_generator_seed: this routine is used to select a random
205 * number stream. The stream that results is
206 * totally determined by the passed in key.
207 * (I.e., calling this routine again with the
208 * same key allows repeating a sequence of
211 * Requires: key is a valid des key. I.e., has correct parity and is not a
215 des_set_random_generator_seed(des_cblock key)
219 /* select the new stream: (note errors are not possible here...) */
220 LOCK_RANDOM des_key_sched(key, random_sequence_key.d);
222 /* "seek" to the start of the stream: */
223 for (i = 0; i < 8; i++)
224 sequence_number[i] = 0;
228 * des_set_sequence_number: this routine is used to set the sequence number
229 * of the current random number stream. This routine
230 * may be used to "seek" within the current random
233 * Note that des_set_random_generator_seed resets the sequence number to 0.
236 des_set_sequence_number(des_cblock new_sequence_number)
238 LOCK_RANDOM memcpy((char *)sequence_number, (char *)new_sequence_number,
239 sizeof(sequence_number));
240 UNLOCK_RANDOM return 0;
244 * des_generate_random_block: routine to return the next random number
245 * from the current random number stream.
246 * The returned number is 64 bits long.
248 * Requires: des_set_random_generator_seed must have been called at least once
249 * before this routine is called.
252 des_generate_random_block(des_cblock block)
256 LOCK_RXKAD_STATS rxkad_stats.des_randoms++;
259 * Encrypt the sequence number to get the new random block:
261 LOCK_RANDOM des_ecb_encrypt(sequence_number, block,
262 random_sequence_key.d, 1);
265 * Increment the sequence number as an 8 byte unsigned number with wrap:
268 for (i = 0; i < 8; i++) {
269 sequence_number[i] = (sequence_number[i] + 1) & 0xff;
270 if (sequence_number[i])
273 UNLOCK_RANDOM return 0;