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