Home | History | Annotate | Download | only in crypto
      1 /*
      2  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
      3  * Use is subject to license terms.
      4  */
      5 
      6 
      7 /*
      8  * Copyright (C) 1998 by the FundsXpress, INC.
      9  *
     10  * All rights reserved.
     11  *
     12  * Export of this software from the United States of America may require
     13  * a specific license from the United States Government.  It is the
     14  * responsibility of any person or organization contemplating export to
     15  * obtain such a license before exporting.
     16  *
     17  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
     18  * distribute this software and its documentation for any purpose and
     19  * without fee is hereby granted, provided that the above copyright
     20  * notice appear in all copies and that both that copyright notice and
     21  * this permission notice appear in supporting documentation, and that
     22  * the name of FundsXpress. not be used in advertising or publicity pertaining
     23  * to distribution of the software without specific, written prior
     24  * permission.  FundsXpress makes no representations about the suitability of
     25  * this software for any purpose.  It is provided "as is" without express
     26  * or implied warranty.
     27  *
     28  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
     29  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
     30  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
     31  */
     32 
     33 #include "k5-int.h"
     34 
     35 /* Solaris Kerberos */
     36 #ifdef _KERNEL
     37 /*
     38  * In kernel, use the Kernel encryption framework HMAC
     39  * operation, its far more efficient than the MIT method.
     40  * Also, a template is used to further improve performance.
     41  */
     42 /* ARGSUSED */
     43 krb5_error_code
     44 krb5_hmac(krb5_context context, const krb5_keyblock *key,
     45 	krb5_const krb5_data *input, krb5_data *output)
     46 {
     47 	int rv = CRYPTO_FAILED;
     48         crypto_mechanism_t mac_mech;
     49 	crypto_data_t dd;
     50 	crypto_data_t mac;
     51 
     52 	KRB5_LOG0(KRB5_INFO, "krb5_hmac() start");
     53 	if (output == NULL || output->data == NULL) {
     54 		KRB5_LOG0(KRB5_INFO, "krb5_hmac() NULL output");
     55 		return (rv);
     56 	}
     57 	if (input == NULL || input->data == NULL) {
     58 		KRB5_LOG0(KRB5_INFO, "krb5_hmac() NULL input");
     59 		return (rv);
     60 	}
     61 
     62 	dd.cd_format = CRYPTO_DATA_RAW;
     63 	dd.cd_offset = 0;
     64 	dd.cd_length = input->length;
     65 	dd.cd_raw.iov_base = (char *)input->data;
     66 	dd.cd_raw.iov_len = input->length;
     67 
     68 	mac.cd_format = CRYPTO_DATA_RAW;
     69 	mac.cd_offset = 0;
     70 	mac.cd_length = output->length;
     71 	mac.cd_raw.iov_base = (char *)output->data;
     72 	mac.cd_raw.iov_len = output->length;
     73 
     74 	mac_mech.cm_type = context->kef_hash_mt;
     75 	mac_mech.cm_param = NULL;
     76 	mac_mech.cm_param_len = 0;
     77 
     78 	rv = crypto_mac(&mac_mech, &dd,
     79 			(crypto_key_t *)&key->kef_key,
     80 			key->key_tmpl, &mac, NULL);
     81 
     82 	if (rv != CRYPTO_SUCCESS) {
     83 		KRB5_LOG(KRB5_ERR,"crypto_mac error: %0x", rv);
     84 	}
     85 
     86 	KRB5_LOG(KRB5_INFO, "krb5_hmac() end ret=%d\n", rv);
     87 	return(rv);
     88 }
     89 
     90 #else
     91 /* Userland implementation of HMAC algorithm */
     92 
     93 /*
     94  * the HMAC transform looks like:
     95  *
     96  * H(K XOR opad, H(K XOR ipad, text))
     97  *
     98  * where H is a cryptographic hash
     99  * K is an n byte key
    100  * ipad is the byte 0x36 repeated blocksize times
    101  * opad is the byte 0x5c repeated blocksize times
    102  * and text is the data being protected
    103  */
    104 
    105 krb5_error_code
    106 krb5_hmac(krb5_context context,
    107 	krb5_const struct krb5_hash_provider *hash,
    108 	krb5_const krb5_keyblock *key,
    109 	krb5_const unsigned int icount,
    110 	krb5_const krb5_data *input,
    111 	krb5_data *output)
    112 {
    113     size_t hashsize, blocksize;
    114     unsigned char *xorkey, *ihash;
    115     int i;
    116     krb5_data *hashin, hashout;
    117     krb5_error_code ret;
    118 
    119     /* Solaris Kerberos */
    120     KRB5_LOG0(KRB5_INFO, "krb5_hmac() start\n");
    121 
    122     if (hash == NULL) {
    123 	KRB5_LOG0(KRB5_ERR, "krb5_hmac() error hash == NULL\n");
    124 	return(EINVAL);
    125     }
    126     if (key == NULL) {
    127 	KRB5_LOG0(KRB5_ERR, "krb5_hmac() error key == NULL\n");
    128 	return(EINVAL);
    129     }
    130     if (input == NULL) {
    131 	KRB5_LOG0(KRB5_ERR, "krb5_hmac() error input == NULL\n");
    132 	return(EINVAL);
    133     }
    134     if (output == NULL) {
    135 	KRB5_LOG0(KRB5_ERR, "krb5_hmac() error output == NULL\n");
    136 	return(EINVAL);
    137     }
    138 
    139     hashsize = hash->hashsize;
    140     blocksize = hash->blocksize;
    141 
    142     if (key->length > blocksize)
    143 	return(KRB5_CRYPTO_INTERNAL);
    144     if (output->length < hashsize)
    145 	return(KRB5_BAD_MSIZE);
    146     /* if this isn't > 0, then there won't be enough space in this
    147        array to compute the outer hash */
    148     if (icount == 0)
    149 	return(KRB5_CRYPTO_INTERNAL);
    150 
    151     /* allocate space for the xor key, hash input vector, and inner hash */
    152 
    153     if ((xorkey = (unsigned char *) MALLOC(blocksize)) == NULL)
    154 	return(ENOMEM);
    155     if ((ihash = (unsigned char *) MALLOC(hashsize)) == NULL) {
    156 	FREE(xorkey, blocksize);
    157 	return(ENOMEM);
    158     }
    159     if ((hashin = (krb5_data *)MALLOC(sizeof(krb5_data)*(icount+1))) == NULL) {
    160 	FREE(ihash, hashsize);
    161 	FREE(xorkey, blocksize);
    162 	return(ENOMEM);
    163     }
    164 
    165     /* create the inner padded key */
    166 
    167     /* Solaris Kerberos */
    168     (void) memset(xorkey, 0x36, blocksize);
    169 
    170     for (i=0; i<key->length; i++)
    171 	xorkey[i] ^= key->contents[i];
    172 
    173     /* compute the inner hash */
    174 
    175     for (i=0; i<icount; i++) {
    176 	hashin[0].length = blocksize;
    177 	hashin[0].data = (char *) xorkey;
    178 	hashin[i+1] = input[i];
    179     }
    180 
    181     hashout.length = hashsize;
    182     hashout.data = (char *) ihash;
    183 
    184     /* Solaris Kerberos */
    185     if ((ret = ((*(hash->hash))(context, icount+1, hashin, &hashout))))
    186 	goto cleanup;
    187 
    188     /* create the outer padded key */
    189 
    190     /* Solaris Kerberos */
    191     (void) memset(xorkey, 0x5c, blocksize);
    192 
    193     for (i=0; i<key->length; i++)
    194 	xorkey[i] ^= key->contents[i];
    195 
    196     /* compute the outer hash */
    197 
    198     hashin[0].length = blocksize;
    199     hashin[0].data = (char *) xorkey;
    200     hashin[1] = hashout;
    201 
    202     output->length = hashsize;
    203 
    204     /* Solaris Kerberos */
    205     if ((ret = ((*(hash->hash))(context, 2, hashin, output))))
    206 	(void) memset(output->data, 0, output->length);
    207 
    208     /* ret is set correctly by the prior call */
    209 
    210 cleanup:
    211     /* Solaris Kerberos */
    212     (void) memset(xorkey, 0, blocksize);
    213     (void) memset(ihash, 0, hashsize);
    214 
    215     FREE(hashin, sizeof(krb5_data)*(icount+1));
    216     FREE(ihash, hashsize);
    217     FREE(xorkey, blocksize);
    218 
    219     /* Solaris Kerberos */
    220     KRB5_LOG(KRB5_INFO, "krb5_hmac() end ret=%d\n", ret);
    221     return(ret);
    222 }
    223 #endif /* _KERNEL */
    224