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