1226031Sstas/*
2226031Sstas * Copyright (c) 1997 - 2008 Kungliga Tekniska H��gskolan
3226031Sstas * (Royal Institute of Technology, Stockholm, Sweden).
4226031Sstas * All rights reserved.
5226031Sstas *
6226031Sstas * Redistribution and use in source and binary forms, with or without
7226031Sstas * modification, are permitted provided that the following conditions
8226031Sstas * are met:
9226031Sstas *
10226031Sstas * 1. Redistributions of source code must retain the above copyright
11226031Sstas *    notice, this list of conditions and the following disclaimer.
12226031Sstas *
13226031Sstas * 2. Redistributions in binary form must reproduce the above copyright
14226031Sstas *    notice, this list of conditions and the following disclaimer in the
15226031Sstas *    documentation and/or other materials provided with the distribution.
16226031Sstas *
17226031Sstas * 3. Neither the name of the Institute nor the names of its contributors
18226031Sstas *    may be used to endorse or promote products derived from this software
19226031Sstas *    without specific prior written permission.
20226031Sstas *
21226031Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22226031Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23226031Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24226031Sstas * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25226031Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26226031Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27226031Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28226031Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29226031Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30226031Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31226031Sstas * SUCH DAMAGE.
32226031Sstas */
33226031Sstas
34226031Sstas/*
35226031Sstas * ARCFOUR
36226031Sstas */
37226031Sstas
38226031Sstas#include "krb5_locl.h"
39226031Sstas
40226031Sstasstatic struct _krb5_key_type keytype_arcfour = {
41226031Sstas    ENCTYPE_ARCFOUR_HMAC_MD5,
42226031Sstas    "arcfour",
43226031Sstas    128,
44226031Sstas    16,
45226031Sstas    sizeof(struct _krb5_evp_schedule),
46226031Sstas    NULL,
47226031Sstas    _krb5_evp_schedule,
48226031Sstas    _krb5_arcfour_salt,
49226031Sstas    NULL,
50226031Sstas    _krb5_evp_cleanup,
51226031Sstas    EVP_rc4
52226031Sstas};
53226031Sstas
54226031Sstas/*
55226031Sstas * checksum according to section 5. of draft-brezak-win2k-krb-rc4-hmac-03.txt
56226031Sstas */
57226031Sstas
58226031Sstaskrb5_error_code
59226031Sstas_krb5_HMAC_MD5_checksum(krb5_context context,
60226031Sstas			struct _krb5_key_data *key,
61226031Sstas			const void *data,
62226031Sstas			size_t len,
63226031Sstas			unsigned usage,
64226031Sstas			Checksum *result)
65226031Sstas{
66226031Sstas    EVP_MD_CTX *m;
67226031Sstas    struct _krb5_checksum_type *c = _krb5_find_checksum (CKSUMTYPE_RSA_MD5);
68226031Sstas    const char signature[] = "signaturekey";
69226031Sstas    Checksum ksign_c;
70226031Sstas    struct _krb5_key_data ksign;
71226031Sstas    krb5_keyblock kb;
72226031Sstas    unsigned char t[4];
73226031Sstas    unsigned char tmp[16];
74226031Sstas    unsigned char ksign_c_data[16];
75226031Sstas    krb5_error_code ret;
76226031Sstas
77226031Sstas    m = EVP_MD_CTX_create();
78226031Sstas    if (m == NULL) {
79226031Sstas	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
80226031Sstas	return ENOMEM;
81226031Sstas    }
82226031Sstas    ksign_c.checksum.length = sizeof(ksign_c_data);
83226031Sstas    ksign_c.checksum.data   = ksign_c_data;
84226031Sstas    ret = _krb5_internal_hmac(context, c, signature, sizeof(signature),
85226031Sstas			      0, key, &ksign_c);
86226031Sstas    if (ret) {
87226031Sstas	EVP_MD_CTX_destroy(m);
88226031Sstas	return ret;
89226031Sstas    }
90226031Sstas    ksign.key = &kb;
91226031Sstas    kb.keyvalue = ksign_c.checksum;
92226031Sstas    EVP_DigestInit_ex(m, EVP_md5(), NULL);
93226031Sstas    t[0] = (usage >>  0) & 0xFF;
94226031Sstas    t[1] = (usage >>  8) & 0xFF;
95226031Sstas    t[2] = (usage >> 16) & 0xFF;
96226031Sstas    t[3] = (usage >> 24) & 0xFF;
97226031Sstas    EVP_DigestUpdate(m, t, 4);
98226031Sstas    EVP_DigestUpdate(m, data, len);
99226031Sstas    EVP_DigestFinal_ex (m, tmp, NULL);
100226031Sstas    EVP_MD_CTX_destroy(m);
101226031Sstas
102226031Sstas    ret = _krb5_internal_hmac(context, c, tmp, sizeof(tmp), 0, &ksign, result);
103226031Sstas    if (ret)
104226031Sstas	return ret;
105226031Sstas    return 0;
106226031Sstas}
107226031Sstas
108226031Sstasstruct _krb5_checksum_type _krb5_checksum_hmac_md5 = {
109226031Sstas    CKSUMTYPE_HMAC_MD5,
110226031Sstas    "hmac-md5",
111226031Sstas    64,
112226031Sstas    16,
113226031Sstas    F_KEYED | F_CPROOF,
114226031Sstas    _krb5_HMAC_MD5_checksum,
115226031Sstas    NULL
116226031Sstas};
117226031Sstas
118226031Sstas/*
119226031Sstas * section 6 of draft-brezak-win2k-krb-rc4-hmac-03
120226031Sstas *
121226031Sstas * warning: not for small children
122226031Sstas */
123226031Sstas
124226031Sstasstatic krb5_error_code
125226031SstasARCFOUR_subencrypt(krb5_context context,
126226031Sstas		   struct _krb5_key_data *key,
127226031Sstas		   void *data,
128226031Sstas		   size_t len,
129226031Sstas		   unsigned usage,
130226031Sstas		   void *ivec)
131226031Sstas{
132226031Sstas    EVP_CIPHER_CTX ctx;
133226031Sstas    struct _krb5_checksum_type *c = _krb5_find_checksum (CKSUMTYPE_RSA_MD5);
134226031Sstas    Checksum k1_c, k2_c, k3_c, cksum;
135226031Sstas    struct _krb5_key_data ke;
136226031Sstas    krb5_keyblock kb;
137226031Sstas    unsigned char t[4];
138226031Sstas    unsigned char *cdata = data;
139226031Sstas    unsigned char k1_c_data[16], k2_c_data[16], k3_c_data[16];
140226031Sstas    krb5_error_code ret;
141226031Sstas
142226031Sstas    t[0] = (usage >>  0) & 0xFF;
143226031Sstas    t[1] = (usage >>  8) & 0xFF;
144226031Sstas    t[2] = (usage >> 16) & 0xFF;
145226031Sstas    t[3] = (usage >> 24) & 0xFF;
146226031Sstas
147226031Sstas    k1_c.checksum.length = sizeof(k1_c_data);
148226031Sstas    k1_c.checksum.data   = k1_c_data;
149226031Sstas
150226031Sstas    ret = _krb5_internal_hmac(NULL, c, t, sizeof(t), 0, key, &k1_c);
151226031Sstas    if (ret)
152226031Sstas	krb5_abortx(context, "hmac failed");
153226031Sstas
154226031Sstas    memcpy (k2_c_data, k1_c_data, sizeof(k1_c_data));
155226031Sstas
156226031Sstas    k2_c.checksum.length = sizeof(k2_c_data);
157226031Sstas    k2_c.checksum.data   = k2_c_data;
158226031Sstas
159226031Sstas    ke.key = &kb;
160226031Sstas    kb.keyvalue = k2_c.checksum;
161226031Sstas
162226031Sstas    cksum.checksum.length = 16;
163226031Sstas    cksum.checksum.data   = data;
164226031Sstas
165226031Sstas    ret = _krb5_internal_hmac(NULL, c, cdata + 16, len - 16, 0, &ke, &cksum);
166226031Sstas    if (ret)
167226031Sstas	krb5_abortx(context, "hmac failed");
168226031Sstas
169226031Sstas    ke.key = &kb;
170226031Sstas    kb.keyvalue = k1_c.checksum;
171226031Sstas
172226031Sstas    k3_c.checksum.length = sizeof(k3_c_data);
173226031Sstas    k3_c.checksum.data   = k3_c_data;
174226031Sstas
175226031Sstas    ret = _krb5_internal_hmac(NULL, c, data, 16, 0, &ke, &k3_c);
176226031Sstas    if (ret)
177226031Sstas	krb5_abortx(context, "hmac failed");
178226031Sstas
179226031Sstas    EVP_CIPHER_CTX_init(&ctx);
180226031Sstas
181226031Sstas    EVP_CipherInit_ex(&ctx, EVP_rc4(), NULL, k3_c.checksum.data, NULL, 1);
182226031Sstas    EVP_Cipher(&ctx, cdata + 16, cdata + 16, len - 16);
183226031Sstas    EVP_CIPHER_CTX_cleanup(&ctx);
184226031Sstas
185226031Sstas    memset (k1_c_data, 0, sizeof(k1_c_data));
186226031Sstas    memset (k2_c_data, 0, sizeof(k2_c_data));
187226031Sstas    memset (k3_c_data, 0, sizeof(k3_c_data));
188226031Sstas    return 0;
189226031Sstas}
190226031Sstas
191226031Sstasstatic krb5_error_code
192226031SstasARCFOUR_subdecrypt(krb5_context context,
193226031Sstas		   struct _krb5_key_data *key,
194226031Sstas		   void *data,
195226031Sstas		   size_t len,
196226031Sstas		   unsigned usage,
197226031Sstas		   void *ivec)
198226031Sstas{
199226031Sstas    EVP_CIPHER_CTX ctx;
200226031Sstas    struct _krb5_checksum_type *c = _krb5_find_checksum (CKSUMTYPE_RSA_MD5);
201226031Sstas    Checksum k1_c, k2_c, k3_c, cksum;
202226031Sstas    struct _krb5_key_data ke;
203226031Sstas    krb5_keyblock kb;
204226031Sstas    unsigned char t[4];
205226031Sstas    unsigned char *cdata = data;
206226031Sstas    unsigned char k1_c_data[16], k2_c_data[16], k3_c_data[16];
207226031Sstas    unsigned char cksum_data[16];
208226031Sstas    krb5_error_code ret;
209226031Sstas
210226031Sstas    t[0] = (usage >>  0) & 0xFF;
211226031Sstas    t[1] = (usage >>  8) & 0xFF;
212226031Sstas    t[2] = (usage >> 16) & 0xFF;
213226031Sstas    t[3] = (usage >> 24) & 0xFF;
214226031Sstas
215226031Sstas    k1_c.checksum.length = sizeof(k1_c_data);
216226031Sstas    k1_c.checksum.data   = k1_c_data;
217226031Sstas
218226031Sstas    ret = _krb5_internal_hmac(NULL, c, t, sizeof(t), 0, key, &k1_c);
219226031Sstas    if (ret)
220226031Sstas	krb5_abortx(context, "hmac failed");
221226031Sstas
222226031Sstas    memcpy (k2_c_data, k1_c_data, sizeof(k1_c_data));
223226031Sstas
224226031Sstas    k2_c.checksum.length = sizeof(k2_c_data);
225226031Sstas    k2_c.checksum.data   = k2_c_data;
226226031Sstas
227226031Sstas    ke.key = &kb;
228226031Sstas    kb.keyvalue = k1_c.checksum;
229226031Sstas
230226031Sstas    k3_c.checksum.length = sizeof(k3_c_data);
231226031Sstas    k3_c.checksum.data   = k3_c_data;
232226031Sstas
233226031Sstas    ret = _krb5_internal_hmac(NULL, c, cdata, 16, 0, &ke, &k3_c);
234226031Sstas    if (ret)
235226031Sstas	krb5_abortx(context, "hmac failed");
236226031Sstas
237226031Sstas    EVP_CIPHER_CTX_init(&ctx);
238226031Sstas    EVP_CipherInit_ex(&ctx, EVP_rc4(), NULL, k3_c.checksum.data, NULL, 0);
239226031Sstas    EVP_Cipher(&ctx, cdata + 16, cdata + 16, len - 16);
240226031Sstas    EVP_CIPHER_CTX_cleanup(&ctx);
241226031Sstas
242226031Sstas    ke.key = &kb;
243226031Sstas    kb.keyvalue = k2_c.checksum;
244226031Sstas
245226031Sstas    cksum.checksum.length = 16;
246226031Sstas    cksum.checksum.data   = cksum_data;
247226031Sstas
248226031Sstas    ret = _krb5_internal_hmac(NULL, c, cdata + 16, len - 16, 0, &ke, &cksum);
249226031Sstas    if (ret)
250226031Sstas	krb5_abortx(context, "hmac failed");
251226031Sstas
252226031Sstas    memset (k1_c_data, 0, sizeof(k1_c_data));
253226031Sstas    memset (k2_c_data, 0, sizeof(k2_c_data));
254226031Sstas    memset (k3_c_data, 0, sizeof(k3_c_data));
255226031Sstas
256226031Sstas    if (ct_memcmp (cksum.checksum.data, data, 16) != 0) {
257226031Sstas	krb5_clear_error_message (context);
258226031Sstas	return KRB5KRB_AP_ERR_BAD_INTEGRITY;
259226031Sstas    } else {
260226031Sstas	return 0;
261226031Sstas    }
262226031Sstas}
263226031Sstas
264226031Sstas/*
265226031Sstas * convert the usage numbers used in
266226031Sstas * draft-ietf-cat-kerb-key-derivation-00.txt to the ones in
267226031Sstas * draft-brezak-win2k-krb-rc4-hmac-04.txt
268226031Sstas */
269226031Sstas
270226031Sstaskrb5_error_code
271226031Sstas_krb5_usage2arcfour(krb5_context context, unsigned *usage)
272226031Sstas{
273226031Sstas    switch (*usage) {
274226031Sstas    case KRB5_KU_AS_REP_ENC_PART : /* 3 */
275226031Sstas	*usage = 8;
276226031Sstas	return 0;
277226031Sstas    case KRB5_KU_USAGE_SEAL :  /* 22 */
278226031Sstas	*usage = 13;
279226031Sstas	return 0;
280226031Sstas    case KRB5_KU_USAGE_SIGN : /* 23 */
281226031Sstas        *usage = 15;
282226031Sstas        return 0;
283226031Sstas    case KRB5_KU_USAGE_SEQ: /* 24 */
284226031Sstas	*usage = 0;
285226031Sstas	return 0;
286226031Sstas    default :
287226031Sstas	return 0;
288226031Sstas    }
289226031Sstas}
290226031Sstas
291226031Sstasstatic krb5_error_code
292226031SstasARCFOUR_encrypt(krb5_context context,
293226031Sstas		struct _krb5_key_data *key,
294226031Sstas		void *data,
295226031Sstas		size_t len,
296226031Sstas		krb5_boolean encryptp,
297226031Sstas		int usage,
298226031Sstas		void *ivec)
299226031Sstas{
300226031Sstas    krb5_error_code ret;
301226031Sstas    unsigned keyusage = usage;
302226031Sstas
303226031Sstas    if((ret = _krb5_usage2arcfour (context, &keyusage)) != 0)
304226031Sstas	return ret;
305226031Sstas
306226031Sstas    if (encryptp)
307226031Sstas	return ARCFOUR_subencrypt (context, key, data, len, keyusage, ivec);
308226031Sstas    else
309226031Sstas	return ARCFOUR_subdecrypt (context, key, data, len, keyusage, ivec);
310226031Sstas}
311226031Sstas
312226031Sstasstruct _krb5_encryption_type _krb5_enctype_arcfour_hmac_md5 = {
313226031Sstas    ETYPE_ARCFOUR_HMAC_MD5,
314226031Sstas    "arcfour-hmac-md5",
315226031Sstas    1,
316226031Sstas    1,
317226031Sstas    8,
318226031Sstas    &keytype_arcfour,
319226031Sstas    &_krb5_checksum_hmac_md5,
320234027Sstas    &_krb5_checksum_hmac_md5,
321226031Sstas    F_SPECIAL,
322226031Sstas    ARCFOUR_encrypt,
323226031Sstas    0,
324226031Sstas    NULL
325226031Sstas};
326