xref: /illumos-gate/usr/src/uts/common/gssapi/mechs/krb5/crypto/dk/dk_decrypt.c (revision 159d09a20817016f09b3ea28d1bdada4a336bb91)
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