xref: /onnv-gate/usr/src/lib/pkcs11/pkcs11_kms/common/kmsAESCrypt.c (revision 12720:3db6e0082404)
1*12720SWyllys.Ingersoll@Sun.COM /*
2*12720SWyllys.Ingersoll@Sun.COM  * CDDL HEADER START
3*12720SWyllys.Ingersoll@Sun.COM  *
4*12720SWyllys.Ingersoll@Sun.COM  * The contents of this file are subject to the terms of the
5*12720SWyllys.Ingersoll@Sun.COM  * Common Development and Distribution License (the "License").
6*12720SWyllys.Ingersoll@Sun.COM  * You may not use this file except in compliance with the License.
7*12720SWyllys.Ingersoll@Sun.COM  *
8*12720SWyllys.Ingersoll@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*12720SWyllys.Ingersoll@Sun.COM  * or http://www.opensolaris.org/os/licensing.
10*12720SWyllys.Ingersoll@Sun.COM  * See the License for the specific language governing permissions
11*12720SWyllys.Ingersoll@Sun.COM  * and limitations under the License.
12*12720SWyllys.Ingersoll@Sun.COM  *
13*12720SWyllys.Ingersoll@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
14*12720SWyllys.Ingersoll@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*12720SWyllys.Ingersoll@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
16*12720SWyllys.Ingersoll@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
17*12720SWyllys.Ingersoll@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
18*12720SWyllys.Ingersoll@Sun.COM  *
19*12720SWyllys.Ingersoll@Sun.COM  * CDDL HEADER END
20*12720SWyllys.Ingersoll@Sun.COM  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
21*12720SWyllys.Ingersoll@Sun.COM  */
22*12720SWyllys.Ingersoll@Sun.COM 
23*12720SWyllys.Ingersoll@Sun.COM #include <pthread.h>
24*12720SWyllys.Ingersoll@Sun.COM #include <stdlib.h>
25*12720SWyllys.Ingersoll@Sun.COM #include <string.h>
26*12720SWyllys.Ingersoll@Sun.COM #include <strings.h>
27*12720SWyllys.Ingersoll@Sun.COM #include <sys/types.h>
28*12720SWyllys.Ingersoll@Sun.COM #include <security/cryptoki.h>
29*12720SWyllys.Ingersoll@Sun.COM #include <aes_impl.h>
30*12720SWyllys.Ingersoll@Sun.COM 
31*12720SWyllys.Ingersoll@Sun.COM #include "kmsSession.h"
32*12720SWyllys.Ingersoll@Sun.COM #include "kmsObject.h"
33*12720SWyllys.Ingersoll@Sun.COM #include "kmsCrypt.h"
34*12720SWyllys.Ingersoll@Sun.COM 
35*12720SWyllys.Ingersoll@Sun.COM /*
36*12720SWyllys.Ingersoll@Sun.COM  * Add padding bytes with the value of length of padding.
37*12720SWyllys.Ingersoll@Sun.COM  */
38*12720SWyllys.Ingersoll@Sun.COM static void
kms_add_pkcs7_padding(CK_BYTE * buf,int block_size,CK_ULONG data_len)39*12720SWyllys.Ingersoll@Sun.COM kms_add_pkcs7_padding(CK_BYTE *buf, int block_size, CK_ULONG data_len)
40*12720SWyllys.Ingersoll@Sun.COM {
41*12720SWyllys.Ingersoll@Sun.COM 
42*12720SWyllys.Ingersoll@Sun.COM 	ulong_t i, pad_len;
43*12720SWyllys.Ingersoll@Sun.COM 	CK_BYTE pad_value;
44*12720SWyllys.Ingersoll@Sun.COM 
45*12720SWyllys.Ingersoll@Sun.COM 	pad_len = block_size - (data_len % block_size);
46*12720SWyllys.Ingersoll@Sun.COM 	pad_value = (CK_BYTE)pad_len;
47*12720SWyllys.Ingersoll@Sun.COM 
48*12720SWyllys.Ingersoll@Sun.COM 	for (i = 0; i < pad_len; i++)
49*12720SWyllys.Ingersoll@Sun.COM 		buf[i] = pad_value;
50*12720SWyllys.Ingersoll@Sun.COM }
51*12720SWyllys.Ingersoll@Sun.COM 
52*12720SWyllys.Ingersoll@Sun.COM /*
53*12720SWyllys.Ingersoll@Sun.COM  * Remove padding bytes.
54*12720SWyllys.Ingersoll@Sun.COM  */
55*12720SWyllys.Ingersoll@Sun.COM static CK_RV
kms_remove_pkcs7_padding(CK_BYTE * pData,CK_ULONG padded_len,CK_ULONG * pulDataLen,int block_size)56*12720SWyllys.Ingersoll@Sun.COM kms_remove_pkcs7_padding(CK_BYTE *pData, CK_ULONG padded_len,
57*12720SWyllys.Ingersoll@Sun.COM     CK_ULONG *pulDataLen, int block_size)
58*12720SWyllys.Ingersoll@Sun.COM {
59*12720SWyllys.Ingersoll@Sun.COM 
60*12720SWyllys.Ingersoll@Sun.COM 	CK_BYTE  pad_value;
61*12720SWyllys.Ingersoll@Sun.COM 	ulong_t i;
62*12720SWyllys.Ingersoll@Sun.COM 
63*12720SWyllys.Ingersoll@Sun.COM 	pad_value = pData[padded_len - 1];
64*12720SWyllys.Ingersoll@Sun.COM 
65*12720SWyllys.Ingersoll@Sun.COM 
66*12720SWyllys.Ingersoll@Sun.COM 	/* Make sure there is a valid padding value. */
67*12720SWyllys.Ingersoll@Sun.COM 	if ((pad_value == 0) || (pad_value > block_size))
68*12720SWyllys.Ingersoll@Sun.COM 		return (CKR_ENCRYPTED_DATA_INVALID);
69*12720SWyllys.Ingersoll@Sun.COM 
70*12720SWyllys.Ingersoll@Sun.COM 	for (i = padded_len - pad_value; i < padded_len; i++)
71*12720SWyllys.Ingersoll@Sun.COM 		if (pad_value != pData[i])
72*12720SWyllys.Ingersoll@Sun.COM 			return (CKR_ENCRYPTED_DATA_INVALID);
73*12720SWyllys.Ingersoll@Sun.COM 
74*12720SWyllys.Ingersoll@Sun.COM 	*pulDataLen = padded_len - pad_value;
75*12720SWyllys.Ingersoll@Sun.COM 	return (CKR_OK);
76*12720SWyllys.Ingersoll@Sun.COM }
77*12720SWyllys.Ingersoll@Sun.COM 
78*12720SWyllys.Ingersoll@Sun.COM /*
79*12720SWyllys.Ingersoll@Sun.COM  * Allocate context for the active encryption or decryption operation, and
80*12720SWyllys.Ingersoll@Sun.COM  * generate AES key schedule to speed up the operation.
81*12720SWyllys.Ingersoll@Sun.COM  */
82*12720SWyllys.Ingersoll@Sun.COM CK_RV
kms_aes_crypt_init_common(kms_session_t * session_p,CK_MECHANISM_PTR pMechanism,kms_object_t * key_p,boolean_t encrypt)83*12720SWyllys.Ingersoll@Sun.COM kms_aes_crypt_init_common(kms_session_t *session_p,
84*12720SWyllys.Ingersoll@Sun.COM     CK_MECHANISM_PTR pMechanism, kms_object_t *key_p,
85*12720SWyllys.Ingersoll@Sun.COM     boolean_t encrypt)
86*12720SWyllys.Ingersoll@Sun.COM {
87*12720SWyllys.Ingersoll@Sun.COM 	size_t size;
88*12720SWyllys.Ingersoll@Sun.COM 	kms_aes_ctx_t *kms_aes_ctx;
89*12720SWyllys.Ingersoll@Sun.COM 
90*12720SWyllys.Ingersoll@Sun.COM 	kms_aes_ctx = calloc(1, sizeof (kms_aes_ctx_t));
91*12720SWyllys.Ingersoll@Sun.COM 	if (kms_aes_ctx == NULL) {
92*12720SWyllys.Ingersoll@Sun.COM 		return (CKR_HOST_MEMORY);
93*12720SWyllys.Ingersoll@Sun.COM 	}
94*12720SWyllys.Ingersoll@Sun.COM 
95*12720SWyllys.Ingersoll@Sun.COM 	kms_aes_ctx->key_sched = aes_alloc_keysched(&size, 0);
96*12720SWyllys.Ingersoll@Sun.COM 
97*12720SWyllys.Ingersoll@Sun.COM 	if (kms_aes_ctx->key_sched == NULL) {
98*12720SWyllys.Ingersoll@Sun.COM 		free(kms_aes_ctx);
99*12720SWyllys.Ingersoll@Sun.COM 		return (CKR_HOST_MEMORY);
100*12720SWyllys.Ingersoll@Sun.COM 	}
101*12720SWyllys.Ingersoll@Sun.COM 
102*12720SWyllys.Ingersoll@Sun.COM 	kms_aes_ctx->keysched_len = size;
103*12720SWyllys.Ingersoll@Sun.COM 
104*12720SWyllys.Ingersoll@Sun.COM 	(void) pthread_mutex_lock(&session_p->session_mutex);
105*12720SWyllys.Ingersoll@Sun.COM 	if (encrypt) {
106*12720SWyllys.Ingersoll@Sun.COM 		/* Called by C_EncryptInit. */
107*12720SWyllys.Ingersoll@Sun.COM 		session_p->encrypt.context = kms_aes_ctx;
108*12720SWyllys.Ingersoll@Sun.COM 		session_p->encrypt.mech.mechanism = pMechanism->mechanism;
109*12720SWyllys.Ingersoll@Sun.COM 	} else {
110*12720SWyllys.Ingersoll@Sun.COM 		/* Called by C_DecryptInit. */
111*12720SWyllys.Ingersoll@Sun.COM 		session_p->decrypt.context = kms_aes_ctx;
112*12720SWyllys.Ingersoll@Sun.COM 		session_p->decrypt.mech.mechanism = pMechanism->mechanism;
113*12720SWyllys.Ingersoll@Sun.COM 	}
114*12720SWyllys.Ingersoll@Sun.COM 	(void) pthread_mutex_unlock(&session_p->session_mutex);
115*12720SWyllys.Ingersoll@Sun.COM 
116*12720SWyllys.Ingersoll@Sun.COM 	/*
117*12720SWyllys.Ingersoll@Sun.COM 	 * If this is a non-sensitive key and it does NOT have
118*12720SWyllys.Ingersoll@Sun.COM 	 * a key schedule yet, then allocate one and expand it.
119*12720SWyllys.Ingersoll@Sun.COM 	 * Otherwise, if it's a non-sensitive key, and it DOES have
120*12720SWyllys.Ingersoll@Sun.COM 	 * a key schedule already attached to it, just copy the
121*12720SWyllys.Ingersoll@Sun.COM 	 * pre-expanded schedule to the context and avoid the
122*12720SWyllys.Ingersoll@Sun.COM 	 * extra key schedule expansion operation.
123*12720SWyllys.Ingersoll@Sun.COM 	 */
124*12720SWyllys.Ingersoll@Sun.COM 	if (!(key_p->bool_attr_mask & SENSITIVE_BOOL_ON)) {
125*12720SWyllys.Ingersoll@Sun.COM 		if (OBJ_KEY_SCHED(key_p) == NULL) {
126*12720SWyllys.Ingersoll@Sun.COM 			void *ks;
127*12720SWyllys.Ingersoll@Sun.COM 
128*12720SWyllys.Ingersoll@Sun.COM 			(void) pthread_mutex_lock(&key_p->object_mutex);
129*12720SWyllys.Ingersoll@Sun.COM 			if (OBJ_KEY_SCHED(key_p) == NULL) {
130*12720SWyllys.Ingersoll@Sun.COM 				ks = aes_alloc_keysched(&size, 0);
131*12720SWyllys.Ingersoll@Sun.COM 				if (ks == NULL) {
132*12720SWyllys.Ingersoll@Sun.COM 					(void) pthread_mutex_unlock(
133*12720SWyllys.Ingersoll@Sun.COM 					    &key_p->object_mutex);
134*12720SWyllys.Ingersoll@Sun.COM 					free(kms_aes_ctx);
135*12720SWyllys.Ingersoll@Sun.COM 					return (CKR_HOST_MEMORY);
136*12720SWyllys.Ingersoll@Sun.COM 				}
137*12720SWyllys.Ingersoll@Sun.COM #ifdef	__sparcv9
138*12720SWyllys.Ingersoll@Sun.COM 				/* LINTED */
139*12720SWyllys.Ingersoll@Sun.COM 				aes_init_keysched(OBJ_SEC_VALUE(key_p), (uint_t)
140*12720SWyllys.Ingersoll@Sun.COM 				    (OBJ_SEC_VALUE_LEN(key_p) * 8), ks);
141*12720SWyllys.Ingersoll@Sun.COM #else	/* !__sparcv9 */
142*12720SWyllys.Ingersoll@Sun.COM 				aes_init_keysched(OBJ_SEC_VALUE(key_p),
143*12720SWyllys.Ingersoll@Sun.COM 				    (OBJ_SEC_VALUE_LEN(key_p) * 8), ks);
144*12720SWyllys.Ingersoll@Sun.COM #endif	/* __sparcv9 */
145*12720SWyllys.Ingersoll@Sun.COM 				OBJ_KEY_SCHED_LEN(key_p) = size;
146*12720SWyllys.Ingersoll@Sun.COM 				OBJ_KEY_SCHED(key_p) = ks;
147*12720SWyllys.Ingersoll@Sun.COM 			}
148*12720SWyllys.Ingersoll@Sun.COM 			(void) pthread_mutex_unlock(&key_p->object_mutex);
149*12720SWyllys.Ingersoll@Sun.COM 		}
150*12720SWyllys.Ingersoll@Sun.COM 		(void) memcpy(kms_aes_ctx->key_sched, OBJ_KEY_SCHED(key_p),
151*12720SWyllys.Ingersoll@Sun.COM 		    OBJ_KEY_SCHED_LEN(key_p));
152*12720SWyllys.Ingersoll@Sun.COM 		kms_aes_ctx->keysched_len = OBJ_KEY_SCHED_LEN(key_p);
153*12720SWyllys.Ingersoll@Sun.COM 	} else {
154*12720SWyllys.Ingersoll@Sun.COM 		/*
155*12720SWyllys.Ingersoll@Sun.COM 		 * Initialize key schedule for AES. aes_init_keysched()
156*12720SWyllys.Ingersoll@Sun.COM 		 * requires key length in bits.
157*12720SWyllys.Ingersoll@Sun.COM 		 */
158*12720SWyllys.Ingersoll@Sun.COM #ifdef	__sparcv9
159*12720SWyllys.Ingersoll@Sun.COM 		/* LINTED */
160*12720SWyllys.Ingersoll@Sun.COM 		aes_init_keysched(OBJ_SEC_VALUE(key_p), (uint_t)
161*12720SWyllys.Ingersoll@Sun.COM 		    (OBJ_SEC_VALUE_LEN(key_p) * 8), kms_aes_ctx->key_sched);
162*12720SWyllys.Ingersoll@Sun.COM #else	/* !__sparcv9 */
163*12720SWyllys.Ingersoll@Sun.COM 		aes_init_keysched(OBJ_SEC_VALUE(key_p),
164*12720SWyllys.Ingersoll@Sun.COM 		    (OBJ_SEC_VALUE_LEN(key_p) * 8), kms_aes_ctx->key_sched);
165*12720SWyllys.Ingersoll@Sun.COM #endif	/* __sparcv9 */
166*12720SWyllys.Ingersoll@Sun.COM 	}
167*12720SWyllys.Ingersoll@Sun.COM 	return (CKR_OK);
168*12720SWyllys.Ingersoll@Sun.COM }
169*12720SWyllys.Ingersoll@Sun.COM 
170*12720SWyllys.Ingersoll@Sun.COM /*
171*12720SWyllys.Ingersoll@Sun.COM  * kms_aes_encrypt_common()
172*12720SWyllys.Ingersoll@Sun.COM  *
173*12720SWyllys.Ingersoll@Sun.COM  * Arguments:
174*12720SWyllys.Ingersoll@Sun.COM  *      session_p:	pointer to kms_session_t struct
175*12720SWyllys.Ingersoll@Sun.COM  *	pData:		pointer to the input data to be encrypted
176*12720SWyllys.Ingersoll@Sun.COM  *	ulDataLen:	length of the input data
177*12720SWyllys.Ingersoll@Sun.COM  *	pEncrypted:	pointer to the output data after encryption
178*12720SWyllys.Ingersoll@Sun.COM  *	pulEncryptedLen: pointer to the length of the output data
179*12720SWyllys.Ingersoll@Sun.COM  *	update:		boolean flag indicates caller is kms_encrypt
180*12720SWyllys.Ingersoll@Sun.COM  *			or kms_encrypt_update
181*12720SWyllys.Ingersoll@Sun.COM  *
182*12720SWyllys.Ingersoll@Sun.COM  * Description:
183*12720SWyllys.Ingersoll@Sun.COM  *      This function calls the corresponding encrypt routine based
184*12720SWyllys.Ingersoll@Sun.COM  *	on the mechanism.
185*12720SWyllys.Ingersoll@Sun.COM  *
186*12720SWyllys.Ingersoll@Sun.COM  * Returns:
187*12720SWyllys.Ingersoll@Sun.COM  *      CKR_OK: success
188*12720SWyllys.Ingersoll@Sun.COM  *      CKR_BUFFER_TOO_SMALL: the output buffer provided by application
189*12720SWyllys.Ingersoll@Sun.COM  *			      is too small
190*12720SWyllys.Ingersoll@Sun.COM  *	CKR_FUNCTION_FAILED: encrypt function failed
191*12720SWyllys.Ingersoll@Sun.COM  *	CKR_DATA_LEN_RANGE: the input data is not a multiple of blocksize
192*12720SWyllys.Ingersoll@Sun.COM  */
193*12720SWyllys.Ingersoll@Sun.COM CK_RV
kms_aes_encrypt_common(kms_session_t * session_p,CK_BYTE_PTR pData,CK_ULONG ulDataLen,CK_BYTE_PTR pEncrypted,CK_ULONG_PTR pulEncryptedLen,boolean_t update)194*12720SWyllys.Ingersoll@Sun.COM kms_aes_encrypt_common(kms_session_t *session_p, CK_BYTE_PTR pData,
195*12720SWyllys.Ingersoll@Sun.COM     CK_ULONG ulDataLen, CK_BYTE_PTR pEncrypted,
196*12720SWyllys.Ingersoll@Sun.COM     CK_ULONG_PTR pulEncryptedLen, boolean_t update)
197*12720SWyllys.Ingersoll@Sun.COM {
198*12720SWyllys.Ingersoll@Sun.COM 
199*12720SWyllys.Ingersoll@Sun.COM 	int rc = 0;
200*12720SWyllys.Ingersoll@Sun.COM 	CK_RV rv = CKR_OK;
201*12720SWyllys.Ingersoll@Sun.COM 	kms_aes_ctx_t *kms_aes_ctx =
202*12720SWyllys.Ingersoll@Sun.COM 	    (kms_aes_ctx_t *)session_p->encrypt.context;
203*12720SWyllys.Ingersoll@Sun.COM 	aes_ctx_t *aes_ctx;
204*12720SWyllys.Ingersoll@Sun.COM 	CK_MECHANISM_TYPE mechanism = session_p->encrypt.mech.mechanism;
205*12720SWyllys.Ingersoll@Sun.COM 	CK_BYTE *in_buf = NULL;
206*12720SWyllys.Ingersoll@Sun.COM 	CK_BYTE *out_buf = NULL;
207*12720SWyllys.Ingersoll@Sun.COM 	CK_ULONG out_len;
208*12720SWyllys.Ingersoll@Sun.COM 	CK_ULONG total_len;
209*12720SWyllys.Ingersoll@Sun.COM 	CK_ULONG remain;
210*12720SWyllys.Ingersoll@Sun.COM 
211*12720SWyllys.Ingersoll@Sun.COM 	if (mechanism == CKM_AES_CTR)
212*12720SWyllys.Ingersoll@Sun.COM 		goto do_encryption;
213*12720SWyllys.Ingersoll@Sun.COM 
214*12720SWyllys.Ingersoll@Sun.COM 	/*
215*12720SWyllys.Ingersoll@Sun.COM 	 * AES only takes input length that is a multiple of blocksize
216*12720SWyllys.Ingersoll@Sun.COM 	 * for C_Encrypt function with the mechanism CKM_AES_ECB or
217*12720SWyllys.Ingersoll@Sun.COM 	 * CKM_AES_CBC.
218*12720SWyllys.Ingersoll@Sun.COM 	 *
219*12720SWyllys.Ingersoll@Sun.COM 	 * AES allows any input length for C_Encrypt function with the
220*12720SWyllys.Ingersoll@Sun.COM 	 * mechanism CKM_AES_CBC_PAD and for C_EncryptUpdate function.
221*12720SWyllys.Ingersoll@Sun.COM 	 */
222*12720SWyllys.Ingersoll@Sun.COM 	if ((!update) && (mechanism != CKM_AES_CBC_PAD)) {
223*12720SWyllys.Ingersoll@Sun.COM 		if ((ulDataLen % AES_BLOCK_LEN) != 0) {
224*12720SWyllys.Ingersoll@Sun.COM 			rv = CKR_DATA_LEN_RANGE;
225*12720SWyllys.Ingersoll@Sun.COM 			goto cleanup;
226*12720SWyllys.Ingersoll@Sun.COM 		}
227*12720SWyllys.Ingersoll@Sun.COM 	}
228*12720SWyllys.Ingersoll@Sun.COM 
229*12720SWyllys.Ingersoll@Sun.COM 	if (!update) {
230*12720SWyllys.Ingersoll@Sun.COM 		/*
231*12720SWyllys.Ingersoll@Sun.COM 		 * Called by C_Encrypt
232*12720SWyllys.Ingersoll@Sun.COM 		 */
233*12720SWyllys.Ingersoll@Sun.COM 		if (mechanism == CKM_AES_CBC_PAD) {
234*12720SWyllys.Ingersoll@Sun.COM 			/*
235*12720SWyllys.Ingersoll@Sun.COM 			 * For CKM_AES_CBC_PAD, compute output length to
236*12720SWyllys.Ingersoll@Sun.COM 			 * count for the padding. If the length of input
237*12720SWyllys.Ingersoll@Sun.COM 			 * data is a multiple of blocksize, then make output
238*12720SWyllys.Ingersoll@Sun.COM 			 * length to be the sum of the input length and
239*12720SWyllys.Ingersoll@Sun.COM 			 * one blocksize. Otherwise, output length will
240*12720SWyllys.Ingersoll@Sun.COM 			 * be rounded up to the next multiple of blocksize.
241*12720SWyllys.Ingersoll@Sun.COM 			 */
242*12720SWyllys.Ingersoll@Sun.COM 			out_len = AES_BLOCK_LEN *
243*12720SWyllys.Ingersoll@Sun.COM 			    (ulDataLen / AES_BLOCK_LEN + 1);
244*12720SWyllys.Ingersoll@Sun.COM 		} else {
245*12720SWyllys.Ingersoll@Sun.COM 			/*
246*12720SWyllys.Ingersoll@Sun.COM 			 * For non-padding mode, the output length will
247*12720SWyllys.Ingersoll@Sun.COM 			 * be same as the input length.
248*12720SWyllys.Ingersoll@Sun.COM 			 */
249*12720SWyllys.Ingersoll@Sun.COM 			out_len = ulDataLen;
250*12720SWyllys.Ingersoll@Sun.COM 		}
251*12720SWyllys.Ingersoll@Sun.COM 
252*12720SWyllys.Ingersoll@Sun.COM 		/*
253*12720SWyllys.Ingersoll@Sun.COM 		 * If application asks for the length of the output buffer
254*12720SWyllys.Ingersoll@Sun.COM 		 * to hold the ciphertext?
255*12720SWyllys.Ingersoll@Sun.COM 		 */
256*12720SWyllys.Ingersoll@Sun.COM 		if (pEncrypted == NULL) {
257*12720SWyllys.Ingersoll@Sun.COM 			*pulEncryptedLen = out_len;
258*12720SWyllys.Ingersoll@Sun.COM 			return (CKR_OK);
259*12720SWyllys.Ingersoll@Sun.COM 		}
260*12720SWyllys.Ingersoll@Sun.COM 
261*12720SWyllys.Ingersoll@Sun.COM 		/* Is the application-supplied buffer large enough? */
262*12720SWyllys.Ingersoll@Sun.COM 		if (*pulEncryptedLen < out_len) {
263*12720SWyllys.Ingersoll@Sun.COM 			*pulEncryptedLen = out_len;
264*12720SWyllys.Ingersoll@Sun.COM 			return (CKR_BUFFER_TOO_SMALL);
265*12720SWyllys.Ingersoll@Sun.COM 		}
266*12720SWyllys.Ingersoll@Sun.COM 
267*12720SWyllys.Ingersoll@Sun.COM 		/* Encrypt pad bytes in a separate operation */
268*12720SWyllys.Ingersoll@Sun.COM 		if (mechanism == CKM_AES_CBC_PAD) {
269*12720SWyllys.Ingersoll@Sun.COM 			out_len -= AES_BLOCK_LEN;
270*12720SWyllys.Ingersoll@Sun.COM 		}
271*12720SWyllys.Ingersoll@Sun.COM 
272*12720SWyllys.Ingersoll@Sun.COM 		in_buf = pData;
273*12720SWyllys.Ingersoll@Sun.COM 		out_buf = pEncrypted;
274*12720SWyllys.Ingersoll@Sun.COM 	} else {
275*12720SWyllys.Ingersoll@Sun.COM 		/*
276*12720SWyllys.Ingersoll@Sun.COM 		 * Called by C_EncryptUpdate
277*12720SWyllys.Ingersoll@Sun.COM 		 *
278*12720SWyllys.Ingersoll@Sun.COM 		 * Add the lengths of last remaining data and current
279*12720SWyllys.Ingersoll@Sun.COM 		 * plaintext together to get the total input length.
280*12720SWyllys.Ingersoll@Sun.COM 		 */
281*12720SWyllys.Ingersoll@Sun.COM 		total_len = kms_aes_ctx->remain_len + ulDataLen;
282*12720SWyllys.Ingersoll@Sun.COM 
283*12720SWyllys.Ingersoll@Sun.COM 		/*
284*12720SWyllys.Ingersoll@Sun.COM 		 * If the total input length is less than one blocksize,
285*12720SWyllys.Ingersoll@Sun.COM 		 * or if the total input length is just one blocksize and
286*12720SWyllys.Ingersoll@Sun.COM 		 * the mechanism is CKM_AES_CBC_PAD, we will need to delay
287*12720SWyllys.Ingersoll@Sun.COM 		 * encryption until when more data comes in next
288*12720SWyllys.Ingersoll@Sun.COM 		 * C_EncryptUpdate or when C_EncryptFinal is called.
289*12720SWyllys.Ingersoll@Sun.COM 		 */
290*12720SWyllys.Ingersoll@Sun.COM 		if ((total_len < AES_BLOCK_LEN) ||
291*12720SWyllys.Ingersoll@Sun.COM 		    ((mechanism == CKM_AES_CBC_PAD) &&
292*12720SWyllys.Ingersoll@Sun.COM 		    (total_len == AES_BLOCK_LEN))) {
293*12720SWyllys.Ingersoll@Sun.COM 			if (pEncrypted != NULL) {
294*12720SWyllys.Ingersoll@Sun.COM 				/*
295*12720SWyllys.Ingersoll@Sun.COM 				 * Save input data and its length in
296*12720SWyllys.Ingersoll@Sun.COM 				 * the remaining buffer of AES context.
297*12720SWyllys.Ingersoll@Sun.COM 				 */
298*12720SWyllys.Ingersoll@Sun.COM 				(void) memcpy(kms_aes_ctx->data +
299*12720SWyllys.Ingersoll@Sun.COM 				    kms_aes_ctx->remain_len, pData, ulDataLen);
300*12720SWyllys.Ingersoll@Sun.COM 				kms_aes_ctx->remain_len += ulDataLen;
301*12720SWyllys.Ingersoll@Sun.COM 			}
302*12720SWyllys.Ingersoll@Sun.COM 
303*12720SWyllys.Ingersoll@Sun.COM 			/* Set encrypted data length to 0. */
304*12720SWyllys.Ingersoll@Sun.COM 			*pulEncryptedLen = 0;
305*12720SWyllys.Ingersoll@Sun.COM 			return (CKR_OK);
306*12720SWyllys.Ingersoll@Sun.COM 		}
307*12720SWyllys.Ingersoll@Sun.COM 
308*12720SWyllys.Ingersoll@Sun.COM 		/* Compute the length of remaing data. */
309*12720SWyllys.Ingersoll@Sun.COM 		remain = total_len % AES_BLOCK_LEN;
310*12720SWyllys.Ingersoll@Sun.COM 
311*12720SWyllys.Ingersoll@Sun.COM 		/*
312*12720SWyllys.Ingersoll@Sun.COM 		 * Make sure that the output length is a multiple of
313*12720SWyllys.Ingersoll@Sun.COM 		 * blocksize.
314*12720SWyllys.Ingersoll@Sun.COM 		 */
315*12720SWyllys.Ingersoll@Sun.COM 		out_len = total_len - remain;
316*12720SWyllys.Ingersoll@Sun.COM 
317*12720SWyllys.Ingersoll@Sun.COM 		/*
318*12720SWyllys.Ingersoll@Sun.COM 		 * If application asks for the length of the output buffer
319*12720SWyllys.Ingersoll@Sun.COM 		 * to hold the ciphertext?
320*12720SWyllys.Ingersoll@Sun.COM 		 */
321*12720SWyllys.Ingersoll@Sun.COM 		if (pEncrypted == NULL) {
322*12720SWyllys.Ingersoll@Sun.COM 			*pulEncryptedLen = out_len;
323*12720SWyllys.Ingersoll@Sun.COM 			return (CKR_OK);
324*12720SWyllys.Ingersoll@Sun.COM 		}
325*12720SWyllys.Ingersoll@Sun.COM 
326*12720SWyllys.Ingersoll@Sun.COM 		/* Is the application-supplied buffer large enough? */
327*12720SWyllys.Ingersoll@Sun.COM 		if (*pulEncryptedLen < out_len) {
328*12720SWyllys.Ingersoll@Sun.COM 			*pulEncryptedLen = out_len;
329*12720SWyllys.Ingersoll@Sun.COM 			return (CKR_BUFFER_TOO_SMALL);
330*12720SWyllys.Ingersoll@Sun.COM 		}
331*12720SWyllys.Ingersoll@Sun.COM 
332*12720SWyllys.Ingersoll@Sun.COM 		if (kms_aes_ctx->remain_len != 0) {
333*12720SWyllys.Ingersoll@Sun.COM 			/*
334*12720SWyllys.Ingersoll@Sun.COM 			 * Copy last remaining data and current input data
335*12720SWyllys.Ingersoll@Sun.COM 			 * to the output buffer.
336*12720SWyllys.Ingersoll@Sun.COM 			 */
337*12720SWyllys.Ingersoll@Sun.COM 			(void) memmove(pEncrypted + kms_aes_ctx->remain_len,
338*12720SWyllys.Ingersoll@Sun.COM 			    pData, out_len - kms_aes_ctx->remain_len);
339*12720SWyllys.Ingersoll@Sun.COM 			(void) memcpy(pEncrypted, kms_aes_ctx->data,
340*12720SWyllys.Ingersoll@Sun.COM 			    kms_aes_ctx->remain_len);
341*12720SWyllys.Ingersoll@Sun.COM 			bzero(kms_aes_ctx->data, kms_aes_ctx->remain_len);
342*12720SWyllys.Ingersoll@Sun.COM 
343*12720SWyllys.Ingersoll@Sun.COM 			in_buf = pEncrypted;
344*12720SWyllys.Ingersoll@Sun.COM 		} else {
345*12720SWyllys.Ingersoll@Sun.COM 			in_buf = pData;
346*12720SWyllys.Ingersoll@Sun.COM 		}
347*12720SWyllys.Ingersoll@Sun.COM 		out_buf = pEncrypted;
348*12720SWyllys.Ingersoll@Sun.COM 	}
349*12720SWyllys.Ingersoll@Sun.COM 
350*12720SWyllys.Ingersoll@Sun.COM do_encryption:
351*12720SWyllys.Ingersoll@Sun.COM 	/*
352*12720SWyllys.Ingersoll@Sun.COM 	 * Begin Encryption now.
353*12720SWyllys.Ingersoll@Sun.COM 	 */
354*12720SWyllys.Ingersoll@Sun.COM 	switch (mechanism) {
355*12720SWyllys.Ingersoll@Sun.COM 
356*12720SWyllys.Ingersoll@Sun.COM 	case CKM_AES_CBC:
357*12720SWyllys.Ingersoll@Sun.COM 	case CKM_AES_CBC_PAD:
358*12720SWyllys.Ingersoll@Sun.COM 	{
359*12720SWyllys.Ingersoll@Sun.COM 		crypto_data_t out;
360*12720SWyllys.Ingersoll@Sun.COM 
361*12720SWyllys.Ingersoll@Sun.COM 		out.cd_format = CRYPTO_DATA_RAW;
362*12720SWyllys.Ingersoll@Sun.COM 		out.cd_offset = 0;
363*12720SWyllys.Ingersoll@Sun.COM 		out.cd_length = out_len;
364*12720SWyllys.Ingersoll@Sun.COM 		out.cd_raw.iov_base = (char *)out_buf;
365*12720SWyllys.Ingersoll@Sun.COM 		out.cd_raw.iov_len = out_len;
366*12720SWyllys.Ingersoll@Sun.COM 
367*12720SWyllys.Ingersoll@Sun.COM 		/* Encrypt multiple blocks of data. */
368*12720SWyllys.Ingersoll@Sun.COM 		rc = aes_encrypt_contiguous_blocks(
369*12720SWyllys.Ingersoll@Sun.COM 		    (aes_ctx_t *)kms_aes_ctx->aes_cbc,
370*12720SWyllys.Ingersoll@Sun.COM 		    (char *)in_buf, out_len, &out);
371*12720SWyllys.Ingersoll@Sun.COM 
372*12720SWyllys.Ingersoll@Sun.COM 		if (rc != 0)
373*12720SWyllys.Ingersoll@Sun.COM 			goto encrypt_failed;
374*12720SWyllys.Ingersoll@Sun.COM 
375*12720SWyllys.Ingersoll@Sun.COM 		if (update) {
376*12720SWyllys.Ingersoll@Sun.COM 			/*
377*12720SWyllys.Ingersoll@Sun.COM 			 * For encrypt update, if there is remaining data,
378*12720SWyllys.Ingersoll@Sun.COM 			 * save it and its length in the context.
379*12720SWyllys.Ingersoll@Sun.COM 			 */
380*12720SWyllys.Ingersoll@Sun.COM 			if (remain != 0)
381*12720SWyllys.Ingersoll@Sun.COM 				(void) memcpy(kms_aes_ctx->data, pData +
382*12720SWyllys.Ingersoll@Sun.COM 				    (ulDataLen - remain), remain);
383*12720SWyllys.Ingersoll@Sun.COM 			kms_aes_ctx->remain_len = remain;
384*12720SWyllys.Ingersoll@Sun.COM 		} else if (mechanism == CKM_AES_CBC_PAD) {
385*12720SWyllys.Ingersoll@Sun.COM 			/*
386*12720SWyllys.Ingersoll@Sun.COM 			 * Save the remainder of the input
387*12720SWyllys.Ingersoll@Sun.COM 			 * block in a temporary block because
388*12720SWyllys.Ingersoll@Sun.COM 			 * we dont want to overrun the buffer
389*12720SWyllys.Ingersoll@Sun.COM 			 * by tacking on pad bytes.
390*12720SWyllys.Ingersoll@Sun.COM 			 */
391*12720SWyllys.Ingersoll@Sun.COM 			CK_BYTE tmpblock[AES_BLOCK_LEN];
392*12720SWyllys.Ingersoll@Sun.COM 			(void) memcpy(tmpblock, in_buf + out_len,
393*12720SWyllys.Ingersoll@Sun.COM 			    ulDataLen - out_len);
394*12720SWyllys.Ingersoll@Sun.COM 			kms_add_pkcs7_padding(tmpblock +
395*12720SWyllys.Ingersoll@Sun.COM 			    (ulDataLen - out_len),
396*12720SWyllys.Ingersoll@Sun.COM 			    AES_BLOCK_LEN, ulDataLen - out_len);
397*12720SWyllys.Ingersoll@Sun.COM 
398*12720SWyllys.Ingersoll@Sun.COM 			out.cd_offset = out_len;
399*12720SWyllys.Ingersoll@Sun.COM 			out.cd_length = AES_BLOCK_LEN;
400*12720SWyllys.Ingersoll@Sun.COM 			out.cd_raw.iov_base = (char *)out_buf;
401*12720SWyllys.Ingersoll@Sun.COM 			out.cd_raw.iov_len = out_len + AES_BLOCK_LEN;
402*12720SWyllys.Ingersoll@Sun.COM 
403*12720SWyllys.Ingersoll@Sun.COM 			/* Encrypt last block containing pad bytes. */
404*12720SWyllys.Ingersoll@Sun.COM 			rc = aes_encrypt_contiguous_blocks(
405*12720SWyllys.Ingersoll@Sun.COM 			    (aes_ctx_t *)kms_aes_ctx->aes_cbc,
406*12720SWyllys.Ingersoll@Sun.COM 			    (char *)tmpblock, AES_BLOCK_LEN, &out);
407*12720SWyllys.Ingersoll@Sun.COM 
408*12720SWyllys.Ingersoll@Sun.COM 			out_len += AES_BLOCK_LEN;
409*12720SWyllys.Ingersoll@Sun.COM 		}
410*12720SWyllys.Ingersoll@Sun.COM 
411*12720SWyllys.Ingersoll@Sun.COM 		if (rc == 0) {
412*12720SWyllys.Ingersoll@Sun.COM 			*pulEncryptedLen = out_len;
413*12720SWyllys.Ingersoll@Sun.COM 			break;
414*12720SWyllys.Ingersoll@Sun.COM 		}
415*12720SWyllys.Ingersoll@Sun.COM encrypt_failed:
416*12720SWyllys.Ingersoll@Sun.COM 		*pulEncryptedLen = 0;
417*12720SWyllys.Ingersoll@Sun.COM 		rv = CKR_FUNCTION_FAILED;
418*12720SWyllys.Ingersoll@Sun.COM 		goto cleanup;
419*12720SWyllys.Ingersoll@Sun.COM 	}
420*12720SWyllys.Ingersoll@Sun.COM 	default:
421*12720SWyllys.Ingersoll@Sun.COM 		rv = CKR_MECHANISM_INVALID;
422*12720SWyllys.Ingersoll@Sun.COM 		goto cleanup;
423*12720SWyllys.Ingersoll@Sun.COM 	} /* end switch */
424*12720SWyllys.Ingersoll@Sun.COM 
425*12720SWyllys.Ingersoll@Sun.COM 	if (update)
426*12720SWyllys.Ingersoll@Sun.COM 		return (CKR_OK);
427*12720SWyllys.Ingersoll@Sun.COM 
428*12720SWyllys.Ingersoll@Sun.COM 	/*
429*12720SWyllys.Ingersoll@Sun.COM 	 * The following code will be executed if the caller is
430*12720SWyllys.Ingersoll@Sun.COM 	 * kms_encrypt() or an error occurred. The encryption
431*12720SWyllys.Ingersoll@Sun.COM 	 * operation will be terminated so we need to do some cleanup.
432*12720SWyllys.Ingersoll@Sun.COM 	 */
433*12720SWyllys.Ingersoll@Sun.COM cleanup:
434*12720SWyllys.Ingersoll@Sun.COM 	(void) pthread_mutex_lock(&session_p->session_mutex);
435*12720SWyllys.Ingersoll@Sun.COM 	aes_ctx = (aes_ctx_t *)kms_aes_ctx->aes_cbc;
436*12720SWyllys.Ingersoll@Sun.COM 	if (aes_ctx != NULL) {
437*12720SWyllys.Ingersoll@Sun.COM 		bzero(aes_ctx->ac_keysched, aes_ctx->ac_keysched_len);
438*12720SWyllys.Ingersoll@Sun.COM 		free(kms_aes_ctx->aes_cbc);
439*12720SWyllys.Ingersoll@Sun.COM 	}
440*12720SWyllys.Ingersoll@Sun.COM 
441*12720SWyllys.Ingersoll@Sun.COM 	bzero(kms_aes_ctx->key_sched, kms_aes_ctx->keysched_len);
442*12720SWyllys.Ingersoll@Sun.COM 	free(kms_aes_ctx->key_sched);
443*12720SWyllys.Ingersoll@Sun.COM 	free(session_p->encrypt.context);
444*12720SWyllys.Ingersoll@Sun.COM 	session_p->encrypt.context = NULL;
445*12720SWyllys.Ingersoll@Sun.COM 	(void) pthread_mutex_unlock(&session_p->session_mutex);
446*12720SWyllys.Ingersoll@Sun.COM 
447*12720SWyllys.Ingersoll@Sun.COM 	return (rv);
448*12720SWyllys.Ingersoll@Sun.COM }
449*12720SWyllys.Ingersoll@Sun.COM 
450*12720SWyllys.Ingersoll@Sun.COM 
451*12720SWyllys.Ingersoll@Sun.COM /*
452*12720SWyllys.Ingersoll@Sun.COM  * kms_aes_decrypt_common()
453*12720SWyllys.Ingersoll@Sun.COM  *
454*12720SWyllys.Ingersoll@Sun.COM  * Arguments:
455*12720SWyllys.Ingersoll@Sun.COM  *      session_p:	pointer to kms_session_t struct
456*12720SWyllys.Ingersoll@Sun.COM  *	pEncrypted:	pointer to the input data to be decrypted
457*12720SWyllys.Ingersoll@Sun.COM  *	ulEncryptedLen:	length of the input data
458*12720SWyllys.Ingersoll@Sun.COM  *	pData:		pointer to the output data
459*12720SWyllys.Ingersoll@Sun.COM  *	pulDataLen:	pointer to the length of the output data
460*12720SWyllys.Ingersoll@Sun.COM  *	Update:		boolean flag indicates caller is kms_decrypt
461*12720SWyllys.Ingersoll@Sun.COM  *			or kms_decrypt_update
462*12720SWyllys.Ingersoll@Sun.COM  *
463*12720SWyllys.Ingersoll@Sun.COM  * Description:
464*12720SWyllys.Ingersoll@Sun.COM  *      This function calls the corresponding decrypt routine based
465*12720SWyllys.Ingersoll@Sun.COM  *	on the mechanism.
466*12720SWyllys.Ingersoll@Sun.COM  *
467*12720SWyllys.Ingersoll@Sun.COM  * Returns:
468*12720SWyllys.Ingersoll@Sun.COM  *      CKR_OK: success
469*12720SWyllys.Ingersoll@Sun.COM  *      CKR_BUFFER_TOO_SMALL: the output buffer provided by application
470*12720SWyllys.Ingersoll@Sun.COM  *			      is too small
471*12720SWyllys.Ingersoll@Sun.COM  *	CKR_ENCRYPTED_DATA_LEN_RANGE: the input data is not a multiple
472*12720SWyllys.Ingersoll@Sun.COM  *				      of blocksize
473*12720SWyllys.Ingersoll@Sun.COM  *	CKR_FUNCTION_FAILED: decrypt function failed
474*12720SWyllys.Ingersoll@Sun.COM  */
475*12720SWyllys.Ingersoll@Sun.COM CK_RV
kms_aes_decrypt_common(kms_session_t * session_p,CK_BYTE_PTR pEncrypted,CK_ULONG ulEncryptedLen,CK_BYTE_PTR pData,CK_ULONG_PTR pulDataLen,boolean_t update)476*12720SWyllys.Ingersoll@Sun.COM kms_aes_decrypt_common(kms_session_t *session_p, CK_BYTE_PTR pEncrypted,
477*12720SWyllys.Ingersoll@Sun.COM     CK_ULONG ulEncryptedLen, CK_BYTE_PTR pData,
478*12720SWyllys.Ingersoll@Sun.COM     CK_ULONG_PTR pulDataLen, boolean_t update)
479*12720SWyllys.Ingersoll@Sun.COM {
480*12720SWyllys.Ingersoll@Sun.COM 
481*12720SWyllys.Ingersoll@Sun.COM 	int rc = 0;
482*12720SWyllys.Ingersoll@Sun.COM 	CK_RV rv = CKR_OK;
483*12720SWyllys.Ingersoll@Sun.COM 	kms_aes_ctx_t *kms_aes_ctx =
484*12720SWyllys.Ingersoll@Sun.COM 	    (kms_aes_ctx_t *)session_p->decrypt.context;
485*12720SWyllys.Ingersoll@Sun.COM 	aes_ctx_t *aes_ctx;
486*12720SWyllys.Ingersoll@Sun.COM 	CK_MECHANISM_TYPE mechanism = session_p->decrypt.mech.mechanism;
487*12720SWyllys.Ingersoll@Sun.COM 	CK_BYTE *in_buf = NULL;
488*12720SWyllys.Ingersoll@Sun.COM 	CK_BYTE *out_buf = NULL;
489*12720SWyllys.Ingersoll@Sun.COM 	CK_ULONG out_len;
490*12720SWyllys.Ingersoll@Sun.COM 	CK_ULONG total_len;
491*12720SWyllys.Ingersoll@Sun.COM 	CK_ULONG remain;
492*12720SWyllys.Ingersoll@Sun.COM 
493*12720SWyllys.Ingersoll@Sun.COM 	if (mechanism == CKM_AES_CTR)
494*12720SWyllys.Ingersoll@Sun.COM 		goto do_decryption;
495*12720SWyllys.Ingersoll@Sun.COM 
496*12720SWyllys.Ingersoll@Sun.COM 	/*
497*12720SWyllys.Ingersoll@Sun.COM 	 * AES only takes input length that is a multiple of 16 bytes
498*12720SWyllys.Ingersoll@Sun.COM 	 * for C_Decrypt function with the mechanism CKM_AES_ECB,
499*12720SWyllys.Ingersoll@Sun.COM 	 * CKM_AES_CBC or CKM_AES_CBC_PAD.
500*12720SWyllys.Ingersoll@Sun.COM 	 *
501*12720SWyllys.Ingersoll@Sun.COM 	 * AES allows any input length for C_DecryptUpdate function.
502*12720SWyllys.Ingersoll@Sun.COM 	 */
503*12720SWyllys.Ingersoll@Sun.COM 	if (!update) {
504*12720SWyllys.Ingersoll@Sun.COM 		/*
505*12720SWyllys.Ingersoll@Sun.COM 		 * Called by C_Decrypt
506*12720SWyllys.Ingersoll@Sun.COM 		 */
507*12720SWyllys.Ingersoll@Sun.COM 		if ((ulEncryptedLen % AES_BLOCK_LEN) != 0) {
508*12720SWyllys.Ingersoll@Sun.COM 			rv = CKR_ENCRYPTED_DATA_LEN_RANGE;
509*12720SWyllys.Ingersoll@Sun.COM 			goto cleanup;
510*12720SWyllys.Ingersoll@Sun.COM 		}
511*12720SWyllys.Ingersoll@Sun.COM 
512*12720SWyllys.Ingersoll@Sun.COM 		/*
513*12720SWyllys.Ingersoll@Sun.COM 		 * If application asks for the length of the output buffer
514*12720SWyllys.Ingersoll@Sun.COM 		 * to hold the plaintext?
515*12720SWyllys.Ingersoll@Sun.COM 		 */
516*12720SWyllys.Ingersoll@Sun.COM 		if (pData == NULL) {
517*12720SWyllys.Ingersoll@Sun.COM 			*pulDataLen = ulEncryptedLen;
518*12720SWyllys.Ingersoll@Sun.COM 			return (CKR_OK);
519*12720SWyllys.Ingersoll@Sun.COM 		}
520*12720SWyllys.Ingersoll@Sun.COM 
521*12720SWyllys.Ingersoll@Sun.COM 		/* Is the application-supplied buffer large enough? */
522*12720SWyllys.Ingersoll@Sun.COM 		if (mechanism != CKM_AES_CBC_PAD) {
523*12720SWyllys.Ingersoll@Sun.COM 			if (*pulDataLen < ulEncryptedLen) {
524*12720SWyllys.Ingersoll@Sun.COM 				*pulDataLen = ulEncryptedLen;
525*12720SWyllys.Ingersoll@Sun.COM 				return (CKR_BUFFER_TOO_SMALL);
526*12720SWyllys.Ingersoll@Sun.COM 			}
527*12720SWyllys.Ingersoll@Sun.COM 			out_len = ulEncryptedLen;
528*12720SWyllys.Ingersoll@Sun.COM 		} else {
529*12720SWyllys.Ingersoll@Sun.COM 			/*
530*12720SWyllys.Ingersoll@Sun.COM 			 * For CKM_AES_CBC_PAD, we don't know how
531*12720SWyllys.Ingersoll@Sun.COM 			 * many bytes for padding at this time, so
532*12720SWyllys.Ingersoll@Sun.COM 			 * we'd assume one block was padded.
533*12720SWyllys.Ingersoll@Sun.COM 			 */
534*12720SWyllys.Ingersoll@Sun.COM 			if (*pulDataLen < (ulEncryptedLen - AES_BLOCK_LEN)) {
535*12720SWyllys.Ingersoll@Sun.COM 				*pulDataLen = ulEncryptedLen - AES_BLOCK_LEN;
536*12720SWyllys.Ingersoll@Sun.COM 				return (CKR_BUFFER_TOO_SMALL);
537*12720SWyllys.Ingersoll@Sun.COM 			}
538*12720SWyllys.Ingersoll@Sun.COM 			out_len = ulEncryptedLen - AES_BLOCK_LEN;
539*12720SWyllys.Ingersoll@Sun.COM 		}
540*12720SWyllys.Ingersoll@Sun.COM 		in_buf = pEncrypted;
541*12720SWyllys.Ingersoll@Sun.COM 		out_buf = pData;
542*12720SWyllys.Ingersoll@Sun.COM 	} else {
543*12720SWyllys.Ingersoll@Sun.COM 		/*
544*12720SWyllys.Ingersoll@Sun.COM 		 *  Called by C_DecryptUpdate
545*12720SWyllys.Ingersoll@Sun.COM 		 *
546*12720SWyllys.Ingersoll@Sun.COM 		 * Add the lengths of last remaining data and current
547*12720SWyllys.Ingersoll@Sun.COM 		 * input data together to get the total input length.
548*12720SWyllys.Ingersoll@Sun.COM 		 */
549*12720SWyllys.Ingersoll@Sun.COM 		total_len = kms_aes_ctx->remain_len + ulEncryptedLen;
550*12720SWyllys.Ingersoll@Sun.COM 
551*12720SWyllys.Ingersoll@Sun.COM 		/*
552*12720SWyllys.Ingersoll@Sun.COM 		 * If the total input length is less than one blocksize,
553*12720SWyllys.Ingersoll@Sun.COM 		 * or if the total input length is just one blocksize and
554*12720SWyllys.Ingersoll@Sun.COM 		 * the mechanism is CKM_AES_CBC_PAD, we will need to delay
555*12720SWyllys.Ingersoll@Sun.COM 		 * decryption until when more data comes in next
556*12720SWyllys.Ingersoll@Sun.COM 		 * C_DecryptUpdate or when C_DecryptFinal is called.
557*12720SWyllys.Ingersoll@Sun.COM 		 */
558*12720SWyllys.Ingersoll@Sun.COM 		if ((total_len < AES_BLOCK_LEN) ||
559*12720SWyllys.Ingersoll@Sun.COM 		    ((mechanism == CKM_AES_CBC_PAD) &&
560*12720SWyllys.Ingersoll@Sun.COM 		    (total_len == AES_BLOCK_LEN))) {
561*12720SWyllys.Ingersoll@Sun.COM 			if (pData != NULL) {
562*12720SWyllys.Ingersoll@Sun.COM 				/*
563*12720SWyllys.Ingersoll@Sun.COM 				 * Save input data and its length in
564*12720SWyllys.Ingersoll@Sun.COM 				 * the remaining buffer of AES context.
565*12720SWyllys.Ingersoll@Sun.COM 				 */
566*12720SWyllys.Ingersoll@Sun.COM 				(void) memcpy(kms_aes_ctx->data +
567*12720SWyllys.Ingersoll@Sun.COM 				    kms_aes_ctx->remain_len,
568*12720SWyllys.Ingersoll@Sun.COM 				    pEncrypted, ulEncryptedLen);
569*12720SWyllys.Ingersoll@Sun.COM 				kms_aes_ctx->remain_len += ulEncryptedLen;
570*12720SWyllys.Ingersoll@Sun.COM 			}
571*12720SWyllys.Ingersoll@Sun.COM 
572*12720SWyllys.Ingersoll@Sun.COM 			/* Set output data length to 0. */
573*12720SWyllys.Ingersoll@Sun.COM 			*pulDataLen = 0;
574*12720SWyllys.Ingersoll@Sun.COM 			return (CKR_OK);
575*12720SWyllys.Ingersoll@Sun.COM 		}
576*12720SWyllys.Ingersoll@Sun.COM 
577*12720SWyllys.Ingersoll@Sun.COM 		/* Compute the length of remaing data. */
578*12720SWyllys.Ingersoll@Sun.COM 		remain = total_len % AES_BLOCK_LEN;
579*12720SWyllys.Ingersoll@Sun.COM 
580*12720SWyllys.Ingersoll@Sun.COM 		/*
581*12720SWyllys.Ingersoll@Sun.COM 		 * Make sure that the output length is a multiple of
582*12720SWyllys.Ingersoll@Sun.COM 		 * blocksize.
583*12720SWyllys.Ingersoll@Sun.COM 		 */
584*12720SWyllys.Ingersoll@Sun.COM 		out_len = total_len - remain;
585*12720SWyllys.Ingersoll@Sun.COM 
586*12720SWyllys.Ingersoll@Sun.COM 		if (mechanism == CKM_AES_CBC_PAD) {
587*12720SWyllys.Ingersoll@Sun.COM 			/*
588*12720SWyllys.Ingersoll@Sun.COM 			 * If the input data length is a multiple of
589*12720SWyllys.Ingersoll@Sun.COM 			 * blocksize, then save the last block of input
590*12720SWyllys.Ingersoll@Sun.COM 			 * data in the remaining buffer. C_DecryptFinal
591*12720SWyllys.Ingersoll@Sun.COM 			 * will handle this last block of data.
592*12720SWyllys.Ingersoll@Sun.COM 			 */
593*12720SWyllys.Ingersoll@Sun.COM 			if (remain == 0) {
594*12720SWyllys.Ingersoll@Sun.COM 				remain = AES_BLOCK_LEN;
595*12720SWyllys.Ingersoll@Sun.COM 				out_len -= AES_BLOCK_LEN;
596*12720SWyllys.Ingersoll@Sun.COM 			}
597*12720SWyllys.Ingersoll@Sun.COM 		}
598*12720SWyllys.Ingersoll@Sun.COM 
599*12720SWyllys.Ingersoll@Sun.COM 		/*
600*12720SWyllys.Ingersoll@Sun.COM 		 * If application asks for the length of the output buffer
601*12720SWyllys.Ingersoll@Sun.COM 		 * to hold the plaintext?
602*12720SWyllys.Ingersoll@Sun.COM 		 */
603*12720SWyllys.Ingersoll@Sun.COM 		if (pData == NULL) {
604*12720SWyllys.Ingersoll@Sun.COM 			*pulDataLen = out_len;
605*12720SWyllys.Ingersoll@Sun.COM 			return (CKR_OK);
606*12720SWyllys.Ingersoll@Sun.COM 		}
607*12720SWyllys.Ingersoll@Sun.COM 
608*12720SWyllys.Ingersoll@Sun.COM 		/*
609*12720SWyllys.Ingersoll@Sun.COM 		 * Is the application-supplied buffer large enough?
610*12720SWyllys.Ingersoll@Sun.COM 		 */
611*12720SWyllys.Ingersoll@Sun.COM 		if (*pulDataLen < out_len) {
612*12720SWyllys.Ingersoll@Sun.COM 			*pulDataLen = out_len;
613*12720SWyllys.Ingersoll@Sun.COM 			return (CKR_BUFFER_TOO_SMALL);
614*12720SWyllys.Ingersoll@Sun.COM 		}
615*12720SWyllys.Ingersoll@Sun.COM 
616*12720SWyllys.Ingersoll@Sun.COM 		if (kms_aes_ctx->remain_len != 0) {
617*12720SWyllys.Ingersoll@Sun.COM 			/*
618*12720SWyllys.Ingersoll@Sun.COM 			 * Copy last remaining data and current input data
619*12720SWyllys.Ingersoll@Sun.COM 			 * to the output buffer.
620*12720SWyllys.Ingersoll@Sun.COM 			 */
621*12720SWyllys.Ingersoll@Sun.COM 			(void) memmove(pData + kms_aes_ctx->remain_len,
622*12720SWyllys.Ingersoll@Sun.COM 			    pEncrypted, out_len - kms_aes_ctx->remain_len);
623*12720SWyllys.Ingersoll@Sun.COM 			(void) memcpy(pData, kms_aes_ctx->data,
624*12720SWyllys.Ingersoll@Sun.COM 			    kms_aes_ctx->remain_len);
625*12720SWyllys.Ingersoll@Sun.COM 			bzero(kms_aes_ctx->data, kms_aes_ctx->remain_len);
626*12720SWyllys.Ingersoll@Sun.COM 
627*12720SWyllys.Ingersoll@Sun.COM 			in_buf = pData;
628*12720SWyllys.Ingersoll@Sun.COM 		} else {
629*12720SWyllys.Ingersoll@Sun.COM 			in_buf = pEncrypted;
630*12720SWyllys.Ingersoll@Sun.COM 		}
631*12720SWyllys.Ingersoll@Sun.COM 		out_buf = pData;
632*12720SWyllys.Ingersoll@Sun.COM 	}
633*12720SWyllys.Ingersoll@Sun.COM 
634*12720SWyllys.Ingersoll@Sun.COM do_decryption:
635*12720SWyllys.Ingersoll@Sun.COM 	/*
636*12720SWyllys.Ingersoll@Sun.COM 	 * Begin Decryption.
637*12720SWyllys.Ingersoll@Sun.COM 	 */
638*12720SWyllys.Ingersoll@Sun.COM 	switch (mechanism) {
639*12720SWyllys.Ingersoll@Sun.COM 	case CKM_AES_CBC:
640*12720SWyllys.Ingersoll@Sun.COM 	case CKM_AES_CBC_PAD:
641*12720SWyllys.Ingersoll@Sun.COM 	{
642*12720SWyllys.Ingersoll@Sun.COM 		crypto_data_t out;
643*12720SWyllys.Ingersoll@Sun.COM 		CK_ULONG rem_len;
644*12720SWyllys.Ingersoll@Sun.COM 		uint8_t last_block[AES_BLOCK_LEN];
645*12720SWyllys.Ingersoll@Sun.COM 
646*12720SWyllys.Ingersoll@Sun.COM 		out.cd_format = CRYPTO_DATA_RAW;
647*12720SWyllys.Ingersoll@Sun.COM 		out.cd_offset = 0;
648*12720SWyllys.Ingersoll@Sun.COM 		out.cd_length = out_len;
649*12720SWyllys.Ingersoll@Sun.COM 		out.cd_raw.iov_base = (char *)out_buf;
650*12720SWyllys.Ingersoll@Sun.COM 		out.cd_raw.iov_len = out_len;
651*12720SWyllys.Ingersoll@Sun.COM 
652*12720SWyllys.Ingersoll@Sun.COM 		/* Decrypt multiple blocks of data. */
653*12720SWyllys.Ingersoll@Sun.COM 		rc = aes_decrypt_contiguous_blocks(
654*12720SWyllys.Ingersoll@Sun.COM 		    (aes_ctx_t *)kms_aes_ctx->aes_cbc,
655*12720SWyllys.Ingersoll@Sun.COM 		    (char *)in_buf, out_len, &out);
656*12720SWyllys.Ingersoll@Sun.COM 
657*12720SWyllys.Ingersoll@Sun.COM 		if (rc != 0)
658*12720SWyllys.Ingersoll@Sun.COM 			goto decrypt_failed;
659*12720SWyllys.Ingersoll@Sun.COM 
660*12720SWyllys.Ingersoll@Sun.COM 		if ((mechanism == CKM_AES_CBC_PAD) && (!update)) {
661*12720SWyllys.Ingersoll@Sun.COM 			/* Decrypt last block containing pad bytes. */
662*12720SWyllys.Ingersoll@Sun.COM 			out.cd_offset = 0;
663*12720SWyllys.Ingersoll@Sun.COM 			out.cd_length = AES_BLOCK_LEN;
664*12720SWyllys.Ingersoll@Sun.COM 			out.cd_raw.iov_base = (char *)last_block;
665*12720SWyllys.Ingersoll@Sun.COM 			out.cd_raw.iov_len = AES_BLOCK_LEN;
666*12720SWyllys.Ingersoll@Sun.COM 
667*12720SWyllys.Ingersoll@Sun.COM 			/* Decrypt last block containing pad bytes. */
668*12720SWyllys.Ingersoll@Sun.COM 			rc = aes_decrypt_contiguous_blocks(
669*12720SWyllys.Ingersoll@Sun.COM 			    (aes_ctx_t *)kms_aes_ctx->aes_cbc,
670*12720SWyllys.Ingersoll@Sun.COM 			    (char *)in_buf + out_len, AES_BLOCK_LEN, &out);
671*12720SWyllys.Ingersoll@Sun.COM 
672*12720SWyllys.Ingersoll@Sun.COM 			if (rc != 0)
673*12720SWyllys.Ingersoll@Sun.COM 				goto decrypt_failed;
674*12720SWyllys.Ingersoll@Sun.COM 
675*12720SWyllys.Ingersoll@Sun.COM 			/*
676*12720SWyllys.Ingersoll@Sun.COM 			 * Remove padding bytes after decryption of
677*12720SWyllys.Ingersoll@Sun.COM 			 * ciphertext block to produce the original
678*12720SWyllys.Ingersoll@Sun.COM 			 * plaintext.
679*12720SWyllys.Ingersoll@Sun.COM 			 */
680*12720SWyllys.Ingersoll@Sun.COM 			rv = kms_remove_pkcs7_padding(last_block,
681*12720SWyllys.Ingersoll@Sun.COM 			    AES_BLOCK_LEN, &rem_len, AES_BLOCK_LEN);
682*12720SWyllys.Ingersoll@Sun.COM 			if (rv == CKR_OK) {
683*12720SWyllys.Ingersoll@Sun.COM 				if (rem_len != 0)
684*12720SWyllys.Ingersoll@Sun.COM 					(void) memcpy(out_buf + out_len,
685*12720SWyllys.Ingersoll@Sun.COM 					    last_block, rem_len);
686*12720SWyllys.Ingersoll@Sun.COM 				*pulDataLen = out_len + rem_len;
687*12720SWyllys.Ingersoll@Sun.COM 			} else {
688*12720SWyllys.Ingersoll@Sun.COM 				*pulDataLen = 0;
689*12720SWyllys.Ingersoll@Sun.COM 				goto cleanup;
690*12720SWyllys.Ingersoll@Sun.COM 			}
691*12720SWyllys.Ingersoll@Sun.COM 		} else {
692*12720SWyllys.Ingersoll@Sun.COM 			*pulDataLen = out_len;
693*12720SWyllys.Ingersoll@Sun.COM 		}
694*12720SWyllys.Ingersoll@Sun.COM 
695*12720SWyllys.Ingersoll@Sun.COM 		if (update) {
696*12720SWyllys.Ingersoll@Sun.COM 			/*
697*12720SWyllys.Ingersoll@Sun.COM 			 * For decrypt update, if there is remaining data,
698*12720SWyllys.Ingersoll@Sun.COM 			 * save it and its length in the context.
699*12720SWyllys.Ingersoll@Sun.COM 			 */
700*12720SWyllys.Ingersoll@Sun.COM 			if (remain != 0)
701*12720SWyllys.Ingersoll@Sun.COM 				(void) memcpy(kms_aes_ctx->data, pEncrypted +
702*12720SWyllys.Ingersoll@Sun.COM 				    (ulEncryptedLen - remain), remain);
703*12720SWyllys.Ingersoll@Sun.COM 			kms_aes_ctx->remain_len = remain;
704*12720SWyllys.Ingersoll@Sun.COM 		}
705*12720SWyllys.Ingersoll@Sun.COM 
706*12720SWyllys.Ingersoll@Sun.COM 		if (rc == 0)
707*12720SWyllys.Ingersoll@Sun.COM 			break;
708*12720SWyllys.Ingersoll@Sun.COM decrypt_failed:
709*12720SWyllys.Ingersoll@Sun.COM 		*pulDataLen = 0;
710*12720SWyllys.Ingersoll@Sun.COM 		rv = CKR_FUNCTION_FAILED;
711*12720SWyllys.Ingersoll@Sun.COM 		goto cleanup;
712*12720SWyllys.Ingersoll@Sun.COM 	}
713*12720SWyllys.Ingersoll@Sun.COM 	default:
714*12720SWyllys.Ingersoll@Sun.COM 		rv = CKR_MECHANISM_INVALID;
715*12720SWyllys.Ingersoll@Sun.COM 		goto cleanup;
716*12720SWyllys.Ingersoll@Sun.COM 	} /* end switch */
717*12720SWyllys.Ingersoll@Sun.COM 
718*12720SWyllys.Ingersoll@Sun.COM 	if (update)
719*12720SWyllys.Ingersoll@Sun.COM 		return (CKR_OK);
720*12720SWyllys.Ingersoll@Sun.COM 
721*12720SWyllys.Ingersoll@Sun.COM 	/*
722*12720SWyllys.Ingersoll@Sun.COM 	 * The following code will be executed if the caller is
723*12720SWyllys.Ingersoll@Sun.COM 	 * kms_decrypt() or an error occurred. The decryption
724*12720SWyllys.Ingersoll@Sun.COM 	 * operation will be terminated so we need to do some cleanup.
725*12720SWyllys.Ingersoll@Sun.COM 	 */
726*12720SWyllys.Ingersoll@Sun.COM cleanup:
727*12720SWyllys.Ingersoll@Sun.COM 	(void) pthread_mutex_lock(&session_p->session_mutex);
728*12720SWyllys.Ingersoll@Sun.COM 	aes_ctx = (aes_ctx_t *)kms_aes_ctx->aes_cbc;
729*12720SWyllys.Ingersoll@Sun.COM 	if (aes_ctx != NULL) {
730*12720SWyllys.Ingersoll@Sun.COM 		bzero(aes_ctx->ac_keysched, aes_ctx->ac_keysched_len);
731*12720SWyllys.Ingersoll@Sun.COM 		free(kms_aes_ctx->aes_cbc);
732*12720SWyllys.Ingersoll@Sun.COM 	}
733*12720SWyllys.Ingersoll@Sun.COM 
734*12720SWyllys.Ingersoll@Sun.COM 	bzero(kms_aes_ctx->key_sched, kms_aes_ctx->keysched_len);
735*12720SWyllys.Ingersoll@Sun.COM 	free(kms_aes_ctx->key_sched);
736*12720SWyllys.Ingersoll@Sun.COM 	free(session_p->decrypt.context);
737*12720SWyllys.Ingersoll@Sun.COM 	session_p->decrypt.context = NULL;
738*12720SWyllys.Ingersoll@Sun.COM 	(void) pthread_mutex_unlock(&session_p->session_mutex);
739*12720SWyllys.Ingersoll@Sun.COM 
740*12720SWyllys.Ingersoll@Sun.COM 	return (rv);
741*12720SWyllys.Ingersoll@Sun.COM }
742*12720SWyllys.Ingersoll@Sun.COM 
743*12720SWyllys.Ingersoll@Sun.COM 
744*12720SWyllys.Ingersoll@Sun.COM /*
745*12720SWyllys.Ingersoll@Sun.COM  * Allocate and initialize a context for AES CBC mode of operation.
746*12720SWyllys.Ingersoll@Sun.COM  */
747*12720SWyllys.Ingersoll@Sun.COM void *
aes_cbc_ctx_init(void * key_sched,size_t size,uint8_t * ivec)748*12720SWyllys.Ingersoll@Sun.COM aes_cbc_ctx_init(void *key_sched, size_t size, uint8_t *ivec)
749*12720SWyllys.Ingersoll@Sun.COM {
750*12720SWyllys.Ingersoll@Sun.COM 	aes_ctx_t *aes_ctx;
751*12720SWyllys.Ingersoll@Sun.COM 
752*12720SWyllys.Ingersoll@Sun.COM 	if ((aes_ctx = calloc(1, sizeof (aes_ctx_t))) == NULL)
753*12720SWyllys.Ingersoll@Sun.COM 		return (NULL);
754*12720SWyllys.Ingersoll@Sun.COM 
755*12720SWyllys.Ingersoll@Sun.COM 	aes_ctx->ac_keysched = key_sched;
756*12720SWyllys.Ingersoll@Sun.COM 
757*12720SWyllys.Ingersoll@Sun.COM 	(void) memcpy(&aes_ctx->ac_iv[0], ivec, AES_BLOCK_LEN);
758*12720SWyllys.Ingersoll@Sun.COM 
759*12720SWyllys.Ingersoll@Sun.COM 	aes_ctx->ac_lastp = (uint8_t *)aes_ctx->ac_iv;
760*12720SWyllys.Ingersoll@Sun.COM 	aes_ctx->ac_keysched_len = size;
761*12720SWyllys.Ingersoll@Sun.COM 	aes_ctx->ac_flags |= CBC_MODE;
762*12720SWyllys.Ingersoll@Sun.COM 
763*12720SWyllys.Ingersoll@Sun.COM 	return ((void *)aes_ctx);
764*12720SWyllys.Ingersoll@Sun.COM }
765*12720SWyllys.Ingersoll@Sun.COM 
766*12720SWyllys.Ingersoll@Sun.COM /*
767*12720SWyllys.Ingersoll@Sun.COM  * kms_encrypt_final()
768*12720SWyllys.Ingersoll@Sun.COM  *
769*12720SWyllys.Ingersoll@Sun.COM  * Arguments:
770*12720SWyllys.Ingersoll@Sun.COM  *      session_p:		pointer to kms_session_t struct
771*12720SWyllys.Ingersoll@Sun.COM  *      pLastEncryptedPart:	pointer to the last encrypted data part
772*12720SWyllys.Ingersoll@Sun.COM  *      pulLastEncryptedPartLen: pointer to the length of the last
773*12720SWyllys.Ingersoll@Sun.COM  *				encrypted data part
774*12720SWyllys.Ingersoll@Sun.COM  *
775*12720SWyllys.Ingersoll@Sun.COM  * Description:
776*12720SWyllys.Ingersoll@Sun.COM  *      called by C_EncryptFinal().
777*12720SWyllys.Ingersoll@Sun.COM  *
778*12720SWyllys.Ingersoll@Sun.COM  * Returns:
779*12720SWyllys.Ingersoll@Sun.COM  *	CKR_OK: success
780*12720SWyllys.Ingersoll@Sun.COM  *	CKR_FUNCTION_FAILED: encrypt final function failed
781*12720SWyllys.Ingersoll@Sun.COM  *	CKR_DATA_LEN_RANGE: remaining buffer contains bad length
782*12720SWyllys.Ingersoll@Sun.COM  */
783*12720SWyllys.Ingersoll@Sun.COM CK_RV
kms_aes_encrypt_final(kms_session_t * session_p,CK_BYTE_PTR pLastEncryptedPart,CK_ULONG_PTR pulLastEncryptedPartLen)784*12720SWyllys.Ingersoll@Sun.COM kms_aes_encrypt_final(kms_session_t *session_p, CK_BYTE_PTR pLastEncryptedPart,
785*12720SWyllys.Ingersoll@Sun.COM 	CK_ULONG_PTR pulLastEncryptedPartLen)
786*12720SWyllys.Ingersoll@Sun.COM {
787*12720SWyllys.Ingersoll@Sun.COM 
788*12720SWyllys.Ingersoll@Sun.COM 	CK_MECHANISM_TYPE mechanism = session_p->encrypt.mech.mechanism;
789*12720SWyllys.Ingersoll@Sun.COM 	CK_ULONG out_len;
790*12720SWyllys.Ingersoll@Sun.COM 	CK_RV rv = CKR_OK;
791*12720SWyllys.Ingersoll@Sun.COM 	int rc;
792*12720SWyllys.Ingersoll@Sun.COM 
793*12720SWyllys.Ingersoll@Sun.COM 	(void) pthread_mutex_lock(&session_p->session_mutex);
794*12720SWyllys.Ingersoll@Sun.COM 
795*12720SWyllys.Ingersoll@Sun.COM 	if (session_p->encrypt.context == NULL) {
796*12720SWyllys.Ingersoll@Sun.COM 		rv = CKR_OPERATION_NOT_INITIALIZED;
797*12720SWyllys.Ingersoll@Sun.COM 		*pulLastEncryptedPartLen = 0;
798*12720SWyllys.Ingersoll@Sun.COM 
799*12720SWyllys.Ingersoll@Sun.COM 	}
800*12720SWyllys.Ingersoll@Sun.COM 	if (mechanism == CKM_AES_CBC_PAD) {
801*12720SWyllys.Ingersoll@Sun.COM 		kms_aes_ctx_t *aes_ctx;
802*12720SWyllys.Ingersoll@Sun.COM 
803*12720SWyllys.Ingersoll@Sun.COM 		aes_ctx = (kms_aes_ctx_t *)session_p->encrypt.context;
804*12720SWyllys.Ingersoll@Sun.COM 		/*
805*12720SWyllys.Ingersoll@Sun.COM 		 * For CKM_AES_CBC_PAD, compute output length with
806*12720SWyllys.Ingersoll@Sun.COM 		 * padding. If the remaining buffer has one block
807*12720SWyllys.Ingersoll@Sun.COM 		 * of data, then output length will be two blocksize of
808*12720SWyllys.Ingersoll@Sun.COM 		 * ciphertext. If the remaining buffer has less than
809*12720SWyllys.Ingersoll@Sun.COM 		 * one block of data, then output length will be
810*12720SWyllys.Ingersoll@Sun.COM 		 * one blocksize.
811*12720SWyllys.Ingersoll@Sun.COM 		 */
812*12720SWyllys.Ingersoll@Sun.COM 		if (aes_ctx->remain_len == AES_BLOCK_LEN)
813*12720SWyllys.Ingersoll@Sun.COM 			out_len = 2 * AES_BLOCK_LEN;
814*12720SWyllys.Ingersoll@Sun.COM 		else
815*12720SWyllys.Ingersoll@Sun.COM 			out_len = AES_BLOCK_LEN;
816*12720SWyllys.Ingersoll@Sun.COM 
817*12720SWyllys.Ingersoll@Sun.COM 		if (pLastEncryptedPart == NULL) {
818*12720SWyllys.Ingersoll@Sun.COM 			/*
819*12720SWyllys.Ingersoll@Sun.COM 			 * Application asks for the length of the output
820*12720SWyllys.Ingersoll@Sun.COM 			 * buffer to hold the ciphertext.
821*12720SWyllys.Ingersoll@Sun.COM 			 */
822*12720SWyllys.Ingersoll@Sun.COM 			*pulLastEncryptedPartLen = out_len;
823*12720SWyllys.Ingersoll@Sun.COM 			goto clean1;
824*12720SWyllys.Ingersoll@Sun.COM 		} else {
825*12720SWyllys.Ingersoll@Sun.COM 			crypto_data_t out;
826*12720SWyllys.Ingersoll@Sun.COM 
827*12720SWyllys.Ingersoll@Sun.COM 			/* Copy remaining data to the output buffer. */
828*12720SWyllys.Ingersoll@Sun.COM 			(void) memcpy(pLastEncryptedPart, aes_ctx->data,
829*12720SWyllys.Ingersoll@Sun.COM 			    aes_ctx->remain_len);
830*12720SWyllys.Ingersoll@Sun.COM 
831*12720SWyllys.Ingersoll@Sun.COM 			/*
832*12720SWyllys.Ingersoll@Sun.COM 			 * Add padding bytes prior to encrypt final.
833*12720SWyllys.Ingersoll@Sun.COM 			 */
834*12720SWyllys.Ingersoll@Sun.COM 			kms_add_pkcs7_padding(pLastEncryptedPart +
835*12720SWyllys.Ingersoll@Sun.COM 			    aes_ctx->remain_len, AES_BLOCK_LEN,
836*12720SWyllys.Ingersoll@Sun.COM 			    aes_ctx->remain_len);
837*12720SWyllys.Ingersoll@Sun.COM 
838*12720SWyllys.Ingersoll@Sun.COM 			out.cd_format = CRYPTO_DATA_RAW;
839*12720SWyllys.Ingersoll@Sun.COM 			out.cd_offset = 0;
840*12720SWyllys.Ingersoll@Sun.COM 			out.cd_length = out_len;
841*12720SWyllys.Ingersoll@Sun.COM 			out.cd_raw.iov_base = (char *)pLastEncryptedPart;
842*12720SWyllys.Ingersoll@Sun.COM 			out.cd_raw.iov_len = out_len;
843*12720SWyllys.Ingersoll@Sun.COM 
844*12720SWyllys.Ingersoll@Sun.COM 			/* Encrypt multiple blocks of data. */
845*12720SWyllys.Ingersoll@Sun.COM 			rc = aes_encrypt_contiguous_blocks(
846*12720SWyllys.Ingersoll@Sun.COM 			    (aes_ctx_t *)aes_ctx->aes_cbc,
847*12720SWyllys.Ingersoll@Sun.COM 			    (char *)pLastEncryptedPart, out_len, &out);
848*12720SWyllys.Ingersoll@Sun.COM 
849*12720SWyllys.Ingersoll@Sun.COM 			if (rc == 0) {
850*12720SWyllys.Ingersoll@Sun.COM 				*pulLastEncryptedPartLen = out_len;
851*12720SWyllys.Ingersoll@Sun.COM 			} else {
852*12720SWyllys.Ingersoll@Sun.COM 				*pulLastEncryptedPartLen = 0;
853*12720SWyllys.Ingersoll@Sun.COM 				rv = CKR_FUNCTION_FAILED;
854*12720SWyllys.Ingersoll@Sun.COM 			}
855*12720SWyllys.Ingersoll@Sun.COM 
856*12720SWyllys.Ingersoll@Sun.COM 			/* Cleanup memory space. */
857*12720SWyllys.Ingersoll@Sun.COM 			free(aes_ctx->aes_cbc);
858*12720SWyllys.Ingersoll@Sun.COM 			bzero(aes_ctx->key_sched,
859*12720SWyllys.Ingersoll@Sun.COM 			    aes_ctx->keysched_len);
860*12720SWyllys.Ingersoll@Sun.COM 			free(aes_ctx->key_sched);
861*12720SWyllys.Ingersoll@Sun.COM 		}
862*12720SWyllys.Ingersoll@Sun.COM 	} else if (mechanism == CKM_AES_CBC) {
863*12720SWyllys.Ingersoll@Sun.COM 		kms_aes_ctx_t *aes_ctx;
864*12720SWyllys.Ingersoll@Sun.COM 
865*12720SWyllys.Ingersoll@Sun.COM 		aes_ctx = (kms_aes_ctx_t *)session_p->encrypt.context;
866*12720SWyllys.Ingersoll@Sun.COM 		/*
867*12720SWyllys.Ingersoll@Sun.COM 		 * CKM_AES_CBC and CKM_AES_ECB does not do any padding,
868*12720SWyllys.Ingersoll@Sun.COM 		 * so when the final is called, the remaining buffer
869*12720SWyllys.Ingersoll@Sun.COM 		 * should not contain any more data.
870*12720SWyllys.Ingersoll@Sun.COM 		 */
871*12720SWyllys.Ingersoll@Sun.COM 		*pulLastEncryptedPartLen = 0;
872*12720SWyllys.Ingersoll@Sun.COM 		if (aes_ctx->remain_len != 0) {
873*12720SWyllys.Ingersoll@Sun.COM 			rv = CKR_DATA_LEN_RANGE;
874*12720SWyllys.Ingersoll@Sun.COM 		} else {
875*12720SWyllys.Ingersoll@Sun.COM 			if (pLastEncryptedPart == NULL)
876*12720SWyllys.Ingersoll@Sun.COM 				goto clean1;
877*12720SWyllys.Ingersoll@Sun.COM 		}
878*12720SWyllys.Ingersoll@Sun.COM 
879*12720SWyllys.Ingersoll@Sun.COM 		/* Cleanup memory space. */
880*12720SWyllys.Ingersoll@Sun.COM 		free(aes_ctx->aes_cbc);
881*12720SWyllys.Ingersoll@Sun.COM 		bzero(aes_ctx->key_sched, aes_ctx->keysched_len);
882*12720SWyllys.Ingersoll@Sun.COM 		free(aes_ctx->key_sched);
883*12720SWyllys.Ingersoll@Sun.COM 	} else {
884*12720SWyllys.Ingersoll@Sun.COM 		rv = CKR_MECHANISM_INVALID;
885*12720SWyllys.Ingersoll@Sun.COM 	}
886*12720SWyllys.Ingersoll@Sun.COM 
887*12720SWyllys.Ingersoll@Sun.COM 	free(session_p->encrypt.context);
888*12720SWyllys.Ingersoll@Sun.COM 	session_p->encrypt.context = NULL;
889*12720SWyllys.Ingersoll@Sun.COM clean1:
890*12720SWyllys.Ingersoll@Sun.COM 	(void) pthread_mutex_unlock(&session_p->session_mutex);
891*12720SWyllys.Ingersoll@Sun.COM 	return (rv);
892*12720SWyllys.Ingersoll@Sun.COM }
893*12720SWyllys.Ingersoll@Sun.COM 
894*12720SWyllys.Ingersoll@Sun.COM /*
895*12720SWyllys.Ingersoll@Sun.COM  * kms_decrypt_final()
896*12720SWyllys.Ingersoll@Sun.COM  *
897*12720SWyllys.Ingersoll@Sun.COM  * Arguments:
898*12720SWyllys.Ingersoll@Sun.COM  *      session_p:	pointer to kms_session_t struct
899*12720SWyllys.Ingersoll@Sun.COM  *      pLastPart:	pointer to the last recovered data part
900*12720SWyllys.Ingersoll@Sun.COM  *      pulLastPartLen:	pointer to the length of the last recovered data part
901*12720SWyllys.Ingersoll@Sun.COM  *
902*12720SWyllys.Ingersoll@Sun.COM  * Description:
903*12720SWyllys.Ingersoll@Sun.COM  *      called by C_DecryptFinal().
904*12720SWyllys.Ingersoll@Sun.COM  *
905*12720SWyllys.Ingersoll@Sun.COM  * Returns:
906*12720SWyllys.Ingersoll@Sun.COM  *	CKR_OK: success
907*12720SWyllys.Ingersoll@Sun.COM  *	CKR_FUNCTION_FAILED: decrypt final function failed
908*12720SWyllys.Ingersoll@Sun.COM  *	CKR_ENCRYPTED_DATA_LEN_RANGE: remaining buffer contains bad length
909*12720SWyllys.Ingersoll@Sun.COM  */
910*12720SWyllys.Ingersoll@Sun.COM CK_RV
kms_aes_decrypt_final(kms_session_t * session_p,CK_BYTE_PTR pLastPart,CK_ULONG_PTR pulLastPartLen)911*12720SWyllys.Ingersoll@Sun.COM kms_aes_decrypt_final(kms_session_t *session_p, CK_BYTE_PTR pLastPart,
912*12720SWyllys.Ingersoll@Sun.COM 	CK_ULONG_PTR pulLastPartLen)
913*12720SWyllys.Ingersoll@Sun.COM {
914*12720SWyllys.Ingersoll@Sun.COM 
915*12720SWyllys.Ingersoll@Sun.COM 	CK_MECHANISM_TYPE mechanism = session_p->decrypt.mech.mechanism;
916*12720SWyllys.Ingersoll@Sun.COM 	CK_ULONG out_len;
917*12720SWyllys.Ingersoll@Sun.COM 	CK_RV rv = CKR_OK;
918*12720SWyllys.Ingersoll@Sun.COM 	int rc;
919*12720SWyllys.Ingersoll@Sun.COM 
920*12720SWyllys.Ingersoll@Sun.COM 	(void) pthread_mutex_lock(&session_p->session_mutex);
921*12720SWyllys.Ingersoll@Sun.COM 
922*12720SWyllys.Ingersoll@Sun.COM 	if (session_p->decrypt.context == NULL) {
923*12720SWyllys.Ingersoll@Sun.COM 		rv = CKR_OPERATION_NOT_INITIALIZED;
924*12720SWyllys.Ingersoll@Sun.COM 		*pulLastPartLen = 0;
925*12720SWyllys.Ingersoll@Sun.COM 		goto clean2;
926*12720SWyllys.Ingersoll@Sun.COM 	}
927*12720SWyllys.Ingersoll@Sun.COM 	switch (mechanism) {
928*12720SWyllys.Ingersoll@Sun.COM 
929*12720SWyllys.Ingersoll@Sun.COM 	case CKM_AES_CBC_PAD:
930*12720SWyllys.Ingersoll@Sun.COM 	{
931*12720SWyllys.Ingersoll@Sun.COM 		kms_aes_ctx_t *kms_aes_ctx;
932*12720SWyllys.Ingersoll@Sun.COM 		kms_aes_ctx = (kms_aes_ctx_t *)session_p->decrypt.context;
933*12720SWyllys.Ingersoll@Sun.COM 
934*12720SWyllys.Ingersoll@Sun.COM 		/*
935*12720SWyllys.Ingersoll@Sun.COM 		 * We should have only one block of data left in the
936*12720SWyllys.Ingersoll@Sun.COM 		 * remaining buffer.
937*12720SWyllys.Ingersoll@Sun.COM 		 */
938*12720SWyllys.Ingersoll@Sun.COM 		if (kms_aes_ctx->remain_len != AES_BLOCK_LEN) {
939*12720SWyllys.Ingersoll@Sun.COM 			*pulLastPartLen = 0;
940*12720SWyllys.Ingersoll@Sun.COM 			rv = CKR_ENCRYPTED_DATA_LEN_RANGE;
941*12720SWyllys.Ingersoll@Sun.COM 			/* Cleanup memory space. */
942*12720SWyllys.Ingersoll@Sun.COM 			free(kms_aes_ctx->aes_cbc);
943*12720SWyllys.Ingersoll@Sun.COM 			bzero(kms_aes_ctx->key_sched,
944*12720SWyllys.Ingersoll@Sun.COM 			    kms_aes_ctx->keysched_len);
945*12720SWyllys.Ingersoll@Sun.COM 			free(kms_aes_ctx->key_sched);
946*12720SWyllys.Ingersoll@Sun.COM 
947*12720SWyllys.Ingersoll@Sun.COM 			goto clean1;
948*12720SWyllys.Ingersoll@Sun.COM 		}
949*12720SWyllys.Ingersoll@Sun.COM 
950*12720SWyllys.Ingersoll@Sun.COM 		out_len = AES_BLOCK_LEN;
951*12720SWyllys.Ingersoll@Sun.COM 
952*12720SWyllys.Ingersoll@Sun.COM 		/*
953*12720SWyllys.Ingersoll@Sun.COM 		 * If application asks for the length of the output buffer
954*12720SWyllys.Ingersoll@Sun.COM 		 * to hold the plaintext?
955*12720SWyllys.Ingersoll@Sun.COM 		 */
956*12720SWyllys.Ingersoll@Sun.COM 		if (pLastPart == NULL) {
957*12720SWyllys.Ingersoll@Sun.COM 			*pulLastPartLen = out_len;
958*12720SWyllys.Ingersoll@Sun.COM 			rv = CKR_OK;
959*12720SWyllys.Ingersoll@Sun.COM 			goto clean2;
960*12720SWyllys.Ingersoll@Sun.COM 		} else {
961*12720SWyllys.Ingersoll@Sun.COM 			crypto_data_t out;
962*12720SWyllys.Ingersoll@Sun.COM 
963*12720SWyllys.Ingersoll@Sun.COM 			/* Copy remaining data to the output buffer. */
964*12720SWyllys.Ingersoll@Sun.COM 			(void) memcpy(pLastPart, kms_aes_ctx->data,
965*12720SWyllys.Ingersoll@Sun.COM 			    AES_BLOCK_LEN);
966*12720SWyllys.Ingersoll@Sun.COM 
967*12720SWyllys.Ingersoll@Sun.COM 			out.cd_format = CRYPTO_DATA_RAW;
968*12720SWyllys.Ingersoll@Sun.COM 			out.cd_offset = 0;
969*12720SWyllys.Ingersoll@Sun.COM 			out.cd_length = AES_BLOCK_LEN;
970*12720SWyllys.Ingersoll@Sun.COM 			out.cd_raw.iov_base = (char *)pLastPart;
971*12720SWyllys.Ingersoll@Sun.COM 			out.cd_raw.iov_len = AES_BLOCK_LEN;
972*12720SWyllys.Ingersoll@Sun.COM 
973*12720SWyllys.Ingersoll@Sun.COM 			/* Decrypt final block of data. */
974*12720SWyllys.Ingersoll@Sun.COM 			rc = aes_decrypt_contiguous_blocks(
975*12720SWyllys.Ingersoll@Sun.COM 			    (aes_ctx_t *)kms_aes_ctx->aes_cbc,
976*12720SWyllys.Ingersoll@Sun.COM 			    (char *)pLastPart, AES_BLOCK_LEN, &out);
977*12720SWyllys.Ingersoll@Sun.COM 
978*12720SWyllys.Ingersoll@Sun.COM 			if (rc == 0) {
979*12720SWyllys.Ingersoll@Sun.COM 				/*
980*12720SWyllys.Ingersoll@Sun.COM 				 * Remove padding bytes after decryption of
981*12720SWyllys.Ingersoll@Sun.COM 				 * ciphertext block to produce the original
982*12720SWyllys.Ingersoll@Sun.COM 				 * plaintext.
983*12720SWyllys.Ingersoll@Sun.COM 				 */
984*12720SWyllys.Ingersoll@Sun.COM 				rv = kms_remove_pkcs7_padding(pLastPart,
985*12720SWyllys.Ingersoll@Sun.COM 				    AES_BLOCK_LEN, &out_len, AES_BLOCK_LEN);
986*12720SWyllys.Ingersoll@Sun.COM 				if (rv != CKR_OK)
987*12720SWyllys.Ingersoll@Sun.COM 					*pulLastPartLen = 0;
988*12720SWyllys.Ingersoll@Sun.COM 				else
989*12720SWyllys.Ingersoll@Sun.COM 					*pulLastPartLen = out_len;
990*12720SWyllys.Ingersoll@Sun.COM 			} else {
991*12720SWyllys.Ingersoll@Sun.COM 				*pulLastPartLen = 0;
992*12720SWyllys.Ingersoll@Sun.COM 				rv = CKR_FUNCTION_FAILED;
993*12720SWyllys.Ingersoll@Sun.COM 			}
994*12720SWyllys.Ingersoll@Sun.COM 
995*12720SWyllys.Ingersoll@Sun.COM 			/* Cleanup memory space. */
996*12720SWyllys.Ingersoll@Sun.COM 			free(kms_aes_ctx->aes_cbc);
997*12720SWyllys.Ingersoll@Sun.COM 			bzero(kms_aes_ctx->key_sched,
998*12720SWyllys.Ingersoll@Sun.COM 			    kms_aes_ctx->keysched_len);
999*12720SWyllys.Ingersoll@Sun.COM 			free(kms_aes_ctx->key_sched);
1000*12720SWyllys.Ingersoll@Sun.COM 
1001*12720SWyllys.Ingersoll@Sun.COM 		}
1002*12720SWyllys.Ingersoll@Sun.COM 
1003*12720SWyllys.Ingersoll@Sun.COM 		break;
1004*12720SWyllys.Ingersoll@Sun.COM 	}
1005*12720SWyllys.Ingersoll@Sun.COM 
1006*12720SWyllys.Ingersoll@Sun.COM 	case CKM_AES_CBC:
1007*12720SWyllys.Ingersoll@Sun.COM 	{
1008*12720SWyllys.Ingersoll@Sun.COM 		kms_aes_ctx_t *kms_aes_ctx;
1009*12720SWyllys.Ingersoll@Sun.COM 
1010*12720SWyllys.Ingersoll@Sun.COM 		kms_aes_ctx = (kms_aes_ctx_t *)session_p->decrypt.context;
1011*12720SWyllys.Ingersoll@Sun.COM 		/*
1012*12720SWyllys.Ingersoll@Sun.COM 		 * CKM_AES_CBC and CKM_AES_ECB does not do any padding,
1013*12720SWyllys.Ingersoll@Sun.COM 		 * so when the final is called, the remaining buffer
1014*12720SWyllys.Ingersoll@Sun.COM 		 * should not contain any more data.
1015*12720SWyllys.Ingersoll@Sun.COM 		 */
1016*12720SWyllys.Ingersoll@Sun.COM 		*pulLastPartLen = 0;
1017*12720SWyllys.Ingersoll@Sun.COM 		if (kms_aes_ctx->remain_len != 0) {
1018*12720SWyllys.Ingersoll@Sun.COM 			rv = CKR_ENCRYPTED_DATA_LEN_RANGE;
1019*12720SWyllys.Ingersoll@Sun.COM 		} else {
1020*12720SWyllys.Ingersoll@Sun.COM 			if (pLastPart == NULL)
1021*12720SWyllys.Ingersoll@Sun.COM 				goto clean2;
1022*12720SWyllys.Ingersoll@Sun.COM 		}
1023*12720SWyllys.Ingersoll@Sun.COM 
1024*12720SWyllys.Ingersoll@Sun.COM 		/* Cleanup memory space. */
1025*12720SWyllys.Ingersoll@Sun.COM 		free(kms_aes_ctx->aes_cbc);
1026*12720SWyllys.Ingersoll@Sun.COM 		bzero(kms_aes_ctx->key_sched, kms_aes_ctx->keysched_len);
1027*12720SWyllys.Ingersoll@Sun.COM 		free(kms_aes_ctx->key_sched);
1028*12720SWyllys.Ingersoll@Sun.COM 
1029*12720SWyllys.Ingersoll@Sun.COM 		break;
1030*12720SWyllys.Ingersoll@Sun.COM 	}
1031*12720SWyllys.Ingersoll@Sun.COM 	default:
1032*12720SWyllys.Ingersoll@Sun.COM 		/* PKCS11: The mechanism only supports single-part operation. */
1033*12720SWyllys.Ingersoll@Sun.COM 		rv = CKR_MECHANISM_INVALID;
1034*12720SWyllys.Ingersoll@Sun.COM 		break;
1035*12720SWyllys.Ingersoll@Sun.COM 	}
1036*12720SWyllys.Ingersoll@Sun.COM 
1037*12720SWyllys.Ingersoll@Sun.COM clean1:
1038*12720SWyllys.Ingersoll@Sun.COM 	free(session_p->decrypt.context);
1039*12720SWyllys.Ingersoll@Sun.COM 	session_p->decrypt.context = NULL;
1040*12720SWyllys.Ingersoll@Sun.COM 
1041*12720SWyllys.Ingersoll@Sun.COM clean2:
1042*12720SWyllys.Ingersoll@Sun.COM 	(void) pthread_mutex_unlock(&session_p->session_mutex);
1043*12720SWyllys.Ingersoll@Sun.COM 
1044*12720SWyllys.Ingersoll@Sun.COM 	return (rv);
1045*12720SWyllys.Ingersoll@Sun.COM 
1046*12720SWyllys.Ingersoll@Sun.COM }
1047