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
40static 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
58krb5_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
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(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
191static krb5_error_code
192ARCFOUR_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
270krb5_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
291static krb5_error_code
292ARCFOUR_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
312struct _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