HEIMDAL: move code from source4/heimdal* to third_party/heimdal*
[samba.git] / third_party / heimdal / lib / krb5 / crypto-arcfour.c
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     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
52 };
53
54 /*
55  * checksum according to section 5. of draft-brezak-win2k-krb-rc4-hmac-03.txt
56  */
57
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)
66 {
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;
78
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();
87
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;
94
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);
106     }
107     EVP_DigestFinal_ex (m, tmp, NULL);
108
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);
113
114     return ret;
115 }
116
117 struct _krb5_checksum_type _krb5_checksum_hmac_md5 = {
118     CKSUMTYPE_HMAC_MD5,
119     "hmac-md5",
120     64,
121     16,
122     F_KEYED | F_CPROOF,
123     _krb5_HMAC_MD5_checksum,
124     NULL
125 };
126
127 /*
128  * section 6 of draft-brezak-win2k-krb-rc4-hmac-03
129  *
130  * warning: not for small children
131  */
132
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)
140 {
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;
150
151     if (len < 16) {
152             return KRB5KRB_AP_ERR_INAPP_CKSUM;
153     }
154
155     t[0] = (usage >>  0) & 0xFF;
156     t[1] = (usage >>  8) & 0xFF;
157     t[2] = (usage >> 16) & 0xFF;
158     t[3] = (usage >> 24) & 0xFF;
159
160     k1_c.checksum.length = sizeof(k1_c_data);
161     k1_c.checksum.data   = k1_c_data;
162
163     ret = _krb5_internal_hmac(context, NULL, c, t, sizeof(t), 0, key, &k1_c);
164     if (ret)
165         krb5_abortx(context, "hmac failed");
166
167     memcpy (k2_c_data, k1_c_data, sizeof(k1_c_data));
168
169     k2_c.checksum.length = sizeof(k2_c_data);
170     k2_c.checksum.data   = k2_c_data;
171
172     ke.key = &kb;
173     kb.keyvalue = k2_c.checksum;
174
175     cksum.checksum.length = 16;
176     cksum.checksum.data   = data;
177
178     ret = _krb5_internal_hmac(context, NULL, c, cdata + 16, len - 16, 0, &ke, &cksum);
179     if (ret)
180         krb5_abortx(context, "hmac failed");
181
182     ke.key = &kb;
183     kb.keyvalue = k1_c.checksum;
184
185     k3_c.checksum.length = sizeof(k3_c_data);
186     k3_c.checksum.data   = k3_c_data;
187
188     ret = _krb5_internal_hmac(context, NULL, c, data, 16, 0, &ke, &k3_c);
189     if (ret)
190         krb5_abortx(context, "hmac failed");
191
192     EVP_CIPHER_CTX_init(&ctx);
193
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);
197
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;
202 }
203
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)
211 {
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;
222
223     if (len < 16) {
224             return KRB5KRB_AP_ERR_INAPP_CKSUM;
225     }
226
227     t[0] = (usage >>  0) & 0xFF;
228     t[1] = (usage >>  8) & 0xFF;
229     t[2] = (usage >> 16) & 0xFF;
230     t[3] = (usage >> 24) & 0xFF;
231
232     k1_c.checksum.length = sizeof(k1_c_data);
233     k1_c.checksum.data   = k1_c_data;
234
235     ret = _krb5_internal_hmac(context, NULL, c, t, sizeof(t), 0, key, &k1_c);
236     if (ret)
237         krb5_abortx(context, "hmac failed");
238
239     memcpy (k2_c_data, k1_c_data, sizeof(k1_c_data));
240
241     k2_c.checksum.length = sizeof(k2_c_data);
242     k2_c.checksum.data   = k2_c_data;
243
244     ke.key = &kb;
245     kb.keyvalue = k1_c.checksum;
246
247     k3_c.checksum.length = sizeof(k3_c_data);
248     k3_c.checksum.data   = k3_c_data;
249
250     ret = _krb5_internal_hmac(context, NULL, c, cdata, 16, 0, &ke, &k3_c);
251     if (ret)
252         krb5_abortx(context, "hmac failed");
253
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);
258
259     ke.key = &kb;
260     kb.keyvalue = k2_c.checksum;
261
262     cksum.checksum.length = 16;
263     cksum.checksum.data   = cksum_data;
264
265     ret = _krb5_internal_hmac(context, NULL, c, cdata + 16, len - 16, 0, &ke, &cksum);
266     if (ret)
267         krb5_abortx(context, "hmac failed");
268
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));
272
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;
278     }
279 }
280
281 /*
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
285  */
286
287 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
288 _krb5_usage2arcfour(krb5_context context, unsigned *usage)
289 {
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;
305     }
306 }
307
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)
316 {
317     krb5_error_code ret;
318     unsigned keyusage = usage;
319
320     if((ret = _krb5_usage2arcfour (context, &keyusage)) != 0)
321         return ret;
322
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);
327 }
328
329 static krb5_error_code
330 ARCFOUR_prf(krb5_context context,
331             krb5_crypto crypto,
332             const krb5_data *in,
333             krb5_data *out)
334 {
335     struct _krb5_checksum_type *c = _krb5_find_checksum(CKSUMTYPE_SHA1);
336     krb5_error_code ret;
337     Checksum res;
338
339     ret = krb5_data_alloc(out, c->checksumsize);
340     if (ret)
341         return ret;
342
343     res.checksum.data = out->data;
344     res.checksum.length = out->length;
345
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;
350 }
351
352
353 struct _krb5_encryption_type _krb5_enctype_arcfour_hmac_md5 = {
354     ETYPE_ARCFOUR_HMAC_MD5,
355     "arcfour-hmac-md5",
356     "rc4-hmac",
357     1,
358     1,
359     8,
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,
366     0,
367     ARCFOUR_prf
368 };