1 /*
2 * Copyright 2010 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
krb5_dk_decrypt(krb5_context context,const struct krb5_enc_provider * enc,const struct krb5_hash_provider * hash,const krb5_keyblock * key,krb5_keyusage usage,const krb5_data * ivec,const krb5_data * input,krb5_data * output)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
krb5int_aes_dk_decrypt(krb5_context context,const struct krb5_enc_provider * enc,const struct krb5_hash_provider * hash,const krb5_keyblock * key,krb5_keyusage usage,const krb5_data * ivec,const krb5_data * input,krb5_data * output)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
krb5_dk_decrypt_maybe_trunc_hmac(krb5_context context,const struct krb5_enc_provider * enc,const struct krb5_hash_provider * hash,const krb5_keyblock * key,krb5_keyusage usage,const krb5_data * ivec,const krb5_data * input,krb5_data * output,size_t hmacsize)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 /* Verify input and output lengths. */
115 if (input->length < blocksize + hmacsize)
116 return KRB5_BAD_MSIZE;
117 if (output->length < input->length - blocksize - hmacsize)
118 return KRB5_BAD_MSIZE;
119
120 enclen = input->length - hmacsize;
121
122 if ((plaindata = (unsigned char *) MALLOC(enclen)) == NULL) {
123 ret = ENOMEM;
124 goto cleanup;
125 }
126
127 /* decrypt the ciphertext */
128
129 d1.length = enclen;
130 d1.data = input->data;
131
132 d2.length = enclen;
133 d2.data = (char *) plaindata;
134
135 if ((ret = ((*(enc->decrypt))(context, derived_encr_key,
136 ivec, &d1, &d2))) != 0)
137 goto cleanup;
138
139 if (ivec != NULL && ivec->length == blocksize) {
140 cn = (unsigned char *) d1.data + d1.length - blocksize;
141 } else {
142 cn = NULL;
143 }
144
145 /* verify the hash */
146
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