17c478bd9Sstevel@tonic-gate /*
2159d09a2SMark Phalan  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
37c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
47c478bd9Sstevel@tonic-gate  */
57c478bd9Sstevel@tonic-gate 
67c478bd9Sstevel@tonic-gate 
77c478bd9Sstevel@tonic-gate /*
87c478bd9Sstevel@tonic-gate  * Copyright (C) 1998 by the FundsXpress, INC.
9*55fea89dSDan Cross  *
107c478bd9Sstevel@tonic-gate  * All rights reserved.
11*55fea89dSDan Cross  *
127c478bd9Sstevel@tonic-gate  * Export of this software from the United States of America may require
137c478bd9Sstevel@tonic-gate  * a specific license from the United States Government.  It is the
147c478bd9Sstevel@tonic-gate  * responsibility of any person or organization contemplating export to
157c478bd9Sstevel@tonic-gate  * obtain such a license before exporting.
16*55fea89dSDan Cross  *
177c478bd9Sstevel@tonic-gate  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
187c478bd9Sstevel@tonic-gate  * distribute this software and its documentation for any purpose and
197c478bd9Sstevel@tonic-gate  * without fee is hereby granted, provided that the above copyright
207c478bd9Sstevel@tonic-gate  * notice appear in all copies and that both that copyright notice and
217c478bd9Sstevel@tonic-gate  * this permission notice appear in supporting documentation, and that
227c478bd9Sstevel@tonic-gate  * the name of FundsXpress. not be used in advertising or publicity pertaining
237c478bd9Sstevel@tonic-gate  * to distribution of the software without specific, written prior
247c478bd9Sstevel@tonic-gate  * permission.  FundsXpress makes no representations about the suitability of
257c478bd9Sstevel@tonic-gate  * this software for any purpose.  It is provided "as is" without express
267c478bd9Sstevel@tonic-gate  * or implied warranty.
27*55fea89dSDan Cross  *
287c478bd9Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
297c478bd9Sstevel@tonic-gate  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
307c478bd9Sstevel@tonic-gate  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
317c478bd9Sstevel@tonic-gate  */
327c478bd9Sstevel@tonic-gate 
33159d09a2SMark Phalan #include "k5-int.h"
34159d09a2SMark Phalan #include "des_int.h"
35159d09a2SMark Phalan #include "keyhash_provider.h"
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate #define CONFLENGTH 8
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate /* Force acceptance of krb5-beta5 md5des checksum for now. */
407c478bd9Sstevel@tonic-gate #define KRB5_MD5DES_BETA5_COMPAT
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate /* des-cbc(xorkey, conf | rsa-md5(conf | data)) */
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate /* this could be done in terms of the md5 and des providers, but
457c478bd9Sstevel@tonic-gate    that's less efficient, and there's no need for this to be generic */
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate /*ARGSUSED*/
487c478bd9Sstevel@tonic-gate static krb5_error_code
k5_md5des_hash(krb5_context context,krb5_const krb5_keyblock * key,krb5_keyusage usage,const krb5_data * ivec,const krb5_data * input,krb5_data * output)49159d09a2SMark Phalan k5_md5des_hash(krb5_context context, krb5_const krb5_keyblock *key,
50159d09a2SMark Phalan 	       krb5_keyusage usage, const krb5_data *ivec,
51159d09a2SMark Phalan 	       const krb5_data *input, krb5_data *output)
527c478bd9Sstevel@tonic-gate {
537c478bd9Sstevel@tonic-gate     krb5_error_code ret = 0;
547c478bd9Sstevel@tonic-gate     krb5_data data;
557c478bd9Sstevel@tonic-gate     unsigned char conf[CONFLENGTH];
567c478bd9Sstevel@tonic-gate     krb5_keyblock xorkey;
577c478bd9Sstevel@tonic-gate     int i;
587c478bd9Sstevel@tonic-gate     CK_MECHANISM mechanism;
597c478bd9Sstevel@tonic-gate     CK_RV rv;
607c478bd9Sstevel@tonic-gate     CK_ULONG hashlen = MD5_CKSUM_LENGTH;
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate     if (key->length != 8)
637c478bd9Sstevel@tonic-gate 	return(KRB5_BAD_KEYSIZE);
647c478bd9Sstevel@tonic-gate     if (ivec)
657c478bd9Sstevel@tonic-gate 	return(KRB5_CRYPTO_INTERNAL);
667c478bd9Sstevel@tonic-gate     if (output->length != (CONFLENGTH+MD5_CKSUM_LENGTH))
677c478bd9Sstevel@tonic-gate 	return(KRB5_CRYPTO_INTERNAL);
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate     /* create the confouder */
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate     data.length = CONFLENGTH;
727c478bd9Sstevel@tonic-gate     data.data = (char *) conf;
737c478bd9Sstevel@tonic-gate     if ((ret = krb5_c_random_make_octets(context, &data)))
747c478bd9Sstevel@tonic-gate 	return(ret);
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate     xorkey.magic = key->magic;
777c478bd9Sstevel@tonic-gate     xorkey.enctype = key->enctype;
787c478bd9Sstevel@tonic-gate     xorkey.length = key->length;
797c478bd9Sstevel@tonic-gate     xorkey.contents = (krb5_octet *)malloc(key->length);
807c478bd9Sstevel@tonic-gate     if (xorkey.contents == NULL)
817c478bd9Sstevel@tonic-gate 	return(KRB5_CRYPTO_INTERNAL);
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate     (void) memcpy(xorkey.contents, key->contents, xorkey.length);
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate     for (i=0; i<xorkey.length; i++)
867c478bd9Sstevel@tonic-gate 	xorkey.contents[i] ^= 0xf0;
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate     if (!mit_des_check_key_parity(xorkey.contents)) {
897c478bd9Sstevel@tonic-gate 	ret = KRB5DES_BAD_KEYPAR;
907c478bd9Sstevel@tonic-gate 	goto cleanup;
917c478bd9Sstevel@tonic-gate     }
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate     if (mit_des_is_weak_key(xorkey.contents)) {
947c478bd9Sstevel@tonic-gate 	ret = KRB5DES_WEAK_KEY;
957c478bd9Sstevel@tonic-gate 	goto cleanup;
967c478bd9Sstevel@tonic-gate     }
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate     /* hash the confounder, then the input data */
997c478bd9Sstevel@tonic-gate     mechanism.mechanism = CKM_MD5;
1007c478bd9Sstevel@tonic-gate     mechanism.pParameter = NULL_PTR;
1017c478bd9Sstevel@tonic-gate     mechanism.ulParameterLen = 0;
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate     if ((rv = C_DigestInit(krb_ctx_hSession(context), &mechanism)) != CKR_OK) {
1047c478bd9Sstevel@tonic-gate 	KRB5_LOG(KRB5_ERR, "C_DigestInit failed in k5_md5des_hash: "
1057c478bd9Sstevel@tonic-gate 	"rv = 0x%x.", rv);
1067c478bd9Sstevel@tonic-gate 	ret = PKCS_ERR;
1077c478bd9Sstevel@tonic-gate 	goto cleanup;
1087c478bd9Sstevel@tonic-gate     }
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate     if ((rv = C_DigestUpdate(krb_ctx_hSession(context),
1117c478bd9Sstevel@tonic-gate 	(CK_BYTE_PTR)conf, (CK_ULONG)sizeof(conf))) != CKR_OK) {
1127c478bd9Sstevel@tonic-gate 	KRB5_LOG(KRB5_ERR, "C_DigestUpdate failed in k5_md5des_hash: "
1137c478bd9Sstevel@tonic-gate 	    "rv = 0x%x", rv);
1147c478bd9Sstevel@tonic-gate 	ret = PKCS_ERR;
1157c478bd9Sstevel@tonic-gate 	goto cleanup;
1167c478bd9Sstevel@tonic-gate     }
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate     if ((rv = C_DigestUpdate(krb_ctx_hSession(context),
1197c478bd9Sstevel@tonic-gate 	(CK_BYTE_PTR)input->data, (CK_ULONG)input->length)) != CKR_OK) {
1207c478bd9Sstevel@tonic-gate 	KRB5_LOG(KRB5_ERR, "C_DigestUpdate failed in k5_md5des_hash: "
1217c478bd9Sstevel@tonic-gate 	    "rv = 0x%x", rv);
1227c478bd9Sstevel@tonic-gate 	return(PKCS_ERR);
1237c478bd9Sstevel@tonic-gate     }
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate     if ((rv = C_DigestFinal(krb_ctx_hSession(context),
1267c478bd9Sstevel@tonic-gate 	(CK_BYTE_PTR)(output->data + CONFLENGTH),
1277c478bd9Sstevel@tonic-gate 	(CK_ULONG_PTR)&hashlen)) != CKR_OK) {
1287c478bd9Sstevel@tonic-gate 	KRB5_LOG(KRB5_ERR, "C_DigestFinal failed in k5_md5des_hash: "
1297c478bd9Sstevel@tonic-gate 	    "rv = 0x%x", rv);
1307c478bd9Sstevel@tonic-gate 	ret = PKCS_ERR;
1317c478bd9Sstevel@tonic-gate 	goto cleanup;
1327c478bd9Sstevel@tonic-gate     }
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate     /* construct the buffer to be encrypted */
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate     (void) memcpy(output->data, conf, CONFLENGTH);
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate     /* encrypt it, in place.  this has a return value, but it's
1397c478bd9Sstevel@tonic-gate        always zero.  */
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate     ret = mit_des_cbc_encrypt(context,
1427c478bd9Sstevel@tonic-gate 	(krb5_pointer) output->data,
1437c478bd9Sstevel@tonic-gate 	(krb5_pointer) output->data, output->length,
1447c478bd9Sstevel@tonic-gate 	&xorkey, (unsigned char*) mit_des_zeroblock, 1);
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate cleanup:
1477c478bd9Sstevel@tonic-gate     free(xorkey.contents);
1487c478bd9Sstevel@tonic-gate     return(ret);
1497c478bd9Sstevel@tonic-gate }
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1527c478bd9Sstevel@tonic-gate static krb5_error_code
k5_md5des_verify(krb5_context context,krb5_const krb5_keyblock * key,krb5_keyusage usage,krb5_const krb5_data * ivec,krb5_const krb5_data * input,krb5_const krb5_data * hash,krb5_boolean * valid)1537c478bd9Sstevel@tonic-gate k5_md5des_verify(krb5_context context,
154*55fea89dSDan Cross 	krb5_const krb5_keyblock *key,
1557c478bd9Sstevel@tonic-gate 	krb5_keyusage usage,
1567c478bd9Sstevel@tonic-gate 	krb5_const krb5_data *ivec,
1577c478bd9Sstevel@tonic-gate 	krb5_const krb5_data *input,
1587c478bd9Sstevel@tonic-gate 	krb5_const krb5_data *hash,
1597c478bd9Sstevel@tonic-gate 	krb5_boolean *valid)
1607c478bd9Sstevel@tonic-gate {
1617c478bd9Sstevel@tonic-gate     krb5_error_code ret = 0;
1627c478bd9Sstevel@tonic-gate     unsigned char plaintext[CONFLENGTH+MD5_CKSUM_LENGTH];
1637c478bd9Sstevel@tonic-gate     unsigned char digest[MD5_CKSUM_LENGTH];
1647c478bd9Sstevel@tonic-gate     krb5_keyblock xorkey;
1657c478bd9Sstevel@tonic-gate     int i;
1667c478bd9Sstevel@tonic-gate     int compathash = 0;
1677c478bd9Sstevel@tonic-gate     CK_MECHANISM mechanism;
1687c478bd9Sstevel@tonic-gate     CK_RV rv;
1697c478bd9Sstevel@tonic-gate     CK_ULONG hashlen = MD5_CKSUM_LENGTH;
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate     if (key->length != 8)
1727c478bd9Sstevel@tonic-gate 	return(KRB5_BAD_KEYSIZE);
1737c478bd9Sstevel@tonic-gate     if (ivec)
1747c478bd9Sstevel@tonic-gate 	return(KRB5_CRYPTO_INTERNAL);
1757c478bd9Sstevel@tonic-gate     if (hash->length != (CONFLENGTH + MD5_CKSUM_LENGTH)) {
1767c478bd9Sstevel@tonic-gate #ifdef KRB5_MD5DES_BETA5_COMPAT
1777c478bd9Sstevel@tonic-gate 	if (hash->length != MD5_CKSUM_LENGTH)
1787c478bd9Sstevel@tonic-gate 	    return(KRB5_CRYPTO_INTERNAL);
1797c478bd9Sstevel@tonic-gate 	else
1807c478bd9Sstevel@tonic-gate 	    compathash = 1;
1817c478bd9Sstevel@tonic-gate #else
1827c478bd9Sstevel@tonic-gate 	return(KRB5_CRYPTO_INTERNAL);
1837c478bd9Sstevel@tonic-gate #endif
1847c478bd9Sstevel@tonic-gate     }
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate     /* create and the encryption key */
1877c478bd9Sstevel@tonic-gate     xorkey.magic = key->magic;
1887c478bd9Sstevel@tonic-gate     xorkey.enctype = key->enctype;
1897c478bd9Sstevel@tonic-gate     xorkey.length = key->length;
1907c478bd9Sstevel@tonic-gate     xorkey.contents = (krb5_octet *)malloc(key->length);
1917c478bd9Sstevel@tonic-gate     if (xorkey.contents == NULL)
1927c478bd9Sstevel@tonic-gate 	return(KRB5_CRYPTO_INTERNAL);
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate     (void) memcpy(xorkey.contents, key->contents, xorkey.length);
1957c478bd9Sstevel@tonic-gate     if (!compathash) {
1967c478bd9Sstevel@tonic-gate         for (i=0; i<xorkey.length; i++)
1977c478bd9Sstevel@tonic-gate 	    xorkey.contents[i] ^= 0xf0;
1987c478bd9Sstevel@tonic-gate     }
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate     if (!mit_des_check_key_parity(xorkey.contents)) {
2017c478bd9Sstevel@tonic-gate 	ret = KRB5DES_BAD_KEYPAR;
2027c478bd9Sstevel@tonic-gate 	goto cleanup;
2037c478bd9Sstevel@tonic-gate     }
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate     if (mit_des_is_weak_key(xorkey.contents)) {
2067c478bd9Sstevel@tonic-gate 	ret = KRB5DES_WEAK_KEY;
2077c478bd9Sstevel@tonic-gate 	goto cleanup;
2087c478bd9Sstevel@tonic-gate     }
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate     /* decrypt it.  this has a return value, but it's always zero.  */
2117c478bd9Sstevel@tonic-gate     if (!compathash) {
2127c478bd9Sstevel@tonic-gate 	ret = mit_des_cbc_encrypt(context,
2137c478bd9Sstevel@tonic-gate 		(krb5_pointer) hash->data,
2147c478bd9Sstevel@tonic-gate 		(krb5_pointer) plaintext, hash->length,
2157c478bd9Sstevel@tonic-gate 		&xorkey, (unsigned char*) mit_des_zeroblock, 0);
2167c478bd9Sstevel@tonic-gate     } else {
2177c478bd9Sstevel@tonic-gate 	ret = mit_des_cbc_encrypt(context,
2187c478bd9Sstevel@tonic-gate 		(krb5_pointer) hash->data,
2197c478bd9Sstevel@tonic-gate 		(krb5_pointer) plaintext, hash->length,
2207c478bd9Sstevel@tonic-gate 		&xorkey, xorkey.contents, 0);
2217c478bd9Sstevel@tonic-gate     }
2227c478bd9Sstevel@tonic-gate     if (ret) goto cleanup;
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate     /* hash the confounder, then the input data */
2257c478bd9Sstevel@tonic-gate     mechanism.mechanism = CKM_MD5;
2267c478bd9Sstevel@tonic-gate     mechanism.pParameter = NULL_PTR;
2277c478bd9Sstevel@tonic-gate     mechanism.ulParameterLen = 0;
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate     if ((rv = C_DigestInit(krb_ctx_hSession(context), &mechanism)) != CKR_OK) {
2307c478bd9Sstevel@tonic-gate 	KRB5_LOG(KRB5_ERR, "C_DigestInit failed in k5_md5des_verify: "
2317c478bd9Sstevel@tonic-gate 	"rv = 0x%x.", rv);
2327c478bd9Sstevel@tonic-gate 	ret = PKCS_ERR;
2337c478bd9Sstevel@tonic-gate 	goto cleanup;
2347c478bd9Sstevel@tonic-gate     }
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate     if (!compathash) {
2377c478bd9Sstevel@tonic-gate 	if ((rv = C_DigestUpdate(krb_ctx_hSession(context),
2387c478bd9Sstevel@tonic-gate 	    (CK_BYTE_PTR)plaintext, (CK_ULONG)CONFLENGTH)) != CKR_OK) {
2397c478bd9Sstevel@tonic-gate 	    KRB5_LOG(KRB5_ERR, "C_DigestUpdate failed in k5_md5des_verify: "
2407c478bd9Sstevel@tonic-gate 		"rv = 0x%x", rv);
2417c478bd9Sstevel@tonic-gate 	    ret = PKCS_ERR;
2427c478bd9Sstevel@tonic-gate 	    goto cleanup;
2437c478bd9Sstevel@tonic-gate 	}
2447c478bd9Sstevel@tonic-gate     }
2457c478bd9Sstevel@tonic-gate     if ((rv = C_DigestUpdate(krb_ctx_hSession(context),
2467c478bd9Sstevel@tonic-gate 	(CK_BYTE_PTR)input->data, (CK_ULONG)input->length)) != CKR_OK) {
2477c478bd9Sstevel@tonic-gate 	KRB5_LOG(KRB5_ERR, "C_DigestUpdate failed in k5_md5des_verify: "
2487c478bd9Sstevel@tonic-gate 	    "rv = 0x%x", rv);
2497c478bd9Sstevel@tonic-gate 	ret = PKCS_ERR;
2507c478bd9Sstevel@tonic-gate 	goto cleanup;
2517c478bd9Sstevel@tonic-gate     }
2527c478bd9Sstevel@tonic-gate     if ((rv = C_DigestFinal(krb_ctx_hSession(context),
2537c478bd9Sstevel@tonic-gate 	(CK_BYTE_PTR)digest, (CK_ULONG_PTR)&hashlen)) != CKR_OK) {
2547c478bd9Sstevel@tonic-gate 	KRB5_LOG(KRB5_ERR, "C_DigestFinal failed in k5_md5des_verify: "
2557c478bd9Sstevel@tonic-gate 	    "rv = 0x%x", rv);
2567c478bd9Sstevel@tonic-gate 	ret = PKCS_ERR;
2577c478bd9Sstevel@tonic-gate 	goto cleanup;
2587c478bd9Sstevel@tonic-gate     }
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate     /* compare the decrypted hash to the computed one */
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate     if (!compathash) {
2637c478bd9Sstevel@tonic-gate 	*valid = (memcmp(plaintext+CONFLENGTH, digest, sizeof(digest)) == 0);
2647c478bd9Sstevel@tonic-gate     } else {
2657c478bd9Sstevel@tonic-gate 	*valid = (memcmp(plaintext, digest, sizeof(digest)) == 0);
2667c478bd9Sstevel@tonic-gate     }
2677c478bd9Sstevel@tonic-gate     (void) memset(plaintext, 0, sizeof(plaintext));
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate cleanup:
2707c478bd9Sstevel@tonic-gate     free(xorkey.contents);
2717c478bd9Sstevel@tonic-gate     return(ret);
2727c478bd9Sstevel@tonic-gate }
2737c478bd9Sstevel@tonic-gate 
274159d09a2SMark Phalan const struct krb5_keyhash_provider krb5int_keyhash_md5des = {
275505d05c7Sgtb     CONFLENGTH + MD5_CKSUM_LENGTH,
2767c478bd9Sstevel@tonic-gate     k5_md5des_hash,
2777c478bd9Sstevel@tonic-gate     k5_md5des_verify
2787c478bd9Sstevel@tonic-gate };
279