xref: /illumos-gate/usr/src/uts/common/gssapi/mechs/krb5/crypto/keyhash_provider/k5_kmd5des.c (revision 505d05c73a6e56769f263d4803b22eddd168ee24)
17c478bd9Sstevel@tonic-gate /*
2*505d05c7Sgtb  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
37c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
47c478bd9Sstevel@tonic-gate  */
57c478bd9Sstevel@tonic-gate 
67c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
77c478bd9Sstevel@tonic-gate 
87c478bd9Sstevel@tonic-gate /*
97c478bd9Sstevel@tonic-gate  * Copyright (C) 1998 by the FundsXpress, INC.
107c478bd9Sstevel@tonic-gate  *
117c478bd9Sstevel@tonic-gate  * All rights reserved.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * Export of this software from the United States of America may require
147c478bd9Sstevel@tonic-gate  * a specific license from the United States Government.  It is the
157c478bd9Sstevel@tonic-gate  * responsibility of any person or organization contemplating export to
167c478bd9Sstevel@tonic-gate  * obtain such a license before exporting.
177c478bd9Sstevel@tonic-gate  *
187c478bd9Sstevel@tonic-gate  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
197c478bd9Sstevel@tonic-gate  * distribute this software and its documentation for any purpose and
207c478bd9Sstevel@tonic-gate  * without fee is hereby granted, provided that the above copyright
217c478bd9Sstevel@tonic-gate  * notice appear in all copies and that both that copyright notice and
227c478bd9Sstevel@tonic-gate  * this permission notice appear in supporting documentation, and that
237c478bd9Sstevel@tonic-gate  * the name of FundsXpress. not be used in advertising or publicity pertaining
247c478bd9Sstevel@tonic-gate  * to distribution of the software without specific, written prior
257c478bd9Sstevel@tonic-gate  * permission.  FundsXpress makes no representations about the suitability of
267c478bd9Sstevel@tonic-gate  * this software for any purpose.  It is provided "as is" without express
277c478bd9Sstevel@tonic-gate  * or implied warranty.
287c478bd9Sstevel@tonic-gate  *
297c478bd9Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
307c478bd9Sstevel@tonic-gate  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
317c478bd9Sstevel@tonic-gate  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
327c478bd9Sstevel@tonic-gate  */
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate /* Solaris Kerberos:
357c478bd9Sstevel@tonic-gate  * this code is based on the
367c478bd9Sstevel@tonic-gate  * usr/src/lib/gss_mechs/mech_krb5/crypto/keyhash_provider/k5_md5des.c
377c478bd9Sstevel@tonic-gate  * file, but has been modified to use the Solaris resident md5.o kernel
387c478bd9Sstevel@tonic-gate  * module and associated header /usr/include/sys/md5.o.
397c478bd9Sstevel@tonic-gate  * This means that the MD5* functions are called instead of krb5_MD5*.
407c478bd9Sstevel@tonic-gate  */
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate #include <krb5.h>
437c478bd9Sstevel@tonic-gate #include <des_int.h>
447c478bd9Sstevel@tonic-gate #include <keyhash_provider.h>
457c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
467c478bd9Sstevel@tonic-gate #include <sys/crypto/api.h>
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate #define CONFLENGTH 8
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate /* Force acceptance of krb5-beta5 md5des checksum for now. */
517c478bd9Sstevel@tonic-gate #define KRB5_MD5DES_BETA5_COMPAT
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate /* des-cbc(xorkey, conf | rsa-md5(conf | data)) */
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate /* this could be done in terms of the md5 and des providers, but
567c478bd9Sstevel@tonic-gate    that's less efficient, and there's no need for this to be generic */
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate /*ARGSUSED*/
597c478bd9Sstevel@tonic-gate static krb5_error_code
607c478bd9Sstevel@tonic-gate k5_md5des_hash(krb5_context context,
617c478bd9Sstevel@tonic-gate 	krb5_const krb5_keyblock *key,
627c478bd9Sstevel@tonic-gate 	krb5_keyusage usage,
637c478bd9Sstevel@tonic-gate 	krb5_const krb5_data *ivec,
647c478bd9Sstevel@tonic-gate 	krb5_const krb5_data *input, krb5_data *output)
657c478bd9Sstevel@tonic-gate {
667c478bd9Sstevel@tonic-gate     krb5_error_code ret = 0;
677c478bd9Sstevel@tonic-gate     krb5_data data;
687c478bd9Sstevel@tonic-gate     unsigned char conf[CONFLENGTH];
697c478bd9Sstevel@tonic-gate     unsigned char xorkey[MIT_DES_KEYSIZE];
707c478bd9Sstevel@tonic-gate     int i;
717c478bd9Sstevel@tonic-gate     krb5_data *hash_input;
727c478bd9Sstevel@tonic-gate     char *outptr;
737c478bd9Sstevel@tonic-gate     krb5_keyblock newkey;
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate     if (key->length != MIT_DES_KEYSIZE)
767c478bd9Sstevel@tonic-gate 	return(KRB5_BAD_KEYSIZE);
777c478bd9Sstevel@tonic-gate     if (ivec)
787c478bd9Sstevel@tonic-gate 	return(KRB5_CRYPTO_INTERNAL);
797c478bd9Sstevel@tonic-gate     if (output->length != (CONFLENGTH + MD5_CKSUM_LENGTH))
807c478bd9Sstevel@tonic-gate 	return(KRB5_CRYPTO_INTERNAL);
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate     /* create the confounder */
837c478bd9Sstevel@tonic-gate     data.length = CONFLENGTH;
847c478bd9Sstevel@tonic-gate     data.data = (char *) conf;
857c478bd9Sstevel@tonic-gate     if ((ret = krb5_c_random_make_octets(context, &data)))
867c478bd9Sstevel@tonic-gate 	return(ret);
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate     /* hash the confounder, then the input data */
897c478bd9Sstevel@tonic-gate     hash_input = (krb5_data *)MALLOC(sizeof(krb5_data) * 2);
907c478bd9Sstevel@tonic-gate     if (hash_input == NULL)
917c478bd9Sstevel@tonic-gate 	return(KRB5_RC_MALLOC);
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate     hash_input[0].data = (char *)conf;
947c478bd9Sstevel@tonic-gate     hash_input[0].length = CONFLENGTH;
957c478bd9Sstevel@tonic-gate     hash_input[1].data = input->data;
967c478bd9Sstevel@tonic-gate     hash_input[1].length = input->length;
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate     /* Save the pointer to the beginning of the output buffer */
997c478bd9Sstevel@tonic-gate     outptr = (char *)output->data;
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate     /*
1027c478bd9Sstevel@tonic-gate      * Move the output ptr ahead so we can write the hash
1037c478bd9Sstevel@tonic-gate      * digest directly into the buffer.
1047c478bd9Sstevel@tonic-gate      */
1057c478bd9Sstevel@tonic-gate     output->data = output->data + CONFLENGTH;
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate     /* Use generic hash function that calls to kEF */
1087c478bd9Sstevel@tonic-gate     if (k5_ef_hash(context, 2, hash_input, output)) {
1097c478bd9Sstevel@tonic-gate 	FREE(hash_input, sizeof(krb5_data) * 2);
1107c478bd9Sstevel@tonic-gate 	return(KRB5_KEF_ERROR);
1117c478bd9Sstevel@tonic-gate     }
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate     /* restore the original ptr to the output data */
1147c478bd9Sstevel@tonic-gate     output->data = outptr;
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate     /*
1177c478bd9Sstevel@tonic-gate      * Put the confounder in the beginning of the buffer to be
1187c478bd9Sstevel@tonic-gate      * encrypted.
1197c478bd9Sstevel@tonic-gate      */
1207c478bd9Sstevel@tonic-gate     bcopy(conf, output->data, CONFLENGTH);
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate     bcopy(key->contents, xorkey, sizeof(xorkey));
1237c478bd9Sstevel@tonic-gate     for (i=0; i<sizeof(xorkey); i++)
1247c478bd9Sstevel@tonic-gate 	xorkey[i] ^= 0xf0;
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate     /*
1277c478bd9Sstevel@tonic-gate      * Solaris Kerberos:
1287c478bd9Sstevel@tonic-gate      * Encryption Framework checks for parity and weak keys.
1297c478bd9Sstevel@tonic-gate      */
1307c478bd9Sstevel@tonic-gate     bzero(&newkey, sizeof(krb5_keyblock));
1317c478bd9Sstevel@tonic-gate     newkey.enctype = key->enctype;
1327c478bd9Sstevel@tonic-gate     newkey.contents = xorkey;
1337c478bd9Sstevel@tonic-gate     newkey.length = sizeof(xorkey);
1347c478bd9Sstevel@tonic-gate     newkey.dk_list = NULL;
1357c478bd9Sstevel@tonic-gate     newkey.kef_key.ck_data = NULL;
1367c478bd9Sstevel@tonic-gate     ret = init_key_kef(context->kef_cipher_mt, &newkey);
1377c478bd9Sstevel@tonic-gate     if (ret) {
1387c478bd9Sstevel@tonic-gate 	FREE(hash_input, sizeof(krb5_data) * 2);
1397c478bd9Sstevel@tonic-gate 	return (ret);
1407c478bd9Sstevel@tonic-gate     }
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate     /* encrypt it, in place.  this has a return value, but it's
1437c478bd9Sstevel@tonic-gate        always zero.  */
1447c478bd9Sstevel@tonic-gate     ret = mit_des_cbc_encrypt(context, (krb5_pointer) output->data,
1457c478bd9Sstevel@tonic-gate 	(krb5_pointer) output->data, output->length,
1467c478bd9Sstevel@tonic-gate 	&newkey, (unsigned char*) mit_des_zeroblock, 1);
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate     FREE(hash_input, sizeof(krb5_data) * 2);
1497c478bd9Sstevel@tonic-gate     (void)crypto_destroy_ctx_template(newkey.key_tmpl);
1507c478bd9Sstevel@tonic-gate     return(ret);
1517c478bd9Sstevel@tonic-gate }
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1547c478bd9Sstevel@tonic-gate static krb5_error_code
1557c478bd9Sstevel@tonic-gate k5_md5des_verify(krb5_context context,
1567c478bd9Sstevel@tonic-gate 	krb5_const krb5_keyblock *key,
1577c478bd9Sstevel@tonic-gate 	krb5_keyusage usage,
1587c478bd9Sstevel@tonic-gate 	krb5_const krb5_data *ivec,
1597c478bd9Sstevel@tonic-gate 	krb5_const krb5_data *input,
1607c478bd9Sstevel@tonic-gate 	krb5_const krb5_data *hash,
1617c478bd9Sstevel@tonic-gate 	krb5_boolean *valid)
1627c478bd9Sstevel@tonic-gate {
1637c478bd9Sstevel@tonic-gate     krb5_error_code ret = 0;
1647c478bd9Sstevel@tonic-gate     unsigned char plaintext[CONFLENGTH + MD5_CKSUM_LENGTH];
1657c478bd9Sstevel@tonic-gate     unsigned char xorkey[8];
1667c478bd9Sstevel@tonic-gate     int i;
1677c478bd9Sstevel@tonic-gate     int compathash = 0;
1687c478bd9Sstevel@tonic-gate     krb5_octet outtmp[MD5_CKSUM_LENGTH];
1697c478bd9Sstevel@tonic-gate     size_t hisize;
1707c478bd9Sstevel@tonic-gate     krb5_data *hash_input;
1717c478bd9Sstevel@tonic-gate     krb5_data hash_output;
1727c478bd9Sstevel@tonic-gate     krb5_keyblock newkey;
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate     if (key->length != MIT_DES_KEYSIZE)
1757c478bd9Sstevel@tonic-gate 	return(KRB5_BAD_KEYSIZE);
1767c478bd9Sstevel@tonic-gate     if (ivec)
1777c478bd9Sstevel@tonic-gate 	return(KRB5_CRYPTO_INTERNAL);
1787c478bd9Sstevel@tonic-gate     if (hash->length != (CONFLENGTH + MD5_CKSUM_LENGTH)) {
1797c478bd9Sstevel@tonic-gate #ifdef KRB5_MD5DES_BETA5_COMPAT
1807c478bd9Sstevel@tonic-gate 	if (hash->length != MD5_CKSUM_LENGTH)
1817c478bd9Sstevel@tonic-gate 	    return(KRB5_CRYPTO_INTERNAL);
1827c478bd9Sstevel@tonic-gate 	else
1837c478bd9Sstevel@tonic-gate 	    compathash = 1;
1847c478bd9Sstevel@tonic-gate #else
1857c478bd9Sstevel@tonic-gate 	return(KRB5_CRYPTO_INTERNAL);
1867c478bd9Sstevel@tonic-gate #endif
1877c478bd9Sstevel@tonic-gate     }
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate     /* create and schedule the encryption key */
1907c478bd9Sstevel@tonic-gate     (void) bcopy(key->contents, xorkey, sizeof(xorkey));
1917c478bd9Sstevel@tonic-gate     if (!compathash) {
1927c478bd9Sstevel@tonic-gate 	for (i=0; i<sizeof(xorkey); i++)
1937c478bd9Sstevel@tonic-gate 	    xorkey[i] ^= 0xf0;
1947c478bd9Sstevel@tonic-gate     }
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate     /*
1977c478bd9Sstevel@tonic-gate      * Solaris Kerberos:
1987c478bd9Sstevel@tonic-gate      * Encryption Framework checks for parity and weak keys
1997c478bd9Sstevel@tonic-gate      */
2007c478bd9Sstevel@tonic-gate     bzero(&newkey, sizeof(krb5_keyblock));
2017c478bd9Sstevel@tonic-gate     newkey.enctype = key->enctype;
2027c478bd9Sstevel@tonic-gate     newkey.contents = xorkey;
2037c478bd9Sstevel@tonic-gate     newkey.length = sizeof(xorkey);
2047c478bd9Sstevel@tonic-gate     newkey.dk_list = NULL;
2057c478bd9Sstevel@tonic-gate     newkey.kef_key.ck_data = NULL;
2067c478bd9Sstevel@tonic-gate     ret = init_key_kef(context->kef_cipher_mt, &newkey);
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate     /* decrypt it.  this has a return value, but it's always zero.  */
2097c478bd9Sstevel@tonic-gate     if (!compathash) {
2107c478bd9Sstevel@tonic-gate 	ret = mit_des_cbc_encrypt(context, (krb5_pointer) hash->data,
2117c478bd9Sstevel@tonic-gate 			    (krb5_pointer) plaintext, hash->length,
2127c478bd9Sstevel@tonic-gate 			    &newkey, (unsigned char*) mit_des_zeroblock, 0);
2137c478bd9Sstevel@tonic-gate     } else {
2147c478bd9Sstevel@tonic-gate 	ret = mit_des_cbc_encrypt(context, (krb5_pointer) hash->data,
2157c478bd9Sstevel@tonic-gate 			    (krb5_pointer) plaintext, hash->length,
2167c478bd9Sstevel@tonic-gate 			    &newkey, xorkey, 0);
2177c478bd9Sstevel@tonic-gate     }
2187c478bd9Sstevel@tonic-gate     if (ret) goto cleanup;
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate     /* hash the confounder, then the input data */
2217c478bd9Sstevel@tonic-gate     i = 1;
2227c478bd9Sstevel@tonic-gate     if (!compathash)
2237c478bd9Sstevel@tonic-gate 	i++;
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate     hisize = sizeof(krb5_data) * i;
2267c478bd9Sstevel@tonic-gate     hash_input = (krb5_data *)MALLOC(hisize);
2277c478bd9Sstevel@tonic-gate     if (hash_input == NULL)
2287c478bd9Sstevel@tonic-gate 	return(KRB5_RC_MALLOC);
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate     i=0;
2317c478bd9Sstevel@tonic-gate     if (!compathash) {
2327c478bd9Sstevel@tonic-gate     	hash_input[i].data = (char *)plaintext;
2337c478bd9Sstevel@tonic-gate     	hash_input[i].length = CONFLENGTH;
2347c478bd9Sstevel@tonic-gate 	i++;
2357c478bd9Sstevel@tonic-gate     }
2367c478bd9Sstevel@tonic-gate     hash_input[i].data = input->data;
2377c478bd9Sstevel@tonic-gate     hash_input[i].length = input->length;
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate     hash_output.data = (char *)outtmp;
2407c478bd9Sstevel@tonic-gate     hash_output.length = sizeof(outtmp);
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate     if (k5_ef_hash(context, 1, hash_input, &hash_output)) {
2437c478bd9Sstevel@tonic-gate 	ret = KRB5_KEF_ERROR;
2447c478bd9Sstevel@tonic-gate 	goto cleanup;
2457c478bd9Sstevel@tonic-gate     }
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate     /* compare the decrypted hash to the computed one */
2487c478bd9Sstevel@tonic-gate     if (!compathash) {
2497c478bd9Sstevel@tonic-gate 	*valid = !bcmp((const void *)(plaintext+CONFLENGTH),
2507c478bd9Sstevel@tonic-gate 		(void *)outtmp, MD5_CKSUM_LENGTH);
2517c478bd9Sstevel@tonic-gate     } else {
2527c478bd9Sstevel@tonic-gate 	*valid = !bcmp((const void *)plaintext,
2537c478bd9Sstevel@tonic-gate 		(void *)outtmp, MD5_CKSUM_LENGTH);
2547c478bd9Sstevel@tonic-gate     }
2557c478bd9Sstevel@tonic-gate     bzero((void *)plaintext, sizeof(plaintext));
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate cleanup:
2587c478bd9Sstevel@tonic-gate     if (hash_input != NULL && hisize > 0)
2597c478bd9Sstevel@tonic-gate 	    FREE(hash_input, hisize);
2607c478bd9Sstevel@tonic-gate     (void)crypto_destroy_ctx_template(newkey.key_tmpl);
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate     return(ret);
2637c478bd9Sstevel@tonic-gate }
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate const struct krb5_keyhash_provider krb5_keyhash_md5des = {
266*505d05c7Sgtb     CONFLENGTH+MD5_CKSUM_LENGTH,
2677c478bd9Sstevel@tonic-gate     k5_md5des_hash,
2687c478bd9Sstevel@tonic-gate     k5_md5des_verify
2697c478bd9Sstevel@tonic-gate };
270