2N/A/*
2N/A * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A/*
2N/A * Copyright (C) 1998 by the FundsXpress, INC.
2N/A *
2N/A * All rights reserved.
2N/A *
2N/A * Export of this software from the United States of America may require
2N/A * a specific license from the United States Government. It is the
2N/A * responsibility of any person or organization contemplating export to
2N/A * obtain such a license before exporting.
2N/A *
2N/A * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
2N/A * distribute this software and its documentation for any purpose and
2N/A * without fee is hereby granted, provided that the above copyright
2N/A * notice appear in all copies and that both that copyright notice and
2N/A * this permission notice appear in supporting documentation, and that
2N/A * the name of FundsXpress. not be used in advertising or publicity pertaining
2N/A * to distribution of the software without specific, written prior
2N/A * permission. FundsXpress makes no representations about the suitability of
2N/A * this software for any purpose. It is provided "as is" without express
2N/A * or implied warranty.
2N/A *
2N/A * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
2N/A * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
2N/A * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2N/A */
2N/A
2N/A#include "k5-int.h"
2N/A#include "des_int.h"
2N/A#include "keyhash_provider.h"
2N/A
2N/A#define CONFLENGTH 8
2N/A
2N/A/* Force acceptance of krb5-beta5 md5des checksum for now. */
2N/A#define KRB5_MD5DES_BETA5_COMPAT
2N/A
2N/A/* des-cbc(xorkey, conf | rsa-md5(conf | data)) */
2N/A
2N/A/* this could be done in terms of the md5 and des providers, but
2N/A that's less efficient, and there's no need for this to be generic */
2N/A
2N/A/*ARGSUSED*/
2N/Astatic krb5_error_code
2N/Ak5_md5des_hash(krb5_context context, krb5_const krb5_keyblock *key,
2N/A krb5_keyusage usage, const krb5_data *ivec,
2N/A const krb5_data *input, krb5_data *output)
2N/A{
2N/A krb5_error_code ret = 0;
2N/A krb5_data data;
2N/A unsigned char conf[CONFLENGTH];
2N/A krb5_keyblock xorkey;
2N/A int i;
2N/A CK_MECHANISM mechanism;
2N/A CK_RV rv;
2N/A CK_ULONG hashlen = MD5_CKSUM_LENGTH;
2N/A
2N/A /* Solaris Kerberos */
2N/A memset(&xorkey, 0, sizeof (krb5_keyblock));
2N/A
2N/A if (key->length != 8)
2N/A return(KRB5_BAD_KEYSIZE);
2N/A if (ivec)
2N/A return(KRB5_CRYPTO_INTERNAL);
2N/A if (output->length != (CONFLENGTH+MD5_CKSUM_LENGTH))
2N/A return(KRB5_CRYPTO_INTERNAL);
2N/A
2N/A /* create the confouder */
2N/A
2N/A data.length = CONFLENGTH;
2N/A data.data = (char *) conf;
2N/A if ((ret = krb5_c_random_make_octets(context, &data)))
2N/A return(ret);
2N/A
2N/A xorkey.magic = key->magic;
2N/A xorkey.enctype = key->enctype;
2N/A xorkey.length = key->length;
2N/A xorkey.contents = (krb5_octet *)malloc(key->length);
2N/A if (xorkey.contents == NULL)
2N/A return(KRB5_CRYPTO_INTERNAL);
2N/A
2N/A (void) memcpy(xorkey.contents, key->contents, xorkey.length);
2N/A
2N/A for (i=0; i<xorkey.length; i++)
2N/A xorkey.contents[i] ^= 0xf0;
2N/A
2N/A if (!mit_des_check_key_parity(xorkey.contents)) {
2N/A ret = KRB5DES_BAD_KEYPAR;
2N/A goto cleanup;
2N/A }
2N/A
2N/A if (mit_des_is_weak_key(xorkey.contents)) {
2N/A ret = KRB5DES_WEAK_KEY;
2N/A goto cleanup;
2N/A }
2N/A
2N/A /* hash the confounder, then the input data */
2N/A mechanism.mechanism = CKM_MD5;
2N/A mechanism.pParameter = NULL_PTR;
2N/A mechanism.ulParameterLen = 0;
2N/A
2N/A if ((rv = C_DigestInit(krb_ctx_hSession(context), &mechanism)) != CKR_OK) {
2N/A ret = PKCS_ERR;
2N/A goto cleanup;
2N/A }
2N/A
2N/A if ((rv = C_DigestUpdate(krb_ctx_hSession(context),
2N/A (CK_BYTE_PTR)conf, (CK_ULONG)sizeof(conf))) != CKR_OK) {
2N/A ret = PKCS_ERR;
2N/A goto cleanup;
2N/A }
2N/A
2N/A if ((rv = C_DigestUpdate(krb_ctx_hSession(context),
2N/A (CK_BYTE_PTR)input->data, (CK_ULONG)input->length)) != CKR_OK) {
2N/A return(PKCS_ERR);
2N/A }
2N/A
2N/A if ((rv = C_DigestFinal(krb_ctx_hSession(context),
2N/A (CK_BYTE_PTR)(output->data + CONFLENGTH),
2N/A (CK_ULONG_PTR)&hashlen)) != CKR_OK) {
2N/A ret = PKCS_ERR;
2N/A goto cleanup;
2N/A }
2N/A
2N/A /* construct the buffer to be encrypted */
2N/A
2N/A (void) memcpy(output->data, conf, CONFLENGTH);
2N/A
2N/A /* encrypt it, in place. this has a return value, but it's
2N/A always zero. */
2N/A
2N/A ret = mit_des_cbc_encrypt(context,
2N/A (krb5_pointer) output->data,
2N/A (krb5_pointer) output->data, output->length,
2N/A &xorkey, (unsigned char*) mit_des_zeroblock, 1);
2N/A
2N/Acleanup:
2N/A free(xorkey.contents);
2N/A return(ret);
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Astatic krb5_error_code
2N/Ak5_md5des_verify(krb5_context context,
2N/A krb5_const krb5_keyblock *key,
2N/A krb5_keyusage usage,
2N/A krb5_const krb5_data *ivec,
2N/A krb5_const krb5_data *input,
2N/A krb5_const krb5_data *hash,
2N/A krb5_boolean *valid)
2N/A{
2N/A krb5_error_code ret = 0;
2N/A unsigned char plaintext[CONFLENGTH+MD5_CKSUM_LENGTH];
2N/A unsigned char digest[MD5_CKSUM_LENGTH];
2N/A krb5_keyblock xorkey;
2N/A int i;
2N/A int compathash = 0;
2N/A CK_MECHANISM mechanism;
2N/A CK_RV rv;
2N/A CK_ULONG hashlen = MD5_CKSUM_LENGTH;
2N/A
2N/A if (key->length != 8)
2N/A return(KRB5_BAD_KEYSIZE);
2N/A if (ivec)
2N/A return(KRB5_CRYPTO_INTERNAL);
2N/A if (hash->length != (CONFLENGTH + MD5_CKSUM_LENGTH)) {
2N/A#ifdef KRB5_MD5DES_BETA5_COMPAT
2N/A if (hash->length != MD5_CKSUM_LENGTH)
2N/A return(KRB5_CRYPTO_INTERNAL);
2N/A else
2N/A compathash = 1;
2N/A#else
2N/A return(KRB5_CRYPTO_INTERNAL);
2N/A#endif
2N/A }
2N/A
2N/A /* create and the encryption key */
2N/A xorkey.magic = key->magic;
2N/A xorkey.enctype = key->enctype;
2N/A xorkey.length = key->length;
2N/A xorkey.contents = (krb5_octet *)malloc(key->length);
2N/A if (xorkey.contents == NULL)
2N/A return(KRB5_CRYPTO_INTERNAL);
2N/A
2N/A (void) memcpy(xorkey.contents, key->contents, xorkey.length);
2N/A if (!compathash) {
2N/A for (i=0; i<xorkey.length; i++)
2N/A xorkey.contents[i] ^= 0xf0;
2N/A }
2N/A
2N/A if (!mit_des_check_key_parity(xorkey.contents)) {
2N/A ret = KRB5DES_BAD_KEYPAR;
2N/A goto cleanup;
2N/A }
2N/A
2N/A if (mit_des_is_weak_key(xorkey.contents)) {
2N/A ret = KRB5DES_WEAK_KEY;
2N/A goto cleanup;
2N/A }
2N/A
2N/A /* decrypt it. this has a return value, but it's always zero. */
2N/A if (!compathash) {
2N/A ret = mit_des_cbc_encrypt(context,
2N/A (krb5_pointer) hash->data,
2N/A (krb5_pointer) plaintext, hash->length,
2N/A &xorkey, (unsigned char*) mit_des_zeroblock, 0);
2N/A } else {
2N/A ret = mit_des_cbc_encrypt(context,
2N/A (krb5_pointer) hash->data,
2N/A (krb5_pointer) plaintext, hash->length,
2N/A &xorkey, xorkey.contents, 0);
2N/A }
2N/A if (ret) goto cleanup;
2N/A
2N/A /* hash the confounder, then the input data */
2N/A mechanism.mechanism = CKM_MD5;
2N/A mechanism.pParameter = NULL_PTR;
2N/A mechanism.ulParameterLen = 0;
2N/A
2N/A if ((rv = C_DigestInit(krb_ctx_hSession(context), &mechanism)) != CKR_OK) {
2N/A ret = PKCS_ERR;
2N/A goto cleanup;
2N/A }
2N/A
2N/A if (!compathash) {
2N/A if ((rv = C_DigestUpdate(krb_ctx_hSession(context),
2N/A (CK_BYTE_PTR)plaintext, (CK_ULONG)CONFLENGTH)) != CKR_OK) {
2N/A ret = PKCS_ERR;
2N/A goto cleanup;
2N/A }
2N/A }
2N/A if ((rv = C_DigestUpdate(krb_ctx_hSession(context),
2N/A (CK_BYTE_PTR)input->data, (CK_ULONG)input->length)) != CKR_OK) {
2N/A ret = PKCS_ERR;
2N/A goto cleanup;
2N/A }
2N/A if ((rv = C_DigestFinal(krb_ctx_hSession(context),
2N/A (CK_BYTE_PTR)digest, (CK_ULONG_PTR)&hashlen)) != CKR_OK) {
2N/A ret = PKCS_ERR;
2N/A goto cleanup;
2N/A }
2N/A
2N/A /* compare the decrypted hash to the computed one */
2N/A
2N/A if (!compathash) {
2N/A *valid = (memcmp(plaintext+CONFLENGTH, digest, sizeof(digest)) == 0);
2N/A } else {
2N/A *valid = (memcmp(plaintext, digest, sizeof(digest)) == 0);
2N/A }
2N/A (void) memset(plaintext, 0, sizeof(plaintext));
2N/A
2N/Acleanup:
2N/A free(xorkey.contents);
2N/A return(ret);
2N/A}
2N/A
2N/Aconst struct krb5_keyhash_provider krb5int_keyhash_md5des = {
2N/A CONFLENGTH + MD5_CKSUM_LENGTH,
2N/A k5_md5des_hash,
2N/A k5_md5des_verify
2N/A};