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 #include "dk.h" 35 36 #define K5CLENGTH 5 /* 32 bit net byte order integer + one byte seed */ 37 38 static krb5_error_code 39 krb5_dk_decrypt_maybe_trunc_hmac(krb5_context context, 40 const struct krb5_enc_provider *enc, 41 const struct krb5_hash_provider *hash, 42 const krb5_keyblock *key, 43 krb5_keyusage usage, 44 const krb5_data *ivec, 45 const krb5_data *input, 46 krb5_data *output, 47 size_t hmacsize); 48 49 krb5_error_code 50 krb5_dk_decrypt( 51 krb5_context context, 52 const struct krb5_enc_provider *enc, 53 const struct krb5_hash_provider *hash, 54 const krb5_keyblock *key, krb5_keyusage usage, 55 const krb5_data *ivec, const krb5_data *input, 56 krb5_data *output) 57 { 58 return krb5_dk_decrypt_maybe_trunc_hmac(context, enc, hash, key, usage, 59 ivec, input, output, 0); 60 } 61 62 krb5_error_code 63 krb5int_aes_dk_decrypt( 64 krb5_context context, 65 const struct krb5_enc_provider *enc, 66 const struct krb5_hash_provider *hash, 67 const krb5_keyblock *key, krb5_keyusage usage, 68 const krb5_data *ivec, const krb5_data *input, 69 krb5_data *output) 70 { 71 return krb5_dk_decrypt_maybe_trunc_hmac(context, enc, hash, key, usage, 72 ivec, input, output, 96 / 8); 73 } 74 75 static krb5_error_code 76 krb5_dk_decrypt_maybe_trunc_hmac( 77 krb5_context context, 78 const struct krb5_enc_provider *enc, 79 const struct krb5_hash_provider *hash, 80 const krb5_keyblock *key, krb5_keyusage usage, 81 const krb5_data *ivec, const krb5_data *input, 82 krb5_data *output, size_t hmacsize) 83 { 84 krb5_error_code ret; 85 size_t hashsize, blocksize, enclen, plainlen; 86 unsigned char *plaindata = NULL, *cksum = NULL, *cn; 87 krb5_data d1, d2; 88 krb5_keyblock *derived_encr_key = NULL; 89 krb5_keyblock *derived_hmac_key = NULL; 90 91 KRB5_LOG0(KRB5_INFO, "krb5_dk_decrypt() start\n"); 92 93 /* 94 * Derive the encryption and hmac keys. 95 * This routine is optimized to fetch the DK 96 * from the original key's DK list. 97 */ 98 ret = init_derived_keydata(context, enc, 99 (krb5_keyblock *)key, 100 usage, 101 &derived_encr_key, 102 &derived_hmac_key); 103 if (ret) 104 return (ret); 105 106 hashsize = hash->hashsize; 107 blocksize = enc->block_size; 108 109 if (hmacsize == 0) 110 hmacsize = hashsize; 111 else if (hmacsize > hashsize) 112 return (KRB5KRB_AP_ERR_BAD_INTEGRITY); 113 114 enclen = input->length - hmacsize; 115 116 if ((plaindata = (unsigned char *) MALLOC(enclen)) == NULL) { 117 ret = ENOMEM; 118 goto cleanup; 119 } 120 121 /* decrypt the ciphertext */ 122 123 d1.length = enclen; 124 d1.data = input->data; 125 126 d2.length = enclen; 127 d2.data = (char *) plaindata; 128 129 if ((ret = ((*(enc->decrypt))(context, derived_encr_key, 130 ivec, &d1, &d2))) != 0) 131 goto cleanup; 132 133 if (ivec != NULL && ivec->length == blocksize) { 134 cn = (unsigned char *) d1.data + d1.length - blocksize; 135 } else { 136 cn = NULL; 137 } 138 139 /* verify the hash */ 140 141 if ((cksum = (unsigned char *) MALLOC(hashsize)) == NULL) { 142 ret = ENOMEM; 143 goto cleanup; 144 } 145 d1.length = hashsize; 146 d1.data = (char *) cksum; 147 148 #ifdef _KERNEL 149 if ((ret = krb5_hmac(context, derived_hmac_key, &d2, &d1)) != 0) 150 goto cleanup; 151 #else 152 if ((ret = krb5_hmac(context, hash, derived_hmac_key, 153 1, &d2, &d1)) != 0) 154 goto cleanup; 155 #endif /* _KERNEL */ 156 157 if (memcmp(cksum, input->data+enclen, hmacsize) != 0) { 158 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; 159 goto cleanup; 160 } 161 162 /* because this encoding isn't self-describing wrt length, the 163 best we can do here is to compute the length minus the 164 confounder. */ 165 166 plainlen = enclen - blocksize; 167 168 if (output->length < plainlen) { 169 ret = KRB5_BAD_MSIZE; 170 goto cleanup; 171 } 172 173 output->length = plainlen; 174 175 (void) memcpy(output->data, d2.data+blocksize, output->length); 176 177 /* 178 * AES crypto updates the ivec differently, it is handled 179 * in the AES crypto routines directly. 180 */ 181 if (cn != NULL && 182 key->enctype != ENCTYPE_AES128_CTS_HMAC_SHA1_96 && 183 key->enctype != ENCTYPE_AES256_CTS_HMAC_SHA1_96) { 184 (void) memcpy(ivec->data, cn, blocksize); 185 } 186 187 ret = 0; 188 189 cleanup: 190 if (plaindata) { 191 (void) memset(plaindata, 0, enclen); 192 FREE(plaindata, enclen); 193 } 194 if (cksum) { 195 (void) memset(cksum, 0, hashsize); 196 FREE(cksum, hashsize); 197 } 198 199 KRB5_LOG(KRB5_INFO, "krb5_dk_decrypt() end, ret=%d\n", ret); 200 return(ret); 201 } 202 203