xref: /netbsd-src/crypto/external/bsd/heimdal/dist/lib/krb5/crypto-arcfour.c (revision afab4e300d3a9fb07dd8c80daf53d0feb3345706)
1 /*	$NetBSD: crypto-arcfour.c,v 1.6 2023/06/19 21:41:44 christos 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     KRB5_ENCTYPE_ARCFOUR_HMAC_MD5,
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
_krb5_HMAC_MD5_checksum(krb5_context context,struct _krb5_key_data * key,const void * data,size_t len,unsigned usage,Checksum * result)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 	return krb5_enomem(context);
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
ARCFOUR_subencrypt(krb5_context context,struct _krb5_key_data * key,void * data,size_t len,unsigned usage,void * ivec)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(context, 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(context, 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(context, c, data, 16, 0, &ke, &k3_c);
176     if (ret)
177 	krb5_abortx(context, "hmac failed");
178 
179 #if OPENSSL_VERSION_NUMBER < 0x10100000UL
180     EVP_CIPHER_CTX ctxst;
181     ctx = &ctxst;
182     EVP_CIPHER_CTX_init(ctx);
183 #else
184     ctx = EVP_CIPHER_CTX_new();
185 #endif
186 
187     if (!EVP_CipherInit_ex(ctx, EVP_rc4(), NULL, k3_c.checksum.data, NULL, 1))
188 	krb5_abortx(context, "rc4 cipher not supported");
189     EVP_Cipher(ctx, cdata + 16, cdata + 16, len - 16);
190 #if OPENSSL_VERSION_NUMBER < 0x10100000UL
191     EVP_CIPHER_CTX_cleanup(ctx);
192 #else
193     EVP_CIPHER_CTX_free(ctx);
194 #endif
195 
196     memset_s(k1_c_data, sizeof(k1_c_data), 0, sizeof(k1_c_data));
197     memset_s(k2_c_data, sizeof(k2_c_data), 0, sizeof(k2_c_data));
198     memset_s(k3_c_data, sizeof(k3_c_data), 0, sizeof(k3_c_data));
199     return 0;
200 }
201 
202 static krb5_error_code
ARCFOUR_subdecrypt(krb5_context context,struct _krb5_key_data * key,void * data,size_t len,unsigned usage,void * ivec)203 ARCFOUR_subdecrypt(krb5_context context,
204 		   struct _krb5_key_data *key,
205 		   void *data,
206 		   size_t len,
207 		   unsigned usage,
208 		   void *ivec)
209 {
210     EVP_CIPHER_CTX *ctx;
211     struct _krb5_checksum_type *c = _krb5_find_checksum (CKSUMTYPE_RSA_MD5);
212     Checksum k1_c, k2_c, k3_c, cksum;
213     struct _krb5_key_data ke;
214     krb5_keyblock kb;
215     unsigned char t[4];
216     unsigned char *cdata = data;
217     unsigned char k1_c_data[16], k2_c_data[16], k3_c_data[16];
218     unsigned char cksum_data[16];
219     krb5_error_code ret;
220 
221     t[0] = (usage >>  0) & 0xFF;
222     t[1] = (usage >>  8) & 0xFF;
223     t[2] = (usage >> 16) & 0xFF;
224     t[3] = (usage >> 24) & 0xFF;
225 
226     k1_c.checksum.length = sizeof(k1_c_data);
227     k1_c.checksum.data   = k1_c_data;
228 
229     ret = _krb5_internal_hmac(context, c, t, sizeof(t), 0, key, &k1_c);
230     if (ret)
231 	krb5_abortx(context, "hmac failed");
232 
233     memcpy (k2_c_data, k1_c_data, sizeof(k1_c_data));
234 
235     k2_c.checksum.length = sizeof(k2_c_data);
236     k2_c.checksum.data   = k2_c_data;
237 
238     ke.key = &kb;
239     kb.keyvalue = k1_c.checksum;
240 
241     k3_c.checksum.length = sizeof(k3_c_data);
242     k3_c.checksum.data   = k3_c_data;
243 
244     ret = _krb5_internal_hmac(context, c, cdata, 16, 0, &ke, &k3_c);
245     if (ret)
246 	krb5_abortx(context, "hmac failed");
247 
248 #if OPENSSL_VERSION_NUMBER < 0x10100000UL
249     EVP_CIPHER_CTX ctxst;
250     ctx = &ctxst;
251     EVP_CIPHER_CTX_init(ctx);
252 #else
253     ctx = EVP_CIPHER_CTX_new();
254 #endif
255     if (!EVP_CipherInit_ex(ctx, EVP_rc4(), NULL, k3_c.checksum.data, NULL, 0))
256 	krb5_abortx(context, "rc4 cipher not supported");
257     EVP_Cipher(ctx, cdata + 16, cdata + 16, len - 16);
258 #if OPENSSL_VERSION_NUMBER < 0x10100000UL
259     EVP_CIPHER_CTX_cleanup(ctx);
260 #else
261     EVP_CIPHER_CTX_free(ctx);
262 #endif
263 
264     ke.key = &kb;
265     kb.keyvalue = k2_c.checksum;
266 
267     cksum.checksum.length = 16;
268     cksum.checksum.data   = cksum_data;
269 
270     ret = _krb5_internal_hmac(context, c, cdata + 16, len - 16, 0, &ke, &cksum);
271     if (ret)
272 	krb5_abortx(context, "hmac failed");
273 
274     memset_s(k1_c_data, sizeof(k1_c_data), 0, sizeof(k1_c_data));
275     memset_s(k2_c_data, sizeof(k2_c_data), 0, sizeof(k2_c_data));
276     memset_s(k3_c_data, sizeof(k3_c_data), 0, sizeof(k3_c_data));
277 
278     if (ct_memcmp (cksum.checksum.data, data, 16) != 0) {
279 	krb5_clear_error_message (context);
280 	return KRB5KRB_AP_ERR_BAD_INTEGRITY;
281     } else {
282 	return 0;
283     }
284 }
285 
286 /*
287  * convert the usage numbers used in
288  * draft-ietf-cat-kerb-key-derivation-00.txt to the ones in
289  * draft-brezak-win2k-krb-rc4-hmac-04.txt
290  */
291 
292 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
_krb5_usage2arcfour(krb5_context context,unsigned * usage)293 _krb5_usage2arcfour(krb5_context context, unsigned *usage)
294 {
295     switch (*usage) {
296     case KRB5_KU_AS_REP_ENC_PART : /* 3 */
297 	*usage = 8;
298 	return 0;
299     case KRB5_KU_USAGE_SEAL :  /* 22 */
300 	*usage = 13;
301 	return 0;
302     case KRB5_KU_USAGE_SIGN : /* 23 */
303         *usage = 15;
304         return 0;
305     case KRB5_KU_USAGE_SEQ: /* 24 */
306 	*usage = 0;
307 	return 0;
308     default :
309 	return 0;
310     }
311 }
312 
313 static krb5_error_code
ARCFOUR_encrypt(krb5_context context,struct _krb5_key_data * key,void * data,size_t len,krb5_boolean encryptp,int usage,void * ivec)314 ARCFOUR_encrypt(krb5_context context,
315 		struct _krb5_key_data *key,
316 		void *data,
317 		size_t len,
318 		krb5_boolean encryptp,
319 		int usage,
320 		void *ivec)
321 {
322     krb5_error_code ret;
323     unsigned keyusage = usage;
324 
325     if((ret = _krb5_usage2arcfour (context, &keyusage)) != 0)
326 	return ret;
327 
328     if (encryptp)
329 	return ARCFOUR_subencrypt (context, key, data, len, keyusage, ivec);
330     else
331 	return ARCFOUR_subdecrypt (context, key, data, len, keyusage, ivec);
332 }
333 
334 static krb5_error_code
ARCFOUR_prf(krb5_context context,krb5_crypto crypto,const krb5_data * in,krb5_data * out)335 ARCFOUR_prf(krb5_context context,
336 	    krb5_crypto crypto,
337 	    const krb5_data *in,
338 	    krb5_data *out)
339 {
340     struct _krb5_checksum_type *c = _krb5_find_checksum(CKSUMTYPE_SHA1);
341     krb5_error_code ret;
342     Checksum res;
343 
344     ret = krb5_data_alloc(out, c->checksumsize);
345     if (ret)
346 	return ret;
347 
348     res.checksum.data = out->data;
349     res.checksum.length = out->length;
350 
351     ret = _krb5_internal_hmac(context, c, in->data, in->length, 0, &crypto->key, &res);
352     if (ret)
353 	krb5_data_free(out);
354     return 0;
355 }
356 
357 
358 struct _krb5_encryption_type _krb5_enctype_arcfour_hmac_md5 = {
359     ETYPE_ARCFOUR_HMAC_MD5,
360     "arcfour-hmac-md5",
361     "rc4-hmac",
362     1,
363     1,
364     8,
365     &keytype_arcfour,
366     &_krb5_checksum_hmac_md5,
367     &_krb5_checksum_hmac_md5,
368     F_SPECIAL | F_WEAK,
369     ARCFOUR_encrypt,
370     0,
371     ARCFOUR_prf
372 };
373