Windows global stuff:
[krb5.git] / src / lib / crypto / des / new_rn_key.c
1 /*
2  * lib/crypto/des/new_rn_key.c
3  *
4  * Copyright 1988,1990 by the Massachusetts Institute of Technology.
5  * All Rights Reserved.
6  *
7  * Export of this software from the United States of America may
8  *   require a specific license from the United States Government.
9  *   It is the responsibility of any person or organization contemplating
10  *   export to obtain such a license before exporting.
11  * 
12  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13  * distribute this software and its documentation for any purpose and
14  * without fee is hereby granted, provided that the above copyright
15  * notice appear in all copies and that both that copyright notice and
16  * this permission notice appear in supporting documentation, and that
17  * the name of M.I.T. not be used in advertising or publicity pertaining
18  * to distribution of the software without specific, written prior
19  * permission.  M.I.T. makes no representations about the suitability of
20  * this software for any purpose.  It is provided "as is" without express
21  * or implied warranty.
22  * 
23  *
24  * New pseudo-random key generator, using DES encryption to make the
25  * pseudo-random cycle as hard to break as DES.
26  *
27  * Written by Mark Lillibridge, MIT Project Athena
28  *
29  * Under U.S. law, this software may not be exported outside the US
30  * without license from the U.S. Commerce department.
31  */
32
33 #include "k5-int.h"
34 #include "des_int.h"
35
36 #ifndef min
37 #define min(a,b) (((a) < (b)) ? (a) : (b))
38 #endif
39
40 /*
41  * mit_des_new_random_key: create a random des key
42  *
43  * Requires: mit_des_set_random_number_generater_seed must be at called least
44  *           once before this routine is called.
45  *
46  * Notes: the returned key has correct parity and is guarenteed not
47  *        to be a weak des key.  Mit_Des_generate_random_block is used to
48  *        provide the random bits.
49  */
50 int
51 mit_des_new_random_key(key, p_seed)
52     mit_des_cblock key;
53     mit_des_random_key_seed     *p_seed;
54 {
55     do {
56         mit_des_generate_random_block(key, p_seed);
57         mit_des_fixup_key_parity(key);
58     } while (mit_des_is_weak_key(key));
59
60     return(0);
61 }
62
63 /*
64  * mit_des_init_random_number_generator:
65  *
66  *    This routine takes a secret key possibly shared by a number
67  * of servers and uses it to generate a random number stream that is
68  * not shared by any of the other servers.  It does this by using the current
69  * process id, host id, and the current time to the nearest second.  The
70  * resulting stream seed is not useful information for cracking the secret
71  * key.   Moreover, this routine keeps no copy of the secret key.
72  * This routine is used for example, by the kerberos server(s) with the
73  * key in question being the kerberos master key.
74  *
75  * Note: this routine calls mit_des_set_random_generator_seed.
76  */
77
78 void
79 mit_des_init_random_number_generator(key,p_seed)
80     mit_des_cblock key;
81     mit_des_random_key_seed     *p_seed;
82 {
83     mit_des_cblock seed; /* This must be 64 bits exactly */
84     struct tval {
85         krb5_int32 seconds;
86         krb5_int32 microseconds;
87     } timenow;
88     mit_des_cblock new_key;
89
90     krb5_address **addrs = 0;
91     krb5_context context;
92
93     /*
94      * use a host id in generating the seed to ensure
95      * that different servers have different streams:
96      */
97     memset((char *)seed, 0, sizeof(seed));
98     if (!krb5_os_localaddr(&addrs) && addrs && *addrs) {
99         memcpy((char *)seed, (char *)addrs[0]->contents,
100               min(sizeof(seed), addrs[0]->length));
101         /* XXX may not do all of the seed. */
102     }
103     if (addrs) {
104         /* can't use krb5_free_addresses due to circular dependencies in
105            libraries */
106         register krb5_address **addr2;
107         for (addr2 = addrs; *addr2; addr2++) {
108             krb5_xfree((*addr2)->contents);
109             krb5_xfree(*addr2);
110         }
111         krb5_xfree(addrs);
112     }
113     /*
114      * Generate a temporary value that depends on the key and host_id
115      * such that it gives no useful information about the key:
116      */
117     mit_des_set_random_generator_seed(key, p_seed);
118     mit_des_set_sequence_number(seed, p_seed);
119     mit_des_new_random_key(new_key, p_seed);
120
121     /*
122      * use it to select a random stream:
123      */      
124     mit_des_set_random_generator_seed(new_key, p_seed);
125
126     /*
127      * use a time stamp to ensure that a server started later does not reuse
128      * an old stream:
129      */
130     (void) krb5_us_timeofday(context, &timenow.seconds,
131                              &timenow.microseconds); /* XXX return value */
132     mit_des_set_sequence_number((unsigned char *)&timenow, p_seed);
133
134     /*
135      * use the time stamp finally to select the final seed using the
136      * current random number stream:
137      */
138     mit_des_new_random_key(new_key, p_seed);
139     mit_des_set_random_generator_seed(new_key, p_seed);
140 }
141
142 /*
143  * This module implements a random number generator faculty such that the next
144  * number in any random number stream is very hard to predict without knowing
145  * the seed for that stream even given the preceeding random numbers.
146  */
147
148 /*
149  * mit_des_set_random_generator_seed: this routine is used to select a random
150  *                                number stream.  The stream that results is
151  *                                totally determined by the passed in key.
152  *                                (I.e., calling this routine again with the
153  *                                same key allows repeating a sequence of
154  *                                random numbers)
155  *
156  * Requires: key is a valid des key.  I.e., has correct parity and is not a
157  *           weak des key.
158  */
159 void
160 mit_des_set_random_generator_seed(key, p_seed)
161     mit_des_cblock key;
162     mit_des_random_key_seed     *p_seed;
163 {
164     register int i;
165
166     /* select the new stream: (note errors are not possible here...) */
167     mit_des_key_sched(key, p_seed->random_sequence_key);
168
169     /* "seek" to the start of the stream: */
170     for (i=0; i<8; i++)
171       p_seed->sequence_number[i] = 0;
172 }
173
174 /*
175  * mit_des_set_sequence_number: this routine is used to set the sequence number
176  *                          of the current random number stream.  This routine
177  *                          may be used to "seek" within the current random
178  *                          number stream.
179  *
180  * Note that mit_des_set_random_generator_seed resets the sequence number to 0.
181  */
182 void
183 mit_des_set_sequence_number(new_sequence_number, p_seed)
184     mit_des_cblock new_sequence_number;
185     mit_des_random_key_seed     *p_seed;
186 {
187     memcpy((char *)p_seed->sequence_number, (char *)new_sequence_number,
188           sizeof(p_seed->sequence_number));
189 }
190
191 /*
192  * mit_des_generate_random_block: routine to return the next random number
193  *                            from the current random number stream.
194  *                            The returned number is 64 bits long.
195  *
196  * Requires: mit_des_set_random_generator_seed must have been called at least once
197  *           before this routine is called.
198  */
199 void
200 mit_des_generate_random_block(block, p_seed)
201     mit_des_cblock block;
202     mit_des_random_key_seed     *p_seed;
203 {
204     int i;
205
206     /*
207      * Encrypt the sequence number to get the new random block:
208      */
209     mit_des_ecb_encrypt((unsigned long *)p_seed->sequence_number, 
210                     (unsigned long *)block, 
211                     p_seed->random_sequence_key, 1);
212
213     /*
214      * Increment the sequence number as an 8 byte unsigned number with wrap:
215      * (using LSB here)
216      */
217     for (i=0; i<8; i++) {
218         p_seed->sequence_number[i] = (p_seed->sequence_number[i] + 1) & 0xff;
219         if (p_seed->sequence_number[i])
220           break;
221     }
222 }