xref: /titanic_51/usr/src/lib/pkcs11/pkcs11_softtoken/common/softBlowfishCrypt.c (revision 16239bc82c111618343e0a5b1a70e0fc702d00e0)
1f66d273dSizick /*
24c21f043Sizick  * CDDL HEADER START
34c21f043Sizick  *
44c21f043Sizick  * The contents of this file are subject to the terms of the
54c21f043Sizick  * Common Development and Distribution License (the "License").
64c21f043Sizick  * You may not use this file except in compliance with the License.
74c21f043Sizick  *
84c21f043Sizick  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
94c21f043Sizick  * or http://www.opensolaris.org/os/licensing.
104c21f043Sizick  * See the License for the specific language governing permissions
114c21f043Sizick  * and limitations under the License.
124c21f043Sizick  *
134c21f043Sizick  * When distributing Covered Code, include this CDDL HEADER in each
144c21f043Sizick  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
154c21f043Sizick  * If applicable, add the following below this CDDL HEADER, with the
164c21f043Sizick  * fields enclosed by brackets "[]" replaced with your own identifying
174c21f043Sizick  * information: Portions Copyright [yyyy] [name of copyright owner]
184c21f043Sizick  *
194c21f043Sizick  * CDDL HEADER END
204c21f043Sizick  */
214c21f043Sizick /*
229627968bSmcpowers  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23f66d273dSizick  * Use is subject to license terms.
24f66d273dSizick  */
25f66d273dSizick 
26f66d273dSizick #include <pthread.h>
27f66d273dSizick #include <stdlib.h>
28f66d273dSizick #include <string.h>
29f66d273dSizick #include <strings.h>
30f66d273dSizick #include <sys/types.h>
31f66d273dSizick #include <security/cryptoki.h>
32f66d273dSizick #include "softSession.h"
33f66d273dSizick #include "softObject.h"
34f66d273dSizick #include "softCrypt.h"
3523c57df7Smcpowers #include <blowfish_impl.h>
36f66d273dSizick 
37f66d273dSizick CK_RV
38f66d273dSizick soft_blowfish_crypt_init_common(soft_session_t *session_p,
39f66d273dSizick     CK_MECHANISM_PTR pMechanism, soft_object_t *key_p, boolean_t encrypt) {
40f66d273dSizick 
41f66d273dSizick 	size_t size;
42f66d273dSizick 	soft_blowfish_ctx_t *soft_blowfish_ctx;
43f66d273dSizick 
44f66d273dSizick 	soft_blowfish_ctx = calloc(1, sizeof (soft_blowfish_ctx_t));
45f66d273dSizick 	if (soft_blowfish_ctx == NULL) {
46f66d273dSizick 		return (CKR_HOST_MEMORY);
47f66d273dSizick 	}
48f66d273dSizick 
49f66d273dSizick 	soft_blowfish_ctx->key_sched = blowfish_alloc_keysched(&size, 0);
50f66d273dSizick 
51f66d273dSizick 	if (soft_blowfish_ctx->key_sched == NULL) {
52f66d273dSizick 		free(soft_blowfish_ctx);
53f66d273dSizick 		return (CKR_HOST_MEMORY);
54f66d273dSizick 	}
55f66d273dSizick 
56f66d273dSizick 	soft_blowfish_ctx->keysched_len = size;
57f66d273dSizick 
58f66d273dSizick 	(void) pthread_mutex_lock(&session_p->session_mutex);
59f66d273dSizick 	if (encrypt) {
60f66d273dSizick 		/* Called by C_EncryptInit */
61f66d273dSizick 		session_p->encrypt.context = soft_blowfish_ctx;
62f66d273dSizick 		session_p->encrypt.mech.mechanism = pMechanism->mechanism;
63f66d273dSizick 	} else {
64f66d273dSizick 		/* Called by C_DecryptInit */
65f66d273dSizick 		session_p->decrypt.context = soft_blowfish_ctx;
66f66d273dSizick 		session_p->decrypt.mech.mechanism = pMechanism->mechanism;
67f66d273dSizick 	}
68f66d273dSizick 	(void) pthread_mutex_unlock(&session_p->session_mutex);
69f66d273dSizick 
70f66d273dSizick 	/*
71f66d273dSizick 	 * If this is a non-sensitive key and it does NOT have
72f66d273dSizick 	 * a key schedule yet, then allocate one and expand it.
73f66d273dSizick 	 * Otherwise, if it's a non-sensitive key, and it DOES have
74f66d273dSizick 	 * a key schedule already attached to it, just copy the
75f66d273dSizick 	 * pre-expanded schedule to the context and avoid the
76f66d273dSizick 	 * extra key schedule expansion operation.
77f66d273dSizick 	 */
78f66d273dSizick 	if (!(key_p->bool_attr_mask & SENSITIVE_BOOL_ON)) {
799627968bSmcpowers 		if (OBJ_KEY_SCHED(key_p) == NULL) {
80f66d273dSizick 			void *ks;
819627968bSmcpowers 
829627968bSmcpowers 			(void) pthread_mutex_lock(&key_p->object_mutex);
839627968bSmcpowers 			if (OBJ_KEY_SCHED(key_p) == NULL) {
84f66d273dSizick 				ks = blowfish_alloc_keysched(&size, 0);
85f66d273dSizick 				if (ks == NULL) {
869627968bSmcpowers 					(void) pthread_mutex_unlock(
879627968bSmcpowers 					    &key_p->object_mutex);
88f66d273dSizick 					free(soft_blowfish_ctx);
89f66d273dSizick 					return (CKR_HOST_MEMORY);
90f66d273dSizick 				}
91f66d273dSizick 
92f66d273dSizick 				blowfish_init_keysched(OBJ_SEC_VALUE(key_p),
939627968bSmcpowers 				    (OBJ_SEC_VALUE_LEN(key_p) * 8), ks);
949627968bSmcpowers 
959627968bSmcpowers 				OBJ_KEY_SCHED_LEN(key_p) = size;
969627968bSmcpowers 				OBJ_KEY_SCHED(key_p) = ks;
979627968bSmcpowers 			}
989627968bSmcpowers 			(void) pthread_mutex_unlock(&key_p->object_mutex);
99f66d273dSizick 		}
100f66d273dSizick 		(void) memcpy(soft_blowfish_ctx->key_sched,
101f66d273dSizick 		    OBJ_KEY_SCHED(key_p), OBJ_KEY_SCHED_LEN(key_p));
102f66d273dSizick 		soft_blowfish_ctx->keysched_len = OBJ_KEY_SCHED_LEN(key_p);
103f66d273dSizick 
104f66d273dSizick 	} else {
105f66d273dSizick 		/*
106f66d273dSizick 		 * Initialize key schedule for Blowfish.
107f66d273dSizick 		 * blowfish_init_keysched() requires key length in bits.
108f66d273dSizick 		 */
109f66d273dSizick 		blowfish_init_keysched(OBJ_SEC_VALUE(key_p),
110f66d273dSizick 		    (OBJ_SEC_VALUE_LEN(key_p) * 8),
111f66d273dSizick 		    soft_blowfish_ctx->key_sched);
112f66d273dSizick 	}
113f66d273dSizick 	return (CKR_OK);
114f66d273dSizick }
115f66d273dSizick 
116f66d273dSizick 
117f66d273dSizick /*
118f66d273dSizick  * soft_blowfish_encrypt_common()
119f66d273dSizick  *
120f66d273dSizick  * Arguments:
121f66d273dSizick  *      session_p:	pointer to soft_session_t struct
122f66d273dSizick  *	pData:		pointer to the input data to be encrypted
123f66d273dSizick  *	ulDataLen:	length of the input data
124f66d273dSizick  *	pEncrypted:	pointer to the output data after encryption
125f66d273dSizick  *	pulEncryptedLen: pointer to the length of the output data
126f66d273dSizick  *	update:		boolean flag indicates caller is soft_encrypt
127f66d273dSizick  *			or soft_encrypt_update
128f66d273dSizick  *
129f66d273dSizick  * Description:
130f66d273dSizick  *      This function calls the corresponding encrypt routine based
131f66d273dSizick  *	on the mechanism.
132f66d273dSizick  *
133f66d273dSizick  * Returns:
134f66d273dSizick  *      CKR_OK: success
135f66d273dSizick  *      CKR_BUFFER_TOO_SMALL: the output buffer provided by application
136f66d273dSizick  *			      is too small
137f66d273dSizick  *	CKR_FUNCTION_FAILED: encrypt function failed
138f66d273dSizick  *	CKR_DATA_LEN_RANGE: the input data is not a multiple of blocksize
139f66d273dSizick  */
140f66d273dSizick CK_RV
141f66d273dSizick soft_blowfish_encrypt_common(soft_session_t *session_p, CK_BYTE_PTR pData,
142f66d273dSizick     CK_ULONG ulDataLen, CK_BYTE_PTR pEncrypted, CK_ULONG_PTR pulEncryptedLen,
143f66d273dSizick     boolean_t update) {
144f66d273dSizick 
145f66d273dSizick 	int rc = 0;
146f66d273dSizick 	CK_RV rv = CKR_OK;
147f66d273dSizick 	soft_blowfish_ctx_t *soft_blowfish_ctx =
148f66d273dSizick 	    (soft_blowfish_ctx_t *)session_p->encrypt.context;
149f66d273dSizick 	blowfish_ctx_t *blowfish_ctx;
150f66d273dSizick 	CK_BYTE *in_buf = NULL;
151f66d273dSizick 	CK_BYTE *out_buf = NULL;
152f66d273dSizick 	CK_ULONG out_len;
153f66d273dSizick 	CK_ULONG total_len;
154f66d273dSizick 	CK_ULONG remain;
155f66d273dSizick 	crypto_data_t out;
156f66d273dSizick 
157f66d273dSizick 	/*
158f66d273dSizick 	 * Blowfish only takes input length that is a multiple of blocksize
159f66d273dSizick 	 * for C_Encrypt function with the mechanism CKM_BLOWFISH_CBC.
160f66d273dSizick 	 *
161f66d273dSizick 	 */
162f66d273dSizick 	if (!update) {
163f66d273dSizick 		if ((ulDataLen % BLOWFISH_BLOCK_LEN) != 0) {
164f66d273dSizick 			rv = CKR_DATA_LEN_RANGE;
165f66d273dSizick 			goto cleanup;
166f66d273dSizick 		}
167f66d273dSizick 
168f66d273dSizick 		out_len = ulDataLen;
169f66d273dSizick 		/*
170f66d273dSizick 		 * If application asks for the length of the output buffer
171f66d273dSizick 		 * to hold the ciphertext?
172f66d273dSizick 		 */
173f66d273dSizick 		if (pEncrypted == NULL) {
174f66d273dSizick 			*pulEncryptedLen = out_len;
175f66d273dSizick 			return (CKR_OK);
176f66d273dSizick 		}
177f66d273dSizick 
178f66d273dSizick 		/* Is the application-supplied buffer large enough? */
179f66d273dSizick 		if (*pulEncryptedLen < out_len) {
180f66d273dSizick 			*pulEncryptedLen = out_len;
181f66d273dSizick 			return (CKR_BUFFER_TOO_SMALL);
182f66d273dSizick 		}
183f66d273dSizick 
184f66d273dSizick 		in_buf = pData;
185f66d273dSizick 		out_buf = pEncrypted;
186f66d273dSizick 	} else {
187f66d273dSizick 		/*
188f66d273dSizick 		 * Called by C_EncryptUpdate
189f66d273dSizick 		 *
190f66d273dSizick 		 * Add the lengths of last remaining data and current
191f66d273dSizick 		 * plaintext together to get the total input length.
192f66d273dSizick 		 */
193f66d273dSizick 		total_len = soft_blowfish_ctx->remain_len + ulDataLen;
194f66d273dSizick 
195f66d273dSizick 		/*
196f66d273dSizick 		 * If the total input length is less than one blocksize,
197f66d273dSizick 		 * we will need to delay encryption until when more data
198f66d273dSizick 		 * comes in next C_EncryptUpdate or when C_EncryptFinal
199f66d273dSizick 		 * is called.
200f66d273dSizick 		 */
201f66d273dSizick 		if (total_len < BLOWFISH_BLOCK_LEN) {
202f66d273dSizick 			if (pEncrypted != NULL) {
203f66d273dSizick 				/*
204f66d273dSizick 				 * Save input data and its length in
205f66d273dSizick 				 * the remaining buffer of BLOWFISH context.
206f66d273dSizick 				 */
207f66d273dSizick 				(void) memcpy(soft_blowfish_ctx->data +
208f66d273dSizick 				    soft_blowfish_ctx->remain_len, pData,
209f66d273dSizick 				    ulDataLen);
210f66d273dSizick 				soft_blowfish_ctx->remain_len += ulDataLen;
211f66d273dSizick 			}
212f66d273dSizick 
213f66d273dSizick 			/* Set encrypted data length to 0. */
214f66d273dSizick 			*pulEncryptedLen = 0;
215f66d273dSizick 			return (CKR_OK);
216f66d273dSizick 		}
217f66d273dSizick 
218f66d273dSizick 		/* Compute the length of remaing data. */
219f66d273dSizick 		remain = total_len % BLOWFISH_BLOCK_LEN;
220f66d273dSizick 
221f66d273dSizick 		/*
222f66d273dSizick 		 * Make sure that the output length is a multiple of
223f66d273dSizick 		 * blocksize.
224f66d273dSizick 		 */
225f66d273dSizick 		out_len = total_len - remain;
226f66d273dSizick 
227f66d273dSizick 		/*
228f66d273dSizick 		 * If application asks for the length of the output buffer
229f66d273dSizick 		 * to hold the ciphertext?
230f66d273dSizick 		 */
231f66d273dSizick 		if (pEncrypted == NULL) {
232f66d273dSizick 			*pulEncryptedLen = out_len;
233f66d273dSizick 			return (CKR_OK);
234f66d273dSizick 		}
235f66d273dSizick 
236f66d273dSizick 		/* Is the application-supplied buffer large enough? */
237f66d273dSizick 		if (*pulEncryptedLen < out_len) {
238f66d273dSizick 			*pulEncryptedLen = out_len;
239f66d273dSizick 			return (CKR_BUFFER_TOO_SMALL);
240f66d273dSizick 		}
241f66d273dSizick 
242f66d273dSizick 		if (soft_blowfish_ctx->remain_len != 0) {
243f66d273dSizick 			/*
244f66d273dSizick 			 * Copy last remaining data and current input data
245f66d273dSizick 			 * to the output buffer.
246f66d273dSizick 			 */
247f66d273dSizick 			(void) memmove(pEncrypted +
248f66d273dSizick 			    soft_blowfish_ctx->remain_len,
249f66d273dSizick 			    pData, out_len - soft_blowfish_ctx->remain_len);
250f66d273dSizick 			(void) memcpy(pEncrypted, soft_blowfish_ctx->data,
251f66d273dSizick 			    soft_blowfish_ctx->remain_len);
252f66d273dSizick 			bzero(soft_blowfish_ctx->data,
253f66d273dSizick 			    soft_blowfish_ctx->remain_len);
254f66d273dSizick 
255f66d273dSizick 			in_buf = pEncrypted;
256f66d273dSizick 		} else {
257f66d273dSizick 			in_buf = pData;
258f66d273dSizick 		}
259f66d273dSizick 		out_buf = pEncrypted;
260f66d273dSizick 	}
261f66d273dSizick 
262f66d273dSizick 	/*
263f66d273dSizick 	 * Begin Encryption now.
264f66d273dSizick 	 */
265f66d273dSizick 
266f66d273dSizick 	out.cd_format = CRYPTO_DATA_RAW;
267f66d273dSizick 	out.cd_offset = 0;
268f66d273dSizick 	out.cd_length = out_len;
269f66d273dSizick 	out.cd_raw.iov_base = (char *)out_buf;
270f66d273dSizick 	out.cd_raw.iov_len = out_len;
271f66d273dSizick 
272f66d273dSizick 	/* Encrypt multiple blocks of data. */
273f66d273dSizick 	rc = blowfish_encrypt_contiguous_blocks(
274f66d273dSizick 		(blowfish_ctx_t *)soft_blowfish_ctx->blowfish_cbc,
275f66d273dSizick 		    (char *)in_buf, out_len, &out);
276f66d273dSizick 
277f66d273dSizick 	if (rc == 0) {
278f66d273dSizick 		*pulEncryptedLen = out_len;
279f66d273dSizick 		if (update) {
280f66d273dSizick 			/*
281f66d273dSizick 			 * For encrypt update, if there is remaining data,
282f66d273dSizick 			 * save it and it's length in the context.
283f66d273dSizick 			 */
284f66d273dSizick 			if (remain != 0)
285f66d273dSizick 				(void) memcpy(soft_blowfish_ctx->data, pData +
286f66d273dSizick 				    (ulDataLen - remain), remain);
287f66d273dSizick 
288f66d273dSizick 			soft_blowfish_ctx->remain_len = remain;
289f66d273dSizick 			return (CKR_OK);
290f66d273dSizick 		}
291f66d273dSizick 
2924c21f043Sizick 	} else {
293f66d273dSizick 		*pulEncryptedLen = 0;
294f66d273dSizick 		rv = CKR_FUNCTION_FAILED;
2954c21f043Sizick 	}
296f66d273dSizick 
297f66d273dSizick cleanup:
298f66d273dSizick 	(void) pthread_mutex_lock(&session_p->session_mutex);
299f66d273dSizick 	blowfish_ctx = (blowfish_ctx_t *)soft_blowfish_ctx->blowfish_cbc;
300f66d273dSizick 	if (blowfish_ctx != NULL) {
301f66d273dSizick 		bzero(blowfish_ctx->bc_keysched,
302f66d273dSizick 		    blowfish_ctx->bc_keysched_len);
303f66d273dSizick 		free(soft_blowfish_ctx->blowfish_cbc);
304f66d273dSizick 	}
305f66d273dSizick 
306f66d273dSizick 	bzero(soft_blowfish_ctx->key_sched, soft_blowfish_ctx->keysched_len);
307f66d273dSizick 	free(soft_blowfish_ctx->key_sched);
308f66d273dSizick 	free(session_p->encrypt.context);
309f66d273dSizick 	session_p->encrypt.context = NULL;
310f66d273dSizick 	(void) pthread_mutex_unlock(&session_p->session_mutex);
311f66d273dSizick 
312f66d273dSizick 	return (rv);
313f66d273dSizick }
314f66d273dSizick 
315f66d273dSizick 
316f66d273dSizick CK_RV
317f66d273dSizick soft_blowfish_decrypt_common(soft_session_t *session_p, CK_BYTE_PTR pEncrypted,
318f66d273dSizick     CK_ULONG ulEncryptedLen, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen,
319f66d273dSizick     boolean_t update) {
320f66d273dSizick 
321f66d273dSizick 	int rc = 0;
322f66d273dSizick 	CK_RV rv = CKR_OK;
323f66d273dSizick 	soft_blowfish_ctx_t *soft_blowfish_ctx =
324f66d273dSizick 	    (soft_blowfish_ctx_t *)session_p->decrypt.context;
325f66d273dSizick 	blowfish_ctx_t *blowfish_ctx;
326f66d273dSizick 	CK_BYTE *in_buf = NULL;
327f66d273dSizick 	CK_BYTE *out_buf = NULL;
328f66d273dSizick 	CK_ULONG out_len;
329f66d273dSizick 	CK_ULONG total_len;
330f66d273dSizick 	CK_ULONG remain;
331f66d273dSizick 	crypto_data_t out;
332f66d273dSizick 
333f66d273dSizick 	/*
334f66d273dSizick 	 * Blowfish only takes input length that is a multiple of 16 bytes
335f66d273dSizick 	 * for C_Decrypt function using CKM_BLOWFISH_CBC.
336f66d273dSizick 	 */
337f66d273dSizick 
338f66d273dSizick 	if (!update) {
339f66d273dSizick 		/* Called by C_Decrypt */
340f66d273dSizick 		if ((ulEncryptedLen % BLOWFISH_BLOCK_LEN) != 0) {
341f66d273dSizick 			rv = CKR_ENCRYPTED_DATA_LEN_RANGE;
342f66d273dSizick 			goto cleanup;
343f66d273dSizick 		}
344f66d273dSizick 
345f66d273dSizick 		/*
3464c21f043Sizick 		 * If application asks for the length of the output buffer
347f66d273dSizick 		 * to hold the plaintext?
348f66d273dSizick 		 */
349f66d273dSizick 		if (pData == NULL) {
350f66d273dSizick 			*pulDataLen = ulEncryptedLen;
351f66d273dSizick 			return (CKR_OK);
352f66d273dSizick 		}
353f66d273dSizick 
354f66d273dSizick 		/* Is the application-supplied buffer large enough? */
355f66d273dSizick 		if (*pulDataLen < ulEncryptedLen) {
356f66d273dSizick 			*pulDataLen = ulEncryptedLen;
357f66d273dSizick 			return (CKR_BUFFER_TOO_SMALL);
358f66d273dSizick 		}
359f66d273dSizick 		out_len = ulEncryptedLen;
360f66d273dSizick 		in_buf = pEncrypted;
361f66d273dSizick 		out_buf = pData;
362f66d273dSizick 	} else {
363f66d273dSizick 		/*
364f66d273dSizick 		 * Called by C_DecryptUpdate
365f66d273dSizick 		 *
366f66d273dSizick 		 * Add the lengths of last remaining data and current
367f66d273dSizick 		 * input data together to get the total input length.
368f66d273dSizick 		 */
369f66d273dSizick 		total_len = soft_blowfish_ctx->remain_len + ulEncryptedLen;
370f66d273dSizick 
371f66d273dSizick 		if (total_len < BLOWFISH_BLOCK_LEN) {
372f66d273dSizick 			if (pData != NULL) {
373f66d273dSizick 				(void) memcpy(soft_blowfish_ctx->data +
374f66d273dSizick 				    soft_blowfish_ctx->remain_len,
375f66d273dSizick 				    pEncrypted, ulEncryptedLen);
376f66d273dSizick 
377f66d273dSizick 				soft_blowfish_ctx->remain_len += ulEncryptedLen;
378f66d273dSizick 			}
379f66d273dSizick 
380f66d273dSizick 			/* Set output data length to 0. */
381f66d273dSizick 			*pulDataLen = 0;
382f66d273dSizick 			return (CKR_OK);
383f66d273dSizick 		}
384f66d273dSizick 
385f66d273dSizick 		/* Compute the length of remaining data. */
386f66d273dSizick 		remain = total_len % BLOWFISH_BLOCK_LEN;
387f66d273dSizick 
388f66d273dSizick 		/*
389f66d273dSizick 		 * Make sure that the output length is a multiple of
390f66d273dSizick 		 * blocksize.
391f66d273dSizick 		 */
392f66d273dSizick 		out_len = total_len - remain;
393f66d273dSizick 
394f66d273dSizick 		/*
395f66d273dSizick 		 * if application asks for the length of the output buffer
396f66d273dSizick 		 * to hold the plaintext?
397f66d273dSizick 		 */
398f66d273dSizick 		if (pData == NULL) {
399f66d273dSizick 			*pulDataLen = out_len;
400f66d273dSizick 			return (CKR_OK);
401f66d273dSizick 		}
402f66d273dSizick 
403f66d273dSizick 		/*
404f66d273dSizick 		 * Is the application-supplied buffer large enough?
405f66d273dSizick 		 */
406f66d273dSizick 		if (*pulDataLen < out_len) {
407f66d273dSizick 			*pulDataLen = out_len;
408f66d273dSizick 			return (CKR_BUFFER_TOO_SMALL);
409f66d273dSizick 		}
410f66d273dSizick 
411f66d273dSizick 		if (soft_blowfish_ctx->remain_len != 0) {
412f66d273dSizick 			/*
413f66d273dSizick 			 * Copy last remaining data and current input data
414f66d273dSizick 			 * to the output buffer.
415f66d273dSizick 			 */
416f66d273dSizick 			(void) memmove(pData + soft_blowfish_ctx->remain_len,
417f66d273dSizick 			    pEncrypted,
418f66d273dSizick 			    out_len - soft_blowfish_ctx->remain_len);
419f66d273dSizick 			(void) memcpy(pData, soft_blowfish_ctx->data,
420f66d273dSizick 			    soft_blowfish_ctx->remain_len);
421f66d273dSizick 			bzero(soft_blowfish_ctx->data,
422f66d273dSizick 			    soft_blowfish_ctx->remain_len);
423f66d273dSizick 
424f66d273dSizick 
425f66d273dSizick 			in_buf = pData;
426f66d273dSizick 		} else {
427f66d273dSizick 			in_buf = pEncrypted;
428f66d273dSizick 		}
429f66d273dSizick 
430f66d273dSizick 		out_buf = pData;
431f66d273dSizick 	}
432f66d273dSizick 
433f66d273dSizick 	out.cd_format = CRYPTO_DATA_RAW;
434f66d273dSizick 	out.cd_offset = 0;
435f66d273dSizick 	out.cd_length = out_len;
436f66d273dSizick 	out.cd_raw.iov_base = (char *)out_buf;
437f66d273dSizick 	out.cd_raw.iov_len = out_len;
438f66d273dSizick 
439f66d273dSizick 	/* Decrypt multiple blocks of data. */
440f66d273dSizick 	rc = blowfish_decrypt_contiguous_blocks(
441f66d273dSizick 		(blowfish_ctx_t *)soft_blowfish_ctx->blowfish_cbc,
442f66d273dSizick 		(char *)in_buf, out_len, &out);
443f66d273dSizick 
444f66d273dSizick 	if (rc == 0) {
445f66d273dSizick 		*pulDataLen = out_len;
446f66d273dSizick 		if (update) {
447f66d273dSizick 			/*
448f66d273dSizick 			 * For decrypt update, if there is remaining data,
449f66d273dSizick 			 * save it and its length in the context.
450f66d273dSizick 			 */
451f66d273dSizick 			if (remain != 0)
452f66d273dSizick 				(void) memcpy(soft_blowfish_ctx->data,
453f66d273dSizick 				    pEncrypted + (ulEncryptedLen - remain),
454f66d273dSizick 				    remain);
455f66d273dSizick 			soft_blowfish_ctx->remain_len = remain;
456f66d273dSizick 			return (CKR_OK);
457f66d273dSizick 		}
458f66d273dSizick 
459f66d273dSizick 
460f66d273dSizick 	} else {
461f66d273dSizick 		*pulDataLen = 0;
462f66d273dSizick 		rv = CKR_FUNCTION_FAILED;
463f66d273dSizick 	}
464f66d273dSizick 
465f66d273dSizick cleanup:
466f66d273dSizick 	(void) pthread_mutex_lock(&session_p->session_mutex);
467f66d273dSizick 	blowfish_ctx = (blowfish_ctx_t *)soft_blowfish_ctx->blowfish_cbc;
468f66d273dSizick 	if (blowfish_ctx != NULL) {
469f66d273dSizick 		bzero(blowfish_ctx->bc_keysched,
470f66d273dSizick 		    blowfish_ctx->bc_keysched_len);
471f66d273dSizick 		free(soft_blowfish_ctx->blowfish_cbc);
472f66d273dSizick 	}
473f66d273dSizick 
474f66d273dSizick 	bzero(soft_blowfish_ctx->key_sched, soft_blowfish_ctx->keysched_len);
475f66d273dSizick 	free(soft_blowfish_ctx->key_sched);
476f66d273dSizick 	free(session_p->decrypt.context);
477f66d273dSizick 	session_p->decrypt.context = NULL;
478f66d273dSizick 	(void) pthread_mutex_unlock(&session_p->session_mutex);
479f66d273dSizick 
480f66d273dSizick 	return (rv);
481f66d273dSizick }
482f66d273dSizick 
483f66d273dSizick /*
484f66d273dSizick  * Allocate and initialize a context for BLOWFISH CBC mode of operation.
485f66d273dSizick  */
486f66d273dSizick 
487f66d273dSizick void *
488f66d273dSizick blowfish_cbc_ctx_init(void *key_sched, size_t size, uint8_t *ivec)
489f66d273dSizick {
490f66d273dSizick 
49123c57df7Smcpowers 	cbc_ctx_t *cbc_ctx;
492f66d273dSizick 
49323c57df7Smcpowers 	if ((cbc_ctx = calloc(1, sizeof (cbc_ctx_t))) == NULL)
494f66d273dSizick 		return (NULL);
495f66d273dSizick 
496*16239bc8SMark Powers 	cbc_ctx->cbc_keysched = key_sched;
497f66d273dSizick 
498*16239bc8SMark Powers 	(void) memcpy(&cbc_ctx->cbc_iv[0], ivec, BLOWFISH_BLOCK_LEN);
499f66d273dSizick 
500*16239bc8SMark Powers 	cbc_ctx->cbc_lastp = (uint8_t *)&(cbc_ctx->cbc_iv);
501*16239bc8SMark Powers 	cbc_ctx->cbc_keysched_len = size;
502*16239bc8SMark Powers 	cbc_ctx->cbc_flags |= CBC_MODE;
503f66d273dSizick 
50423c57df7Smcpowers 	return (cbc_ctx);
505f66d273dSizick }
506