xref: /illumos-gate/usr/src/uts/common/gssapi/mechs/krb5/crypto/keyhash_provider/k5_kmd5des.c (revision 505d05c73a6e56769f263d4803b22eddd168ee24)
1 /*
2  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 #pragma ident	"%Z%%M%	%I%	%E% SMI"
7 
8 /*
9  * Copyright (C) 1998 by the FundsXpress, INC.
10  *
11  * All rights reserved.
12  *
13  * Export of this software from the United States of America may require
14  * a specific license from the United States Government.  It is the
15  * responsibility of any person or organization contemplating export to
16  * obtain such a license before exporting.
17  *
18  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
19  * distribute this software and its documentation for any purpose and
20  * without fee is hereby granted, provided that the above copyright
21  * notice appear in all copies and that both that copyright notice and
22  * this permission notice appear in supporting documentation, and that
23  * the name of FundsXpress. not be used in advertising or publicity pertaining
24  * to distribution of the software without specific, written prior
25  * permission.  FundsXpress makes no representations about the suitability of
26  * this software for any purpose.  It is provided "as is" without express
27  * or implied warranty.
28  *
29  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
30  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
31  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
32  */
33 
34 /* Solaris Kerberos:
35  * this code is based on the
36  * usr/src/lib/gss_mechs/mech_krb5/crypto/keyhash_provider/k5_md5des.c
37  * file, but has been modified to use the Solaris resident md5.o kernel
38  * module and associated header /usr/include/sys/md5.o.
39  * This means that the MD5* functions are called instead of krb5_MD5*.
40  */
41 
42 #include <krb5.h>
43 #include <des_int.h>
44 #include <keyhash_provider.h>
45 #include <sys/kmem.h>
46 #include <sys/crypto/api.h>
47 
48 #define CONFLENGTH 8
49 
50 /* Force acceptance of krb5-beta5 md5des checksum for now. */
51 #define KRB5_MD5DES_BETA5_COMPAT
52 
53 /* des-cbc(xorkey, conf | rsa-md5(conf | data)) */
54 
55 /* this could be done in terms of the md5 and des providers, but
56    that's less efficient, and there's no need for this to be generic */
57 
58 /*ARGSUSED*/
59 static krb5_error_code
60 k5_md5des_hash(krb5_context context,
61 	krb5_const krb5_keyblock *key,
62 	krb5_keyusage usage,
63 	krb5_const krb5_data *ivec,
64 	krb5_const krb5_data *input, krb5_data *output)
65 {
66     krb5_error_code ret = 0;
67     krb5_data data;
68     unsigned char conf[CONFLENGTH];
69     unsigned char xorkey[MIT_DES_KEYSIZE];
70     int i;
71     krb5_data *hash_input;
72     char *outptr;
73     krb5_keyblock newkey;
74 
75     if (key->length != MIT_DES_KEYSIZE)
76 	return(KRB5_BAD_KEYSIZE);
77     if (ivec)
78 	return(KRB5_CRYPTO_INTERNAL);
79     if (output->length != (CONFLENGTH + MD5_CKSUM_LENGTH))
80 	return(KRB5_CRYPTO_INTERNAL);
81 
82     /* create the confounder */
83     data.length = CONFLENGTH;
84     data.data = (char *) conf;
85     if ((ret = krb5_c_random_make_octets(context, &data)))
86 	return(ret);
87 
88     /* hash the confounder, then the input data */
89     hash_input = (krb5_data *)MALLOC(sizeof(krb5_data) * 2);
90     if (hash_input == NULL)
91 	return(KRB5_RC_MALLOC);
92 
93     hash_input[0].data = (char *)conf;
94     hash_input[0].length = CONFLENGTH;
95     hash_input[1].data = input->data;
96     hash_input[1].length = input->length;
97 
98     /* Save the pointer to the beginning of the output buffer */
99     outptr = (char *)output->data;
100 
101     /*
102      * Move the output ptr ahead so we can write the hash
103      * digest directly into the buffer.
104      */
105     output->data = output->data + CONFLENGTH;
106 
107     /* Use generic hash function that calls to kEF */
108     if (k5_ef_hash(context, 2, hash_input, output)) {
109 	FREE(hash_input, sizeof(krb5_data) * 2);
110 	return(KRB5_KEF_ERROR);
111     }
112 
113     /* restore the original ptr to the output data */
114     output->data = outptr;
115 
116     /*
117      * Put the confounder in the beginning of the buffer to be
118      * encrypted.
119      */
120     bcopy(conf, output->data, CONFLENGTH);
121 
122     bcopy(key->contents, xorkey, sizeof(xorkey));
123     for (i=0; i<sizeof(xorkey); i++)
124 	xorkey[i] ^= 0xf0;
125 
126     /*
127      * Solaris Kerberos:
128      * Encryption Framework checks for parity and weak keys.
129      */
130     bzero(&newkey, sizeof(krb5_keyblock));
131     newkey.enctype = key->enctype;
132     newkey.contents = xorkey;
133     newkey.length = sizeof(xorkey);
134     newkey.dk_list = NULL;
135     newkey.kef_key.ck_data = NULL;
136     ret = init_key_kef(context->kef_cipher_mt, &newkey);
137     if (ret) {
138 	FREE(hash_input, sizeof(krb5_data) * 2);
139 	return (ret);
140     }
141 
142     /* encrypt it, in place.  this has a return value, but it's
143        always zero.  */
144     ret = mit_des_cbc_encrypt(context, (krb5_pointer) output->data,
145 	(krb5_pointer) output->data, output->length,
146 	&newkey, (unsigned char*) mit_des_zeroblock, 1);
147 
148     FREE(hash_input, sizeof(krb5_data) * 2);
149     (void)crypto_destroy_ctx_template(newkey.key_tmpl);
150     return(ret);
151 }
152 
153 /*ARGSUSED*/
154 static krb5_error_code
155 k5_md5des_verify(krb5_context context,
156 	krb5_const krb5_keyblock *key,
157 	krb5_keyusage usage,
158 	krb5_const krb5_data *ivec,
159 	krb5_const krb5_data *input,
160 	krb5_const krb5_data *hash,
161 	krb5_boolean *valid)
162 {
163     krb5_error_code ret = 0;
164     unsigned char plaintext[CONFLENGTH + MD5_CKSUM_LENGTH];
165     unsigned char xorkey[8];
166     int i;
167     int compathash = 0;
168     krb5_octet outtmp[MD5_CKSUM_LENGTH];
169     size_t hisize;
170     krb5_data *hash_input;
171     krb5_data hash_output;
172     krb5_keyblock newkey;
173 
174     if (key->length != MIT_DES_KEYSIZE)
175 	return(KRB5_BAD_KEYSIZE);
176     if (ivec)
177 	return(KRB5_CRYPTO_INTERNAL);
178     if (hash->length != (CONFLENGTH + MD5_CKSUM_LENGTH)) {
179 #ifdef KRB5_MD5DES_BETA5_COMPAT
180 	if (hash->length != MD5_CKSUM_LENGTH)
181 	    return(KRB5_CRYPTO_INTERNAL);
182 	else
183 	    compathash = 1;
184 #else
185 	return(KRB5_CRYPTO_INTERNAL);
186 #endif
187     }
188 
189     /* create and schedule the encryption key */
190     (void) bcopy(key->contents, xorkey, sizeof(xorkey));
191     if (!compathash) {
192 	for (i=0; i<sizeof(xorkey); i++)
193 	    xorkey[i] ^= 0xf0;
194     }
195 
196     /*
197      * Solaris Kerberos:
198      * Encryption Framework checks for parity and weak keys
199      */
200     bzero(&newkey, sizeof(krb5_keyblock));
201     newkey.enctype = key->enctype;
202     newkey.contents = xorkey;
203     newkey.length = sizeof(xorkey);
204     newkey.dk_list = NULL;
205     newkey.kef_key.ck_data = NULL;
206     ret = init_key_kef(context->kef_cipher_mt, &newkey);
207 
208     /* decrypt it.  this has a return value, but it's always zero.  */
209     if (!compathash) {
210 	ret = mit_des_cbc_encrypt(context, (krb5_pointer) hash->data,
211 			    (krb5_pointer) plaintext, hash->length,
212 			    &newkey, (unsigned char*) mit_des_zeroblock, 0);
213     } else {
214 	ret = mit_des_cbc_encrypt(context, (krb5_pointer) hash->data,
215 			    (krb5_pointer) plaintext, hash->length,
216 			    &newkey, xorkey, 0);
217     }
218     if (ret) goto cleanup;
219 
220     /* hash the confounder, then the input data */
221     i = 1;
222     if (!compathash)
223 	i++;
224 
225     hisize = sizeof(krb5_data) * i;
226     hash_input = (krb5_data *)MALLOC(hisize);
227     if (hash_input == NULL)
228 	return(KRB5_RC_MALLOC);
229 
230     i=0;
231     if (!compathash) {
232     	hash_input[i].data = (char *)plaintext;
233     	hash_input[i].length = CONFLENGTH;
234 	i++;
235     }
236     hash_input[i].data = input->data;
237     hash_input[i].length = input->length;
238 
239     hash_output.data = (char *)outtmp;
240     hash_output.length = sizeof(outtmp);
241 
242     if (k5_ef_hash(context, 1, hash_input, &hash_output)) {
243 	ret = KRB5_KEF_ERROR;
244 	goto cleanup;
245     }
246 
247     /* compare the decrypted hash to the computed one */
248     if (!compathash) {
249 	*valid = !bcmp((const void *)(plaintext+CONFLENGTH),
250 		(void *)outtmp, MD5_CKSUM_LENGTH);
251     } else {
252 	*valid = !bcmp((const void *)plaintext,
253 		(void *)outtmp, MD5_CKSUM_LENGTH);
254     }
255     bzero((void *)plaintext, sizeof(plaintext));
256 
257 cleanup:
258     if (hash_input != NULL && hisize > 0)
259 	    FREE(hash_input, hisize);
260     (void)crypto_destroy_ctx_template(newkey.key_tmpl);
261 
262     return(ret);
263 }
264 
265 const struct krb5_keyhash_provider krb5_keyhash_md5des = {
266     CONFLENGTH+MD5_CKSUM_LENGTH,
267     k5_md5des_hash,
268     k5_md5des_verify
269 };
270