Blame src/lib/crypto/builtin/hmac.c

Packit fd8b60
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
Packit fd8b60
/*
Packit fd8b60
 * Copyright (C) 1998 by the FundsXpress, INC.
Packit fd8b60
 *
Packit fd8b60
 * All rights reserved.
Packit fd8b60
 *
Packit fd8b60
 * Export of this software from the United States of America may require
Packit fd8b60
 * a specific license from the United States Government.  It is the
Packit fd8b60
 * responsibility of any person or organization contemplating export to
Packit fd8b60
 * obtain such a license before exporting.
Packit fd8b60
 *
Packit fd8b60
 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
Packit fd8b60
 * distribute this software and its documentation for any purpose and
Packit fd8b60
 * without fee is hereby granted, provided that the above copyright
Packit fd8b60
 * notice appear in all copies and that both that copyright notice and
Packit fd8b60
 * this permission notice appear in supporting documentation, and that
Packit fd8b60
 * the name of FundsXpress. not be used in advertising or publicity pertaining
Packit fd8b60
 * to distribution of the software without specific, written prior
Packit fd8b60
 * permission.  FundsXpress makes no representations about the suitability of
Packit fd8b60
 * this software for any purpose.  It is provided "as is" without express
Packit fd8b60
 * or implied warranty.
Packit fd8b60
 *
Packit fd8b60
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
Packit fd8b60
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
Packit fd8b60
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
Packit fd8b60
 */
Packit fd8b60
Packit fd8b60
#include "crypto_int.h"
Packit fd8b60
Packit fd8b60
/*
Packit fd8b60
 * Because our built-in HMAC implementation doesn't need to invoke any
Packit fd8b60
 * encryption or keyed hash functions, it is simplest to define it in terms of
Packit fd8b60
 * keyblocks, and then supply a simple wrapper for the "normal" krb5_key-using
Packit fd8b60
 * interfaces.  The keyblock interfaces are useful for code which creates
Packit fd8b60
 * intermediate keyblocks.
Packit fd8b60
 */
Packit fd8b60
Packit fd8b60
/*
Packit fd8b60
 * The HMAC transform looks like:
Packit fd8b60
 *
Packit fd8b60
 * H(K XOR opad, H(K XOR ipad, text))
Packit fd8b60
 *
Packit fd8b60
 * where H is a cryptographic hash
Packit fd8b60
 * K is an n byte key
Packit fd8b60
 * ipad is the byte 0x36 repeated blocksize times
Packit fd8b60
 * opad is the byte 0x5c repeated blocksize times
Packit fd8b60
 * and text is the data being protected
Packit fd8b60
 */
Packit fd8b60
Packit fd8b60
krb5_error_code
Packit fd8b60
krb5int_hmac_keyblock(const struct krb5_hash_provider *hash,
Packit fd8b60
                      const krb5_keyblock *keyblock,
Packit fd8b60
                      const krb5_crypto_iov *data, size_t num_data,
Packit fd8b60
                      krb5_data *output)
Packit fd8b60
{
Packit fd8b60
    unsigned char *xorkey = NULL, *ihash = NULL;
Packit fd8b60
    unsigned int i;
Packit fd8b60
    krb5_crypto_iov *ihash_iov = NULL, ohash_iov[2];
Packit fd8b60
    krb5_data hashout;
Packit fd8b60
    krb5_error_code ret;
Packit fd8b60
Packit fd8b60
    if (keyblock->length > hash->blocksize)
Packit fd8b60
        return KRB5_CRYPTO_INTERNAL;
Packit fd8b60
    if (output->length < hash->hashsize)
Packit fd8b60
        return KRB5_BAD_MSIZE;
Packit fd8b60
Packit fd8b60
    /* Allocate space for the xor key, hash input vector, and inner hash */
Packit fd8b60
    xorkey = k5alloc(hash->blocksize, &ret;;
Packit fd8b60
    if (xorkey == NULL)
Packit fd8b60
        goto cleanup;
Packit fd8b60
    ihash = k5alloc(hash->hashsize, &ret;;
Packit fd8b60
    if (ihash == NULL)
Packit fd8b60
        goto cleanup;
Packit fd8b60
    ihash_iov = k5calloc(num_data + 1, sizeof(krb5_crypto_iov), &ret;;
Packit fd8b60
    if (ihash_iov == NULL)
Packit fd8b60
        goto cleanup;
Packit fd8b60
Packit fd8b60
    /* Create the inner padded key. */
Packit fd8b60
    memset(xorkey, 0x36, hash->blocksize);
Packit fd8b60
    for (i = 0; i < keyblock->length; i++)
Packit fd8b60
        xorkey[i] ^= keyblock->contents[i];
Packit fd8b60
Packit fd8b60
    /* Compute the inner hash over the inner key and input data. */
Packit fd8b60
    ihash_iov[0].flags = KRB5_CRYPTO_TYPE_DATA;
Packit fd8b60
    ihash_iov[0].data = make_data(xorkey, hash->blocksize);
Packit fd8b60
    memcpy(ihash_iov + 1, data, num_data * sizeof(krb5_crypto_iov));
Packit fd8b60
    hashout = make_data(ihash, hash->hashsize);
Packit fd8b60
    ret = hash->hash(ihash_iov, num_data + 1, &hashout);
Packit fd8b60
    if (ret != 0)
Packit fd8b60
        goto cleanup;
Packit fd8b60
Packit fd8b60
    /* Create the outer padded key. */
Packit fd8b60
    memset(xorkey, 0x5c, hash->blocksize);
Packit fd8b60
    for (i = 0; i < keyblock->length; i++)
Packit fd8b60
        xorkey[i] ^= keyblock->contents[i];
Packit fd8b60
Packit fd8b60
    /* Compute the outer hash over the outer key and inner hash value. */
Packit fd8b60
    ohash_iov[0].flags = KRB5_CRYPTO_TYPE_DATA;
Packit fd8b60
    ohash_iov[0].data = make_data(xorkey, hash->blocksize);
Packit fd8b60
    ohash_iov[1].flags = KRB5_CRYPTO_TYPE_DATA;
Packit fd8b60
    ohash_iov[1].data = make_data(ihash, hash->hashsize);
Packit fd8b60
    output->length = hash->hashsize;
Packit fd8b60
    ret = hash->hash(ohash_iov, 2, output);
Packit fd8b60
    if (ret != 0)
Packit fd8b60
        memset(output->data, 0, output->length);
Packit fd8b60
Packit fd8b60
cleanup:
Packit fd8b60
    zapfree(xorkey, hash->blocksize);
Packit fd8b60
    zapfree(ihash, hash->hashsize);
Packit fd8b60
    free(ihash_iov);
Packit fd8b60
    return ret;
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
krb5_error_code
Packit fd8b60
krb5int_hmac(const struct krb5_hash_provider *hash, krb5_key key,
Packit fd8b60
             const krb5_crypto_iov *data, size_t num_data,
Packit fd8b60
             krb5_data *output)
Packit fd8b60
{
Packit fd8b60
    return krb5int_hmac_keyblock(hash, &key->keyblock, data, num_data, output);
Packit fd8b60
}