xref: /freebsd/crypto/heimdal/lib/krb5/crypto-arcfour.c (revision c6879c6c14eedbd060ba588a3129a6c60ebbe783)
1ae771770SStanislav Sedov /*
2ae771770SStanislav Sedov  * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan
3ae771770SStanislav Sedov  * (Royal Institute of Technology, Stockholm, Sweden).
4ae771770SStanislav Sedov  * All rights reserved.
5ae771770SStanislav Sedov  *
6ae771770SStanislav Sedov  * Redistribution and use in source and binary forms, with or without
7ae771770SStanislav Sedov  * modification, are permitted provided that the following conditions
8ae771770SStanislav Sedov  * are met:
9ae771770SStanislav Sedov  *
10ae771770SStanislav Sedov  * 1. Redistributions of source code must retain the above copyright
11ae771770SStanislav Sedov  *    notice, this list of conditions and the following disclaimer.
12ae771770SStanislav Sedov  *
13ae771770SStanislav Sedov  * 2. Redistributions in binary form must reproduce the above copyright
14ae771770SStanislav Sedov  *    notice, this list of conditions and the following disclaimer in the
15ae771770SStanislav Sedov  *    documentation and/or other materials provided with the distribution.
16ae771770SStanislav Sedov  *
17ae771770SStanislav Sedov  * 3. Neither the name of the Institute nor the names of its contributors
18ae771770SStanislav Sedov  *    may be used to endorse or promote products derived from this software
19ae771770SStanislav Sedov  *    without specific prior written permission.
20ae771770SStanislav Sedov  *
21ae771770SStanislav Sedov  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22ae771770SStanislav Sedov  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23ae771770SStanislav Sedov  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24ae771770SStanislav Sedov  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25ae771770SStanislav Sedov  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26ae771770SStanislav Sedov  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27ae771770SStanislav Sedov  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28ae771770SStanislav Sedov  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29ae771770SStanislav Sedov  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30ae771770SStanislav Sedov  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31ae771770SStanislav Sedov  * SUCH DAMAGE.
32ae771770SStanislav Sedov  */
33ae771770SStanislav Sedov 
34ae771770SStanislav Sedov /*
35ae771770SStanislav Sedov  * ARCFOUR
36ae771770SStanislav Sedov  */
37ae771770SStanislav Sedov 
38ae771770SStanislav Sedov #include "krb5_locl.h"
39ae771770SStanislav Sedov 
40ae771770SStanislav Sedov static struct _krb5_key_type keytype_arcfour = {
41ae771770SStanislav Sedov     ENCTYPE_ARCFOUR_HMAC_MD5,
42ae771770SStanislav Sedov     "arcfour",
43ae771770SStanislav Sedov     128,
44ae771770SStanislav Sedov     16,
45ae771770SStanislav Sedov     sizeof(struct _krb5_evp_schedule),
46ae771770SStanislav Sedov     NULL,
47ae771770SStanislav Sedov     _krb5_evp_schedule,
48ae771770SStanislav Sedov     _krb5_arcfour_salt,
49ae771770SStanislav Sedov     NULL,
50ae771770SStanislav Sedov     _krb5_evp_cleanup,
51ae771770SStanislav Sedov     EVP_rc4
52ae771770SStanislav Sedov };
53ae771770SStanislav Sedov 
54ae771770SStanislav Sedov /*
55ae771770SStanislav Sedov  * checksum according to section 5. of draft-brezak-win2k-krb-rc4-hmac-03.txt
56ae771770SStanislav Sedov  */
57ae771770SStanislav Sedov 
58ae771770SStanislav Sedov 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)59ae771770SStanislav Sedov _krb5_HMAC_MD5_checksum(krb5_context context,
60ae771770SStanislav Sedov 			struct _krb5_key_data *key,
61ae771770SStanislav Sedov 			const void *data,
62ae771770SStanislav Sedov 			size_t len,
63ae771770SStanislav Sedov 			unsigned usage,
64ae771770SStanislav Sedov 			Checksum *result)
65ae771770SStanislav Sedov {
66ae771770SStanislav Sedov     EVP_MD_CTX *m;
67ae771770SStanislav Sedov     struct _krb5_checksum_type *c = _krb5_find_checksum (CKSUMTYPE_RSA_MD5);
68ae771770SStanislav Sedov     const char signature[] = "signaturekey";
69ae771770SStanislav Sedov     Checksum ksign_c;
70ae771770SStanislav Sedov     struct _krb5_key_data ksign;
71ae771770SStanislav Sedov     krb5_keyblock kb;
72ae771770SStanislav Sedov     unsigned char t[4];
73ae771770SStanislav Sedov     unsigned char tmp[16];
74ae771770SStanislav Sedov     unsigned char ksign_c_data[16];
75ae771770SStanislav Sedov     krb5_error_code ret;
76ae771770SStanislav Sedov 
77ae771770SStanislav Sedov     m = EVP_MD_CTX_create();
78ae771770SStanislav Sedov     if (m == NULL) {
79ae771770SStanislav Sedov 	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
80ae771770SStanislav Sedov 	return ENOMEM;
81ae771770SStanislav Sedov     }
82ae771770SStanislav Sedov     ksign_c.checksum.length = sizeof(ksign_c_data);
83ae771770SStanislav Sedov     ksign_c.checksum.data   = ksign_c_data;
84ae771770SStanislav Sedov     ret = _krb5_internal_hmac(context, c, signature, sizeof(signature),
85ae771770SStanislav Sedov 			      0, key, &ksign_c);
86ae771770SStanislav Sedov     if (ret) {
87ae771770SStanislav Sedov 	EVP_MD_CTX_destroy(m);
88ae771770SStanislav Sedov 	return ret;
89ae771770SStanislav Sedov     }
90ae771770SStanislav Sedov     ksign.key = &kb;
91ae771770SStanislav Sedov     kb.keyvalue = ksign_c.checksum;
92ae771770SStanislav Sedov     EVP_DigestInit_ex(m, EVP_md5(), NULL);
93ae771770SStanislav Sedov     t[0] = (usage >>  0) & 0xFF;
94ae771770SStanislav Sedov     t[1] = (usage >>  8) & 0xFF;
95ae771770SStanislav Sedov     t[2] = (usage >> 16) & 0xFF;
96ae771770SStanislav Sedov     t[3] = (usage >> 24) & 0xFF;
97ae771770SStanislav Sedov     EVP_DigestUpdate(m, t, 4);
98ae771770SStanislav Sedov     EVP_DigestUpdate(m, data, len);
99ae771770SStanislav Sedov     EVP_DigestFinal_ex (m, tmp, NULL);
100ae771770SStanislav Sedov     EVP_MD_CTX_destroy(m);
101ae771770SStanislav Sedov 
102ae771770SStanislav Sedov     ret = _krb5_internal_hmac(context, c, tmp, sizeof(tmp), 0, &ksign, result);
103ae771770SStanislav Sedov     if (ret)
104ae771770SStanislav Sedov 	return ret;
105ae771770SStanislav Sedov     return 0;
106ae771770SStanislav Sedov }
107ae771770SStanislav Sedov 
108ae771770SStanislav Sedov struct _krb5_checksum_type _krb5_checksum_hmac_md5 = {
109ae771770SStanislav Sedov     CKSUMTYPE_HMAC_MD5,
110ae771770SStanislav Sedov     "hmac-md5",
111ae771770SStanislav Sedov     64,
112ae771770SStanislav Sedov     16,
113ae771770SStanislav Sedov     F_KEYED | F_CPROOF,
114ae771770SStanislav Sedov     _krb5_HMAC_MD5_checksum,
115ae771770SStanislav Sedov     NULL
116ae771770SStanislav Sedov };
117ae771770SStanislav Sedov 
118ae771770SStanislav Sedov /*
119ae771770SStanislav Sedov  * section 6 of draft-brezak-win2k-krb-rc4-hmac-03
120ae771770SStanislav Sedov  *
121ae771770SStanislav Sedov  * warning: not for small children
122ae771770SStanislav Sedov  */
123ae771770SStanislav Sedov 
124ae771770SStanislav Sedov static krb5_error_code
ARCFOUR_subencrypt(krb5_context context,struct _krb5_key_data * key,void * data,size_t len,unsigned usage,void * ivec)125ae771770SStanislav Sedov ARCFOUR_subencrypt(krb5_context context,
126ae771770SStanislav Sedov 		   struct _krb5_key_data *key,
127ae771770SStanislav Sedov 		   void *data,
128ae771770SStanislav Sedov 		   size_t len,
129ae771770SStanislav Sedov 		   unsigned usage,
130ae771770SStanislav Sedov 		   void *ivec)
131ae771770SStanislav Sedov {
132*e4456411SJohn Baldwin     EVP_CIPHER_CTX *ctx;
133ae771770SStanislav Sedov     struct _krb5_checksum_type *c = _krb5_find_checksum (CKSUMTYPE_RSA_MD5);
134ae771770SStanislav Sedov     Checksum k1_c, k2_c, k3_c, cksum;
135ae771770SStanislav Sedov     struct _krb5_key_data ke;
136ae771770SStanislav Sedov     krb5_keyblock kb;
137ae771770SStanislav Sedov     unsigned char t[4];
138ae771770SStanislav Sedov     unsigned char *cdata = data;
139ae771770SStanislav Sedov     unsigned char k1_c_data[16], k2_c_data[16], k3_c_data[16];
140ae771770SStanislav Sedov     krb5_error_code ret;
141ae771770SStanislav Sedov 
142ae771770SStanislav Sedov     t[0] = (usage >>  0) & 0xFF;
143ae771770SStanislav Sedov     t[1] = (usage >>  8) & 0xFF;
144ae771770SStanislav Sedov     t[2] = (usage >> 16) & 0xFF;
145ae771770SStanislav Sedov     t[3] = (usage >> 24) & 0xFF;
146ae771770SStanislav Sedov 
147ae771770SStanislav Sedov     k1_c.checksum.length = sizeof(k1_c_data);
148ae771770SStanislav Sedov     k1_c.checksum.data   = k1_c_data;
149ae771770SStanislav Sedov 
150ae771770SStanislav Sedov     ret = _krb5_internal_hmac(NULL, c, t, sizeof(t), 0, key, &k1_c);
151ae771770SStanislav Sedov     if (ret)
152ae771770SStanislav Sedov 	krb5_abortx(context, "hmac failed");
153ae771770SStanislav Sedov 
154ae771770SStanislav Sedov     memcpy (k2_c_data, k1_c_data, sizeof(k1_c_data));
155ae771770SStanislav Sedov 
156ae771770SStanislav Sedov     k2_c.checksum.length = sizeof(k2_c_data);
157ae771770SStanislav Sedov     k2_c.checksum.data   = k2_c_data;
158ae771770SStanislav Sedov 
159ae771770SStanislav Sedov     ke.key = &kb;
160ae771770SStanislav Sedov     kb.keyvalue = k2_c.checksum;
161ae771770SStanislav Sedov 
162ae771770SStanislav Sedov     cksum.checksum.length = 16;
163ae771770SStanislav Sedov     cksum.checksum.data   = data;
164ae771770SStanislav Sedov 
165ae771770SStanislav Sedov     ret = _krb5_internal_hmac(NULL, c, cdata + 16, len - 16, 0, &ke, &cksum);
166ae771770SStanislav Sedov     if (ret)
167ae771770SStanislav Sedov 	krb5_abortx(context, "hmac failed");
168ae771770SStanislav Sedov 
169ae771770SStanislav Sedov     ke.key = &kb;
170ae771770SStanislav Sedov     kb.keyvalue = k1_c.checksum;
171ae771770SStanislav Sedov 
172ae771770SStanislav Sedov     k3_c.checksum.length = sizeof(k3_c_data);
173ae771770SStanislav Sedov     k3_c.checksum.data   = k3_c_data;
174ae771770SStanislav Sedov 
175ae771770SStanislav Sedov     ret = _krb5_internal_hmac(NULL, c, data, 16, 0, &ke, &k3_c);
176ae771770SStanislav Sedov     if (ret)
177ae771770SStanislav Sedov 	krb5_abortx(context, "hmac failed");
178ae771770SStanislav Sedov 
179*e4456411SJohn Baldwin     ctx = EVP_CIPHER_CTX_new();
180*e4456411SJohn Baldwin     if (ctx == NULL)
181*e4456411SJohn Baldwin 	krb5_abortx(context, "malloc failed");
182ae771770SStanislav Sedov 
183*e4456411SJohn Baldwin     EVP_CipherInit_ex(ctx, EVP_rc4(), NULL, k3_c.checksum.data, NULL, 1);
184*e4456411SJohn Baldwin     EVP_Cipher(ctx, cdata + 16, cdata + 16, len - 16);
185*e4456411SJohn Baldwin     EVP_CIPHER_CTX_free(ctx);
186ae771770SStanislav Sedov 
187ae771770SStanislav Sedov     memset (k1_c_data, 0, sizeof(k1_c_data));
188ae771770SStanislav Sedov     memset (k2_c_data, 0, sizeof(k2_c_data));
189ae771770SStanislav Sedov     memset (k3_c_data, 0, sizeof(k3_c_data));
190ae771770SStanislav Sedov     return 0;
191ae771770SStanislav Sedov }
192ae771770SStanislav Sedov 
193ae771770SStanislav Sedov static krb5_error_code
ARCFOUR_subdecrypt(krb5_context context,struct _krb5_key_data * key,void * data,size_t len,unsigned usage,void * ivec)194ae771770SStanislav Sedov ARCFOUR_subdecrypt(krb5_context context,
195ae771770SStanislav Sedov 		   struct _krb5_key_data *key,
196ae771770SStanislav Sedov 		   void *data,
197ae771770SStanislav Sedov 		   size_t len,
198ae771770SStanislav Sedov 		   unsigned usage,
199ae771770SStanislav Sedov 		   void *ivec)
200ae771770SStanislav Sedov {
201*e4456411SJohn Baldwin     EVP_CIPHER_CTX *ctx;
202ae771770SStanislav Sedov     struct _krb5_checksum_type *c = _krb5_find_checksum (CKSUMTYPE_RSA_MD5);
203ae771770SStanislav Sedov     Checksum k1_c, k2_c, k3_c, cksum;
204ae771770SStanislav Sedov     struct _krb5_key_data ke;
205ae771770SStanislav Sedov     krb5_keyblock kb;
206ae771770SStanislav Sedov     unsigned char t[4];
207ae771770SStanislav Sedov     unsigned char *cdata = data;
208ae771770SStanislav Sedov     unsigned char k1_c_data[16], k2_c_data[16], k3_c_data[16];
209ae771770SStanislav Sedov     unsigned char cksum_data[16];
210ae771770SStanislav Sedov     krb5_error_code ret;
211ae771770SStanislav Sedov 
212ae771770SStanislav Sedov     t[0] = (usage >>  0) & 0xFF;
213ae771770SStanislav Sedov     t[1] = (usage >>  8) & 0xFF;
214ae771770SStanislav Sedov     t[2] = (usage >> 16) & 0xFF;
215ae771770SStanislav Sedov     t[3] = (usage >> 24) & 0xFF;
216ae771770SStanislav Sedov 
217ae771770SStanislav Sedov     k1_c.checksum.length = sizeof(k1_c_data);
218ae771770SStanislav Sedov     k1_c.checksum.data   = k1_c_data;
219ae771770SStanislav Sedov 
220ae771770SStanislav Sedov     ret = _krb5_internal_hmac(NULL, c, t, sizeof(t), 0, key, &k1_c);
221ae771770SStanislav Sedov     if (ret)
222ae771770SStanislav Sedov 	krb5_abortx(context, "hmac failed");
223ae771770SStanislav Sedov 
224ae771770SStanislav Sedov     memcpy (k2_c_data, k1_c_data, sizeof(k1_c_data));
225ae771770SStanislav Sedov 
226ae771770SStanislav Sedov     k2_c.checksum.length = sizeof(k2_c_data);
227ae771770SStanislav Sedov     k2_c.checksum.data   = k2_c_data;
228ae771770SStanislav Sedov 
229ae771770SStanislav Sedov     ke.key = &kb;
230ae771770SStanislav Sedov     kb.keyvalue = k1_c.checksum;
231ae771770SStanislav Sedov 
232ae771770SStanislav Sedov     k3_c.checksum.length = sizeof(k3_c_data);
233ae771770SStanislav Sedov     k3_c.checksum.data   = k3_c_data;
234ae771770SStanislav Sedov 
235ae771770SStanislav Sedov     ret = _krb5_internal_hmac(NULL, c, cdata, 16, 0, &ke, &k3_c);
236ae771770SStanislav Sedov     if (ret)
237ae771770SStanislav Sedov 	krb5_abortx(context, "hmac failed");
238ae771770SStanislav Sedov 
239*e4456411SJohn Baldwin     ctx = EVP_CIPHER_CTX_new();
240*e4456411SJohn Baldwin     if (ctx == NULL)
241*e4456411SJohn Baldwin 	krb5_abortx(context, "malloc failed");
242*e4456411SJohn Baldwin     EVP_CipherInit_ex(ctx, EVP_rc4(), NULL, k3_c.checksum.data, NULL, 0);
243*e4456411SJohn Baldwin     EVP_Cipher(ctx, cdata + 16, cdata + 16, len - 16);
244*e4456411SJohn Baldwin     EVP_CIPHER_CTX_free(ctx);
245ae771770SStanislav Sedov 
246ae771770SStanislav Sedov     ke.key = &kb;
247ae771770SStanislav Sedov     kb.keyvalue = k2_c.checksum;
248ae771770SStanislav Sedov 
249ae771770SStanislav Sedov     cksum.checksum.length = 16;
250ae771770SStanislav Sedov     cksum.checksum.data   = cksum_data;
251ae771770SStanislav Sedov 
252ae771770SStanislav Sedov     ret = _krb5_internal_hmac(NULL, c, cdata + 16, len - 16, 0, &ke, &cksum);
253ae771770SStanislav Sedov     if (ret)
254ae771770SStanislav Sedov 	krb5_abortx(context, "hmac failed");
255ae771770SStanislav Sedov 
256ae771770SStanislav Sedov     memset (k1_c_data, 0, sizeof(k1_c_data));
257ae771770SStanislav Sedov     memset (k2_c_data, 0, sizeof(k2_c_data));
258ae771770SStanislav Sedov     memset (k3_c_data, 0, sizeof(k3_c_data));
259ae771770SStanislav Sedov 
260ae771770SStanislav Sedov     if (ct_memcmp (cksum.checksum.data, data, 16) != 0) {
261ae771770SStanislav Sedov 	krb5_clear_error_message (context);
262ae771770SStanislav Sedov 	return KRB5KRB_AP_ERR_BAD_INTEGRITY;
263ae771770SStanislav Sedov     } else {
264ae771770SStanislav Sedov 	return 0;
265ae771770SStanislav Sedov     }
266ae771770SStanislav Sedov }
267ae771770SStanislav Sedov 
268ae771770SStanislav Sedov /*
269ae771770SStanislav Sedov  * convert the usage numbers used in
270ae771770SStanislav Sedov  * draft-ietf-cat-kerb-key-derivation-00.txt to the ones in
271ae771770SStanislav Sedov  * draft-brezak-win2k-krb-rc4-hmac-04.txt
272ae771770SStanislav Sedov  */
273ae771770SStanislav Sedov 
274ae771770SStanislav Sedov krb5_error_code
_krb5_usage2arcfour(krb5_context context,unsigned * usage)275ae771770SStanislav Sedov _krb5_usage2arcfour(krb5_context context, unsigned *usage)
276ae771770SStanislav Sedov {
277ae771770SStanislav Sedov     switch (*usage) {
278ae771770SStanislav Sedov     case KRB5_KU_AS_REP_ENC_PART : /* 3 */
279ae771770SStanislav Sedov 	*usage = 8;
280ae771770SStanislav Sedov 	return 0;
281ae771770SStanislav Sedov     case KRB5_KU_USAGE_SEAL :  /* 22 */
282ae771770SStanislav Sedov 	*usage = 13;
283ae771770SStanislav Sedov 	return 0;
284ae771770SStanislav Sedov     case KRB5_KU_USAGE_SIGN : /* 23 */
285ae771770SStanislav Sedov         *usage = 15;
286ae771770SStanislav Sedov         return 0;
287ae771770SStanislav Sedov     case KRB5_KU_USAGE_SEQ: /* 24 */
288ae771770SStanislav Sedov 	*usage = 0;
289ae771770SStanislav Sedov 	return 0;
290ae771770SStanislav Sedov     default :
291ae771770SStanislav Sedov 	return 0;
292ae771770SStanislav Sedov     }
293ae771770SStanislav Sedov }
294ae771770SStanislav Sedov 
295ae771770SStanislav Sedov 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)296ae771770SStanislav Sedov ARCFOUR_encrypt(krb5_context context,
297ae771770SStanislav Sedov 		struct _krb5_key_data *key,
298ae771770SStanislav Sedov 		void *data,
299ae771770SStanislav Sedov 		size_t len,
300ae771770SStanislav Sedov 		krb5_boolean encryptp,
301ae771770SStanislav Sedov 		int usage,
302ae771770SStanislav Sedov 		void *ivec)
303ae771770SStanislav Sedov {
304ae771770SStanislav Sedov     krb5_error_code ret;
305ae771770SStanislav Sedov     unsigned keyusage = usage;
306ae771770SStanislav Sedov 
307ae771770SStanislav Sedov     if((ret = _krb5_usage2arcfour (context, &keyusage)) != 0)
308ae771770SStanislav Sedov 	return ret;
309ae771770SStanislav Sedov 
310ae771770SStanislav Sedov     if (encryptp)
311ae771770SStanislav Sedov 	return ARCFOUR_subencrypt (context, key, data, len, keyusage, ivec);
312ae771770SStanislav Sedov     else
313ae771770SStanislav Sedov 	return ARCFOUR_subdecrypt (context, key, data, len, keyusage, ivec);
314ae771770SStanislav Sedov }
315ae771770SStanislav Sedov 
316ae771770SStanislav Sedov struct _krb5_encryption_type _krb5_enctype_arcfour_hmac_md5 = {
317ae771770SStanislav Sedov     ETYPE_ARCFOUR_HMAC_MD5,
318ae771770SStanislav Sedov     "arcfour-hmac-md5",
319ae771770SStanislav Sedov     1,
320ae771770SStanislav Sedov     1,
321ae771770SStanislav Sedov     8,
322ae771770SStanislav Sedov     &keytype_arcfour,
323ae771770SStanislav Sedov     &_krb5_checksum_hmac_md5,
324cf771f22SStanislav Sedov     &_krb5_checksum_hmac_md5,
325ae771770SStanislav Sedov     F_SPECIAL,
326ae771770SStanislav Sedov     ARCFOUR_encrypt,
327ae771770SStanislav Sedov     0,
328ae771770SStanislav Sedov     NULL
329ae771770SStanislav Sedov };
330