xref: /freebsd/crypto/heimdal/lib/krb5/crypto-arcfour.c (revision f4b37ed0f8b307b1f3f0f630ca725d68f1dff30d)
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     EVP_CIPHER_CTX_init(&ctx);
180 
181     EVP_CipherInit_ex(&ctx, EVP_rc4(), NULL, k3_c.checksum.data, NULL, 1);
182     EVP_Cipher(&ctx, cdata + 16, cdata + 16, len - 16);
183     EVP_CIPHER_CTX_cleanup(&ctx);
184 
185     memset (k1_c_data, 0, sizeof(k1_c_data));
186     memset (k2_c_data, 0, sizeof(k2_c_data));
187     memset (k3_c_data, 0, sizeof(k3_c_data));
188     return 0;
189 }
190 
191 static krb5_error_code
192 ARCFOUR_subdecrypt(krb5_context context,
193 		   struct _krb5_key_data *key,
194 		   void *data,
195 		   size_t len,
196 		   unsigned usage,
197 		   void *ivec)
198 {
199     EVP_CIPHER_CTX ctx;
200     struct _krb5_checksum_type *c = _krb5_find_checksum (CKSUMTYPE_RSA_MD5);
201     Checksum k1_c, k2_c, k3_c, cksum;
202     struct _krb5_key_data ke;
203     krb5_keyblock kb;
204     unsigned char t[4];
205     unsigned char *cdata = data;
206     unsigned char k1_c_data[16], k2_c_data[16], k3_c_data[16];
207     unsigned char cksum_data[16];
208     krb5_error_code ret;
209 
210     t[0] = (usage >>  0) & 0xFF;
211     t[1] = (usage >>  8) & 0xFF;
212     t[2] = (usage >> 16) & 0xFF;
213     t[3] = (usage >> 24) & 0xFF;
214 
215     k1_c.checksum.length = sizeof(k1_c_data);
216     k1_c.checksum.data   = k1_c_data;
217 
218     ret = _krb5_internal_hmac(NULL, c, t, sizeof(t), 0, key, &k1_c);
219     if (ret)
220 	krb5_abortx(context, "hmac failed");
221 
222     memcpy (k2_c_data, k1_c_data, sizeof(k1_c_data));
223 
224     k2_c.checksum.length = sizeof(k2_c_data);
225     k2_c.checksum.data   = k2_c_data;
226 
227     ke.key = &kb;
228     kb.keyvalue = k1_c.checksum;
229 
230     k3_c.checksum.length = sizeof(k3_c_data);
231     k3_c.checksum.data   = k3_c_data;
232 
233     ret = _krb5_internal_hmac(NULL, c, cdata, 16, 0, &ke, &k3_c);
234     if (ret)
235 	krb5_abortx(context, "hmac failed");
236 
237     EVP_CIPHER_CTX_init(&ctx);
238     EVP_CipherInit_ex(&ctx, EVP_rc4(), NULL, k3_c.checksum.data, NULL, 0);
239     EVP_Cipher(&ctx, cdata + 16, cdata + 16, len - 16);
240     EVP_CIPHER_CTX_cleanup(&ctx);
241 
242     ke.key = &kb;
243     kb.keyvalue = k2_c.checksum;
244 
245     cksum.checksum.length = 16;
246     cksum.checksum.data   = cksum_data;
247 
248     ret = _krb5_internal_hmac(NULL, c, cdata + 16, len - 16, 0, &ke, &cksum);
249     if (ret)
250 	krb5_abortx(context, "hmac failed");
251 
252     memset (k1_c_data, 0, sizeof(k1_c_data));
253     memset (k2_c_data, 0, sizeof(k2_c_data));
254     memset (k3_c_data, 0, sizeof(k3_c_data));
255 
256     if (ct_memcmp (cksum.checksum.data, data, 16) != 0) {
257 	krb5_clear_error_message (context);
258 	return KRB5KRB_AP_ERR_BAD_INTEGRITY;
259     } else {
260 	return 0;
261     }
262 }
263 
264 /*
265  * convert the usage numbers used in
266  * draft-ietf-cat-kerb-key-derivation-00.txt to the ones in
267  * draft-brezak-win2k-krb-rc4-hmac-04.txt
268  */
269 
270 krb5_error_code
271 _krb5_usage2arcfour(krb5_context context, unsigned *usage)
272 {
273     switch (*usage) {
274     case KRB5_KU_AS_REP_ENC_PART : /* 3 */
275 	*usage = 8;
276 	return 0;
277     case KRB5_KU_USAGE_SEAL :  /* 22 */
278 	*usage = 13;
279 	return 0;
280     case KRB5_KU_USAGE_SIGN : /* 23 */
281         *usage = 15;
282         return 0;
283     case KRB5_KU_USAGE_SEQ: /* 24 */
284 	*usage = 0;
285 	return 0;
286     default :
287 	return 0;
288     }
289 }
290 
291 static krb5_error_code
292 ARCFOUR_encrypt(krb5_context context,
293 		struct _krb5_key_data *key,
294 		void *data,
295 		size_t len,
296 		krb5_boolean encryptp,
297 		int usage,
298 		void *ivec)
299 {
300     krb5_error_code ret;
301     unsigned keyusage = usage;
302 
303     if((ret = _krb5_usage2arcfour (context, &keyusage)) != 0)
304 	return ret;
305 
306     if (encryptp)
307 	return ARCFOUR_subencrypt (context, key, data, len, keyusage, ivec);
308     else
309 	return ARCFOUR_subdecrypt (context, key, data, len, keyusage, ivec);
310 }
311 
312 struct _krb5_encryption_type _krb5_enctype_arcfour_hmac_md5 = {
313     ETYPE_ARCFOUR_HMAC_MD5,
314     "arcfour-hmac-md5",
315     1,
316     1,
317     8,
318     &keytype_arcfour,
319     &_krb5_checksum_hmac_md5,
320     &_krb5_checksum_hmac_md5,
321     F_SPECIAL,
322     ARCFOUR_encrypt,
323     0,
324     NULL
325 };
326