Import of code from heimdal
[openafs.git] / src / external / heimdal / 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                         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         return krb5_enomem(context);
80     ksign_c.checksum.length = sizeof(ksign_c_data);
81     ksign_c.checksum.data   = ksign_c_data;
82     ret = _krb5_internal_hmac(context, c, signature, sizeof(signature),
83                               0, key, &ksign_c);
84     if (ret) {
85         EVP_MD_CTX_destroy(m);
86         return ret;
87     }
88     ksign.key = &kb;
89     kb.keyvalue = ksign_c.checksum;
90     EVP_DigestInit_ex(m, EVP_md5(), NULL);
91     t[0] = (usage >>  0) & 0xFF;
92     t[1] = (usage >>  8) & 0xFF;
93     t[2] = (usage >> 16) & 0xFF;
94     t[3] = (usage >> 24) & 0xFF;
95     EVP_DigestUpdate(m, t, 4);
96     EVP_DigestUpdate(m, data, len);
97     EVP_DigestFinal_ex (m, tmp, NULL);
98     EVP_MD_CTX_destroy(m);
99
100     ret = _krb5_internal_hmac(context, c, tmp, sizeof(tmp), 0, &ksign, result);
101     if (ret)
102         return ret;
103     return 0;
104 }
105
106 struct _krb5_checksum_type _krb5_checksum_hmac_md5 = {
107     CKSUMTYPE_HMAC_MD5,
108     "hmac-md5",
109     64,
110     16,
111     F_KEYED | F_CPROOF,
112     _krb5_HMAC_MD5_checksum,
113     NULL
114 };
115
116 /*
117  * section 6 of draft-brezak-win2k-krb-rc4-hmac-03
118  *
119  * warning: not for small children
120  */
121
122 static krb5_error_code
123 ARCFOUR_subencrypt(krb5_context context,
124                    struct _krb5_key_data *key,
125                    void *data,
126                    size_t len,
127                    unsigned usage,
128                    void *ivec)
129 {
130     EVP_CIPHER_CTX ctx;
131     struct _krb5_checksum_type *c = _krb5_find_checksum (CKSUMTYPE_RSA_MD5);
132     Checksum k1_c, k2_c, k3_c, cksum;
133     struct _krb5_key_data ke;
134     krb5_keyblock kb;
135     unsigned char t[4];
136     unsigned char *cdata = data;
137     unsigned char k1_c_data[16], k2_c_data[16], k3_c_data[16];
138     krb5_error_code ret;
139
140     t[0] = (usage >>  0) & 0xFF;
141     t[1] = (usage >>  8) & 0xFF;
142     t[2] = (usage >> 16) & 0xFF;
143     t[3] = (usage >> 24) & 0xFF;
144
145     k1_c.checksum.length = sizeof(k1_c_data);
146     k1_c.checksum.data   = k1_c_data;
147
148     ret = _krb5_internal_hmac(context, c, t, sizeof(t), 0, key, &k1_c);
149     if (ret)
150         krb5_abortx(context, "hmac failed");
151
152     memcpy (k2_c_data, k1_c_data, sizeof(k1_c_data));
153
154     k2_c.checksum.length = sizeof(k2_c_data);
155     k2_c.checksum.data   = k2_c_data;
156
157     ke.key = &kb;
158     kb.keyvalue = k2_c.checksum;
159
160     cksum.checksum.length = 16;
161     cksum.checksum.data   = data;
162
163     ret = _krb5_internal_hmac(context, c, cdata + 16, len - 16, 0, &ke, &cksum);
164     if (ret)
165         krb5_abortx(context, "hmac failed");
166
167     ke.key = &kb;
168     kb.keyvalue = k1_c.checksum;
169
170     k3_c.checksum.length = sizeof(k3_c_data);
171     k3_c.checksum.data   = k3_c_data;
172
173     ret = _krb5_internal_hmac(context, c, data, 16, 0, &ke, &k3_c);
174     if (ret)
175         krb5_abortx(context, "hmac failed");
176
177     EVP_CIPHER_CTX_init(&ctx);
178
179     EVP_CipherInit_ex(&ctx, EVP_rc4(), NULL, k3_c.checksum.data, NULL, 1);
180     EVP_Cipher(&ctx, cdata + 16, cdata + 16, len - 16);
181     EVP_CIPHER_CTX_cleanup(&ctx);
182
183     memset (k1_c_data, 0, sizeof(k1_c_data));
184     memset (k2_c_data, 0, sizeof(k2_c_data));
185     memset (k3_c_data, 0, sizeof(k3_c_data));
186     return 0;
187 }
188
189 static krb5_error_code
190 ARCFOUR_subdecrypt(krb5_context context,
191                    struct _krb5_key_data *key,
192                    void *data,
193                    size_t len,
194                    unsigned usage,
195                    void *ivec)
196 {
197     EVP_CIPHER_CTX ctx;
198     struct _krb5_checksum_type *c = _krb5_find_checksum (CKSUMTYPE_RSA_MD5);
199     Checksum k1_c, k2_c, k3_c, cksum;
200     struct _krb5_key_data ke;
201     krb5_keyblock kb;
202     unsigned char t[4];
203     unsigned char *cdata = data;
204     unsigned char k1_c_data[16], k2_c_data[16], k3_c_data[16];
205     unsigned char cksum_data[16];
206     krb5_error_code ret;
207
208     t[0] = (usage >>  0) & 0xFF;
209     t[1] = (usage >>  8) & 0xFF;
210     t[2] = (usage >> 16) & 0xFF;
211     t[3] = (usage >> 24) & 0xFF;
212
213     k1_c.checksum.length = sizeof(k1_c_data);
214     k1_c.checksum.data   = k1_c_data;
215
216     ret = _krb5_internal_hmac(context, c, t, sizeof(t), 0, key, &k1_c);
217     if (ret)
218         krb5_abortx(context, "hmac failed");
219
220     memcpy (k2_c_data, k1_c_data, sizeof(k1_c_data));
221
222     k2_c.checksum.length = sizeof(k2_c_data);
223     k2_c.checksum.data   = k2_c_data;
224
225     ke.key = &kb;
226     kb.keyvalue = k1_c.checksum;
227
228     k3_c.checksum.length = sizeof(k3_c_data);
229     k3_c.checksum.data   = k3_c_data;
230
231     ret = _krb5_internal_hmac(context, c, cdata, 16, 0, &ke, &k3_c);
232     if (ret)
233         krb5_abortx(context, "hmac failed");
234
235     EVP_CIPHER_CTX_init(&ctx);
236     EVP_CipherInit_ex(&ctx, EVP_rc4(), NULL, k3_c.checksum.data, NULL, 0);
237     EVP_Cipher(&ctx, cdata + 16, cdata + 16, len - 16);
238     EVP_CIPHER_CTX_cleanup(&ctx);
239
240     ke.key = &kb;
241     kb.keyvalue = k2_c.checksum;
242
243     cksum.checksum.length = 16;
244     cksum.checksum.data   = cksum_data;
245
246     ret = _krb5_internal_hmac(context, c, cdata + 16, len - 16, 0, &ke, &cksum);
247     if (ret)
248         krb5_abortx(context, "hmac failed");
249
250     memset (k1_c_data, 0, sizeof(k1_c_data));
251     memset (k2_c_data, 0, sizeof(k2_c_data));
252     memset (k3_c_data, 0, sizeof(k3_c_data));
253
254     if (ct_memcmp (cksum.checksum.data, data, 16) != 0) {
255         krb5_clear_error_message (context);
256         return KRB5KRB_AP_ERR_BAD_INTEGRITY;
257     } else {
258         return 0;
259     }
260 }
261
262 /*
263  * convert the usage numbers used in
264  * draft-ietf-cat-kerb-key-derivation-00.txt to the ones in
265  * draft-brezak-win2k-krb-rc4-hmac-04.txt
266  */
267
268 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
269 _krb5_usage2arcfour(krb5_context context, unsigned *usage)
270 {
271     switch (*usage) {
272     case KRB5_KU_AS_REP_ENC_PART : /* 3 */
273         *usage = 8;
274         return 0;
275     case KRB5_KU_USAGE_SEAL :  /* 22 */
276         *usage = 13;
277         return 0;
278     case KRB5_KU_USAGE_SIGN : /* 23 */
279         *usage = 15;
280         return 0;
281     case KRB5_KU_USAGE_SEQ: /* 24 */
282         *usage = 0;
283         return 0;
284     default :
285         return 0;
286     }
287 }
288
289 static krb5_error_code
290 ARCFOUR_encrypt(krb5_context context,
291                 struct _krb5_key_data *key,
292                 void *data,
293                 size_t len,
294                 krb5_boolean encryptp,
295                 int usage,
296                 void *ivec)
297 {
298     krb5_error_code ret;
299     unsigned keyusage = usage;
300
301     if((ret = _krb5_usage2arcfour (context, &keyusage)) != 0)
302         return ret;
303
304     if (encryptp)
305         return ARCFOUR_subencrypt (context, key, data, len, keyusage, ivec);
306     else
307         return ARCFOUR_subdecrypt (context, key, data, len, keyusage, ivec);
308 }
309
310 static krb5_error_code
311 ARCFOUR_prf(krb5_context context,
312             krb5_crypto crypto,
313             const krb5_data *in,
314             krb5_data *out)
315 {
316     struct _krb5_checksum_type *c = _krb5_find_checksum(CKSUMTYPE_SHA1);
317     krb5_error_code ret;
318     Checksum res;
319
320     ret = krb5_data_alloc(out, c->checksumsize);
321     if (ret)
322         return ret;
323
324     res.checksum.data = out->data;
325     res.checksum.length = out->length;
326
327     ret = _krb5_internal_hmac(context, c, in->data, in->length, 0, &crypto->key, &res);
328     if (ret)
329         krb5_data_free(out);
330     return 0;
331 }
332
333
334 struct _krb5_encryption_type _krb5_enctype_arcfour_hmac_md5 = {
335     ETYPE_ARCFOUR_HMAC_MD5,
336     "arcfour-hmac-md5",
337     "rc4-hmac",
338     1,
339     1,
340     8,
341     &keytype_arcfour,
342     &_krb5_checksum_hmac_md5,
343     &_krb5_checksum_hmac_md5,
344     F_SPECIAL,
345     ARCFOUR_encrypt,
346     0,
347     ARCFOUR_prf
348 };