xref: /freebsd/crypto/heimdal/lib/krb5/crypto-arcfour.c (revision fe75646a0234a261c0013bf1840fdac4acaf0cec)
1 /*
2  * Copyright (c) 1997 - 2008 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 /*
35  * ARCFOUR
36  */
37 
38 #include "krb5_locl.h"
39 
40 static struct _krb5_key_type keytype_arcfour = {
41     ENCTYPE_ARCFOUR_HMAC_MD5,
42     "arcfour",
43     128,
44     16,
45     sizeof(struct _krb5_evp_schedule),
46     NULL,
47     _krb5_evp_schedule,
48     _krb5_arcfour_salt,
49     NULL,
50     _krb5_evp_cleanup,
51     EVP_rc4
52 };
53 
54 /*
55  * checksum according to section 5. of draft-brezak-win2k-krb-rc4-hmac-03.txt
56  */
57 
58 krb5_error_code
59 _krb5_HMAC_MD5_checksum(krb5_context context,
60 			struct _krb5_key_data *key,
61 			const void *data,
62 			size_t len,
63 			unsigned usage,
64 			Checksum *result)
65 {
66     EVP_MD_CTX *m;
67     struct _krb5_checksum_type *c = _krb5_find_checksum (CKSUMTYPE_RSA_MD5);
68     const char signature[] = "signaturekey";
69     Checksum ksign_c;
70     struct _krb5_key_data ksign;
71     krb5_keyblock kb;
72     unsigned char t[4];
73     unsigned char tmp[16];
74     unsigned char ksign_c_data[16];
75     krb5_error_code ret;
76 
77     m = EVP_MD_CTX_create();
78     if (m == NULL) {
79 	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
80 	return ENOMEM;
81     }
82     ksign_c.checksum.length = sizeof(ksign_c_data);
83     ksign_c.checksum.data   = ksign_c_data;
84     ret = _krb5_internal_hmac(context, c, signature, sizeof(signature),
85 			      0, key, &ksign_c);
86     if (ret) {
87 	EVP_MD_CTX_destroy(m);
88 	return ret;
89     }
90     ksign.key = &kb;
91     kb.keyvalue = ksign_c.checksum;
92     EVP_DigestInit_ex(m, EVP_md5(), NULL);
93     t[0] = (usage >>  0) & 0xFF;
94     t[1] = (usage >>  8) & 0xFF;
95     t[2] = (usage >> 16) & 0xFF;
96     t[3] = (usage >> 24) & 0xFF;
97     EVP_DigestUpdate(m, t, 4);
98     EVP_DigestUpdate(m, data, len);
99     EVP_DigestFinal_ex (m, tmp, NULL);
100     EVP_MD_CTX_destroy(m);
101 
102     ret = _krb5_internal_hmac(context, c, tmp, sizeof(tmp), 0, &ksign, result);
103     if (ret)
104 	return ret;
105     return 0;
106 }
107 
108 struct _krb5_checksum_type _krb5_checksum_hmac_md5 = {
109     CKSUMTYPE_HMAC_MD5,
110     "hmac-md5",
111     64,
112     16,
113     F_KEYED | F_CPROOF,
114     _krb5_HMAC_MD5_checksum,
115     NULL
116 };
117 
118 /*
119  * section 6 of draft-brezak-win2k-krb-rc4-hmac-03
120  *
121  * warning: not for small children
122  */
123 
124 static krb5_error_code
125 ARCFOUR_subencrypt(krb5_context context,
126 		   struct _krb5_key_data *key,
127 		   void *data,
128 		   size_t len,
129 		   unsigned usage,
130 		   void *ivec)
131 {
132     EVP_CIPHER_CTX *ctx;
133     struct _krb5_checksum_type *c = _krb5_find_checksum (CKSUMTYPE_RSA_MD5);
134     Checksum k1_c, k2_c, k3_c, cksum;
135     struct _krb5_key_data ke;
136     krb5_keyblock kb;
137     unsigned char t[4];
138     unsigned char *cdata = data;
139     unsigned char k1_c_data[16], k2_c_data[16], k3_c_data[16];
140     krb5_error_code ret;
141 
142     t[0] = (usage >>  0) & 0xFF;
143     t[1] = (usage >>  8) & 0xFF;
144     t[2] = (usage >> 16) & 0xFF;
145     t[3] = (usage >> 24) & 0xFF;
146 
147     k1_c.checksum.length = sizeof(k1_c_data);
148     k1_c.checksum.data   = k1_c_data;
149 
150     ret = _krb5_internal_hmac(NULL, c, t, sizeof(t), 0, key, &k1_c);
151     if (ret)
152 	krb5_abortx(context, "hmac failed");
153 
154     memcpy (k2_c_data, k1_c_data, sizeof(k1_c_data));
155 
156     k2_c.checksum.length = sizeof(k2_c_data);
157     k2_c.checksum.data   = k2_c_data;
158 
159     ke.key = &kb;
160     kb.keyvalue = k2_c.checksum;
161 
162     cksum.checksum.length = 16;
163     cksum.checksum.data   = data;
164 
165     ret = _krb5_internal_hmac(NULL, c, cdata + 16, len - 16, 0, &ke, &cksum);
166     if (ret)
167 	krb5_abortx(context, "hmac failed");
168 
169     ke.key = &kb;
170     kb.keyvalue = k1_c.checksum;
171 
172     k3_c.checksum.length = sizeof(k3_c_data);
173     k3_c.checksum.data   = k3_c_data;
174 
175     ret = _krb5_internal_hmac(NULL, c, data, 16, 0, &ke, &k3_c);
176     if (ret)
177 	krb5_abortx(context, "hmac failed");
178 
179     ctx = EVP_CIPHER_CTX_new();
180     if (ctx == NULL)
181 	krb5_abortx(context, "malloc failed");
182 
183     EVP_CipherInit_ex(ctx, EVP_rc4(), NULL, k3_c.checksum.data, NULL, 1);
184     EVP_Cipher(ctx, cdata + 16, cdata + 16, len - 16);
185     EVP_CIPHER_CTX_free(ctx);
186 
187     memset (k1_c_data, 0, sizeof(k1_c_data));
188     memset (k2_c_data, 0, sizeof(k2_c_data));
189     memset (k3_c_data, 0, sizeof(k3_c_data));
190     return 0;
191 }
192 
193 static krb5_error_code
194 ARCFOUR_subdecrypt(krb5_context context,
195 		   struct _krb5_key_data *key,
196 		   void *data,
197 		   size_t len,
198 		   unsigned usage,
199 		   void *ivec)
200 {
201     EVP_CIPHER_CTX *ctx;
202     struct _krb5_checksum_type *c = _krb5_find_checksum (CKSUMTYPE_RSA_MD5);
203     Checksum k1_c, k2_c, k3_c, cksum;
204     struct _krb5_key_data ke;
205     krb5_keyblock kb;
206     unsigned char t[4];
207     unsigned char *cdata = data;
208     unsigned char k1_c_data[16], k2_c_data[16], k3_c_data[16];
209     unsigned char cksum_data[16];
210     krb5_error_code ret;
211 
212     t[0] = (usage >>  0) & 0xFF;
213     t[1] = (usage >>  8) & 0xFF;
214     t[2] = (usage >> 16) & 0xFF;
215     t[3] = (usage >> 24) & 0xFF;
216 
217     k1_c.checksum.length = sizeof(k1_c_data);
218     k1_c.checksum.data   = k1_c_data;
219 
220     ret = _krb5_internal_hmac(NULL, c, t, sizeof(t), 0, key, &k1_c);
221     if (ret)
222 	krb5_abortx(context, "hmac failed");
223 
224     memcpy (k2_c_data, k1_c_data, sizeof(k1_c_data));
225 
226     k2_c.checksum.length = sizeof(k2_c_data);
227     k2_c.checksum.data   = k2_c_data;
228 
229     ke.key = &kb;
230     kb.keyvalue = k1_c.checksum;
231 
232     k3_c.checksum.length = sizeof(k3_c_data);
233     k3_c.checksum.data   = k3_c_data;
234 
235     ret = _krb5_internal_hmac(NULL, c, cdata, 16, 0, &ke, &k3_c);
236     if (ret)
237 	krb5_abortx(context, "hmac failed");
238 
239     ctx = EVP_CIPHER_CTX_new();
240     if (ctx == NULL)
241 	krb5_abortx(context, "malloc failed");
242     EVP_CipherInit_ex(ctx, EVP_rc4(), NULL, k3_c.checksum.data, NULL, 0);
243     EVP_Cipher(ctx, cdata + 16, cdata + 16, len - 16);
244     EVP_CIPHER_CTX_free(ctx);
245 
246     ke.key = &kb;
247     kb.keyvalue = k2_c.checksum;
248 
249     cksum.checksum.length = 16;
250     cksum.checksum.data   = cksum_data;
251 
252     ret = _krb5_internal_hmac(NULL, c, cdata + 16, len - 16, 0, &ke, &cksum);
253     if (ret)
254 	krb5_abortx(context, "hmac failed");
255 
256     memset (k1_c_data, 0, sizeof(k1_c_data));
257     memset (k2_c_data, 0, sizeof(k2_c_data));
258     memset (k3_c_data, 0, sizeof(k3_c_data));
259 
260     if (ct_memcmp (cksum.checksum.data, data, 16) != 0) {
261 	krb5_clear_error_message (context);
262 	return KRB5KRB_AP_ERR_BAD_INTEGRITY;
263     } else {
264 	return 0;
265     }
266 }
267 
268 /*
269  * convert the usage numbers used in
270  * draft-ietf-cat-kerb-key-derivation-00.txt to the ones in
271  * draft-brezak-win2k-krb-rc4-hmac-04.txt
272  */
273 
274 krb5_error_code
275 _krb5_usage2arcfour(krb5_context context, unsigned *usage)
276 {
277     switch (*usage) {
278     case KRB5_KU_AS_REP_ENC_PART : /* 3 */
279 	*usage = 8;
280 	return 0;
281     case KRB5_KU_USAGE_SEAL :  /* 22 */
282 	*usage = 13;
283 	return 0;
284     case KRB5_KU_USAGE_SIGN : /* 23 */
285         *usage = 15;
286         return 0;
287     case KRB5_KU_USAGE_SEQ: /* 24 */
288 	*usage = 0;
289 	return 0;
290     default :
291 	return 0;
292     }
293 }
294 
295 static krb5_error_code
296 ARCFOUR_encrypt(krb5_context context,
297 		struct _krb5_key_data *key,
298 		void *data,
299 		size_t len,
300 		krb5_boolean encryptp,
301 		int usage,
302 		void *ivec)
303 {
304     krb5_error_code ret;
305     unsigned keyusage = usage;
306 
307     if((ret = _krb5_usage2arcfour (context, &keyusage)) != 0)
308 	return ret;
309 
310     if (encryptp)
311 	return ARCFOUR_subencrypt (context, key, data, len, keyusage, ivec);
312     else
313 	return ARCFOUR_subdecrypt (context, key, data, len, keyusage, ivec);
314 }
315 
316 struct _krb5_encryption_type _krb5_enctype_arcfour_hmac_md5 = {
317     ETYPE_ARCFOUR_HMAC_MD5,
318     "arcfour-hmac-md5",
319     1,
320     1,
321     8,
322     &keytype_arcfour,
323     &_krb5_checksum_hmac_md5,
324     &_krb5_checksum_hmac_md5,
325     F_SPECIAL,
326     ARCFOUR_encrypt,
327     0,
328     NULL
329 };
330