10Sstevel@tonic-gate /*
2*7934SMark.Phalan@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
30Sstevel@tonic-gate * Use is subject to license terms.
40Sstevel@tonic-gate */
50Sstevel@tonic-gate
60Sstevel@tonic-gate
70Sstevel@tonic-gate /*
80Sstevel@tonic-gate * Copyright (C) 1998 by the FundsXpress, INC.
9*7934SMark.Phalan@Sun.COM *
100Sstevel@tonic-gate * All rights reserved.
11*7934SMark.Phalan@Sun.COM *
120Sstevel@tonic-gate * Export of this software from the United States of America may require
130Sstevel@tonic-gate * a specific license from the United States Government. It is the
140Sstevel@tonic-gate * responsibility of any person or organization contemplating export to
150Sstevel@tonic-gate * obtain such a license before exporting.
16*7934SMark.Phalan@Sun.COM *
170Sstevel@tonic-gate * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
180Sstevel@tonic-gate * distribute this software and its documentation for any purpose and
190Sstevel@tonic-gate * without fee is hereby granted, provided that the above copyright
200Sstevel@tonic-gate * notice appear in all copies and that both that copyright notice and
210Sstevel@tonic-gate * this permission notice appear in supporting documentation, and that
220Sstevel@tonic-gate * the name of FundsXpress. not be used in advertising or publicity pertaining
230Sstevel@tonic-gate * to distribution of the software without specific, written prior
240Sstevel@tonic-gate * permission. FundsXpress makes no representations about the suitability of
250Sstevel@tonic-gate * this software for any purpose. It is provided "as is" without express
260Sstevel@tonic-gate * or implied warranty.
27*7934SMark.Phalan@Sun.COM *
280Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
290Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
300Sstevel@tonic-gate * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
310Sstevel@tonic-gate */
320Sstevel@tonic-gate
33*7934SMark.Phalan@Sun.COM #include "k5-int.h"
340Sstevel@tonic-gate
35*7934SMark.Phalan@Sun.COM /* Solaris Kerberos */
360Sstevel@tonic-gate #ifdef _KERNEL
370Sstevel@tonic-gate /*
380Sstevel@tonic-gate * In kernel, use the Kernel encryption framework HMAC
390Sstevel@tonic-gate * operation, its far more efficient than the MIT method.
400Sstevel@tonic-gate * Also, a template is used to further improve performance.
410Sstevel@tonic-gate */
420Sstevel@tonic-gate /* ARGSUSED */
430Sstevel@tonic-gate krb5_error_code
krb5_hmac(krb5_context context,const krb5_keyblock * key,krb5_const krb5_data * input,krb5_data * output)440Sstevel@tonic-gate krb5_hmac(krb5_context context, const krb5_keyblock *key,
450Sstevel@tonic-gate krb5_const krb5_data *input, krb5_data *output)
460Sstevel@tonic-gate {
470Sstevel@tonic-gate int rv = CRYPTO_FAILED;
480Sstevel@tonic-gate crypto_mechanism_t mac_mech;
490Sstevel@tonic-gate crypto_data_t dd;
500Sstevel@tonic-gate crypto_data_t mac;
510Sstevel@tonic-gate
520Sstevel@tonic-gate KRB5_LOG0(KRB5_INFO, "krb5_hmac() start");
530Sstevel@tonic-gate if (output == NULL || output->data == NULL) {
540Sstevel@tonic-gate KRB5_LOG0(KRB5_INFO, "krb5_hmac() NULL output");
550Sstevel@tonic-gate return (rv);
560Sstevel@tonic-gate }
570Sstevel@tonic-gate if (input == NULL || input->data == NULL) {
580Sstevel@tonic-gate KRB5_LOG0(KRB5_INFO, "krb5_hmac() NULL input");
590Sstevel@tonic-gate return (rv);
600Sstevel@tonic-gate }
610Sstevel@tonic-gate
620Sstevel@tonic-gate dd.cd_format = CRYPTO_DATA_RAW;
630Sstevel@tonic-gate dd.cd_offset = 0;
640Sstevel@tonic-gate dd.cd_length = input->length;
650Sstevel@tonic-gate dd.cd_raw.iov_base = (char *)input->data;
660Sstevel@tonic-gate dd.cd_raw.iov_len = input->length;
670Sstevel@tonic-gate
680Sstevel@tonic-gate mac.cd_format = CRYPTO_DATA_RAW;
690Sstevel@tonic-gate mac.cd_offset = 0;
700Sstevel@tonic-gate mac.cd_length = output->length;
710Sstevel@tonic-gate mac.cd_raw.iov_base = (char *)output->data;
720Sstevel@tonic-gate mac.cd_raw.iov_len = output->length;
730Sstevel@tonic-gate
740Sstevel@tonic-gate mac_mech.cm_type = context->kef_hash_mt;
750Sstevel@tonic-gate mac_mech.cm_param = NULL;
760Sstevel@tonic-gate mac_mech.cm_param_len = 0;
770Sstevel@tonic-gate
780Sstevel@tonic-gate rv = crypto_mac(&mac_mech, &dd,
790Sstevel@tonic-gate (crypto_key_t *)&key->kef_key,
800Sstevel@tonic-gate key->key_tmpl, &mac, NULL);
810Sstevel@tonic-gate
820Sstevel@tonic-gate if (rv != CRYPTO_SUCCESS) {
830Sstevel@tonic-gate KRB5_LOG(KRB5_ERR,"crypto_mac error: %0x", rv);
840Sstevel@tonic-gate }
850Sstevel@tonic-gate
860Sstevel@tonic-gate KRB5_LOG(KRB5_INFO, "krb5_hmac() end ret=%d\n", rv);
870Sstevel@tonic-gate return(rv);
880Sstevel@tonic-gate }
890Sstevel@tonic-gate
900Sstevel@tonic-gate #else
910Sstevel@tonic-gate /* Userland implementation of HMAC algorithm */
920Sstevel@tonic-gate
930Sstevel@tonic-gate /*
940Sstevel@tonic-gate * the HMAC transform looks like:
950Sstevel@tonic-gate *
960Sstevel@tonic-gate * H(K XOR opad, H(K XOR ipad, text))
970Sstevel@tonic-gate *
980Sstevel@tonic-gate * where H is a cryptographic hash
990Sstevel@tonic-gate * K is an n byte key
1000Sstevel@tonic-gate * ipad is the byte 0x36 repeated blocksize times
1010Sstevel@tonic-gate * opad is the byte 0x5c repeated blocksize times
1020Sstevel@tonic-gate * and text is the data being protected
1030Sstevel@tonic-gate */
104*7934SMark.Phalan@Sun.COM
1050Sstevel@tonic-gate krb5_error_code
krb5_hmac(krb5_context context,krb5_const struct krb5_hash_provider * hash,krb5_const krb5_keyblock * key,krb5_const unsigned int icount,krb5_const krb5_data * input,krb5_data * output)1060Sstevel@tonic-gate krb5_hmac(krb5_context context,
1070Sstevel@tonic-gate krb5_const struct krb5_hash_provider *hash,
1080Sstevel@tonic-gate krb5_const krb5_keyblock *key,
1090Sstevel@tonic-gate krb5_const unsigned int icount,
1100Sstevel@tonic-gate krb5_const krb5_data *input,
1110Sstevel@tonic-gate krb5_data *output)
1120Sstevel@tonic-gate {
1130Sstevel@tonic-gate size_t hashsize, blocksize;
1140Sstevel@tonic-gate unsigned char *xorkey, *ihash;
1150Sstevel@tonic-gate int i;
1160Sstevel@tonic-gate krb5_data *hashin, hashout;
1170Sstevel@tonic-gate krb5_error_code ret;
1180Sstevel@tonic-gate
119*7934SMark.Phalan@Sun.COM /* Solaris Kerberos */
1200Sstevel@tonic-gate KRB5_LOG0(KRB5_INFO, "krb5_hmac() start\n");
1210Sstevel@tonic-gate
1220Sstevel@tonic-gate if (hash == NULL) {
1230Sstevel@tonic-gate KRB5_LOG0(KRB5_ERR, "krb5_hmac() error hash == NULL\n");
1240Sstevel@tonic-gate return(EINVAL);
1250Sstevel@tonic-gate }
1260Sstevel@tonic-gate if (key == NULL) {
1270Sstevel@tonic-gate KRB5_LOG0(KRB5_ERR, "krb5_hmac() error key == NULL\n");
1280Sstevel@tonic-gate return(EINVAL);
1290Sstevel@tonic-gate }
1300Sstevel@tonic-gate if (input == NULL) {
1310Sstevel@tonic-gate KRB5_LOG0(KRB5_ERR, "krb5_hmac() error input == NULL\n");
1320Sstevel@tonic-gate return(EINVAL);
1330Sstevel@tonic-gate }
1340Sstevel@tonic-gate if (output == NULL) {
1350Sstevel@tonic-gate KRB5_LOG0(KRB5_ERR, "krb5_hmac() error output == NULL\n");
1360Sstevel@tonic-gate return(EINVAL);
1370Sstevel@tonic-gate }
1380Sstevel@tonic-gate
139781Sgtb hashsize = hash->hashsize;
140781Sgtb blocksize = hash->blocksize;
1410Sstevel@tonic-gate
1420Sstevel@tonic-gate if (key->length > blocksize)
1430Sstevel@tonic-gate return(KRB5_CRYPTO_INTERNAL);
1440Sstevel@tonic-gate if (output->length < hashsize)
1450Sstevel@tonic-gate return(KRB5_BAD_MSIZE);
1460Sstevel@tonic-gate /* if this isn't > 0, then there won't be enough space in this
1470Sstevel@tonic-gate array to compute the outer hash */
1480Sstevel@tonic-gate if (icount == 0)
1490Sstevel@tonic-gate return(KRB5_CRYPTO_INTERNAL);
1500Sstevel@tonic-gate
1510Sstevel@tonic-gate /* allocate space for the xor key, hash input vector, and inner hash */
1520Sstevel@tonic-gate
1530Sstevel@tonic-gate if ((xorkey = (unsigned char *) MALLOC(blocksize)) == NULL)
1540Sstevel@tonic-gate return(ENOMEM);
1550Sstevel@tonic-gate if ((ihash = (unsigned char *) MALLOC(hashsize)) == NULL) {
1560Sstevel@tonic-gate FREE(xorkey, blocksize);
1570Sstevel@tonic-gate return(ENOMEM);
1580Sstevel@tonic-gate }
1590Sstevel@tonic-gate if ((hashin = (krb5_data *)MALLOC(sizeof(krb5_data)*(icount+1))) == NULL) {
1600Sstevel@tonic-gate FREE(ihash, hashsize);
1610Sstevel@tonic-gate FREE(xorkey, blocksize);
1620Sstevel@tonic-gate return(ENOMEM);
1630Sstevel@tonic-gate }
1640Sstevel@tonic-gate
1650Sstevel@tonic-gate /* create the inner padded key */
1660Sstevel@tonic-gate
167*7934SMark.Phalan@Sun.COM /* Solaris Kerberos */
1680Sstevel@tonic-gate (void) memset(xorkey, 0x36, blocksize);
1690Sstevel@tonic-gate
170*7934SMark.Phalan@Sun.COM for (i=0; i<key->length; i++)
1710Sstevel@tonic-gate xorkey[i] ^= key->contents[i];
1720Sstevel@tonic-gate
1730Sstevel@tonic-gate /* compute the inner hash */
1740Sstevel@tonic-gate
1750Sstevel@tonic-gate for (i=0; i<icount; i++) {
1760Sstevel@tonic-gate hashin[0].length = blocksize;
1770Sstevel@tonic-gate hashin[0].data = (char *) xorkey;
1780Sstevel@tonic-gate hashin[i+1] = input[i];
1790Sstevel@tonic-gate }
1800Sstevel@tonic-gate
1810Sstevel@tonic-gate hashout.length = hashsize;
1820Sstevel@tonic-gate hashout.data = (char *) ihash;
1830Sstevel@tonic-gate
184*7934SMark.Phalan@Sun.COM /* Solaris Kerberos */
1850Sstevel@tonic-gate if ((ret = ((*(hash->hash))(context, icount+1, hashin, &hashout))))
1860Sstevel@tonic-gate goto cleanup;
1870Sstevel@tonic-gate
1880Sstevel@tonic-gate /* create the outer padded key */
1890Sstevel@tonic-gate
190*7934SMark.Phalan@Sun.COM /* Solaris Kerberos */
1910Sstevel@tonic-gate (void) memset(xorkey, 0x5c, blocksize);
1920Sstevel@tonic-gate
1930Sstevel@tonic-gate for (i=0; i<key->length; i++)
1940Sstevel@tonic-gate xorkey[i] ^= key->contents[i];
1950Sstevel@tonic-gate
1960Sstevel@tonic-gate /* compute the outer hash */
1970Sstevel@tonic-gate
1980Sstevel@tonic-gate hashin[0].length = blocksize;
1990Sstevel@tonic-gate hashin[0].data = (char *) xorkey;
2000Sstevel@tonic-gate hashin[1] = hashout;
2010Sstevel@tonic-gate
2020Sstevel@tonic-gate output->length = hashsize;
2030Sstevel@tonic-gate
204*7934SMark.Phalan@Sun.COM /* Solaris Kerberos */
2050Sstevel@tonic-gate if ((ret = ((*(hash->hash))(context, 2, hashin, output))))
2060Sstevel@tonic-gate (void) memset(output->data, 0, output->length);
2070Sstevel@tonic-gate
2080Sstevel@tonic-gate /* ret is set correctly by the prior call */
2090Sstevel@tonic-gate
2100Sstevel@tonic-gate cleanup:
211*7934SMark.Phalan@Sun.COM /* Solaris Kerberos */
2120Sstevel@tonic-gate (void) memset(xorkey, 0, blocksize);
2130Sstevel@tonic-gate (void) memset(ihash, 0, hashsize);
2140Sstevel@tonic-gate
2150Sstevel@tonic-gate FREE(hashin, sizeof(krb5_data)*(icount+1));
2160Sstevel@tonic-gate FREE(ihash, hashsize);
2170Sstevel@tonic-gate FREE(xorkey, blocksize);
2180Sstevel@tonic-gate
219*7934SMark.Phalan@Sun.COM /* Solaris Kerberos */
2200Sstevel@tonic-gate KRB5_LOG(KRB5_INFO, "krb5_hmac() end ret=%d\n", ret);
2210Sstevel@tonic-gate return(ret);
2220Sstevel@tonic-gate }
2230Sstevel@tonic-gate #endif /* _KERNEL */
224