root/usr/src/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.
 */

#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);
}