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