1 /*	$NetBSD: crypto-arcfour.c,v 1.1.1.1 2011/04/13 18:15:32 elric Exp $	*/
2 
3 /*
4  * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan
5  * (Royal Institute of Technology, Stockholm, Sweden).
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * 3. Neither the name of the Institute nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 /*
37  * ARCFOUR
38  */
39 
40 #include "krb5_locl.h"
41 
42 static struct _krb5_key_type keytype_arcfour = {
43     KEYTYPE_ARCFOUR,
44     "arcfour",
45     128,
46     16,
47     sizeof(struct _krb5_evp_schedule),
48     NULL,
49     _krb5_evp_schedule,
50     _krb5_arcfour_salt,
51     NULL,
52     _krb5_evp_cleanup,
53     EVP_rc4
54 };
55 
56 /*
57  * checksum according to section 5. of draft-brezak-win2k-krb-rc4-hmac-03.txt
58  */
59 
60 krb5_error_code
61 _krb5_HMAC_MD5_checksum(krb5_context context,
62 			struct _krb5_key_data *key,
63 			const void *data,
64 			size_t len,
65 			unsigned usage,
66 			Checksum *result)
67 {
68     EVP_MD_CTX *m;
69     struct _krb5_checksum_type *c = _krb5_find_checksum (CKSUMTYPE_RSA_MD5);
70     const char signature[] = "signaturekey";
71     Checksum ksign_c;
72     struct _krb5_key_data ksign;
73     krb5_keyblock kb;
74     unsigned char t[4];
75     unsigned char tmp[16];
76     unsigned char ksign_c_data[16];
77     krb5_error_code ret;
78 
79     m = EVP_MD_CTX_create();
80     if (m == NULL) {
81 	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
82 	return ENOMEM;
83     }
84     ksign_c.checksum.length = sizeof(ksign_c_data);
85     ksign_c.checksum.data   = ksign_c_data;
86     ret = _krb5_internal_hmac(context, c, signature, sizeof(signature),
87 			      0, key, &ksign_c);
88     if (ret) {
89 	EVP_MD_CTX_destroy(m);
90 	return ret;
91     }
92     ksign.key = &kb;
93     kb.keyvalue = ksign_c.checksum;
94     EVP_DigestInit_ex(m, EVP_md5(), NULL);
95     t[0] = (usage >>  0) & 0xFF;
96     t[1] = (usage >>  8) & 0xFF;
97     t[2] = (usage >> 16) & 0xFF;
98     t[3] = (usage >> 24) & 0xFF;
99     EVP_DigestUpdate(m, t, 4);
100     EVP_DigestUpdate(m, data, len);
101     EVP_DigestFinal_ex (m, tmp, NULL);
102     EVP_MD_CTX_destroy(m);
103 
104     ret = _krb5_internal_hmac(context, c, tmp, sizeof(tmp), 0, &ksign, result);
105     if (ret)
106 	return ret;
107     return 0;
108 }
109 
110 struct _krb5_checksum_type _krb5_checksum_hmac_md5 = {
111     CKSUMTYPE_HMAC_MD5,
112     "hmac-md5",
113     64,
114     16,
115     F_KEYED | F_CPROOF,
116     _krb5_HMAC_MD5_checksum,
117     NULL
118 };
119 
120 /*
121  * section 6 of draft-brezak-win2k-krb-rc4-hmac-03
122  *
123  * warning: not for small children
124  */
125 
126 static krb5_error_code
127 ARCFOUR_subencrypt(krb5_context context,
128 		   struct _krb5_key_data *key,
129 		   void *data,
130 		   size_t len,
131 		   unsigned usage,
132 		   void *ivec)
133 {
134     EVP_CIPHER_CTX ctx;
135     struct _krb5_checksum_type *c = _krb5_find_checksum (CKSUMTYPE_RSA_MD5);
136     Checksum k1_c, k2_c, k3_c, cksum;
137     struct _krb5_key_data ke;
138     krb5_keyblock kb;
139     unsigned char t[4];
140     unsigned char *cdata = data;
141     unsigned char k1_c_data[16], k2_c_data[16], k3_c_data[16];
142     krb5_error_code ret;
143 
144     t[0] = (usage >>  0) & 0xFF;
145     t[1] = (usage >>  8) & 0xFF;
146     t[2] = (usage >> 16) & 0xFF;
147     t[3] = (usage >> 24) & 0xFF;
148 
149     k1_c.checksum.length = sizeof(k1_c_data);
150     k1_c.checksum.data   = k1_c_data;
151 
152     ret = _krb5_internal_hmac(NULL, c, t, sizeof(t), 0, key, &k1_c);
153     if (ret)
154 	krb5_abortx(context, "hmac failed");
155 
156     memcpy (k2_c_data, k1_c_data, sizeof(k1_c_data));
157 
158     k2_c.checksum.length = sizeof(k2_c_data);
159     k2_c.checksum.data   = k2_c_data;
160 
161     ke.key = &kb;
162     kb.keyvalue = k2_c.checksum;
163 
164     cksum.checksum.length = 16;
165     cksum.checksum.data   = data;
166 
167     ret = _krb5_internal_hmac(NULL, c, cdata + 16, len - 16, 0, &ke, &cksum);
168     if (ret)
169 	krb5_abortx(context, "hmac failed");
170 
171     ke.key = &kb;
172     kb.keyvalue = k1_c.checksum;
173 
174     k3_c.checksum.length = sizeof(k3_c_data);
175     k3_c.checksum.data   = k3_c_data;
176 
177     ret = _krb5_internal_hmac(NULL, c, data, 16, 0, &ke, &k3_c);
178     if (ret)
179 	krb5_abortx(context, "hmac failed");
180 
181     EVP_CIPHER_CTX_init(&ctx);
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_cleanup(&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     EVP_CIPHER_CTX_init(&ctx);
240     EVP_CipherInit_ex(&ctx, EVP_rc4(), NULL, k3_c.checksum.data, NULL, 0);
241     EVP_Cipher(&ctx, cdata + 16, cdata + 16, len - 16);
242     EVP_CIPHER_CTX_cleanup(&ctx);
243 
244     ke.key = &kb;
245     kb.keyvalue = k2_c.checksum;
246 
247     cksum.checksum.length = 16;
248     cksum.checksum.data   = cksum_data;
249 
250     ret = _krb5_internal_hmac(NULL, c, cdata + 16, len - 16, 0, &ke, &cksum);
251     if (ret)
252 	krb5_abortx(context, "hmac failed");
253 
254     memset (k1_c_data, 0, sizeof(k1_c_data));
255     memset (k2_c_data, 0, sizeof(k2_c_data));
256     memset (k3_c_data, 0, sizeof(k3_c_data));
257 
258     if (ct_memcmp (cksum.checksum.data, data, 16) != 0) {
259 	krb5_clear_error_message (context);
260 	return KRB5KRB_AP_ERR_BAD_INTEGRITY;
261     } else {
262 	return 0;
263     }
264 }
265 
266 /*
267  * convert the usage numbers used in
268  * draft-ietf-cat-kerb-key-derivation-00.txt to the ones in
269  * draft-brezak-win2k-krb-rc4-hmac-04.txt
270  */
271 
272 krb5_error_code
273 _krb5_usage2arcfour(krb5_context context, unsigned *usage)
274 {
275     switch (*usage) {
276     case KRB5_KU_AS_REP_ENC_PART : /* 3 */
277 	*usage = 8;
278 	return 0;
279     case KRB5_KU_USAGE_SEAL :  /* 22 */
280 	*usage = 13;
281 	return 0;
282     case KRB5_KU_USAGE_SIGN : /* 23 */
283         *usage = 15;
284         return 0;
285     case KRB5_KU_USAGE_SEQ: /* 24 */
286 	*usage = 0;
287 	return 0;
288     default :
289 	return 0;
290     }
291 }
292 
293 static krb5_error_code
294 ARCFOUR_encrypt(krb5_context context,
295 		struct _krb5_key_data *key,
296 		void *data,
297 		size_t len,
298 		krb5_boolean encryptp,
299 		int usage,
300 		void *ivec)
301 {
302     krb5_error_code ret;
303     unsigned keyusage = usage;
304 
305     if((ret = _krb5_usage2arcfour (context, &keyusage)) != 0)
306 	return ret;
307 
308     if (encryptp)
309 	return ARCFOUR_subencrypt (context, key, data, len, keyusage, ivec);
310     else
311 	return ARCFOUR_subdecrypt (context, key, data, len, keyusage, ivec);
312 }
313 
314 struct _krb5_encryption_type _krb5_enctype_arcfour_hmac_md5 = {
315     ETYPE_ARCFOUR_HMAC_MD5,
316     "arcfour-hmac-md5",
317     1,
318     1,
319     8,
320     &keytype_arcfour,
321     &_krb5_checksum_hmac_md5,
322     NULL,
323     F_SPECIAL,
324     ARCFOUR_encrypt,
325     0,
326     NULL
327 };
328