1 /* 2 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 #pragma ident "%Z%%M% %I% %E% SMI" 7 8 /* 9 * Copyright (C) 1998 by the FundsXpress, INC. 10 * 11 * All rights reserved. 12 * 13 * Export of this software from the United States of America may require 14 * a specific license from the United States Government. It is the 15 * responsibility of any person or organization contemplating export to 16 * obtain such a license before exporting. 17 * 18 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 19 * distribute this software and its documentation for any purpose and 20 * without fee is hereby granted, provided that the above copyright 21 * notice appear in all copies and that both that copyright notice and 22 * this permission notice appear in supporting documentation, and that 23 * the name of FundsXpress. not be used in advertising or publicity pertaining 24 * to distribution of the software without specific, written prior 25 * permission. FundsXpress makes no representations about the suitability of 26 * this software for any purpose. It is provided "as is" without express 27 * or implied warranty. 28 * 29 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 30 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 31 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 32 */ 33 34 #include <k5-int.h> 35 #include <dk.h> 36 37 #define K5CLENGTH 5 /* 32 bit net byte order integer + one byte seed */ 38 39 static krb5_error_code 40 krb5_dk_decrypt_maybe_trunc_hmac(krb5_context context, 41 const struct krb5_enc_provider *enc, 42 const struct krb5_hash_provider *hash, 43 const krb5_keyblock *key, 44 krb5_keyusage usage, 45 const krb5_data *ivec, 46 const krb5_data *input, 47 krb5_data *output, 48 size_t hmacsize); 49 50 krb5_error_code 51 krb5_dk_decrypt( 52 krb5_context context, 53 const struct krb5_enc_provider *enc, 54 const struct krb5_hash_provider *hash, 55 const krb5_keyblock *key, 56 krb5_keyusage usage, 57 const krb5_data *ivec, 58 const krb5_data *input, 59 krb5_data *output) 60 { 61 return krb5_dk_decrypt_maybe_trunc_hmac(context, enc, hash, key, usage, 62 ivec, input, output, 0); 63 } 64 65 krb5_error_code 66 krb5int_aes_dk_decrypt( 67 krb5_context context, 68 const struct krb5_enc_provider *enc, 69 const struct krb5_hash_provider *hash, 70 const krb5_keyblock *key, 71 krb5_keyusage usage, 72 const krb5_data *ivec, 73 const krb5_data *input, 74 krb5_data *output) 75 { 76 return krb5_dk_decrypt_maybe_trunc_hmac(context, enc, hash, key, usage, 77 ivec, input, output, 96 / 8); 78 } 79 80 static krb5_error_code 81 krb5_dk_decrypt_maybe_trunc_hmac( 82 krb5_context context, 83 krb5_const struct krb5_enc_provider *enc, 84 krb5_const struct krb5_hash_provider *hash, 85 krb5_const krb5_keyblock *key, 86 krb5_keyusage usage, 87 krb5_const krb5_data *ivec, 88 krb5_const krb5_data *input, 89 krb5_data *output, 90 size_t hmacsize) 91 { 92 krb5_error_code ret; 93 size_t hashsize, blocksize, enclen, plainlen; 94 unsigned char *plaindata = NULL, *cksum = NULL, *cn; 95 krb5_data d1, d2; 96 krb5_keyblock *derived_encr_key = NULL; 97 krb5_keyblock *derived_hmac_key = NULL; 98 99 KRB5_LOG0(KRB5_INFO, "krb5_dk_decrypt() start\n"); 100 101 /* 102 * Derive the encryption and hmac keys. 103 * This routine is optimized to fetch the DK 104 * from the original key's DK list. 105 */ 106 ret = init_derived_keydata(context, enc, 107 (krb5_keyblock *)key, 108 usage, 109 &derived_encr_key, 110 &derived_hmac_key); 111 if (ret) 112 return (ret); 113 114 hashsize = hash->hashsize; 115 blocksize = enc->block_size; 116 117 if (hmacsize == 0) 118 hmacsize = hashsize; 119 else if (hmacsize > hashsize) 120 return (KRB5KRB_AP_ERR_BAD_INTEGRITY); 121 122 enclen = input->length - hmacsize; 123 124 if ((plaindata = (unsigned char *) MALLOC(enclen)) == NULL) { 125 ret = ENOMEM; 126 goto cleanup; 127 } 128 129 /* decrypt the ciphertext */ 130 d1.length = enclen; 131 d1.data = input->data; 132 133 d2.length = enclen; 134 d2.data = (char *)plaindata; 135 136 if ((ret = ((*(enc->decrypt))(context, derived_encr_key, 137 ivec, &d1, &d2))) != 0) 138 goto cleanup; 139 140 if (ivec != NULL && ivec->length == blocksize) { 141 cn = (unsigned char *) d1.data + d1.length - blocksize; 142 } else { 143 cn = NULL; 144 } 145 146 /* verify the hash */ 147 if ((cksum = (unsigned char *) MALLOC(hashsize)) == NULL) { 148 ret = ENOMEM; 149 goto cleanup; 150 } 151 d1.length = hashsize; 152 d1.data = (char *)cksum; 153 154 #ifdef _KERNEL 155 if ((ret = krb5_hmac(context, derived_hmac_key, &d2, &d1)) != 0) 156 goto cleanup; 157 #else 158 if ((ret = krb5_hmac(context, hash, derived_hmac_key, 159 1, &d2, &d1)) != 0) 160 goto cleanup; 161 #endif /* _KERNEL */ 162 163 if (memcmp(cksum, input->data+enclen, hmacsize) != 0) { 164 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; 165 goto cleanup; 166 } 167 168 /* because this encoding isn't self-describing wrt length, the 169 best we can do here is to compute the length minus the 170 confounder. */ 171 172 plainlen = enclen - blocksize; 173 174 if (output->length < plainlen) { 175 ret = KRB5_BAD_MSIZE; 176 goto cleanup; 177 } 178 179 output->length = plainlen; 180 181 (void) memcpy(output->data, d2.data+blocksize, output->length); 182 183 /* 184 * AES crypto updates the ivec differently, it is handled 185 * in the AES crypto routines directly. 186 */ 187 if (cn != NULL && 188 key->enctype != ENCTYPE_AES128_CTS_HMAC_SHA1_96 && 189 key->enctype != ENCTYPE_AES256_CTS_HMAC_SHA1_96) { 190 (void) memcpy(ivec->data, cn, blocksize); 191 } 192 193 ret = 0; 194 195 cleanup: 196 if (plaindata) { 197 (void) memset(plaindata, 0, enclen); 198 FREE(plaindata, enclen); 199 } 200 if (cksum) { 201 (void) memset(cksum, 0, hashsize); 202 FREE(cksum, hashsize); 203 } 204 205 KRB5_LOG(KRB5_INFO, "krb5_dk_decrypt() end, ret=%d\n", ret); 206 return(ret); 207 } 208 209