heimdal Extra files required for merge up to current heimdal
[sfrench/samba-autobuild/.git] / source4 / 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 key_type keytype_arcfour = {
41     KEYTYPE_ARCFOUR,
42     "arcfour",
43     128,
44     16,
45     sizeof(struct 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 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 checksum_type *c = _krb5_find_checksum (CKSUMTYPE_RSA_MD5);
68     const char signature[] = "signaturekey";
69     Checksum ksign_c;
70     struct 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 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
125 ARCFOUR_subencrypt(krb5_context context,
126                    struct key_data *key,
127                    void *data,
128                    size_t len,
129                    unsigned usage,
130                    void *ivec)
131 {
132     EVP_CIPHER_CTX ctx;
133     struct checksum_type *c = _krb5_find_checksum (CKSUMTYPE_RSA_MD5);
134     Checksum k1_c, k2_c, k3_c, cksum;
135     struct 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     EVP_CIPHER_CTX_init(&ctx);
180
181     EVP_CipherInit_ex(&ctx, EVP_rc4(), NULL, k3_c.checksum.data, NULL, 1);
182     EVP_Cipher(&ctx, cdata + 16, cdata + 16, len - 16);
183     EVP_CIPHER_CTX_cleanup(&ctx);
184
185     memset (k1_c_data, 0, sizeof(k1_c_data));
186     memset (k2_c_data, 0, sizeof(k2_c_data));
187     memset (k3_c_data, 0, sizeof(k3_c_data));
188     return 0;
189 }
190
191 static krb5_error_code
192 ARCFOUR_subdecrypt(krb5_context context,
193                    struct key_data *key,
194                    void *data,
195                    size_t len,
196                    unsigned usage,
197                    void *ivec)
198 {
199     EVP_CIPHER_CTX ctx;
200     struct checksum_type *c = _krb5_find_checksum (CKSUMTYPE_RSA_MD5);
201     Checksum k1_c, k2_c, k3_c, cksum;
202     struct key_data ke;
203     krb5_keyblock kb;
204     unsigned char t[4];
205     unsigned char *cdata = data;
206     unsigned char k1_c_data[16], k2_c_data[16], k3_c_data[16];
207     unsigned char cksum_data[16];
208     krb5_error_code ret;
209
210     t[0] = (usage >>  0) & 0xFF;
211     t[1] = (usage >>  8) & 0xFF;
212     t[2] = (usage >> 16) & 0xFF;
213     t[3] = (usage >> 24) & 0xFF;
214
215     k1_c.checksum.length = sizeof(k1_c_data);
216     k1_c.checksum.data   = k1_c_data;
217
218     ret = _krb5_internal_hmac(NULL, c, t, sizeof(t), 0, key, &k1_c);
219     if (ret)
220         krb5_abortx(context, "hmac failed");
221
222     memcpy (k2_c_data, k1_c_data, sizeof(k1_c_data));
223
224     k2_c.checksum.length = sizeof(k2_c_data);
225     k2_c.checksum.data   = k2_c_data;
226
227     ke.key = &kb;
228     kb.keyvalue = k1_c.checksum;
229
230     k3_c.checksum.length = sizeof(k3_c_data);
231     k3_c.checksum.data   = k3_c_data;
232
233     ret = _krb5_internal_hmac(NULL, c, cdata, 16, 0, &ke, &k3_c);
234     if (ret)
235         krb5_abortx(context, "hmac failed");
236
237     EVP_CIPHER_CTX_init(&ctx);
238     EVP_CipherInit_ex(&ctx, EVP_rc4(), NULL, k3_c.checksum.data, NULL, 0);
239     EVP_Cipher(&ctx, cdata + 16, cdata + 16, len - 16);
240     EVP_CIPHER_CTX_cleanup(&ctx);
241
242     ke.key = &kb;
243     kb.keyvalue = k2_c.checksum;
244
245     cksum.checksum.length = 16;
246     cksum.checksum.data   = cksum_data;
247
248     ret = _krb5_internal_hmac(NULL, c, cdata + 16, len - 16, 0, &ke, &cksum);
249     if (ret)
250         krb5_abortx(context, "hmac failed");
251
252     memset (k1_c_data, 0, sizeof(k1_c_data));
253     memset (k2_c_data, 0, sizeof(k2_c_data));
254     memset (k3_c_data, 0, sizeof(k3_c_data));
255
256     if (ct_memcmp (cksum.checksum.data, data, 16) != 0) {
257         krb5_clear_error_message (context);
258         return KRB5KRB_AP_ERR_BAD_INTEGRITY;
259     } else {
260         return 0;
261     }
262 }
263
264 /*
265  * convert the usage numbers used in
266  * draft-ietf-cat-kerb-key-derivation-00.txt to the ones in
267  * draft-brezak-win2k-krb-rc4-hmac-04.txt
268  */
269
270 krb5_error_code
271 _krb5_usage2arcfour(krb5_context context, unsigned *usage)
272 {
273     switch (*usage) {
274     case KRB5_KU_AS_REP_ENC_PART : /* 3 */
275         *usage = 8;
276         return 0;
277     case KRB5_KU_USAGE_SEAL :  /* 22 */
278         *usage = 13;
279         return 0;
280     case KRB5_KU_USAGE_SIGN : /* 23 */
281         *usage = 15;
282         return 0;
283     case KRB5_KU_USAGE_SEQ: /* 24 */
284         *usage = 0;
285         return 0;
286     default :
287         return 0;
288     }
289 }
290
291 static krb5_error_code
292 ARCFOUR_encrypt(krb5_context context,
293                 struct key_data *key,
294                 void *data,
295                 size_t len,
296                 krb5_boolean encryptp,
297                 int usage,
298                 void *ivec)
299 {
300     krb5_error_code ret;
301     unsigned keyusage = usage;
302
303     if((ret = _krb5_usage2arcfour (context, &keyusage)) != 0)
304         return ret;
305
306     if (encryptp)
307         return ARCFOUR_subencrypt (context, key, data, len, keyusage, ivec);
308     else
309         return ARCFOUR_subdecrypt (context, key, data, len, keyusage, ivec);
310 }
311
312 struct encryption_type _krb5_enctype_arcfour_hmac_md5 = {
313     ETYPE_ARCFOUR_HMAC_MD5,
314     "arcfour-hmac-md5",
315     1,
316     1,
317     8,
318     &keytype_arcfour,
319     &_krb5_checksum_hmac_md5,
320     NULL,
321     F_SPECIAL,
322     ARCFOUR_encrypt,
323     0,
324     NULL
325 };