1 /*
2  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 #include <k5-int.h>
7 #include <des_int.h>
8 
9 krb5_error_code
k5_ef_hash(krb5_context context,CK_MECHANISM * mechanism,unsigned int icount,krb5_const krb5_data * input,krb5_data * output)10 k5_ef_hash(krb5_context context,
11 	CK_MECHANISM *mechanism,
12 	unsigned int icount,
13 	krb5_const krb5_data *input,
14 	krb5_data *output)
15 {
16 	CK_RV rv;
17 	int i;
18 	CK_ULONG outlen = output->length;
19 
20 	if ((rv = C_DigestInit(krb_ctx_hSession(context), mechanism)) !=
21 	    CKR_OK) {
22 	    KRB5_LOG(KRB5_ERR, "C_DigestInit failed in k5_ef_hash: "
23 	    "rv = 0x%x.", rv);
24 	    return (PKCS_ERR);
25 	}
26 
27 	for (i = 0; i < icount; i++) {
28 	    if ((rv = C_DigestUpdate(krb_ctx_hSession(context),
29 		(CK_BYTE_PTR)input[i].data,
30 		(CK_ULONG)input[i].length)) != CKR_OK) {
31 		KRB5_LOG(KRB5_ERR, "C_DigestUpdate failed in k5_ef_hash: "
32 		    "rv = 0x%x", rv);
33 		return (PKCS_ERR);
34 	    }
35 	}
36 
37 	if ((rv = C_DigestFinal(krb_ctx_hSession(context),
38 	    (CK_BYTE_PTR)output->data, &outlen)) != CKR_OK) {
39 	    KRB5_LOG(KRB5_ERR, "C_DigestFinal failed in k5_ef_hash: "
40 		"rv = 0x%x", rv);
41 	    return (PKCS_ERR);
42 	}
43 
44 	/* Narrowing conversion OK because hashes are much smaller than 2^32 */
45 	output->length = outlen;
46 
47 	KRB5_LOG0(KRB5_INFO, "k5_ef_hash() end");
48 	return (0);
49 }
50 
51 
52 /*
53  * Ideally, this would use the PKCS#11 interface
54  * for doing DES_CBC_MAC_* operations, but for now we
55  * can fake it by using the des-cbc crypto operation.
56  * and truncating the output.
57  */
58 krb5_error_code
k5_ef_mac(krb5_context context,krb5_keyblock * key,krb5_data * ivec,krb5_const krb5_data * input,krb5_data * output)59 k5_ef_mac(krb5_context context,
60 	krb5_keyblock *key,
61 	krb5_data *ivec,
62 	krb5_const krb5_data *input,
63 	krb5_data *output)
64 {
65 	krb5_error_code retval = 0;
66 	char *outbuf = NULL;
67 	char *inbuf = NULL;
68 	int inlen;
69 	int outlen;
70 
71 	/*
72 	 * This is ugly but necessary until proper PKCS#11
73 	 * interface is ready.
74 	 */
75 	inlen = K5ROUNDUP(input->length, 8);
76 	outlen = inlen;
77 
78 	if (inlen != input->length) {
79 		inbuf = (char *)malloc(inlen);
80 		if (inbuf == NULL)
81 			retval = ENOMEM;
82 	}
83 	else
84 		inbuf = input->data;
85 
86 	outbuf = (char *)malloc(outlen);
87 	if (outbuf == NULL)
88 		retval = ENOMEM;
89 	(void) memset(outbuf, 0, outlen);
90 	if (outbuf != NULL && inbuf != NULL) {
91 		if (inlen != input->length) {
92 			(void) memset(inbuf, 0, inlen);
93 			(void) memcpy(inbuf, input->data, input->length);
94 		}
95 		retval = mit_des_cbc_encrypt(context,
96 			(const mit_des_cblock *)inbuf,
97 			(mit_des_cblock *)outbuf,
98 			inlen, key,
99 			(unsigned char *)ivec->data, 1);
100 
101 		if (retval == 0) {
102 			(void) memcpy(output->data, &outbuf[outlen-8], 8);
103 			output->length = 8;
104 		}
105 	}
106 	if (inlen != input->length && inbuf != NULL)
107 		free(inbuf);
108 	if (outbuf != NULL)
109 		free(outbuf);
110 	return (retval);
111 }
112