lib/gssapi/krb5: implement GSS_C_CHANNEL_BOUND_FLAG for gss_init_sec_context()
[heimdal.git] / lib / krb5 / crypto-arcfour.c
blob28fc52e4cbf239c7558840e69413ab3220ec9794
1 /*
2 * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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.
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.
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.
35 * ARCFOUR
38 #include "krb5_locl.h"
40 static struct _krb5_key_type keytype_arcfour = {
41 KRB5_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
55 * checksum according to section 5. of draft-brezak-win2k-krb-rc4-hmac-03.txt
58 krb5_error_code
59 _krb5_HMAC_MD5_checksum(krb5_context context,
60 krb5_crypto crypto,
61 struct _krb5_key_data *key,
62 unsigned usage,
63 const struct krb5_crypto_iov *iov,
64 int niov,
65 Checksum *result)
67 EVP_MD_CTX *m;
68 struct _krb5_checksum_type *c = _krb5_find_checksum (CKSUMTYPE_RSA_MD5);
69 const char signature[] = "signaturekey";
70 Checksum ksign_c;
71 struct _krb5_key_data ksign;
72 krb5_keyblock kb;
73 unsigned char t[4];
74 unsigned char tmp[16];
75 unsigned char ksign_c_data[16];
76 krb5_error_code ret;
77 int i;
79 if (crypto != NULL) {
80 if (crypto->mdctx == NULL)
81 crypto->mdctx = EVP_MD_CTX_create();
82 if (crypto->mdctx == NULL)
83 return krb5_enomem(context);
84 m = crypto->mdctx;
85 } else
86 m = EVP_MD_CTX_create();
88 ksign_c.checksum.length = sizeof(ksign_c_data);
89 ksign_c.checksum.data = ksign_c_data;
90 ret = _krb5_internal_hmac(context, crypto, c, signature, sizeof(signature),
91 0, key, &ksign_c);
92 if (ret)
93 goto out;
95 ksign.key = &kb;
96 kb.keyvalue = ksign_c.checksum;
97 EVP_DigestInit_ex(m, EVP_md5(), NULL);
98 t[0] = (usage >> 0) & 0xFF;
99 t[1] = (usage >> 8) & 0xFF;
100 t[2] = (usage >> 16) & 0xFF;
101 t[3] = (usage >> 24) & 0xFF;
102 EVP_DigestUpdate(m, t, 4);
103 for (i = 0; i < niov; i++) {
104 if (_krb5_crypto_iov_should_sign(&iov[i]))
105 EVP_DigestUpdate(m, iov[i].data.data, iov[i].data.length);
107 EVP_DigestFinal_ex (m, tmp, NULL);
109 ret = _krb5_internal_hmac(context, crypto, c, tmp, sizeof(tmp), 0, &ksign, result);
110 out:
111 if (crypto == NULL)
112 EVP_MD_CTX_destroy(m);
114 return ret;
117 struct _krb5_checksum_type _krb5_checksum_hmac_md5 = {
118 CKSUMTYPE_HMAC_MD5,
119 "hmac-md5",
122 F_KEYED | F_CPROOF,
123 _krb5_HMAC_MD5_checksum,
124 NULL
128 * section 6 of draft-brezak-win2k-krb-rc4-hmac-03
130 * warning: not for small children
133 static krb5_error_code
134 ARCFOUR_subencrypt(krb5_context context,
135 struct _krb5_key_data *key,
136 void *data,
137 size_t len,
138 unsigned usage,
139 void *ivec)
141 EVP_CIPHER_CTX ctx;
142 struct _krb5_checksum_type *c = _krb5_find_checksum (CKSUMTYPE_RSA_MD5);
143 Checksum k1_c, k2_c, k3_c, cksum;
144 struct _krb5_key_data ke;
145 krb5_keyblock kb;
146 unsigned char t[4];
147 unsigned char *cdata = data;
148 unsigned char k1_c_data[16], k2_c_data[16], k3_c_data[16];
149 krb5_error_code ret;
151 if (len < 16) {
152 return KRB5KRB_AP_ERR_INAPP_CKSUM;
155 t[0] = (usage >> 0) & 0xFF;
156 t[1] = (usage >> 8) & 0xFF;
157 t[2] = (usage >> 16) & 0xFF;
158 t[3] = (usage >> 24) & 0xFF;
160 k1_c.checksum.length = sizeof(k1_c_data);
161 k1_c.checksum.data = k1_c_data;
163 ret = _krb5_internal_hmac(context, NULL, c, t, sizeof(t), 0, key, &k1_c);
164 if (ret)
165 krb5_abortx(context, "hmac failed");
167 memcpy (k2_c_data, k1_c_data, sizeof(k1_c_data));
169 k2_c.checksum.length = sizeof(k2_c_data);
170 k2_c.checksum.data = k2_c_data;
172 ke.key = &kb;
173 kb.keyvalue = k2_c.checksum;
175 cksum.checksum.length = 16;
176 cksum.checksum.data = data;
178 ret = _krb5_internal_hmac(context, NULL, c, cdata + 16, len - 16, 0, &ke, &cksum);
179 if (ret)
180 krb5_abortx(context, "hmac failed");
182 ke.key = &kb;
183 kb.keyvalue = k1_c.checksum;
185 k3_c.checksum.length = sizeof(k3_c_data);
186 k3_c.checksum.data = k3_c_data;
188 ret = _krb5_internal_hmac(context, NULL, c, data, 16, 0, &ke, &k3_c);
189 if (ret)
190 krb5_abortx(context, "hmac failed");
192 EVP_CIPHER_CTX_init(&ctx);
194 EVP_CipherInit_ex(&ctx, EVP_rc4(), NULL, k3_c.checksum.data, NULL, 1);
195 EVP_Cipher(&ctx, cdata + 16, cdata + 16, len - 16);
196 EVP_CIPHER_CTX_cleanup(&ctx);
198 memset_s(k1_c_data, sizeof(k1_c_data), 0, sizeof(k1_c_data));
199 memset_s(k2_c_data, sizeof(k2_c_data), 0, sizeof(k2_c_data));
200 memset_s(k3_c_data, sizeof(k3_c_data), 0, sizeof(k3_c_data));
201 return 0;
204 static krb5_error_code
205 ARCFOUR_subdecrypt(krb5_context context,
206 struct _krb5_key_data *key,
207 void *data,
208 size_t len,
209 unsigned usage,
210 void *ivec)
212 EVP_CIPHER_CTX ctx;
213 struct _krb5_checksum_type *c = _krb5_find_checksum (CKSUMTYPE_RSA_MD5);
214 Checksum k1_c, k2_c, k3_c, cksum;
215 struct _krb5_key_data ke;
216 krb5_keyblock kb;
217 unsigned char t[4];
218 unsigned char *cdata = data;
219 unsigned char k1_c_data[16], k2_c_data[16], k3_c_data[16];
220 unsigned char cksum_data[16];
221 krb5_error_code ret;
223 if (len < 16) {
224 return KRB5KRB_AP_ERR_INAPP_CKSUM;
227 t[0] = (usage >> 0) & 0xFF;
228 t[1] = (usage >> 8) & 0xFF;
229 t[2] = (usage >> 16) & 0xFF;
230 t[3] = (usage >> 24) & 0xFF;
232 k1_c.checksum.length = sizeof(k1_c_data);
233 k1_c.checksum.data = k1_c_data;
235 ret = _krb5_internal_hmac(context, NULL, c, t, sizeof(t), 0, key, &k1_c);
236 if (ret)
237 krb5_abortx(context, "hmac failed");
239 memcpy (k2_c_data, k1_c_data, sizeof(k1_c_data));
241 k2_c.checksum.length = sizeof(k2_c_data);
242 k2_c.checksum.data = k2_c_data;
244 ke.key = &kb;
245 kb.keyvalue = k1_c.checksum;
247 k3_c.checksum.length = sizeof(k3_c_data);
248 k3_c.checksum.data = k3_c_data;
250 ret = _krb5_internal_hmac(context, NULL, c, cdata, 16, 0, &ke, &k3_c);
251 if (ret)
252 krb5_abortx(context, "hmac failed");
254 EVP_CIPHER_CTX_init(&ctx);
255 EVP_CipherInit_ex(&ctx, EVP_rc4(), NULL, k3_c.checksum.data, NULL, 0);
256 EVP_Cipher(&ctx, cdata + 16, cdata + 16, len - 16);
257 EVP_CIPHER_CTX_cleanup(&ctx);
259 ke.key = &kb;
260 kb.keyvalue = k2_c.checksum;
262 cksum.checksum.length = 16;
263 cksum.checksum.data = cksum_data;
265 ret = _krb5_internal_hmac(context, NULL, c, cdata + 16, len - 16, 0, &ke, &cksum);
266 if (ret)
267 krb5_abortx(context, "hmac failed");
269 memset_s(k1_c_data, sizeof(k1_c_data), 0, sizeof(k1_c_data));
270 memset_s(k2_c_data, sizeof(k2_c_data), 0, sizeof(k2_c_data));
271 memset_s(k3_c_data, sizeof(k3_c_data), 0, sizeof(k3_c_data));
273 if (ct_memcmp (cksum.checksum.data, data, 16) != 0) {
274 krb5_clear_error_message (context);
275 return KRB5KRB_AP_ERR_BAD_INTEGRITY;
276 } else {
277 return 0;
282 * convert the usage numbers used in
283 * draft-ietf-cat-kerb-key-derivation-00.txt to the ones in
284 * draft-brezak-win2k-krb-rc4-hmac-04.txt
287 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
288 _krb5_usage2arcfour(krb5_context context, unsigned *usage)
290 switch (*usage) {
291 case KRB5_KU_AS_REP_ENC_PART : /* 3 */
292 *usage = 8;
293 return 0;
294 case KRB5_KU_USAGE_SEAL : /* 22 */
295 *usage = 13;
296 return 0;
297 case KRB5_KU_USAGE_SIGN : /* 23 */
298 *usage = 15;
299 return 0;
300 case KRB5_KU_USAGE_SEQ: /* 24 */
301 *usage = 0;
302 return 0;
303 default :
304 return 0;
308 static krb5_error_code
309 ARCFOUR_encrypt(krb5_context context,
310 struct _krb5_key_data *key,
311 void *data,
312 size_t len,
313 krb5_boolean encryptp,
314 int usage,
315 void *ivec)
317 krb5_error_code ret;
318 unsigned keyusage = usage;
320 if((ret = _krb5_usage2arcfour (context, &keyusage)) != 0)
321 return ret;
323 if (encryptp)
324 return ARCFOUR_subencrypt (context, key, data, len, keyusage, ivec);
325 else
326 return ARCFOUR_subdecrypt (context, key, data, len, keyusage, ivec);
329 static krb5_error_code
330 ARCFOUR_prf(krb5_context context,
331 krb5_crypto crypto,
332 const krb5_data *in,
333 krb5_data *out)
335 struct _krb5_checksum_type *c = _krb5_find_checksum(CKSUMTYPE_SHA1);
336 krb5_error_code ret;
337 Checksum res;
339 ret = krb5_data_alloc(out, c->checksumsize);
340 if (ret)
341 return ret;
343 res.checksum.data = out->data;
344 res.checksum.length = out->length;
346 ret = _krb5_internal_hmac(context, crypto, c, in->data, in->length, 0, &crypto->key, &res);
347 if (ret)
348 krb5_data_free(out);
349 return 0;
353 struct _krb5_encryption_type _krb5_enctype_arcfour_hmac_md5 = {
354 ETYPE_ARCFOUR_HMAC_MD5,
355 "arcfour-hmac-md5",
356 "rc4-hmac",
360 &keytype_arcfour,
361 &_krb5_checksum_hmac_md5,
362 &_krb5_checksum_hmac_md5,
363 F_SPECIAL | F_WEAK | F_OLD,
364 ARCFOUR_encrypt,
365 NULL,
367 ARCFOUR_prf