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
40 static 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
58 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)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
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(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
193 static krb5_error_code
ARCFOUR_subdecrypt(krb5_context context,struct _krb5_key_data * key,void * data,size_t len,unsigned usage,void * ivec)194 ARCFOUR_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
274 krb5_error_code
_krb5_usage2arcfour(krb5_context context,unsigned * usage)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
295 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)296 ARCFOUR_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
316 struct _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