xref: /titanic_41/usr/src/lib/pkcs11/pkcs11_softtoken/common/softDESCrypt.c (revision 726fad2a65f16c200a03969c29cb5c86c2d427db)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
59627968bSmcpowers  * Common Development and Distribution License (the "License").
69627968bSmcpowers  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21*726fad2aSDina K Nimeh 
227c478bd9Sstevel@tonic-gate /*
23*726fad2aSDina K Nimeh  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include <pthread.h>
277c478bd9Sstevel@tonic-gate #include <stdlib.h>
287c478bd9Sstevel@tonic-gate #include <string.h>
297c478bd9Sstevel@tonic-gate #include <strings.h>
307c478bd9Sstevel@tonic-gate #include <sys/types.h>
317c478bd9Sstevel@tonic-gate #include <security/cryptoki.h>
3223c57df7Smcpowers #include <modes/modes.h>
337c478bd9Sstevel@tonic-gate #include <des_impl.h>
347c478bd9Sstevel@tonic-gate #include "softSession.h"
357c478bd9Sstevel@tonic-gate #include "softObject.h"
367c478bd9Sstevel@tonic-gate #include "softCrypt.h"
377c478bd9Sstevel@tonic-gate #include "softOps.h"
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate /*
407c478bd9Sstevel@tonic-gate  * Allocate context for the active encryption or decryption operation, and
417c478bd9Sstevel@tonic-gate  * generate DES or DES3 key schedule to speed up the operation.
427c478bd9Sstevel@tonic-gate  */
437c478bd9Sstevel@tonic-gate CK_RV
soft_des_crypt_init_common(soft_session_t * session_p,CK_MECHANISM_PTR pMechanism,soft_object_t * key_p,boolean_t encrypt)447c478bd9Sstevel@tonic-gate soft_des_crypt_init_common(soft_session_t *session_p,
457c478bd9Sstevel@tonic-gate     CK_MECHANISM_PTR pMechanism, soft_object_t *key_p,
467c478bd9Sstevel@tonic-gate     boolean_t encrypt)
477c478bd9Sstevel@tonic-gate {
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate 	size_t size;
507c478bd9Sstevel@tonic-gate 	soft_des_ctx_t *soft_des_ctx;
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate 	soft_des_ctx = calloc(1, sizeof (soft_des_ctx_t));
537c478bd9Sstevel@tonic-gate 	if (soft_des_ctx == NULL) {
547c478bd9Sstevel@tonic-gate 		return (CKR_HOST_MEMORY);
557c478bd9Sstevel@tonic-gate 	}
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate 	/* Allocate key schedule for DES or DES3 based on key type. */
587c478bd9Sstevel@tonic-gate 	if (key_p->key_type == CKK_DES)
597c478bd9Sstevel@tonic-gate 		soft_des_ctx->key_sched = des_alloc_keysched(&size, DES, 0);
607c478bd9Sstevel@tonic-gate 	else
617c478bd9Sstevel@tonic-gate 		soft_des_ctx->key_sched = des_alloc_keysched(&size, DES3, 0);
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate 	if (soft_des_ctx->key_sched == NULL) {
647c478bd9Sstevel@tonic-gate 		free(soft_des_ctx);
657c478bd9Sstevel@tonic-gate 		return (CKR_HOST_MEMORY);
667c478bd9Sstevel@tonic-gate 	}
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate 	soft_des_ctx->keysched_len = size;
697c478bd9Sstevel@tonic-gate 	soft_des_ctx->key_type = key_p->key_type;
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&session_p->session_mutex);
727c478bd9Sstevel@tonic-gate 	if (encrypt) {
737c478bd9Sstevel@tonic-gate 		/* Called by C_EncryptInit. */
747c478bd9Sstevel@tonic-gate 		session_p->encrypt.context = soft_des_ctx;
757c478bd9Sstevel@tonic-gate 		session_p->encrypt.mech.mechanism = pMechanism->mechanism;
767c478bd9Sstevel@tonic-gate 	} else {
777c478bd9Sstevel@tonic-gate 		/* Called by C_DecryptInit. */
787c478bd9Sstevel@tonic-gate 		session_p->decrypt.context = soft_des_ctx;
797c478bd9Sstevel@tonic-gate 		session_p->decrypt.mech.mechanism = pMechanism->mechanism;
807c478bd9Sstevel@tonic-gate 	}
817c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&session_p->session_mutex);
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate 	/*
847c478bd9Sstevel@tonic-gate 	 * If this is a non-sensitive key and it does NOT have
857c478bd9Sstevel@tonic-gate 	 * a key schedule yet, then allocate one and expand it.
867c478bd9Sstevel@tonic-gate 	 * Otherwise, if its a non-sensitive key, and it DOES have
877c478bd9Sstevel@tonic-gate 	 * a key schedule already attached to it, just copy the
887c478bd9Sstevel@tonic-gate 	 * pre-expanded schedule to the context and avoid the
897c478bd9Sstevel@tonic-gate 	 * extra key schedule expansion operation.
907c478bd9Sstevel@tonic-gate 	 */
917c478bd9Sstevel@tonic-gate 	if (!(key_p->bool_attr_mask & SENSITIVE_BOOL_ON)) {
929627968bSmcpowers 		if (OBJ_KEY_SCHED(key_p) == NULL) {
937c478bd9Sstevel@tonic-gate 			void *ks;
949627968bSmcpowers 			(void) pthread_mutex_lock(&key_p->object_mutex);
959627968bSmcpowers 			if (OBJ_KEY_SCHED(key_p) == NULL) {
967c478bd9Sstevel@tonic-gate 				if (key_p->key_type == CKK_DES)
977c478bd9Sstevel@tonic-gate 					ks = des_alloc_keysched(&size, DES, 0);
987c478bd9Sstevel@tonic-gate 				else
997c478bd9Sstevel@tonic-gate 					ks = des_alloc_keysched(&size, DES3, 0);
1009627968bSmcpowers 				if (ks == NULL) {
1019627968bSmcpowers 					(void) pthread_mutex_unlock(
1029627968bSmcpowers 					    &key_p->object_mutex);
1037c478bd9Sstevel@tonic-gate 					free(soft_des_ctx);
1047c478bd9Sstevel@tonic-gate 					return (CKR_HOST_MEMORY);
1057c478bd9Sstevel@tonic-gate 				}
1067c478bd9Sstevel@tonic-gate 				/* Initialize key schedule for DES or DES3. */
1077c478bd9Sstevel@tonic-gate 				if (key_p->key_type == CKK_DES)
1089627968bSmcpowers 					des_init_keysched(
1099627968bSmcpowers 					    OBJ_SEC(key_p)->sk_value, DES, ks);
1107c478bd9Sstevel@tonic-gate 				else if (key_p->key_type == CKK_DES2)
1117c478bd9Sstevel@tonic-gate 					/*
1127c478bd9Sstevel@tonic-gate 					 * DES3 encryption/decryption needs to
1137c478bd9Sstevel@tonic-gate 					 * support a DES2 key.
1147c478bd9Sstevel@tonic-gate 					 */
1159627968bSmcpowers 					des_init_keysched(
1169627968bSmcpowers 					    OBJ_SEC(key_p)->sk_value, DES2, ks);
1177c478bd9Sstevel@tonic-gate 				else
1189627968bSmcpowers 					des_init_keysched(
1199627968bSmcpowers 					    OBJ_SEC(key_p)->sk_value, DES3, ks);
1209627968bSmcpowers 
1219627968bSmcpowers 				OBJ_KEY_SCHED_LEN(key_p) = size;
1229627968bSmcpowers 				OBJ_KEY_SCHED(key_p) = ks;
1239627968bSmcpowers 			}
1249627968bSmcpowers 			(void) pthread_mutex_unlock(&key_p->object_mutex);
1257c478bd9Sstevel@tonic-gate 		}
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate 		/* Copy the pre-expanded key schedule from the key object */
1287c478bd9Sstevel@tonic-gate 		(void) memcpy(soft_des_ctx->key_sched, OBJ_KEY_SCHED(key_p),
1297c478bd9Sstevel@tonic-gate 		    OBJ_KEY_SCHED_LEN(key_p));
1307c478bd9Sstevel@tonic-gate 		soft_des_ctx->keysched_len = OBJ_KEY_SCHED_LEN(key_p);
1317c478bd9Sstevel@tonic-gate 	} else {
1327c478bd9Sstevel@tonic-gate 		/* for sensitive keys, we cannot cache the key schedule */
1337c478bd9Sstevel@tonic-gate 		if (key_p->key_type == CKK_DES)
1347c478bd9Sstevel@tonic-gate 			des_init_keysched(OBJ_SEC(key_p)->sk_value,
1357c478bd9Sstevel@tonic-gate 			    DES, soft_des_ctx->key_sched);
1367c478bd9Sstevel@tonic-gate 		else if (key_p->key_type == CKK_DES2)
1377c478bd9Sstevel@tonic-gate 			/*
1387c478bd9Sstevel@tonic-gate 			 * DES3 encryption/decryption needs to
1397c478bd9Sstevel@tonic-gate 			 * support a DES2 key.
1407c478bd9Sstevel@tonic-gate 			 */
1417c478bd9Sstevel@tonic-gate 			des_init_keysched(OBJ_SEC(key_p)->sk_value,
1427c478bd9Sstevel@tonic-gate 			    DES2, soft_des_ctx->key_sched);
1437c478bd9Sstevel@tonic-gate 		else
1447c478bd9Sstevel@tonic-gate 			des_init_keysched(OBJ_SEC(key_p)->sk_value,
1457c478bd9Sstevel@tonic-gate 			    DES3, soft_des_ctx->key_sched);
1467c478bd9Sstevel@tonic-gate 	}
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate 	return (CKR_OK);
1497c478bd9Sstevel@tonic-gate }
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate /*
1537c478bd9Sstevel@tonic-gate  * soft_des_encrypt_common()
1547c478bd9Sstevel@tonic-gate  *
1557c478bd9Sstevel@tonic-gate  * Arguments:
1567c478bd9Sstevel@tonic-gate  *      session_p:	pointer to soft_session_t struct
1577c478bd9Sstevel@tonic-gate  *	pData:		pointer to the input data to be encrypted
1587c478bd9Sstevel@tonic-gate  *	ulDataLen:	length of the input data
1597c478bd9Sstevel@tonic-gate  *	pEncrypted:	pointer to the output data after encryption
1607c478bd9Sstevel@tonic-gate  *	pulEncryptedLen: pointer to the length of the output data
1617c478bd9Sstevel@tonic-gate  *	update:		boolean flag indicates caller is soft_encrypt
1627c478bd9Sstevel@tonic-gate  *			or soft_encrypt_update
1637c478bd9Sstevel@tonic-gate  *
1647c478bd9Sstevel@tonic-gate  * Description:
1657c478bd9Sstevel@tonic-gate  *      This function calls the corresponding encrypt routine based
1667c478bd9Sstevel@tonic-gate  *	on the mechanism.
1677c478bd9Sstevel@tonic-gate  *
1687c478bd9Sstevel@tonic-gate  * Returns:
1697c478bd9Sstevel@tonic-gate  *      CKR_OK: success
1707c478bd9Sstevel@tonic-gate  *      CKR_BUFFER_TOO_SMALL: the output buffer provided by application
1717c478bd9Sstevel@tonic-gate  *			      is too small
1727c478bd9Sstevel@tonic-gate  *	CKR_FUNCTION_FAILED: encrypt function failed
1737c478bd9Sstevel@tonic-gate  *	CKR_DATA_LEN_RANGE: the input data is not a multiple of blocksize
1747c478bd9Sstevel@tonic-gate  */
1757c478bd9Sstevel@tonic-gate CK_RV
soft_des_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)1767c478bd9Sstevel@tonic-gate soft_des_encrypt_common(soft_session_t *session_p, CK_BYTE_PTR pData,
1777c478bd9Sstevel@tonic-gate     CK_ULONG ulDataLen, CK_BYTE_PTR pEncrypted,
1787c478bd9Sstevel@tonic-gate     CK_ULONG_PTR pulEncryptedLen, boolean_t update)
1797c478bd9Sstevel@tonic-gate {
1807c478bd9Sstevel@tonic-gate 	int rc = 0;
1817c478bd9Sstevel@tonic-gate 	CK_RV rv = CKR_OK;
1827c478bd9Sstevel@tonic-gate 	soft_des_ctx_t *soft_des_ctx =
1837c478bd9Sstevel@tonic-gate 	    (soft_des_ctx_t *)session_p->encrypt.context;
1847c478bd9Sstevel@tonic-gate 	des_ctx_t *des_ctx;
1857c478bd9Sstevel@tonic-gate 	CK_MECHANISM_TYPE mechanism = session_p->encrypt.mech.mechanism;
1867c478bd9Sstevel@tonic-gate 	CK_BYTE *in_buf = NULL;
1877c478bd9Sstevel@tonic-gate 	CK_BYTE *out_buf = NULL;
1887c478bd9Sstevel@tonic-gate 	CK_ULONG out_len;
1897c478bd9Sstevel@tonic-gate 	CK_ULONG total_len;
1907c478bd9Sstevel@tonic-gate 	CK_ULONG remain;
1917c478bd9Sstevel@tonic-gate 	boolean_t pad_mechanism = B_FALSE;
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate 	pad_mechanism = (mechanism == CKM_DES_CBC_PAD ||
1947c478bd9Sstevel@tonic-gate 	    mechanism == CKM_DES3_CBC_PAD);
1957c478bd9Sstevel@tonic-gate 	/*
1967c478bd9Sstevel@tonic-gate 	 * DES only takes input length that is a multiple of blocksize
1977c478bd9Sstevel@tonic-gate 	 * for C_Encrypt function with the mechanism CKM_DES<n>_ECB or
1987c478bd9Sstevel@tonic-gate 	 * CKM_DES<n>_CBC.
1997c478bd9Sstevel@tonic-gate 	 *
2007c478bd9Sstevel@tonic-gate 	 * DES allows any input length for C_Encrypt function with the
2017c478bd9Sstevel@tonic-gate 	 * mechanism CKM_DES<n>_CBC_PAD and for C_EncryptUpdate function.
2027c478bd9Sstevel@tonic-gate 	 */
2037c478bd9Sstevel@tonic-gate 	if (!update && !pad_mechanism) {
2047c478bd9Sstevel@tonic-gate 		if ((ulDataLen % DES_BLOCK_LEN) != 0) {
2057c478bd9Sstevel@tonic-gate 			rv = CKR_DATA_LEN_RANGE;
2067c478bd9Sstevel@tonic-gate 			goto cleanup;
2077c478bd9Sstevel@tonic-gate 		}
2087c478bd9Sstevel@tonic-gate 	}
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 	if (!update) {
2117c478bd9Sstevel@tonic-gate 		/*
2127c478bd9Sstevel@tonic-gate 		 * Called by C_Encrypt
2137c478bd9Sstevel@tonic-gate 		 */
2147c478bd9Sstevel@tonic-gate 		if (pad_mechanism) {
2157c478bd9Sstevel@tonic-gate 			/*
2167c478bd9Sstevel@tonic-gate 			 * For CKM_DES<n>_CBC_PAD, compute output length to
2177c478bd9Sstevel@tonic-gate 			 * count for the padding. If the length of input
2187c478bd9Sstevel@tonic-gate 			 * data is a multiple of blocksize, then make output
2197c478bd9Sstevel@tonic-gate 			 * length to be the sum of the input length and
2207c478bd9Sstevel@tonic-gate 			 * one blocksize. Otherwise, output length will
2217c478bd9Sstevel@tonic-gate 			 * be rounded up to the next multiple of blocksize.
2227c478bd9Sstevel@tonic-gate 			 */
2237c478bd9Sstevel@tonic-gate 			out_len = DES_BLOCK_LEN *
2247c478bd9Sstevel@tonic-gate 			    (ulDataLen / DES_BLOCK_LEN + 1);
2257c478bd9Sstevel@tonic-gate 		} else {
2267c478bd9Sstevel@tonic-gate 			/*
2277c478bd9Sstevel@tonic-gate 			 * For non-padding mode, the output length will
2287c478bd9Sstevel@tonic-gate 			 * be same as the input length.
2297c478bd9Sstevel@tonic-gate 			 */
2307c478bd9Sstevel@tonic-gate 			out_len = ulDataLen;
2317c478bd9Sstevel@tonic-gate 		}
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate 		/*
2347c478bd9Sstevel@tonic-gate 		 * If application asks for the length of the output buffer
2357c478bd9Sstevel@tonic-gate 		 * to hold the ciphertext?
2367c478bd9Sstevel@tonic-gate 		 */
2377c478bd9Sstevel@tonic-gate 		if (pEncrypted == NULL) {
2387c478bd9Sstevel@tonic-gate 			*pulEncryptedLen = out_len;
2397c478bd9Sstevel@tonic-gate 			return (CKR_OK);
2407c478bd9Sstevel@tonic-gate 		}
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate 		/* Is the application-supplied buffer large enough? */
2437c478bd9Sstevel@tonic-gate 		if (*pulEncryptedLen < out_len) {
2447c478bd9Sstevel@tonic-gate 			*pulEncryptedLen = out_len;
2457c478bd9Sstevel@tonic-gate 			return (CKR_BUFFER_TOO_SMALL);
2467c478bd9Sstevel@tonic-gate 		}
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate 		/* Encrypt pad bytes in a separate operation */
2497c478bd9Sstevel@tonic-gate 		if (pad_mechanism) {
2507c478bd9Sstevel@tonic-gate 			out_len -= DES_BLOCK_LEN;
2517c478bd9Sstevel@tonic-gate 		}
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate 		in_buf = pData;
2547c478bd9Sstevel@tonic-gate 		out_buf = pEncrypted;
2557c478bd9Sstevel@tonic-gate 	} else {
2567c478bd9Sstevel@tonic-gate 		/*
2577c478bd9Sstevel@tonic-gate 		 * Called by C_EncryptUpdate
2587c478bd9Sstevel@tonic-gate 		 *
2597c478bd9Sstevel@tonic-gate 		 * Add the lengths of last remaining data and current
2607c478bd9Sstevel@tonic-gate 		 * plaintext together to get the total input length.
2617c478bd9Sstevel@tonic-gate 		 */
2627c478bd9Sstevel@tonic-gate 		total_len = soft_des_ctx->remain_len + ulDataLen;
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate 		/*
2657c478bd9Sstevel@tonic-gate 		 * If the total input length is less than one blocksize,
2667c478bd9Sstevel@tonic-gate 		 * or if the total input length is just one blocksize and
2677c478bd9Sstevel@tonic-gate 		 * the mechanism is CKM_DES<n>_CBC_PAD, we will need to delay
2687c478bd9Sstevel@tonic-gate 		 * encryption until when more data comes in next
2697c478bd9Sstevel@tonic-gate 		 * C_EncryptUpdate or when C_EncryptFinal is called.
2707c478bd9Sstevel@tonic-gate 		 */
2717c478bd9Sstevel@tonic-gate 		if ((total_len < DES_BLOCK_LEN) ||
2727c478bd9Sstevel@tonic-gate 		    (pad_mechanism && (total_len == DES_BLOCK_LEN))) {
2737c478bd9Sstevel@tonic-gate 			if (pData != NULL) {
2747c478bd9Sstevel@tonic-gate 				/*
2757c478bd9Sstevel@tonic-gate 				 * Save input data and its length in
2767c478bd9Sstevel@tonic-gate 				 * the remaining buffer of DES context.
2777c478bd9Sstevel@tonic-gate 				 */
2787c478bd9Sstevel@tonic-gate 				(void) memcpy(soft_des_ctx->data +
2797c478bd9Sstevel@tonic-gate 				    soft_des_ctx->remain_len, pData, ulDataLen);
2807c478bd9Sstevel@tonic-gate 				soft_des_ctx->remain_len += ulDataLen;
2817c478bd9Sstevel@tonic-gate 			}
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate 			/* Set encrypted data length to 0. */
2847c478bd9Sstevel@tonic-gate 			*pulEncryptedLen = 0;
2857c478bd9Sstevel@tonic-gate 			return (CKR_OK);
2867c478bd9Sstevel@tonic-gate 		}
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate 		/* Compute the length of remaing data. */
2897c478bd9Sstevel@tonic-gate 		remain = total_len % DES_BLOCK_LEN;
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate 		/*
2927c478bd9Sstevel@tonic-gate 		 * Make sure that the output length is a multiple of
2937c478bd9Sstevel@tonic-gate 		 * blocksize.
2947c478bd9Sstevel@tonic-gate 		 */
2957c478bd9Sstevel@tonic-gate 		out_len = total_len - remain;
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate 		/*
2987c478bd9Sstevel@tonic-gate 		 * If application asks for the length of the output buffer
2997c478bd9Sstevel@tonic-gate 		 * to hold the ciphertext?
3007c478bd9Sstevel@tonic-gate 		 */
3017c478bd9Sstevel@tonic-gate 		if (pEncrypted == NULL) {
3027c478bd9Sstevel@tonic-gate 			*pulEncryptedLen = out_len;
3037c478bd9Sstevel@tonic-gate 			return (CKR_OK);
3047c478bd9Sstevel@tonic-gate 		}
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate 		/* Is the application-supplied buffer large enough? */
3077c478bd9Sstevel@tonic-gate 		if (*pulEncryptedLen < out_len) {
3087c478bd9Sstevel@tonic-gate 			*pulEncryptedLen = out_len;
3097c478bd9Sstevel@tonic-gate 			return (CKR_BUFFER_TOO_SMALL);
3107c478bd9Sstevel@tonic-gate 		}
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate 		if (soft_des_ctx->remain_len != 0) {
3137c478bd9Sstevel@tonic-gate 			/*
3147c478bd9Sstevel@tonic-gate 			 * Copy last remaining data and current input data
3157c478bd9Sstevel@tonic-gate 			 * to the output buffer.
3167c478bd9Sstevel@tonic-gate 			 */
3177c478bd9Sstevel@tonic-gate 			(void) memmove(pEncrypted + soft_des_ctx->remain_len,
3187c478bd9Sstevel@tonic-gate 			    pData, out_len - soft_des_ctx->remain_len);
3197c478bd9Sstevel@tonic-gate 			(void) memcpy(pEncrypted, soft_des_ctx->data,
3207c478bd9Sstevel@tonic-gate 			    soft_des_ctx->remain_len);
3217c478bd9Sstevel@tonic-gate 			bzero(soft_des_ctx->data, soft_des_ctx->remain_len);
3227c478bd9Sstevel@tonic-gate 
3237c478bd9Sstevel@tonic-gate 			in_buf = pEncrypted;
3247c478bd9Sstevel@tonic-gate 		} else {
3257c478bd9Sstevel@tonic-gate 			in_buf = pData;
3267c478bd9Sstevel@tonic-gate 		}
3277c478bd9Sstevel@tonic-gate 		out_buf = pEncrypted;
3287c478bd9Sstevel@tonic-gate 	}
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate 	/*
3317c478bd9Sstevel@tonic-gate 	 * Begin Encryption now.
3327c478bd9Sstevel@tonic-gate 	 */
3337c478bd9Sstevel@tonic-gate 	switch (mechanism) {
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate 	case CKM_DES_ECB:
3367c478bd9Sstevel@tonic-gate 	case CKM_DES3_ECB:
3377c478bd9Sstevel@tonic-gate 	{
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 		ulong_t i;
3407c478bd9Sstevel@tonic-gate 		uint8_t *tmp_inbuf;
3417c478bd9Sstevel@tonic-gate 		uint8_t *tmp_outbuf;
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate 		for (i = 0; i < out_len; i += DES_BLOCK_LEN) {
3447c478bd9Sstevel@tonic-gate 			tmp_inbuf = &in_buf[i];
3457c478bd9Sstevel@tonic-gate 			tmp_outbuf = &out_buf[i];
3467c478bd9Sstevel@tonic-gate 			/* Crunch one block of data for DES. */
3477c478bd9Sstevel@tonic-gate 			if (soft_des_ctx->key_type == CKK_DES)
34823c57df7Smcpowers 				(void) des_crunch_block(
34923c57df7Smcpowers 				    soft_des_ctx->key_sched,
3507c478bd9Sstevel@tonic-gate 				    tmp_inbuf, tmp_outbuf, B_FALSE);
3517c478bd9Sstevel@tonic-gate 			else
35223c57df7Smcpowers 				(void) des3_crunch_block(
35323c57df7Smcpowers 				    soft_des_ctx->key_sched,
3547c478bd9Sstevel@tonic-gate 				    tmp_inbuf, tmp_outbuf, B_FALSE);
3557c478bd9Sstevel@tonic-gate 		}
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate 		if (update) {
3587c478bd9Sstevel@tonic-gate 			/*
3597c478bd9Sstevel@tonic-gate 			 * For encrypt update, if there is remaining
3607c478bd9Sstevel@tonic-gate 			 * data, save it and its length in the context.
3617c478bd9Sstevel@tonic-gate 			 */
3627c478bd9Sstevel@tonic-gate 			if (remain != 0)
3637c478bd9Sstevel@tonic-gate 				(void) memcpy(soft_des_ctx->data, pData +
3647c478bd9Sstevel@tonic-gate 				    (ulDataLen - remain), remain);
3657c478bd9Sstevel@tonic-gate 			soft_des_ctx->remain_len = remain;
3667c478bd9Sstevel@tonic-gate 		}
3677c478bd9Sstevel@tonic-gate 
3687c478bd9Sstevel@tonic-gate 		*pulEncryptedLen = out_len;
3697c478bd9Sstevel@tonic-gate 		break;
3707c478bd9Sstevel@tonic-gate 	}
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate 	case CKM_DES_CBC:
3737c478bd9Sstevel@tonic-gate 	case CKM_DES_CBC_PAD:
3747c478bd9Sstevel@tonic-gate 	case CKM_DES3_CBC:
3757c478bd9Sstevel@tonic-gate 	case CKM_DES3_CBC_PAD:
3767c478bd9Sstevel@tonic-gate 	{
3777c478bd9Sstevel@tonic-gate 		crypto_data_t out;
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate 		out.cd_format =  CRYPTO_DATA_RAW;
3807c478bd9Sstevel@tonic-gate 		out.cd_offset = 0;
3817c478bd9Sstevel@tonic-gate 		out.cd_length = out_len;
3827c478bd9Sstevel@tonic-gate 		out.cd_raw.iov_base = (char *)out_buf;
3837c478bd9Sstevel@tonic-gate 		out.cd_raw.iov_len = out_len;
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate 		/* Encrypt multiple blocks of data. */
3867c478bd9Sstevel@tonic-gate 		rc = des_encrypt_contiguous_blocks(
3877c478bd9Sstevel@tonic-gate 		    (des_ctx_t *)soft_des_ctx->des_cbc,
3887c478bd9Sstevel@tonic-gate 		    (char *)in_buf, out_len, &out);
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate 		if (rc != 0)
3917c478bd9Sstevel@tonic-gate 			goto encrypt_failed;
3927c478bd9Sstevel@tonic-gate 
3937c478bd9Sstevel@tonic-gate 		if (update) {
3947c478bd9Sstevel@tonic-gate 			/*
3957c478bd9Sstevel@tonic-gate 			 * For encrypt update, if there is remaining data,
3967c478bd9Sstevel@tonic-gate 			 * save it and its length in the context.
3977c478bd9Sstevel@tonic-gate 			 */
3987c478bd9Sstevel@tonic-gate 			if (remain != 0)
3997c478bd9Sstevel@tonic-gate 				(void) memcpy(soft_des_ctx->data, pData +
4007c478bd9Sstevel@tonic-gate 				    (ulDataLen - remain), remain);
4017c478bd9Sstevel@tonic-gate 			soft_des_ctx->remain_len = remain;
4027c478bd9Sstevel@tonic-gate 		} else if (pad_mechanism) {
4037c478bd9Sstevel@tonic-gate 			/*
4047c478bd9Sstevel@tonic-gate 			 * Save the remainder of the input
4057c478bd9Sstevel@tonic-gate 			 * block in a temporary block because
4067c478bd9Sstevel@tonic-gate 			 * we don't want to overrun the input buffer
4077c478bd9Sstevel@tonic-gate 			 * by tacking on pad bytes.
4087c478bd9Sstevel@tonic-gate 			 */
4097c478bd9Sstevel@tonic-gate 			CK_BYTE tmpblock[DES_BLOCK_LEN];
4107c478bd9Sstevel@tonic-gate 			(void) memcpy(tmpblock, in_buf + out_len,
4117c478bd9Sstevel@tonic-gate 			    ulDataLen - out_len);
4127c478bd9Sstevel@tonic-gate 			soft_add_pkcs7_padding(tmpblock +
4137c478bd9Sstevel@tonic-gate 			    (ulDataLen - out_len),
4147c478bd9Sstevel@tonic-gate 			    DES_BLOCK_LEN, ulDataLen - out_len);
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate 			out.cd_offset = out_len;
4177c478bd9Sstevel@tonic-gate 			out.cd_length = DES_BLOCK_LEN;
4187c478bd9Sstevel@tonic-gate 			out.cd_raw.iov_base = (char *)out_buf;
4197c478bd9Sstevel@tonic-gate 			out.cd_raw.iov_len = out_len + DES_BLOCK_LEN;
4207c478bd9Sstevel@tonic-gate 
4217c478bd9Sstevel@tonic-gate 			/* Encrypt last block containing pad bytes. */
4227c478bd9Sstevel@tonic-gate 			rc = des_encrypt_contiguous_blocks(
4237c478bd9Sstevel@tonic-gate 			    (des_ctx_t *)soft_des_ctx->des_cbc,
4247c478bd9Sstevel@tonic-gate 			    (char *)tmpblock, DES_BLOCK_LEN, &out);
4257c478bd9Sstevel@tonic-gate 			out_len += DES_BLOCK_LEN;
4267c478bd9Sstevel@tonic-gate 		}
4277c478bd9Sstevel@tonic-gate 
4287c478bd9Sstevel@tonic-gate 		if (rc == 0) {
4297c478bd9Sstevel@tonic-gate 			*pulEncryptedLen = out_len;
4307c478bd9Sstevel@tonic-gate 			break;
4317c478bd9Sstevel@tonic-gate 		}
4327c478bd9Sstevel@tonic-gate encrypt_failed:
4337c478bd9Sstevel@tonic-gate 		*pulEncryptedLen = 0;
4347c478bd9Sstevel@tonic-gate 		rv = CKR_FUNCTION_FAILED;
4357c478bd9Sstevel@tonic-gate 		goto cleanup;
4367c478bd9Sstevel@tonic-gate 
4377c478bd9Sstevel@tonic-gate 	}
4387c478bd9Sstevel@tonic-gate 	} /* end switch */
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate 	if (update)
4417c478bd9Sstevel@tonic-gate 		return (CKR_OK);
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate 	/*
4447c478bd9Sstevel@tonic-gate 	 * The following code will be executed if the caller is
4457c478bd9Sstevel@tonic-gate 	 * soft_encrypt() or an error occurred. The encryption
4467c478bd9Sstevel@tonic-gate 	 * operation will be terminated so we need to do some cleanup.
4477c478bd9Sstevel@tonic-gate 	 */
4487c478bd9Sstevel@tonic-gate cleanup:
4497c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&session_p->session_mutex);
4507c478bd9Sstevel@tonic-gate 	des_ctx = (des_ctx_t *)soft_des_ctx->des_cbc;
4517c478bd9Sstevel@tonic-gate 	if (des_ctx != NULL) {
4527c478bd9Sstevel@tonic-gate 		bzero(des_ctx->dc_keysched, des_ctx->dc_keysched_len);
4537c478bd9Sstevel@tonic-gate 		free(soft_des_ctx->des_cbc);
4547c478bd9Sstevel@tonic-gate 	}
4557c478bd9Sstevel@tonic-gate 
4567c478bd9Sstevel@tonic-gate 	bzero(soft_des_ctx->key_sched, soft_des_ctx->keysched_len);
4577c478bd9Sstevel@tonic-gate 	free(soft_des_ctx->key_sched);
4587c478bd9Sstevel@tonic-gate 	free(session_p->encrypt.context);
4597c478bd9Sstevel@tonic-gate 	session_p->encrypt.context = NULL;
4607c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&session_p->session_mutex);
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate 	return (rv);
4637c478bd9Sstevel@tonic-gate }
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate /*
4677c478bd9Sstevel@tonic-gate  * soft_des_decrypt_common()
4687c478bd9Sstevel@tonic-gate  *
4697c478bd9Sstevel@tonic-gate  * Arguments:
4707c478bd9Sstevel@tonic-gate  *      session_p:	pointer to soft_session_t struct
4717c478bd9Sstevel@tonic-gate  *	pEncrypted:	pointer to the input data to be decrypted
4727c478bd9Sstevel@tonic-gate  *	ulEncryptedLen:	length of the input data
4737c478bd9Sstevel@tonic-gate  *	pData:		pointer to the output data
4747c478bd9Sstevel@tonic-gate  *	pulDataLen:	pointer to the length of the output data
4757c478bd9Sstevel@tonic-gate  *	Update:		boolean flag indicates caller is soft_decrypt
4767c478bd9Sstevel@tonic-gate  *			or soft_decrypt_update
4777c478bd9Sstevel@tonic-gate  *
4787c478bd9Sstevel@tonic-gate  * Description:
4797c478bd9Sstevel@tonic-gate  *      This function calls the corresponding decrypt routine based
4807c478bd9Sstevel@tonic-gate  *	on the mechanism.
4817c478bd9Sstevel@tonic-gate  *
4827c478bd9Sstevel@tonic-gate  * Returns:
4837c478bd9Sstevel@tonic-gate  *      CKR_OK: success
4847c478bd9Sstevel@tonic-gate  *      CKR_BUFFER_TOO_SMALL: the output buffer provided by application
4857c478bd9Sstevel@tonic-gate  *			      is too small
4867c478bd9Sstevel@tonic-gate  *	CKR_ENCRYPTED_DATA_LEN_RANGE: the input data is not a multiple
4877c478bd9Sstevel@tonic-gate  *				      of blocksize
4887c478bd9Sstevel@tonic-gate  *	CKR_FUNCTION_FAILED: decrypt function failed
4897c478bd9Sstevel@tonic-gate  */
4907c478bd9Sstevel@tonic-gate CK_RV
soft_des_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)4917c478bd9Sstevel@tonic-gate soft_des_decrypt_common(soft_session_t *session_p, CK_BYTE_PTR pEncrypted,
4927c478bd9Sstevel@tonic-gate     CK_ULONG ulEncryptedLen, CK_BYTE_PTR pData,
4937c478bd9Sstevel@tonic-gate     CK_ULONG_PTR pulDataLen, boolean_t update)
4947c478bd9Sstevel@tonic-gate {
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate 	int rc = 0;
4977c478bd9Sstevel@tonic-gate 	CK_RV rv = CKR_OK;
4987c478bd9Sstevel@tonic-gate 	soft_des_ctx_t *soft_des_ctx =
4997c478bd9Sstevel@tonic-gate 	    (soft_des_ctx_t *)session_p->decrypt.context;
5007c478bd9Sstevel@tonic-gate 	des_ctx_t *des_ctx;
5017c478bd9Sstevel@tonic-gate 	CK_MECHANISM_TYPE mechanism = session_p->decrypt.mech.mechanism;
5027c478bd9Sstevel@tonic-gate 	CK_BYTE *in_buf = NULL;
5037c478bd9Sstevel@tonic-gate 	CK_BYTE *out_buf = NULL;
5047c478bd9Sstevel@tonic-gate 	CK_ULONG out_len;
5057c478bd9Sstevel@tonic-gate 	CK_ULONG total_len;
5067c478bd9Sstevel@tonic-gate 	CK_ULONG remain;
5077c478bd9Sstevel@tonic-gate 	boolean_t pad_mechanism = B_FALSE;
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate 	pad_mechanism = (mechanism == CKM_DES_CBC_PAD ||
5107c478bd9Sstevel@tonic-gate 	    mechanism == CKM_DES3_CBC_PAD);
5117c478bd9Sstevel@tonic-gate 	/*
5127c478bd9Sstevel@tonic-gate 	 * DES only takes input length that is a multiple of 8 bytes
5137c478bd9Sstevel@tonic-gate 	 * for C_Decrypt function with the mechanism CKM_DES<n>_ECB,
5147c478bd9Sstevel@tonic-gate 	 * CKM_DES<n>_CBC or CKM_DES<n>_CBC_PAD.
5157c478bd9Sstevel@tonic-gate 	 *
5167c478bd9Sstevel@tonic-gate 	 * DES allows any input length for C_DecryptUpdate function.
5177c478bd9Sstevel@tonic-gate 	 */
5187c478bd9Sstevel@tonic-gate 	if (!update) {
5197c478bd9Sstevel@tonic-gate 		/*
5207c478bd9Sstevel@tonic-gate 		 * Called by C_Decrypt
5217c478bd9Sstevel@tonic-gate 		 */
5227c478bd9Sstevel@tonic-gate 		if ((ulEncryptedLen % DES_BLOCK_LEN) != 0) {
5237c478bd9Sstevel@tonic-gate 			rv = CKR_ENCRYPTED_DATA_LEN_RANGE;
5247c478bd9Sstevel@tonic-gate 			goto cleanup;
5257c478bd9Sstevel@tonic-gate 		}
5267c478bd9Sstevel@tonic-gate 
5277c478bd9Sstevel@tonic-gate 		/*
5287c478bd9Sstevel@tonic-gate 		 * If application asks for the length of the output buffer
5297c478bd9Sstevel@tonic-gate 		 * to hold the plaintext?
5307c478bd9Sstevel@tonic-gate 		 */
5317c478bd9Sstevel@tonic-gate 		if (pData == NULL) {
5327c478bd9Sstevel@tonic-gate 			*pulDataLen = ulEncryptedLen;
5337c478bd9Sstevel@tonic-gate 			return (CKR_OK);
5347c478bd9Sstevel@tonic-gate 		}
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate 		/* Is the application-supplied buffer large enough? */
5377c478bd9Sstevel@tonic-gate 		if (!pad_mechanism) {
5387c478bd9Sstevel@tonic-gate 			if (*pulDataLen < ulEncryptedLen) {
5397c478bd9Sstevel@tonic-gate 				*pulDataLen = ulEncryptedLen;
5407c478bd9Sstevel@tonic-gate 				return (CKR_BUFFER_TOO_SMALL);
5417c478bd9Sstevel@tonic-gate 			}
5427c478bd9Sstevel@tonic-gate 
5437c478bd9Sstevel@tonic-gate 			/* Set output length same as input length. */
5447c478bd9Sstevel@tonic-gate 			out_len = ulEncryptedLen;
5457c478bd9Sstevel@tonic-gate 		} else {
5467c478bd9Sstevel@tonic-gate 			/*
5477c478bd9Sstevel@tonic-gate 			 * For CKM_DES<n>_CBC_PAD, we don't know how
5487c478bd9Sstevel@tonic-gate 			 * many bytes for padding at this time, so
5497c478bd9Sstevel@tonic-gate 			 * we'd assume one block was padded.
5507c478bd9Sstevel@tonic-gate 			 */
5517c478bd9Sstevel@tonic-gate 			if (*pulDataLen < (ulEncryptedLen - DES_BLOCK_LEN)) {
5527c478bd9Sstevel@tonic-gate 				*pulDataLen = ulEncryptedLen - DES_BLOCK_LEN;
5537c478bd9Sstevel@tonic-gate 				return (CKR_BUFFER_TOO_SMALL);
5547c478bd9Sstevel@tonic-gate 			}
5557c478bd9Sstevel@tonic-gate 			out_len = ulEncryptedLen - DES_BLOCK_LEN;
5567c478bd9Sstevel@tonic-gate 		}
5577c478bd9Sstevel@tonic-gate 		in_buf = pEncrypted;
5587c478bd9Sstevel@tonic-gate 		out_buf = pData;
5597c478bd9Sstevel@tonic-gate 	} else {
5607c478bd9Sstevel@tonic-gate 		/*
5617c478bd9Sstevel@tonic-gate 		 *  Called by C_DecryptUpdate
5627c478bd9Sstevel@tonic-gate 		 *
5637c478bd9Sstevel@tonic-gate 		 * Add the lengths of last remaining data and current
5647c478bd9Sstevel@tonic-gate 		 * input data together to get the total input length.
5657c478bd9Sstevel@tonic-gate 		 */
5667c478bd9Sstevel@tonic-gate 		total_len = soft_des_ctx->remain_len + ulEncryptedLen;
5677c478bd9Sstevel@tonic-gate 
5687c478bd9Sstevel@tonic-gate 		/*
5697c478bd9Sstevel@tonic-gate 		 * If the total input length is less than one blocksize,
5707c478bd9Sstevel@tonic-gate 		 * or if the total input length is just one blocksize and
5717c478bd9Sstevel@tonic-gate 		 * the mechanism is CKM_DES<n>_CBC_PAD, we will need to delay
5727c478bd9Sstevel@tonic-gate 		 * decryption until when more data comes in next
5737c478bd9Sstevel@tonic-gate 		 * C_DecryptUpdate or when C_DecryptFinal is called.
5747c478bd9Sstevel@tonic-gate 		 */
5757c478bd9Sstevel@tonic-gate 		if ((total_len < DES_BLOCK_LEN) ||
5767c478bd9Sstevel@tonic-gate 		    (pad_mechanism && (total_len == DES_BLOCK_LEN))) {
5777c478bd9Sstevel@tonic-gate 			if (pEncrypted != NULL) {
5787c478bd9Sstevel@tonic-gate 				/*
5797c478bd9Sstevel@tonic-gate 				 * Save input data and its length in
5807c478bd9Sstevel@tonic-gate 				 * the remaining buffer of DES context.
5817c478bd9Sstevel@tonic-gate 				 */
5827c478bd9Sstevel@tonic-gate 				(void) memcpy(soft_des_ctx->data +
5837c478bd9Sstevel@tonic-gate 				    soft_des_ctx->remain_len,
5847c478bd9Sstevel@tonic-gate 				    pEncrypted, ulEncryptedLen);
5857c478bd9Sstevel@tonic-gate 				soft_des_ctx->remain_len += ulEncryptedLen;
5867c478bd9Sstevel@tonic-gate 			}
5877c478bd9Sstevel@tonic-gate 
5887c478bd9Sstevel@tonic-gate 			/* Set output data length to 0. */
5897c478bd9Sstevel@tonic-gate 			*pulDataLen = 0;
5907c478bd9Sstevel@tonic-gate 			return (CKR_OK);
5917c478bd9Sstevel@tonic-gate 		}
5927c478bd9Sstevel@tonic-gate 
5937c478bd9Sstevel@tonic-gate 		/* Compute the length of remaing data. */
5947c478bd9Sstevel@tonic-gate 		remain = total_len % DES_BLOCK_LEN;
5957c478bd9Sstevel@tonic-gate 
5967c478bd9Sstevel@tonic-gate 		/*
5977c478bd9Sstevel@tonic-gate 		 * Make sure that the output length is a multiple of
5987c478bd9Sstevel@tonic-gate 		 * blocksize.
5997c478bd9Sstevel@tonic-gate 		 */
6007c478bd9Sstevel@tonic-gate 		out_len = total_len - remain;
6017c478bd9Sstevel@tonic-gate 
6027c478bd9Sstevel@tonic-gate 		if (pad_mechanism) {
6037c478bd9Sstevel@tonic-gate 			/*
6047c478bd9Sstevel@tonic-gate 			 * If the input data length is a multiple of
6057c478bd9Sstevel@tonic-gate 			 * blocksize, then save the last block of input
6067c478bd9Sstevel@tonic-gate 			 * data in the remaining buffer. C_DecryptFinal
6077c478bd9Sstevel@tonic-gate 			 * will handle this last block of data.
6087c478bd9Sstevel@tonic-gate 			 */
6097c478bd9Sstevel@tonic-gate 			if (remain == 0) {
6107c478bd9Sstevel@tonic-gate 				remain = DES_BLOCK_LEN;
6117c478bd9Sstevel@tonic-gate 				out_len -= DES_BLOCK_LEN;
6127c478bd9Sstevel@tonic-gate 			}
6137c478bd9Sstevel@tonic-gate 		}
6147c478bd9Sstevel@tonic-gate 
6157c478bd9Sstevel@tonic-gate 		/*
6167c478bd9Sstevel@tonic-gate 		 * If application asks for the length of the output buffer
6177c478bd9Sstevel@tonic-gate 		 * to hold the plaintext?
6187c478bd9Sstevel@tonic-gate 		 */
6197c478bd9Sstevel@tonic-gate 		if (pData == NULL) {
6207c478bd9Sstevel@tonic-gate 			*pulDataLen = out_len;
6217c478bd9Sstevel@tonic-gate 			return (CKR_OK);
6227c478bd9Sstevel@tonic-gate 		}
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate 		/*
6257c478bd9Sstevel@tonic-gate 		 * Is the application-supplied buffer large enough?
6267c478bd9Sstevel@tonic-gate 		 */
6277c478bd9Sstevel@tonic-gate 		if (*pulDataLen < out_len) {
6287c478bd9Sstevel@tonic-gate 			*pulDataLen = out_len;
6297c478bd9Sstevel@tonic-gate 			return (CKR_BUFFER_TOO_SMALL);
6307c478bd9Sstevel@tonic-gate 		}
6317c478bd9Sstevel@tonic-gate 
6327c478bd9Sstevel@tonic-gate 		if (soft_des_ctx->remain_len != 0) {
6337c478bd9Sstevel@tonic-gate 			/*
6347c478bd9Sstevel@tonic-gate 			 * Copy last remaining data and current input data
6357c478bd9Sstevel@tonic-gate 			 * to the output buffer.
6367c478bd9Sstevel@tonic-gate 			 */
6377c478bd9Sstevel@tonic-gate 			(void) memmove(pData + soft_des_ctx->remain_len,
6387c478bd9Sstevel@tonic-gate 			    pEncrypted, out_len - soft_des_ctx->remain_len);
6397c478bd9Sstevel@tonic-gate 			(void) memcpy(pData, soft_des_ctx->data,
6407c478bd9Sstevel@tonic-gate 			    soft_des_ctx->remain_len);
6417c478bd9Sstevel@tonic-gate 			bzero(soft_des_ctx->data, soft_des_ctx->remain_len);
6427c478bd9Sstevel@tonic-gate 
6437c478bd9Sstevel@tonic-gate 			in_buf = pData;
6447c478bd9Sstevel@tonic-gate 		} else {
6457c478bd9Sstevel@tonic-gate 			in_buf = pEncrypted;
6467c478bd9Sstevel@tonic-gate 		}
6477c478bd9Sstevel@tonic-gate 		out_buf = pData;
6487c478bd9Sstevel@tonic-gate 	}
6497c478bd9Sstevel@tonic-gate 
6507c478bd9Sstevel@tonic-gate 	/*
6517c478bd9Sstevel@tonic-gate 	 * Begin Decryption.
6527c478bd9Sstevel@tonic-gate 	 */
6537c478bd9Sstevel@tonic-gate 	switch (mechanism) {
6547c478bd9Sstevel@tonic-gate 
6557c478bd9Sstevel@tonic-gate 	case CKM_DES_ECB:
6567c478bd9Sstevel@tonic-gate 	case CKM_DES3_ECB:
6577c478bd9Sstevel@tonic-gate 	{
6587c478bd9Sstevel@tonic-gate 		uint8_t *tmp_inbuf;
6597c478bd9Sstevel@tonic-gate 		uint8_t *tmp_outbuf;
6607c478bd9Sstevel@tonic-gate 		ulong_t i;
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate 		for (i = 0; i < out_len; i += DES_BLOCK_LEN) {
6637c478bd9Sstevel@tonic-gate 			tmp_inbuf = &in_buf[i];
6647c478bd9Sstevel@tonic-gate 			tmp_outbuf = &out_buf[i];
6657c478bd9Sstevel@tonic-gate 			/* Crunch one block of data for DES. */
6667c478bd9Sstevel@tonic-gate 			if (soft_des_ctx->key_type == CKK_DES)
66723c57df7Smcpowers 				(void) des_crunch_block(
66823c57df7Smcpowers 				    soft_des_ctx->key_sched,
6697c478bd9Sstevel@tonic-gate 				    tmp_inbuf, tmp_outbuf, B_TRUE);
6707c478bd9Sstevel@tonic-gate 			else
67123c57df7Smcpowers 				(void) des3_crunch_block(
67223c57df7Smcpowers 				    soft_des_ctx->key_sched,
6737c478bd9Sstevel@tonic-gate 				    tmp_inbuf, tmp_outbuf, B_TRUE);
6747c478bd9Sstevel@tonic-gate 		}
6757c478bd9Sstevel@tonic-gate 
6767c478bd9Sstevel@tonic-gate 		if (update) {
6777c478bd9Sstevel@tonic-gate 			/*
6787c478bd9Sstevel@tonic-gate 			 * For decrypt update, if there is remaining
6797c478bd9Sstevel@tonic-gate 			 * data, save it and its length in the context.
6807c478bd9Sstevel@tonic-gate 			 */
6817c478bd9Sstevel@tonic-gate 			if (remain != 0)
6827c478bd9Sstevel@tonic-gate 				(void) memcpy(soft_des_ctx->data, pEncrypted +
6837c478bd9Sstevel@tonic-gate 				    (ulEncryptedLen - remain), remain);
6847c478bd9Sstevel@tonic-gate 			soft_des_ctx->remain_len = remain;
6857c478bd9Sstevel@tonic-gate 		}
6867c478bd9Sstevel@tonic-gate 
6877c478bd9Sstevel@tonic-gate 		*pulDataLen = out_len;
6887c478bd9Sstevel@tonic-gate 		break;
6897c478bd9Sstevel@tonic-gate 	}
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate 	case CKM_DES_CBC:
6927c478bd9Sstevel@tonic-gate 	case CKM_DES_CBC_PAD:
6937c478bd9Sstevel@tonic-gate 	case CKM_DES3_CBC:
6947c478bd9Sstevel@tonic-gate 	case CKM_DES3_CBC_PAD:
6957c478bd9Sstevel@tonic-gate 	{
6967c478bd9Sstevel@tonic-gate 		crypto_data_t out;
6977c478bd9Sstevel@tonic-gate 		CK_ULONG rem_len;
6987c478bd9Sstevel@tonic-gate 		uint8_t last_block[DES_BLOCK_LEN];
6997c478bd9Sstevel@tonic-gate 
7007c478bd9Sstevel@tonic-gate 		out.cd_format =  CRYPTO_DATA_RAW;
7017c478bd9Sstevel@tonic-gate 		out.cd_offset = 0;
7027c478bd9Sstevel@tonic-gate 		out.cd_length = out_len;
7037c478bd9Sstevel@tonic-gate 		out.cd_raw.iov_base = (char *)out_buf;
7047c478bd9Sstevel@tonic-gate 		out.cd_raw.iov_len = out_len;
7057c478bd9Sstevel@tonic-gate 
7067c478bd9Sstevel@tonic-gate 		/* Decrypt multiple blocks of data. */
7077c478bd9Sstevel@tonic-gate 		rc = des_decrypt_contiguous_blocks(
7087c478bd9Sstevel@tonic-gate 		    (des_ctx_t *)soft_des_ctx->des_cbc,
7097c478bd9Sstevel@tonic-gate 		    (char *)in_buf, out_len, &out);
7107c478bd9Sstevel@tonic-gate 
7117c478bd9Sstevel@tonic-gate 		if (rc != 0)
7127c478bd9Sstevel@tonic-gate 			goto decrypt_failed;
7137c478bd9Sstevel@tonic-gate 
7147c478bd9Sstevel@tonic-gate 		if (pad_mechanism && !update) {
7157c478bd9Sstevel@tonic-gate 			/* Decrypt last block containing pad bytes. */
7167c478bd9Sstevel@tonic-gate 			out.cd_offset = 0;
7177c478bd9Sstevel@tonic-gate 			out.cd_length = DES_BLOCK_LEN;
7187c478bd9Sstevel@tonic-gate 			out.cd_raw.iov_base = (char *)last_block;
7197c478bd9Sstevel@tonic-gate 			out.cd_raw.iov_len = DES_BLOCK_LEN;
7207c478bd9Sstevel@tonic-gate 
7217c478bd9Sstevel@tonic-gate 			/* Decrypt last block containing pad bytes. */
7227c478bd9Sstevel@tonic-gate 			rc = des_decrypt_contiguous_blocks(
7237c478bd9Sstevel@tonic-gate 			    (des_ctx_t *)soft_des_ctx->des_cbc,
7247c478bd9Sstevel@tonic-gate 			    (char *)in_buf + out_len, DES_BLOCK_LEN, &out);
7257c478bd9Sstevel@tonic-gate 
7267c478bd9Sstevel@tonic-gate 			if (rc != 0)
7277c478bd9Sstevel@tonic-gate 				goto decrypt_failed;
7287c478bd9Sstevel@tonic-gate 
7297c478bd9Sstevel@tonic-gate 			/*
7307c478bd9Sstevel@tonic-gate 			 * Remove padding bytes after decryption of
7317c478bd9Sstevel@tonic-gate 			 * ciphertext block to produce the original
7327c478bd9Sstevel@tonic-gate 			 * plaintext.
7337c478bd9Sstevel@tonic-gate 			 */
7347c478bd9Sstevel@tonic-gate 			rv = soft_remove_pkcs7_padding(last_block,
735*726fad2aSDina K Nimeh 			    DES_BLOCK_LEN, &rem_len);
7367c478bd9Sstevel@tonic-gate 			if (rv == CKR_OK) {
7377c478bd9Sstevel@tonic-gate 				if (rem_len != 0)
7387c478bd9Sstevel@tonic-gate 					(void) memcpy(out_buf + out_len,
7397c478bd9Sstevel@tonic-gate 					    last_block, rem_len);
7407c478bd9Sstevel@tonic-gate 				*pulDataLen = out_len + rem_len;
7417c478bd9Sstevel@tonic-gate 			} else {
7427c478bd9Sstevel@tonic-gate 				*pulDataLen = 0;
7437c478bd9Sstevel@tonic-gate 				goto cleanup;
7447c478bd9Sstevel@tonic-gate 			}
7457c478bd9Sstevel@tonic-gate 		} else {
7467c478bd9Sstevel@tonic-gate 			*pulDataLen = out_len;
7477c478bd9Sstevel@tonic-gate 		}
7487c478bd9Sstevel@tonic-gate 
7497c478bd9Sstevel@tonic-gate 		if (update) {
7507c478bd9Sstevel@tonic-gate 			/*
7517c478bd9Sstevel@tonic-gate 			 * For decrypt update, if there is remaining data,
7527c478bd9Sstevel@tonic-gate 			 * save it and its length in the context.
7537c478bd9Sstevel@tonic-gate 			 */
7547c478bd9Sstevel@tonic-gate 			if (remain != 0)
7557c478bd9Sstevel@tonic-gate 				(void) memcpy(soft_des_ctx->data, pEncrypted +
7567c478bd9Sstevel@tonic-gate 				    (ulEncryptedLen - remain), remain);
7577c478bd9Sstevel@tonic-gate 			soft_des_ctx->remain_len = remain;
7587c478bd9Sstevel@tonic-gate 		}
7597c478bd9Sstevel@tonic-gate 
7607c478bd9Sstevel@tonic-gate 		if (rc == 0)
7617c478bd9Sstevel@tonic-gate 			break;
7627c478bd9Sstevel@tonic-gate decrypt_failed:
7637c478bd9Sstevel@tonic-gate 		*pulDataLen = 0;
7647c478bd9Sstevel@tonic-gate 		rv = CKR_FUNCTION_FAILED;
7657c478bd9Sstevel@tonic-gate 		goto cleanup;
7667c478bd9Sstevel@tonic-gate 	}
7677c478bd9Sstevel@tonic-gate 	} /* end switch */
7687c478bd9Sstevel@tonic-gate 
7697c478bd9Sstevel@tonic-gate 	if (update)
7707c478bd9Sstevel@tonic-gate 		return (CKR_OK);
7717c478bd9Sstevel@tonic-gate 
7727c478bd9Sstevel@tonic-gate 	/*
7737c478bd9Sstevel@tonic-gate 	 * The following code will be executed if the caller is
7747c478bd9Sstevel@tonic-gate 	 * soft_decrypt() or an error occurred. The decryption
7757c478bd9Sstevel@tonic-gate 	 * operation will be terminated so we need to do some cleanup.
7767c478bd9Sstevel@tonic-gate 	 */
7777c478bd9Sstevel@tonic-gate cleanup:
7787c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&session_p->session_mutex);
7797c478bd9Sstevel@tonic-gate 	des_ctx = (des_ctx_t *)soft_des_ctx->des_cbc;
7807c478bd9Sstevel@tonic-gate 	if (des_ctx != NULL) {
7817c478bd9Sstevel@tonic-gate 		bzero(des_ctx->dc_keysched, des_ctx->dc_keysched_len);
7827c478bd9Sstevel@tonic-gate 		free(soft_des_ctx->des_cbc);
7837c478bd9Sstevel@tonic-gate 	}
7847c478bd9Sstevel@tonic-gate 
7857c478bd9Sstevel@tonic-gate 	bzero(soft_des_ctx->key_sched, soft_des_ctx->keysched_len);
7867c478bd9Sstevel@tonic-gate 	free(soft_des_ctx->key_sched);
7877c478bd9Sstevel@tonic-gate 	free(session_p->decrypt.context);
7887c478bd9Sstevel@tonic-gate 	session_p->decrypt.context = NULL;
7897c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&session_p->session_mutex);
7907c478bd9Sstevel@tonic-gate 
7917c478bd9Sstevel@tonic-gate 	return (rv);
7927c478bd9Sstevel@tonic-gate }
7937c478bd9Sstevel@tonic-gate 
7947c478bd9Sstevel@tonic-gate 
7957c478bd9Sstevel@tonic-gate /*
7967c478bd9Sstevel@tonic-gate  * Allocate and initialize a context for DES CBC mode of operation.
7977c478bd9Sstevel@tonic-gate  */
7987c478bd9Sstevel@tonic-gate void *
des_cbc_ctx_init(void * key_sched,size_t size,uint8_t * ivec,CK_KEY_TYPE type)7997c478bd9Sstevel@tonic-gate des_cbc_ctx_init(void *key_sched, size_t size, uint8_t *ivec, CK_KEY_TYPE type)
8007c478bd9Sstevel@tonic-gate {
8017c478bd9Sstevel@tonic-gate 
80223c57df7Smcpowers 	cbc_ctx_t *cbc_ctx;
8037c478bd9Sstevel@tonic-gate 
80423c57df7Smcpowers 	if ((cbc_ctx = calloc(1, sizeof (cbc_ctx_t))) == NULL)
8057c478bd9Sstevel@tonic-gate 		return (NULL);
8067c478bd9Sstevel@tonic-gate 
80716239bc8SMark Powers 	cbc_ctx->cbc_keysched = key_sched;
8087c478bd9Sstevel@tonic-gate 
80916239bc8SMark Powers 	(void) memcpy(&cbc_ctx->cbc_iv[0], ivec, DES_BLOCK_LEN);
8107c478bd9Sstevel@tonic-gate 
81116239bc8SMark Powers 	cbc_ctx->cbc_lastp = (uint8_t *)&cbc_ctx->cbc_iv[0];
81216239bc8SMark Powers 	cbc_ctx->cbc_keysched_len = size;
8137c478bd9Sstevel@tonic-gate 	if (type == CKK_DES)
81416239bc8SMark Powers 		cbc_ctx->cbc_flags |= CBC_MODE;
8157c478bd9Sstevel@tonic-gate 	else
81616239bc8SMark Powers 		cbc_ctx->cbc_flags |= CBC_MODE | DES3_STRENGTH;
8177c478bd9Sstevel@tonic-gate 
81823c57df7Smcpowers 	return (cbc_ctx);
8197c478bd9Sstevel@tonic-gate 
8207c478bd9Sstevel@tonic-gate }
8217c478bd9Sstevel@tonic-gate 
8227c478bd9Sstevel@tonic-gate /*
8237c478bd9Sstevel@tonic-gate  * Allocate and initialize DES contexts for both signing and encrypting,
8247c478bd9Sstevel@tonic-gate  * saving both context pointers in the session struct. For general-length DES
8257c478bd9Sstevel@tonic-gate  * MAC, check the length in the parameter to see if it is in the right range.
8267c478bd9Sstevel@tonic-gate  */
8277c478bd9Sstevel@tonic-gate CK_RV
soft_des_sign_verify_init_common(soft_session_t * session_p,CK_MECHANISM_PTR pMechanism,soft_object_t * key_p,boolean_t sign_op)8287c478bd9Sstevel@tonic-gate soft_des_sign_verify_init_common(soft_session_t *session_p,
8297c478bd9Sstevel@tonic-gate 	CK_MECHANISM_PTR pMechanism, soft_object_t *key_p, boolean_t sign_op)
8307c478bd9Sstevel@tonic-gate {
8317c478bd9Sstevel@tonic-gate 	soft_des_ctx_t	*soft_des_ctx;
8327c478bd9Sstevel@tonic-gate 	CK_MECHANISM	encrypt_mech;
8337c478bd9Sstevel@tonic-gate 	CK_RV rv;
8347c478bd9Sstevel@tonic-gate 
8359627968bSmcpowers 	if ((key_p->class != CKO_SECRET_KEY) || (key_p->key_type != CKK_DES)) {
8367c478bd9Sstevel@tonic-gate 		return (CKR_KEY_TYPE_INCONSISTENT);
8377c478bd9Sstevel@tonic-gate 	}
8387c478bd9Sstevel@tonic-gate 
8397c478bd9Sstevel@tonic-gate 	/* allocate memory for the sign/verify context */
8407c478bd9Sstevel@tonic-gate 	soft_des_ctx = malloc(sizeof (soft_des_ctx_t));
8417c478bd9Sstevel@tonic-gate 	if (soft_des_ctx == NULL) {
8427c478bd9Sstevel@tonic-gate 		return (CKR_HOST_MEMORY);
8437c478bd9Sstevel@tonic-gate 	}
8447c478bd9Sstevel@tonic-gate 
8457c478bd9Sstevel@tonic-gate 	soft_des_ctx->key_type = key_p->key_type;
8467c478bd9Sstevel@tonic-gate 
8477c478bd9Sstevel@tonic-gate 	/* initialization vector is zero for DES MAC */
8487c478bd9Sstevel@tonic-gate 	bzero(soft_des_ctx->ivec, DES_BLOCK_LEN);
8497c478bd9Sstevel@tonic-gate 
8507c478bd9Sstevel@tonic-gate 	switch (pMechanism->mechanism) {
8517c478bd9Sstevel@tonic-gate 
8527c478bd9Sstevel@tonic-gate 	case CKM_DES_MAC_GENERAL:
8537c478bd9Sstevel@tonic-gate 
8547c478bd9Sstevel@tonic-gate 		if (pMechanism->ulParameterLen !=
8557c478bd9Sstevel@tonic-gate 		    sizeof (CK_MAC_GENERAL_PARAMS)) {
8567c478bd9Sstevel@tonic-gate 			free(soft_des_ctx);
8577c478bd9Sstevel@tonic-gate 			return (CKR_MECHANISM_PARAM_INVALID);
8587c478bd9Sstevel@tonic-gate 		}
8597c478bd9Sstevel@tonic-gate 
8607c478bd9Sstevel@tonic-gate 		if (*(CK_MAC_GENERAL_PARAMS *)pMechanism->pParameter >
8617c478bd9Sstevel@tonic-gate 		    DES_BLOCK_LEN) {
8627c478bd9Sstevel@tonic-gate 			free(soft_des_ctx);
8637c478bd9Sstevel@tonic-gate 			return (CKR_MECHANISM_PARAM_INVALID);
8647c478bd9Sstevel@tonic-gate 		}
8657c478bd9Sstevel@tonic-gate 
8667c478bd9Sstevel@tonic-gate 		soft_des_ctx->mac_len = *((CK_MAC_GENERAL_PARAMS_PTR)
8677c478bd9Sstevel@tonic-gate 		    pMechanism->pParameter);
8687c478bd9Sstevel@tonic-gate 
8697c478bd9Sstevel@tonic-gate 		/*FALLTHRU*/
8707c478bd9Sstevel@tonic-gate 	case CKM_DES_MAC:
8717c478bd9Sstevel@tonic-gate 
8727c478bd9Sstevel@tonic-gate 		/*
8737c478bd9Sstevel@tonic-gate 		 * For non-general DES MAC, output is always half as
8747c478bd9Sstevel@tonic-gate 		 * large as block size
8757c478bd9Sstevel@tonic-gate 		 */
8767c478bd9Sstevel@tonic-gate 		if (pMechanism->mechanism == CKM_DES_MAC) {
8777c478bd9Sstevel@tonic-gate 			soft_des_ctx->mac_len = DES_MAC_LEN;
8787c478bd9Sstevel@tonic-gate 		}
8797c478bd9Sstevel@tonic-gate 
8807c478bd9Sstevel@tonic-gate 		/* allocate a context for DES encryption */
8817c478bd9Sstevel@tonic-gate 		encrypt_mech.mechanism = CKM_DES_CBC_PAD;
8827c478bd9Sstevel@tonic-gate 		encrypt_mech.pParameter = (void *)soft_des_ctx->ivec;
8837c478bd9Sstevel@tonic-gate 		encrypt_mech.ulParameterLen = DES_BLOCK_LEN;
8847c478bd9Sstevel@tonic-gate 		rv = soft_encrypt_init_internal(session_p, &encrypt_mech,
8857c478bd9Sstevel@tonic-gate 		    key_p);
8867c478bd9Sstevel@tonic-gate 		if (rv != CKR_OK) {
8877c478bd9Sstevel@tonic-gate 			free(soft_des_ctx);
8887c478bd9Sstevel@tonic-gate 			return (rv);
8897c478bd9Sstevel@tonic-gate 		}
8907c478bd9Sstevel@tonic-gate 
8917c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_lock(&session_p->session_mutex);
8927c478bd9Sstevel@tonic-gate 
8937c478bd9Sstevel@tonic-gate 		if (sign_op) {
8947c478bd9Sstevel@tonic-gate 			session_p->sign.context = soft_des_ctx;
8957c478bd9Sstevel@tonic-gate 			session_p->sign.mech.mechanism = pMechanism->mechanism;
8967c478bd9Sstevel@tonic-gate 		} else {
8977c478bd9Sstevel@tonic-gate 			session_p->verify.context = soft_des_ctx;
8987c478bd9Sstevel@tonic-gate 			session_p->verify.mech.mechanism =
8997c478bd9Sstevel@tonic-gate 			    pMechanism->mechanism;
9007c478bd9Sstevel@tonic-gate 		}
9017c478bd9Sstevel@tonic-gate 
9027c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&session_p->session_mutex);
9037c478bd9Sstevel@tonic-gate 
9047c478bd9Sstevel@tonic-gate 		break;
9057c478bd9Sstevel@tonic-gate 	}
9067c478bd9Sstevel@tonic-gate 	return (CKR_OK);
9077c478bd9Sstevel@tonic-gate }
9087c478bd9Sstevel@tonic-gate 
9097c478bd9Sstevel@tonic-gate /*
9107c478bd9Sstevel@tonic-gate  * Called by soft_sign(), soft_sign_final(), soft_verify() or
9117c478bd9Sstevel@tonic-gate  * soft_verify_final().
9127c478bd9Sstevel@tonic-gate  */
9137c478bd9Sstevel@tonic-gate CK_RV
soft_des_sign_verify_common(soft_session_t * session_p,CK_BYTE_PTR pData,CK_ULONG ulDataLen,CK_BYTE_PTR pSigned,CK_ULONG_PTR pulSignedLen,boolean_t sign_op,boolean_t Final)9147c478bd9Sstevel@tonic-gate soft_des_sign_verify_common(soft_session_t *session_p, CK_BYTE_PTR pData,
9157c478bd9Sstevel@tonic-gate 	CK_ULONG ulDataLen, CK_BYTE_PTR pSigned, CK_ULONG_PTR pulSignedLen,
9167c478bd9Sstevel@tonic-gate 	boolean_t sign_op, boolean_t Final)
9177c478bd9Sstevel@tonic-gate {
9187c478bd9Sstevel@tonic-gate 	soft_des_ctx_t		*soft_des_ctx_sign_verify;
9197c478bd9Sstevel@tonic-gate 	soft_des_ctx_t		*soft_des_ctx_encrypt;
9207c478bd9Sstevel@tonic-gate 	CK_RV			rv;
9217c478bd9Sstevel@tonic-gate 	CK_BYTE			*pEncrypted = NULL;
9227c478bd9Sstevel@tonic-gate 	CK_ULONG		ulEncryptedLen = 0;
9237c478bd9Sstevel@tonic-gate 	uint8_t			remainder;
9247c478bd9Sstevel@tonic-gate 	CK_BYTE			last_block[DES_BLOCK_LEN];
9257c478bd9Sstevel@tonic-gate 	des_ctx_t		*des_ctx = NULL;
9267c478bd9Sstevel@tonic-gate 
9277c478bd9Sstevel@tonic-gate 	if (sign_op) {
9287c478bd9Sstevel@tonic-gate 		soft_des_ctx_sign_verify =
9297c478bd9Sstevel@tonic-gate 		    (soft_des_ctx_t *)session_p->sign.context;
9307c478bd9Sstevel@tonic-gate 
9317c478bd9Sstevel@tonic-gate 		if (soft_des_ctx_sign_verify->mac_len == 0) {
9327c478bd9Sstevel@tonic-gate 			*pulSignedLen = 0;
9337c478bd9Sstevel@tonic-gate 			goto clean_exit;
9347c478bd9Sstevel@tonic-gate 		}
9357c478bd9Sstevel@tonic-gate 
9367c478bd9Sstevel@tonic-gate 		/* Application asks for the length of the output buffer. */
9377c478bd9Sstevel@tonic-gate 		if (pSigned == NULL) {
9387c478bd9Sstevel@tonic-gate 			*pulSignedLen = soft_des_ctx_sign_verify->mac_len;
9397c478bd9Sstevel@tonic-gate 			return (CKR_OK);
9407c478bd9Sstevel@tonic-gate 		}
9417c478bd9Sstevel@tonic-gate 
9427c478bd9Sstevel@tonic-gate 		/* Is the application-supplied buffer large enough? */
9437c478bd9Sstevel@tonic-gate 		if (*pulSignedLen < soft_des_ctx_sign_verify->mac_len) {
9447c478bd9Sstevel@tonic-gate 			*pulSignedLen = soft_des_ctx_sign_verify->mac_len;
9457c478bd9Sstevel@tonic-gate 			return (CKR_BUFFER_TOO_SMALL);
9467c478bd9Sstevel@tonic-gate 		}
9477c478bd9Sstevel@tonic-gate 	} else {
9487c478bd9Sstevel@tonic-gate 		soft_des_ctx_sign_verify =
9497c478bd9Sstevel@tonic-gate 		    (soft_des_ctx_t *)session_p->verify.context;
9507c478bd9Sstevel@tonic-gate 	}
9517c478bd9Sstevel@tonic-gate 
9527c478bd9Sstevel@tonic-gate 	if (Final) {
9537c478bd9Sstevel@tonic-gate 		soft_des_ctx_encrypt =
9547c478bd9Sstevel@tonic-gate 		    (soft_des_ctx_t *)session_p->encrypt.context;
9557c478bd9Sstevel@tonic-gate 
9567c478bd9Sstevel@tonic-gate 		/*
9577c478bd9Sstevel@tonic-gate 		 * If there is data left in the buffer from a previous
9587c478bd9Sstevel@tonic-gate 		 * SignUpdate() call, pass enough zeroed data to a
9597c478bd9Sstevel@tonic-gate 		 * soft_sign_update call to pad the remainder
9607c478bd9Sstevel@tonic-gate 		 */
9617c478bd9Sstevel@tonic-gate 		if (soft_des_ctx_encrypt->remain_len != 0) {
9627c478bd9Sstevel@tonic-gate 			bzero(last_block, DES_BLOCK_LEN);
9637c478bd9Sstevel@tonic-gate 			ulEncryptedLen = DES_BLOCK_LEN;
9647c478bd9Sstevel@tonic-gate 
9657c478bd9Sstevel@tonic-gate 			/*
9667c478bd9Sstevel@tonic-gate 			 * By passing a buffer to soft_encrypt_final,
9677c478bd9Sstevel@tonic-gate 			 * we force it to pad the remaining block
9687c478bd9Sstevel@tonic-gate 			 * and encrypt it.
9697c478bd9Sstevel@tonic-gate 			 */
9707c478bd9Sstevel@tonic-gate 			rv = soft_encrypt_final(session_p, last_block,
9717c478bd9Sstevel@tonic-gate 			    &ulEncryptedLen);
9727c478bd9Sstevel@tonic-gate 			if (rv != CKR_OK) {
9737c478bd9Sstevel@tonic-gate 				goto clean_exit;
9747c478bd9Sstevel@tonic-gate 			}
9757c478bd9Sstevel@tonic-gate 		} else {
9767c478bd9Sstevel@tonic-gate 			/*
9777c478bd9Sstevel@tonic-gate 			 * The last block of enciphered data is stored in:
9787c478bd9Sstevel@tonic-gate 			 * soft_des_ctx_encrypt->des_cbc->des_ctx->dc_lastp
9797c478bd9Sstevel@tonic-gate 			 * Copy that data to last_block
9807c478bd9Sstevel@tonic-gate 			 */
9817c478bd9Sstevel@tonic-gate 			soft_des_ctx_encrypt =
9827c478bd9Sstevel@tonic-gate 			    (soft_des_ctx_t *)session_p->encrypt.context;
9837c478bd9Sstevel@tonic-gate 			des_ctx = (des_ctx_t *)soft_des_ctx_encrypt->des_cbc;
9847c478bd9Sstevel@tonic-gate 			(void) memcpy(last_block, des_ctx->dc_lastp,
9857c478bd9Sstevel@tonic-gate 			    DES_BLOCK_LEN);
9867c478bd9Sstevel@tonic-gate 
9877c478bd9Sstevel@tonic-gate 			/*
9887c478bd9Sstevel@tonic-gate 			 * Passing a NULL output buffer here
9897c478bd9Sstevel@tonic-gate 			 * forces the routine to just return.
9907c478bd9Sstevel@tonic-gate 			 */
9917c478bd9Sstevel@tonic-gate 			rv = soft_encrypt_final(session_p, NULL,
9927c478bd9Sstevel@tonic-gate 			    &ulEncryptedLen);
9937c478bd9Sstevel@tonic-gate 		}
9947c478bd9Sstevel@tonic-gate 
9957c478bd9Sstevel@tonic-gate 	} else {
9967c478bd9Sstevel@tonic-gate 		/*
9977c478bd9Sstevel@tonic-gate 		 * If the input length is not multiple of block size, then
9987c478bd9Sstevel@tonic-gate 		 * determine the correct encrypted data length by rounding
9997c478bd9Sstevel@tonic-gate 		 */
10007c478bd9Sstevel@tonic-gate 		remainder = ulDataLen % DES_BLOCK_LEN;
10017c478bd9Sstevel@tonic-gate 		/*
10027c478bd9Sstevel@tonic-gate 		 * Because we always use DES_CBC_PAD mechanism
10037c478bd9Sstevel@tonic-gate 		 * for sign/verify operations, the input will
10047c478bd9Sstevel@tonic-gate 		 * be padded to the next 8 byte boundary.
10057c478bd9Sstevel@tonic-gate 		 * Adjust the length fields here accordingly.
10067c478bd9Sstevel@tonic-gate 		 */
10079627968bSmcpowers 		ulEncryptedLen = ulDataLen + (DES_BLOCK_LEN - remainder);
10087c478bd9Sstevel@tonic-gate 
10097c478bd9Sstevel@tonic-gate 		pEncrypted = malloc(sizeof (CK_BYTE) * ulEncryptedLen);
10107c478bd9Sstevel@tonic-gate 		if (pEncrypted == NULL) {
10117c478bd9Sstevel@tonic-gate 			rv = CKR_HOST_MEMORY;
10127c478bd9Sstevel@tonic-gate 			goto clean_exit;
10137c478bd9Sstevel@tonic-gate 		}
10147c478bd9Sstevel@tonic-gate 
10157c478bd9Sstevel@tonic-gate 		/*
10167c478bd9Sstevel@tonic-gate 		 * Pad the last block with zeros by copying pData into a zeroed
10177c478bd9Sstevel@tonic-gate 		 * pEncrypted. Then pass pEncrypted into soft_encrypt as input
10187c478bd9Sstevel@tonic-gate 		 */
10197c478bd9Sstevel@tonic-gate 		bzero(pEncrypted, ulEncryptedLen);
10207c478bd9Sstevel@tonic-gate 		(void) memcpy(pEncrypted, pData, ulDataLen);
10217c478bd9Sstevel@tonic-gate 
10227c478bd9Sstevel@tonic-gate 		rv = soft_encrypt(session_p, pEncrypted, ulDataLen,
10237c478bd9Sstevel@tonic-gate 		    pEncrypted, &ulEncryptedLen);
10247c478bd9Sstevel@tonic-gate 		(void) memcpy(last_block,
10259627968bSmcpowers 		    &pEncrypted[ulEncryptedLen - DES_BLOCK_LEN], DES_BLOCK_LEN);
10267c478bd9Sstevel@tonic-gate 	}
10277c478bd9Sstevel@tonic-gate 
10287c478bd9Sstevel@tonic-gate 	if (rv == CKR_OK) {
10297c478bd9Sstevel@tonic-gate 		*pulSignedLen = soft_des_ctx_sign_verify->mac_len;
10307c478bd9Sstevel@tonic-gate 
10317c478bd9Sstevel@tonic-gate 		/* the leftmost mac_len bytes of last_block is our MAC */
10327c478bd9Sstevel@tonic-gate 		(void) memcpy(pSigned, last_block, *pulSignedLen);
10337c478bd9Sstevel@tonic-gate 	}
10347c478bd9Sstevel@tonic-gate 
10357c478bd9Sstevel@tonic-gate clean_exit:
10367c478bd9Sstevel@tonic-gate 
10377c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&session_p->session_mutex);
10387c478bd9Sstevel@tonic-gate 
10397c478bd9Sstevel@tonic-gate 	/* soft_encrypt_common() has freed the encrypt context */
10407c478bd9Sstevel@tonic-gate 	if (sign_op) {
10417c478bd9Sstevel@tonic-gate 		free(session_p->sign.context);
10427c478bd9Sstevel@tonic-gate 		session_p->sign.context = NULL;
10437c478bd9Sstevel@tonic-gate 	} else {
10447c478bd9Sstevel@tonic-gate 		free(session_p->verify.context);
10457c478bd9Sstevel@tonic-gate 		session_p->verify.context = NULL;
10467c478bd9Sstevel@tonic-gate 	}
10477c478bd9Sstevel@tonic-gate 	session_p->encrypt.flags = 0;
10487c478bd9Sstevel@tonic-gate 
10497c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&session_p->session_mutex);
10507c478bd9Sstevel@tonic-gate 
10517c478bd9Sstevel@tonic-gate 	if (pEncrypted) {
10527c478bd9Sstevel@tonic-gate 		free(pEncrypted);
10537c478bd9Sstevel@tonic-gate 	}
10547c478bd9Sstevel@tonic-gate 
10557c478bd9Sstevel@tonic-gate 	return (rv);
10567c478bd9Sstevel@tonic-gate }
10577c478bd9Sstevel@tonic-gate 
10587c478bd9Sstevel@tonic-gate /*
10597c478bd9Sstevel@tonic-gate  * Called by soft_sign_update()
10607c478bd9Sstevel@tonic-gate  */
10617c478bd9Sstevel@tonic-gate CK_RV
soft_des_mac_sign_verify_update(soft_session_t * session_p,CK_BYTE_PTR pPart,CK_ULONG ulPartLen)10627c478bd9Sstevel@tonic-gate soft_des_mac_sign_verify_update(soft_session_t *session_p, CK_BYTE_PTR pPart,
10637c478bd9Sstevel@tonic-gate 	CK_ULONG ulPartLen)
10647c478bd9Sstevel@tonic-gate {
10657c478bd9Sstevel@tonic-gate 	/*
10667c478bd9Sstevel@tonic-gate 	 * The DES MAC is calculated by taking the specified number of
10677c478bd9Sstevel@tonic-gate 	 * left-most bytes within the last block of
10687c478bd9Sstevel@tonic-gate 	 * encrypted data, while the context of the multi-part
10697c478bd9Sstevel@tonic-gate 	 * encryption stores the block necessary for XORing with the
10707c478bd9Sstevel@tonic-gate 	 * input as per cipher block chaining . Therefore, none of the
10717c478bd9Sstevel@tonic-gate 	 * intermediary encrypted blocks of data are necessary for
10727c478bd9Sstevel@tonic-gate 	 * the DES MAC, and we can create a placeholder local buffer
10737c478bd9Sstevel@tonic-gate 	 * for the encrypted data, which is immediately throw away.
10747c478bd9Sstevel@tonic-gate 	 */
10757c478bd9Sstevel@tonic-gate 
10767c478bd9Sstevel@tonic-gate 	soft_des_ctx_t	*soft_des_ctx_encrypt;
10777c478bd9Sstevel@tonic-gate 	CK_BYTE		*pEncrypted = NULL;
10787c478bd9Sstevel@tonic-gate 	CK_ULONG	ulEncryptedLen;
10797c478bd9Sstevel@tonic-gate 	CK_ULONG	total_len;
10807c478bd9Sstevel@tonic-gate 	uint8_t		remainder;
10817c478bd9Sstevel@tonic-gate 	CK_RV		rv;
10827c478bd9Sstevel@tonic-gate 
10837c478bd9Sstevel@tonic-gate 	soft_des_ctx_encrypt = (soft_des_ctx_t *)session_p->encrypt.context;
10847c478bd9Sstevel@tonic-gate 
10857c478bd9Sstevel@tonic-gate 	/* Avoid the malloc if we won't be encrypting any data */
10867c478bd9Sstevel@tonic-gate 	total_len = soft_des_ctx_encrypt->remain_len + ulPartLen;
10877c478bd9Sstevel@tonic-gate 
10887c478bd9Sstevel@tonic-gate 	if (total_len < DES_BLOCK_LEN) {
10897c478bd9Sstevel@tonic-gate 		rv = soft_encrypt_update(session_p, pPart, ulPartLen, NULL,
10907c478bd9Sstevel@tonic-gate 		    &ulEncryptedLen);
10917c478bd9Sstevel@tonic-gate 	} else {
10927c478bd9Sstevel@tonic-gate 		remainder = ulPartLen % DES_BLOCK_LEN;
10937c478bd9Sstevel@tonic-gate 
10947c478bd9Sstevel@tonic-gate 		/* round up to the nearest multiple of block size */
10957c478bd9Sstevel@tonic-gate 		ulEncryptedLen = ulPartLen + (DES_BLOCK_LEN - remainder);
10967c478bd9Sstevel@tonic-gate 		pEncrypted = malloc(sizeof (CK_BYTE) * ulEncryptedLen);
10977c478bd9Sstevel@tonic-gate 
10987c478bd9Sstevel@tonic-gate 		if (pEncrypted != NULL) {
10997c478bd9Sstevel@tonic-gate 			rv = soft_encrypt_update(session_p, pPart, ulPartLen,
11007c478bd9Sstevel@tonic-gate 			    pEncrypted, &ulEncryptedLen);
11017c478bd9Sstevel@tonic-gate 			free(pEncrypted);
11027c478bd9Sstevel@tonic-gate 		} else {
11037c478bd9Sstevel@tonic-gate 			rv = CKR_HOST_MEMORY;
11047c478bd9Sstevel@tonic-gate 		}
11057c478bd9Sstevel@tonic-gate 	}
11067c478bd9Sstevel@tonic-gate 	return (rv);
11077c478bd9Sstevel@tonic-gate }
1108