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