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