OpenSolaris_b135/lib/gss_mechs/mech_krb5/crypto/hash_provider/hash_ef_generic.c

/*
 * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */
#pragma ident	"%Z%%M%	%I%	%E% SMI"


#include <k5-int.h>
#include <des_int.h>

krb5_error_code
k5_ef_hash(krb5_context context,
	CK_MECHANISM *mechanism,
	unsigned int icount,
	krb5_const krb5_data *input,
	krb5_data *output)
{
	CK_RV rv;
	int i;
	CK_ULONG outlen = output->length;

	if ((rv = C_DigestInit(krb_ctx_hSession(context), mechanism)) !=
	    CKR_OK) {
	    KRB5_LOG(KRB5_ERR, "C_DigestInit failed in k5_ef_hash: "
	    "rv = 0x%x.", rv);
	    return (PKCS_ERR);
	}

	for (i = 0; i < icount; i++) {
	    if ((rv = C_DigestUpdate(krb_ctx_hSession(context),
		(CK_BYTE_PTR)input[i].data,
		(CK_ULONG)input[i].length)) != CKR_OK) {
		KRB5_LOG(KRB5_ERR, "C_DigestUpdate failed in k5_ef_hash: "
		    "rv = 0x%x", rv);
		return (PKCS_ERR);
	    }
	}

	if ((rv = C_DigestFinal(krb_ctx_hSession(context),
	    (CK_BYTE_PTR)output->data, &outlen)) != CKR_OK) {
	    KRB5_LOG(KRB5_ERR, "C_DigestFinal failed in k5_ef_hash: "
		"rv = 0x%x", rv);
	    return (PKCS_ERR);
	}

	/* Narrowing conversion OK because hashes are much smaller than 2^32 */
	output->length = outlen;

	KRB5_LOG0(KRB5_INFO, "k5_ef_hash() end");
	return (0);
}


/*
 * Ideally, this would use the PKCS#11 interface
 * for doing DES_CBC_MAC_* operations, but for now we
 * can fake it by using the des-cbc crypto operation.
 * and truncating the output.
 */
krb5_error_code
k5_ef_mac(krb5_context context,
	krb5_keyblock *key,
	krb5_data *ivec,
	krb5_const krb5_data *input,
	krb5_data *output)
{
	krb5_error_code retval = 0;
	char *outbuf = NULL;
	char *inbuf = NULL;
	int inlen;
	int outlen;

	/*
	 * This is ugly but necessary until proper PKCS#11
	 * interface is ready.
	 */
	inlen = K5ROUNDUP(input->length, 8);
	outlen = inlen;

	if (inlen != input->length) {
		inbuf = (char *)malloc(inlen);
		if (inbuf == NULL)
			retval = ENOMEM;
	}
	else
		inbuf = input->data;

	outbuf = (char *)malloc(outlen);
	if (outbuf == NULL)
		retval = ENOMEM;
	(void) memset(outbuf, 0, outlen);
	if (outbuf != NULL && inbuf != NULL) {
		if (inlen != input->length) {
			(void) memset(inbuf, 0, inlen);
			(void) memcpy(inbuf, input->data, input->length);
		}
		retval = mit_des_cbc_encrypt(context,
			(const mit_des_cblock *)inbuf,
			(mit_des_cblock *)outbuf,
			inlen, key,
			(unsigned char *)ivec->data, 1);

		if (retval == 0) {
			(void) memcpy(output->data, &outbuf[outlen-8], 8);
			output->length = 8;
		}
	}
	if (inlen != input->length && inbuf != NULL)
		free(inbuf);
	if (outbuf != NULL)
		free(outbuf);
	return (retval);
}