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 "des_int.h"
35 #include "keyhash_provider.h"
36
37 #define CONFLENGTH 8
38
39 /* Force acceptance of krb5-beta5 md5des checksum for now. */
40 #define KRB5_MD5DES_BETA5_COMPAT
41
42 /* des-cbc(xorkey, conf | rsa-md5(conf | data)) */
43
44 /* this could be done in terms of the md5 and des providers, but
45 that's less efficient, and there's no need for this to be generic */
46
47 /*ARGSUSED*/
48 static krb5_error_code
k5_md5des_hash(krb5_context context,krb5_const krb5_keyblock * key,krb5_keyusage usage,const krb5_data * ivec,const krb5_data * input,krb5_data * output)49 k5_md5des_hash(krb5_context context, krb5_const krb5_keyblock *key,
50 krb5_keyusage usage, const krb5_data *ivec,
51 const krb5_data *input, krb5_data *output)
52 {
53 krb5_error_code ret = 0;
54 krb5_data data;
55 unsigned char conf[CONFLENGTH];
56 krb5_keyblock xorkey;
57 int i;
58 CK_MECHANISM mechanism;
59 CK_RV rv;
60 CK_ULONG hashlen = MD5_CKSUM_LENGTH;
61
62 if (key->length != 8)
63 return(KRB5_BAD_KEYSIZE);
64 if (ivec)
65 return(KRB5_CRYPTO_INTERNAL);
66 if (output->length != (CONFLENGTH+MD5_CKSUM_LENGTH))
67 return(KRB5_CRYPTO_INTERNAL);
68
69 /* create the confouder */
70
71 data.length = CONFLENGTH;
72 data.data = (char *) conf;
73 if ((ret = krb5_c_random_make_octets(context, &data)))
74 return(ret);
75
76 xorkey.magic = key->magic;
77 xorkey.enctype = key->enctype;
78 xorkey.length = key->length;
79 xorkey.contents = (krb5_octet *)malloc(key->length);
80 if (xorkey.contents == NULL)
81 return(KRB5_CRYPTO_INTERNAL);
82
83 (void) memcpy(xorkey.contents, key->contents, xorkey.length);
84
85 for (i=0; i<xorkey.length; i++)
86 xorkey.contents[i] ^= 0xf0;
87
88 if (!mit_des_check_key_parity(xorkey.contents)) {
89 ret = KRB5DES_BAD_KEYPAR;
90 goto cleanup;
91 }
92
93 if (mit_des_is_weak_key(xorkey.contents)) {
94 ret = KRB5DES_WEAK_KEY;
95 goto cleanup;
96 }
97
98 /* hash the confounder, then the input data */
99 mechanism.mechanism = CKM_MD5;
100 mechanism.pParameter = NULL_PTR;
101 mechanism.ulParameterLen = 0;
102
103 if ((rv = C_DigestInit(krb_ctx_hSession(context), &mechanism)) != CKR_OK) {
104 KRB5_LOG(KRB5_ERR, "C_DigestInit failed in k5_md5des_hash: "
105 "rv = 0x%x.", rv);
106 ret = PKCS_ERR;
107 goto cleanup;
108 }
109
110 if ((rv = C_DigestUpdate(krb_ctx_hSession(context),
111 (CK_BYTE_PTR)conf, (CK_ULONG)sizeof(conf))) != CKR_OK) {
112 KRB5_LOG(KRB5_ERR, "C_DigestUpdate failed in k5_md5des_hash: "
113 "rv = 0x%x", rv);
114 ret = PKCS_ERR;
115 goto cleanup;
116 }
117
118 if ((rv = C_DigestUpdate(krb_ctx_hSession(context),
119 (CK_BYTE_PTR)input->data, (CK_ULONG)input->length)) != CKR_OK) {
120 KRB5_LOG(KRB5_ERR, "C_DigestUpdate failed in k5_md5des_hash: "
121 "rv = 0x%x", rv);
122 return(PKCS_ERR);
123 }
124
125 if ((rv = C_DigestFinal(krb_ctx_hSession(context),
126 (CK_BYTE_PTR)(output->data + CONFLENGTH),
127 (CK_ULONG_PTR)&hashlen)) != CKR_OK) {
128 KRB5_LOG(KRB5_ERR, "C_DigestFinal failed in k5_md5des_hash: "
129 "rv = 0x%x", rv);
130 ret = PKCS_ERR;
131 goto cleanup;
132 }
133
134 /* construct the buffer to be encrypted */
135
136 (void) memcpy(output->data, conf, CONFLENGTH);
137
138 /* encrypt it, in place. this has a return value, but it's
139 always zero. */
140
141 ret = mit_des_cbc_encrypt(context,
142 (krb5_pointer) output->data,
143 (krb5_pointer) output->data, output->length,
144 &xorkey, (unsigned char*) mit_des_zeroblock, 1);
145
146 cleanup:
147 free(xorkey.contents);
148 return(ret);
149 }
150
151 /*ARGSUSED*/
152 static krb5_error_code
k5_md5des_verify(krb5_context context,krb5_const krb5_keyblock * key,krb5_keyusage usage,krb5_const krb5_data * ivec,krb5_const krb5_data * input,krb5_const krb5_data * hash,krb5_boolean * valid)153 k5_md5des_verify(krb5_context context,
154 krb5_const krb5_keyblock *key,
155 krb5_keyusage usage,
156 krb5_const krb5_data *ivec,
157 krb5_const krb5_data *input,
158 krb5_const krb5_data *hash,
159 krb5_boolean *valid)
160 {
161 krb5_error_code ret = 0;
162 unsigned char plaintext[CONFLENGTH+MD5_CKSUM_LENGTH];
163 unsigned char digest[MD5_CKSUM_LENGTH];
164 krb5_keyblock xorkey;
165 int i;
166 int compathash = 0;
167 CK_MECHANISM mechanism;
168 CK_RV rv;
169 CK_ULONG hashlen = MD5_CKSUM_LENGTH;
170
171 if (key->length != 8)
172 return(KRB5_BAD_KEYSIZE);
173 if (ivec)
174 return(KRB5_CRYPTO_INTERNAL);
175 if (hash->length != (CONFLENGTH + MD5_CKSUM_LENGTH)) {
176 #ifdef KRB5_MD5DES_BETA5_COMPAT
177 if (hash->length != MD5_CKSUM_LENGTH)
178 return(KRB5_CRYPTO_INTERNAL);
179 else
180 compathash = 1;
181 #else
182 return(KRB5_CRYPTO_INTERNAL);
183 #endif
184 }
185
186 /* create and the encryption key */
187 xorkey.magic = key->magic;
188 xorkey.enctype = key->enctype;
189 xorkey.length = key->length;
190 xorkey.contents = (krb5_octet *)malloc(key->length);
191 if (xorkey.contents == NULL)
192 return(KRB5_CRYPTO_INTERNAL);
193
194 (void) memcpy(xorkey.contents, key->contents, xorkey.length);
195 if (!compathash) {
196 for (i=0; i<xorkey.length; i++)
197 xorkey.contents[i] ^= 0xf0;
198 }
199
200 if (!mit_des_check_key_parity(xorkey.contents)) {
201 ret = KRB5DES_BAD_KEYPAR;
202 goto cleanup;
203 }
204
205 if (mit_des_is_weak_key(xorkey.contents)) {
206 ret = KRB5DES_WEAK_KEY;
207 goto cleanup;
208 }
209
210 /* decrypt it. this has a return value, but it's always zero. */
211 if (!compathash) {
212 ret = mit_des_cbc_encrypt(context,
213 (krb5_pointer) hash->data,
214 (krb5_pointer) plaintext, hash->length,
215 &xorkey, (unsigned char*) mit_des_zeroblock, 0);
216 } else {
217 ret = mit_des_cbc_encrypt(context,
218 (krb5_pointer) hash->data,
219 (krb5_pointer) plaintext, hash->length,
220 &xorkey, xorkey.contents, 0);
221 }
222 if (ret) goto cleanup;
223
224 /* hash the confounder, then the input data */
225 mechanism.mechanism = CKM_MD5;
226 mechanism.pParameter = NULL_PTR;
227 mechanism.ulParameterLen = 0;
228
229 if ((rv = C_DigestInit(krb_ctx_hSession(context), &mechanism)) != CKR_OK) {
230 KRB5_LOG(KRB5_ERR, "C_DigestInit failed in k5_md5des_verify: "
231 "rv = 0x%x.", rv);
232 ret = PKCS_ERR;
233 goto cleanup;
234 }
235
236 if (!compathash) {
237 if ((rv = C_DigestUpdate(krb_ctx_hSession(context),
238 (CK_BYTE_PTR)plaintext, (CK_ULONG)CONFLENGTH)) != CKR_OK) {
239 KRB5_LOG(KRB5_ERR, "C_DigestUpdate failed in k5_md5des_verify: "
240 "rv = 0x%x", rv);
241 ret = PKCS_ERR;
242 goto cleanup;
243 }
244 }
245 if ((rv = C_DigestUpdate(krb_ctx_hSession(context),
246 (CK_BYTE_PTR)input->data, (CK_ULONG)input->length)) != CKR_OK) {
247 KRB5_LOG(KRB5_ERR, "C_DigestUpdate failed in k5_md5des_verify: "
248 "rv = 0x%x", rv);
249 ret = PKCS_ERR;
250 goto cleanup;
251 }
252 if ((rv = C_DigestFinal(krb_ctx_hSession(context),
253 (CK_BYTE_PTR)digest, (CK_ULONG_PTR)&hashlen)) != CKR_OK) {
254 KRB5_LOG(KRB5_ERR, "C_DigestFinal failed in k5_md5des_verify: "
255 "rv = 0x%x", rv);
256 ret = PKCS_ERR;
257 goto cleanup;
258 }
259
260 /* compare the decrypted hash to the computed one */
261
262 if (!compathash) {
263 *valid = (memcmp(plaintext+CONFLENGTH, digest, sizeof(digest)) == 0);
264 } else {
265 *valid = (memcmp(plaintext, digest, sizeof(digest)) == 0);
266 }
267 (void) memset(plaintext, 0, sizeof(plaintext));
268
269 cleanup:
270 free(xorkey.contents);
271 return(ret);
272 }
273
274 const struct krb5_keyhash_provider krb5int_keyhash_md5des = {
275 CONFLENGTH + MD5_CKSUM_LENGTH,
276 k5_md5des_hash,
277 k5_md5des_verify
278 };
279