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
42static 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
60krb5_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	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
108struct _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
124static krb5_error_code
125ARCFOUR_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
202static krb5_error_code
203ARCFOUR_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
292KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
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
313static krb5_error_code
314ARCFOUR_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
334static krb5_error_code
335ARCFOUR_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
358struct _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