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