diff options
Diffstat (limited to 'src/lib/crypto/builtin/hmac.c')
-rw-r--r-- | src/lib/crypto/builtin/hmac.c | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/src/lib/crypto/builtin/hmac.c b/src/lib/crypto/builtin/hmac.c new file mode 100644 index 0000000..3bff3cf --- /dev/null +++ b/src/lib/crypto/builtin/hmac.c @@ -0,0 +1,165 @@ +/* + * Copyright (C) 1998 by the FundsXpress, INC. + * + * All rights reserved. + * + * Export of this software from the United States of America may require + * a specific license from the United States Government. It is the + * responsibility of any person or organization contemplating export to + * obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of FundsXpress. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. FundsXpress makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "k5-int.h" +#include "aead.h" + +/* + * the HMAC transform looks like: + * + * H(K XOR opad, H(K XOR ipad, text)) + * + * where H is a cryptographic hash + * K is an n byte key + * ipad is the byte 0x36 repeated blocksize times + * opad is the byte 0x5c repeated blocksize times + * and text is the data being protected + */ + +krb5_error_code +krb5_hmac(const struct krb5_hash_provider *hash, const krb5_keyblock *key, + unsigned int icount, const krb5_data *input, krb5_data *output) +{ + size_t hashsize, blocksize; + unsigned char *xorkey, *ihash; + unsigned int i; + krb5_data *hashin, hashout; + krb5_error_code ret; + + hashsize = hash->hashsize; + blocksize = hash->blocksize; + + if (key->length > blocksize) + return(KRB5_CRYPTO_INTERNAL); + if (output->length < hashsize) + return(KRB5_BAD_MSIZE); + /* if this isn't > 0, then there won't be enough space in this + array to compute the outer hash */ + if (icount == 0) + return(KRB5_CRYPTO_INTERNAL); + + /* allocate space for the xor key, hash input vector, and inner hash */ + + if ((xorkey = (unsigned char *) malloc(blocksize)) == NULL) + return(ENOMEM); + if ((ihash = (unsigned char *) malloc(hashsize)) == NULL) { + free(xorkey); + return(ENOMEM); + } + if ((hashin = (krb5_data *)malloc(sizeof(krb5_data)*(icount+1))) == NULL) { + free(ihash); + free(xorkey); + return(ENOMEM); + } + + /* create the inner padded key */ + + memset(xorkey, 0x36, blocksize); + + for (i=0; i<key->length; i++) + xorkey[i] ^= key->contents[i]; + + /* compute the inner hash */ + + hashin[0].length = blocksize; + hashin[0].data = (char *) xorkey; + for (i=0; i<icount; i++) + hashin[i+1] = input[i]; + + hashout.length = hashsize; + hashout.data = (char *) ihash; + + if ((ret = ((*(hash->hash))(icount+1, hashin, &hashout)))) + goto cleanup; + + /* create the outer padded key */ + + memset(xorkey, 0x5c, blocksize); + + for (i=0; i<key->length; i++) + xorkey[i] ^= key->contents[i]; + + /* compute the outer hash */ + + hashin[0].length = blocksize; + hashin[0].data = (char *) xorkey; + hashin[1] = hashout; + + output->length = hashsize; + + if ((ret = ((*(hash->hash))(2, hashin, output)))) + memset(output->data, 0, output->length); + + /* ret is set correctly by the prior call */ + +cleanup: + memset(xorkey, 0, blocksize); + memset(ihash, 0, hashsize); + + free(hashin); + free(ihash); + free(xorkey); + + return(ret); +} + +krb5_error_code +krb5int_hmac_iov(const struct krb5_hash_provider *hash, const krb5_keyblock *key, + const krb5_crypto_iov *data, size_t num_data, krb5_data *output) +{ + krb5_data *sign_data; + size_t num_sign_data; + krb5_error_code ret; + size_t i, j; + + /* Create a checksum over all the data to be signed */ + for (i = 0, num_sign_data = 0; i < num_data; i++) { + const krb5_crypto_iov *iov = &data[i]; + + if (SIGN_IOV(iov)) + num_sign_data++; + } + + /* XXX cleanup to avoid alloc */ + sign_data = (krb5_data *)calloc(num_sign_data, sizeof(krb5_data)); + if (sign_data == NULL) + return ENOMEM; + + for (i = 0, j = 0; i < num_data; i++) { + const krb5_crypto_iov *iov = &data[i]; + + if (SIGN_IOV(iov)) + sign_data[j++] = iov->data; + } + + /* caller must store checksum in iov as it may be TYPE_TRAILER or TYPE_CHECKSUM */ + ret = krb5_hmac(hash, key, num_sign_data, sign_data, output); + + free(sign_data); + + return ret; +} + |