xref: /titanic_41/usr/src/lib/pkcs11/pkcs11_softtoken/common/softEncryptUtil.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
547c883c7Sdinak  * Common Development and Distribution License (the "License").
647c883c7Sdinak  * 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 <arcfour.h>
347c478bd9Sstevel@tonic-gate #include "softSession.h"
357c478bd9Sstevel@tonic-gate #include "softObject.h"
367c478bd9Sstevel@tonic-gate #include "softOps.h"
377c478bd9Sstevel@tonic-gate #include "softCrypt.h"
387c478bd9Sstevel@tonic-gate #include "softRSA.h"
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate /*
417c478bd9Sstevel@tonic-gate  * Add padding bytes with the value of length of padding.
427c478bd9Sstevel@tonic-gate  */
437c478bd9Sstevel@tonic-gate void
soft_add_pkcs7_padding(CK_BYTE * buf,int block_size,CK_ULONG data_len)447c478bd9Sstevel@tonic-gate soft_add_pkcs7_padding(CK_BYTE *buf, int block_size, CK_ULONG data_len)
457c478bd9Sstevel@tonic-gate {
46*726fad2aSDina K Nimeh 	(void) pkcs7_encode(NULL, data_len, buf, block_size, block_size);
477c478bd9Sstevel@tonic-gate }
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate /*
507c478bd9Sstevel@tonic-gate  * Perform encrypt init operation internally for the support of
517c478bd9Sstevel@tonic-gate  * CKM_DES_MAC and CKM_DES_MAC_GENERAL
527c478bd9Sstevel@tonic-gate  *
537c478bd9Sstevel@tonic-gate  * This function is called with the session being held, and without
547c478bd9Sstevel@tonic-gate  * its mutex taken.
557c478bd9Sstevel@tonic-gate  */
567c478bd9Sstevel@tonic-gate CK_RV
soft_encrypt_init_internal(soft_session_t * session_p,CK_MECHANISM_PTR pMechanism,soft_object_t * key_p)577c478bd9Sstevel@tonic-gate soft_encrypt_init_internal(soft_session_t *session_p, CK_MECHANISM_PTR
587c478bd9Sstevel@tonic-gate 	pMechanism, soft_object_t *key_p)
597c478bd9Sstevel@tonic-gate {
607c478bd9Sstevel@tonic-gate 	CK_RV rv;
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&session_p->session_mutex);
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate 	/* Check to see if encrypt operation is already active */
657c478bd9Sstevel@tonic-gate 	if (session_p->encrypt.flags & CRYPTO_OPERATION_ACTIVE) {
667c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&session_p->session_mutex);
677c478bd9Sstevel@tonic-gate 		return (CKR_OPERATION_ACTIVE);
687c478bd9Sstevel@tonic-gate 	}
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate 	session_p->encrypt.flags = CRYPTO_OPERATION_ACTIVE;
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&session_p->session_mutex);
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate 	rv = soft_encrypt_init(session_p, pMechanism, key_p);
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
777c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_lock(&session_p->session_mutex);
787c478bd9Sstevel@tonic-gate 		session_p->encrypt.flags &= ~CRYPTO_OPERATION_ACTIVE;
797c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&session_p->session_mutex);
807c478bd9Sstevel@tonic-gate 	}
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate 	return (rv);
837c478bd9Sstevel@tonic-gate }
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate /*
867c478bd9Sstevel@tonic-gate  * soft_encrypt_init()
877c478bd9Sstevel@tonic-gate  *
887c478bd9Sstevel@tonic-gate  * Arguments:
897c478bd9Sstevel@tonic-gate  *	session_p:	pointer to soft_session_t struct
907c478bd9Sstevel@tonic-gate  *	pMechanism:	pointer to CK_MECHANISM struct provided by application
917c478bd9Sstevel@tonic-gate  *	key_p:		pointer to key soft_object_t struct
927c478bd9Sstevel@tonic-gate  *
937c478bd9Sstevel@tonic-gate  * Description:
947c478bd9Sstevel@tonic-gate  *	called by C_EncryptInit(). This function calls the corresponding
957c478bd9Sstevel@tonic-gate  *	encrypt init routine based on the mechanism.
967c478bd9Sstevel@tonic-gate  *
977c478bd9Sstevel@tonic-gate  * Returns:
987c478bd9Sstevel@tonic-gate  *	CKR_OK: success
997c478bd9Sstevel@tonic-gate  *	CKR_HOST_MEMORY: run out of system memory
1007c478bd9Sstevel@tonic-gate  *	CKR_MECHANISM_PARAM_INVALID: invalid parameters in mechanism
1017c478bd9Sstevel@tonic-gate  *	CKR_MECHANISM_INVALID: invalid mechanism type
1027c478bd9Sstevel@tonic-gate  *	CKR_KEY_TYPE_INCONSISTENT: incorrect type of key to use
1037c478bd9Sstevel@tonic-gate  *		with the specified mechanism
1047c478bd9Sstevel@tonic-gate  */
1057c478bd9Sstevel@tonic-gate CK_RV
soft_encrypt_init(soft_session_t * session_p,CK_MECHANISM_PTR pMechanism,soft_object_t * key_p)1067c478bd9Sstevel@tonic-gate soft_encrypt_init(soft_session_t *session_p, CK_MECHANISM_PTR pMechanism,
1077c478bd9Sstevel@tonic-gate     soft_object_t *key_p)
1087c478bd9Sstevel@tonic-gate {
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate 	CK_RV rv;
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate 	switch (pMechanism->mechanism) {
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate 	case CKM_DES_ECB:
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate 		if (key_p->key_type != CKK_DES) {
1177c478bd9Sstevel@tonic-gate 			return (CKR_KEY_TYPE_INCONSISTENT);
1187c478bd9Sstevel@tonic-gate 		}
1197c478bd9Sstevel@tonic-gate 		goto ecb_common;
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate 	case CKM_DES3_ECB:
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate 		if ((key_p->key_type != CKK_DES2) &&
1247c478bd9Sstevel@tonic-gate 		    (key_p->key_type != CKK_DES3)) {
1257c478bd9Sstevel@tonic-gate 			return (CKR_KEY_TYPE_INCONSISTENT);
1267c478bd9Sstevel@tonic-gate 		}
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate ecb_common:
1297c478bd9Sstevel@tonic-gate 		return (soft_des_crypt_init_common(session_p, pMechanism,
1307c478bd9Sstevel@tonic-gate 		    key_p, B_TRUE));
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate 	case CKM_DES_CBC:
1337c478bd9Sstevel@tonic-gate 	case CKM_DES_CBC_PAD:
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate 		if (key_p->key_type != CKK_DES) {
1367c478bd9Sstevel@tonic-gate 			return (CKR_KEY_TYPE_INCONSISTENT);
1377c478bd9Sstevel@tonic-gate 		}
1387c478bd9Sstevel@tonic-gate 
1397c478bd9Sstevel@tonic-gate 		goto cbc_common;
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate 	case CKM_DES3_CBC:
1427c478bd9Sstevel@tonic-gate 	case CKM_DES3_CBC_PAD:
1437c478bd9Sstevel@tonic-gate 	{
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate 		soft_des_ctx_t *soft_des_ctx;
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate 		if ((key_p->key_type != CKK_DES2) &&
1487c478bd9Sstevel@tonic-gate 		    (key_p->key_type != CKK_DES3)) {
1497c478bd9Sstevel@tonic-gate 			return (CKR_KEY_TYPE_INCONSISTENT);
1507c478bd9Sstevel@tonic-gate 		}
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate cbc_common:
1537c478bd9Sstevel@tonic-gate 		if ((pMechanism->pParameter == NULL) ||
1547c478bd9Sstevel@tonic-gate 		    (pMechanism->ulParameterLen != DES_BLOCK_LEN)) {
1557c478bd9Sstevel@tonic-gate 			return (CKR_MECHANISM_PARAM_INVALID);
1567c478bd9Sstevel@tonic-gate 		}
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate 		rv = soft_des_crypt_init_common(session_p, pMechanism,
1597c478bd9Sstevel@tonic-gate 		    key_p, B_TRUE);
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate 		if (rv != CKR_OK)
1627c478bd9Sstevel@tonic-gate 			return (rv);
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_lock(&session_p->session_mutex);
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate 		soft_des_ctx = (soft_des_ctx_t *)session_p->encrypt.context;
1677c478bd9Sstevel@tonic-gate 		/* Copy Initialization Vector (IV) into the context. */
1687c478bd9Sstevel@tonic-gate 		(void) memcpy(soft_des_ctx->ivec, pMechanism->pParameter,
1697c478bd9Sstevel@tonic-gate 		    DES_BLOCK_LEN);
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate 		/* Allocate a context for DES cipher-block chaining. */
1727c478bd9Sstevel@tonic-gate 		soft_des_ctx->des_cbc = (void *)des_cbc_ctx_init(
1737c478bd9Sstevel@tonic-gate 		    soft_des_ctx->key_sched, soft_des_ctx->keysched_len,
1747c478bd9Sstevel@tonic-gate 		    soft_des_ctx->ivec, key_p->key_type);
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 		if (soft_des_ctx->des_cbc == NULL) {
1777c478bd9Sstevel@tonic-gate 			bzero(soft_des_ctx->key_sched,
1787c478bd9Sstevel@tonic-gate 			    soft_des_ctx->keysched_len);
1797c478bd9Sstevel@tonic-gate 			free(soft_des_ctx->key_sched);
1807c478bd9Sstevel@tonic-gate 			free(session_p->encrypt.context);
1817c478bd9Sstevel@tonic-gate 			session_p->encrypt.context = NULL;
1827c478bd9Sstevel@tonic-gate 			rv = CKR_HOST_MEMORY;
1837c478bd9Sstevel@tonic-gate 		}
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&session_p->session_mutex);
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate 		return (rv);
1887c478bd9Sstevel@tonic-gate 	}
1897c478bd9Sstevel@tonic-gate 	case CKM_AES_ECB:
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate 		if (key_p->key_type != CKK_AES) {
1927c478bd9Sstevel@tonic-gate 			return (CKR_KEY_TYPE_INCONSISTENT);
1937c478bd9Sstevel@tonic-gate 		}
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate 		return (soft_aes_crypt_init_common(session_p, pMechanism,
1967c478bd9Sstevel@tonic-gate 		    key_p, B_TRUE));
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate 	case CKM_AES_CBC:
1997c478bd9Sstevel@tonic-gate 	case CKM_AES_CBC_PAD:
2007c478bd9Sstevel@tonic-gate 	{
2017c478bd9Sstevel@tonic-gate 		soft_aes_ctx_t *soft_aes_ctx;
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate 		if (key_p->key_type != CKK_AES) {
2047c478bd9Sstevel@tonic-gate 			return (CKR_KEY_TYPE_INCONSISTENT);
2057c478bd9Sstevel@tonic-gate 		}
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate 		if ((pMechanism->pParameter == NULL) ||
2087c478bd9Sstevel@tonic-gate 		    (pMechanism->ulParameterLen != AES_BLOCK_LEN)) {
2097c478bd9Sstevel@tonic-gate 			return (CKR_MECHANISM_PARAM_INVALID);
2107c478bd9Sstevel@tonic-gate 		}
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate 		rv = soft_aes_crypt_init_common(session_p, pMechanism,
2137c478bd9Sstevel@tonic-gate 		    key_p, B_TRUE);
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate 		if (rv != CKR_OK)
2167c478bd9Sstevel@tonic-gate 			return (rv);
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_lock(&session_p->session_mutex);
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate 		soft_aes_ctx = (soft_aes_ctx_t *)session_p->encrypt.context;
2217c478bd9Sstevel@tonic-gate 		/* Copy Initialization Vector (IV) into the context. */
2227c478bd9Sstevel@tonic-gate 		(void) memcpy(soft_aes_ctx->ivec, pMechanism->pParameter,
2237c478bd9Sstevel@tonic-gate 		    AES_BLOCK_LEN);
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate 		/* Allocate a context for AES cipher-block chaining. */
2267c478bd9Sstevel@tonic-gate 		soft_aes_ctx->aes_cbc = (void *)aes_cbc_ctx_init(
2277c478bd9Sstevel@tonic-gate 		    soft_aes_ctx->key_sched, soft_aes_ctx->keysched_len,
2287c478bd9Sstevel@tonic-gate 		    soft_aes_ctx->ivec);
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate 		if (soft_aes_ctx->aes_cbc == NULL) {
2317c478bd9Sstevel@tonic-gate 			bzero(soft_aes_ctx->key_sched,
2327c478bd9Sstevel@tonic-gate 			    soft_aes_ctx->keysched_len);
2337c478bd9Sstevel@tonic-gate 			free(soft_aes_ctx->key_sched);
2347c478bd9Sstevel@tonic-gate 			free(session_p->encrypt.context);
2357c478bd9Sstevel@tonic-gate 			session_p->encrypt.context = NULL;
2367c478bd9Sstevel@tonic-gate 			rv = CKR_HOST_MEMORY;
2377c478bd9Sstevel@tonic-gate 		}
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&session_p->session_mutex);
2407c478bd9Sstevel@tonic-gate 
2417c478bd9Sstevel@tonic-gate 		return (rv);
2427c478bd9Sstevel@tonic-gate 	}
24323c57df7Smcpowers 	case CKM_AES_CTR:
24423c57df7Smcpowers 	{
24523c57df7Smcpowers 		soft_aes_ctx_t *soft_aes_ctx;
24623c57df7Smcpowers 
24723c57df7Smcpowers 		if (key_p->key_type != CKK_AES) {
24823c57df7Smcpowers 			return (CKR_KEY_TYPE_INCONSISTENT);
24923c57df7Smcpowers 		}
25023c57df7Smcpowers 
25123c57df7Smcpowers 		if (pMechanism->pParameter == NULL ||
25223c57df7Smcpowers 		    pMechanism->ulParameterLen != sizeof (CK_AES_CTR_PARAMS)) {
25323c57df7Smcpowers 			return (CKR_MECHANISM_PARAM_INVALID);
25423c57df7Smcpowers 		}
25523c57df7Smcpowers 
25623c57df7Smcpowers 		rv = soft_aes_crypt_init_common(session_p, pMechanism,
25723c57df7Smcpowers 		    key_p, B_TRUE);
25823c57df7Smcpowers 
25923c57df7Smcpowers 		if (rv != CKR_OK)
26023c57df7Smcpowers 			return (rv);
26123c57df7Smcpowers 
26223c57df7Smcpowers 		(void) pthread_mutex_lock(&session_p->session_mutex);
26323c57df7Smcpowers 
26423c57df7Smcpowers 		soft_aes_ctx = (soft_aes_ctx_t *)session_p->encrypt.context;
26523c57df7Smcpowers 		soft_aes_ctx->aes_cbc = aes_ctr_ctx_init(
26623c57df7Smcpowers 		    soft_aes_ctx->key_sched, soft_aes_ctx->keysched_len,
26723c57df7Smcpowers 		    pMechanism->pParameter);
26823c57df7Smcpowers 
26923c57df7Smcpowers 		if (soft_aes_ctx->aes_cbc == NULL) {
27023c57df7Smcpowers 			bzero(soft_aes_ctx->key_sched,
27123c57df7Smcpowers 			    soft_aes_ctx->keysched_len);
27223c57df7Smcpowers 			free(soft_aes_ctx->key_sched);
27323c57df7Smcpowers 			free(session_p->encrypt.context);
27423c57df7Smcpowers 			session_p->encrypt.context = NULL;
27523c57df7Smcpowers 			rv = CKR_HOST_MEMORY;
27623c57df7Smcpowers 		}
27723c57df7Smcpowers 
27823c57df7Smcpowers 		(void) pthread_mutex_unlock(&session_p->session_mutex);
27923c57df7Smcpowers 
28023c57df7Smcpowers 		return (rv);
28123c57df7Smcpowers 	}
2827c478bd9Sstevel@tonic-gate 	case CKM_RC4:
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate 		if (key_p->key_type != CKK_RC4) {
2857c478bd9Sstevel@tonic-gate 			return (CKR_KEY_TYPE_INCONSISTENT);
2867c478bd9Sstevel@tonic-gate 		}
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate 		return (soft_arcfour_crypt_init(session_p, pMechanism, key_p,
2897c478bd9Sstevel@tonic-gate 		    B_TRUE));
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate 	case CKM_RSA_X_509:
2927c478bd9Sstevel@tonic-gate 	case CKM_RSA_PKCS:
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate 		if (key_p->key_type != CKK_RSA) {
2957c478bd9Sstevel@tonic-gate 			return (CKR_KEY_TYPE_INCONSISTENT);
2967c478bd9Sstevel@tonic-gate 		}
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate 		return (soft_rsa_crypt_init_common(session_p, pMechanism,
2997c478bd9Sstevel@tonic-gate 		    key_p, B_TRUE));
3007c478bd9Sstevel@tonic-gate 
301f66d273dSizick 	case CKM_BLOWFISH_CBC:
302f66d273dSizick 	{
303f66d273dSizick 		soft_blowfish_ctx_t *soft_blowfish_ctx;
304f66d273dSizick 
305f66d273dSizick 		if (key_p->key_type != CKK_BLOWFISH)
306f66d273dSizick 			return (CKR_KEY_TYPE_INCONSISTENT);
307f66d273dSizick 
308f66d273dSizick 		if ((pMechanism->pParameter == NULL) ||
309f66d273dSizick 		    (pMechanism->ulParameterLen != BLOWFISH_BLOCK_LEN))
310f66d273dSizick 			return (CKR_MECHANISM_PARAM_INVALID);
311f66d273dSizick 
312f66d273dSizick 		rv = soft_blowfish_crypt_init_common(session_p, pMechanism,
313f66d273dSizick 		    key_p, B_TRUE);
314f66d273dSizick 
315f66d273dSizick 		if (rv != CKR_OK)
316f66d273dSizick 			return (rv);
317f66d273dSizick 
318f66d273dSizick 		(void) pthread_mutex_lock(&session_p->session_mutex);
319f66d273dSizick 
320f66d273dSizick 		soft_blowfish_ctx =
321f66d273dSizick 		    (soft_blowfish_ctx_t *)session_p->encrypt.context;
322f66d273dSizick 		/* Copy Initialization Vector (IV) into the context. */
323f66d273dSizick 		(void) memcpy(soft_blowfish_ctx->ivec, pMechanism->pParameter,
324f66d273dSizick 		    BLOWFISH_BLOCK_LEN);
325f66d273dSizick 
326f66d273dSizick 		/* Allocate a context for Blowfish cipher-block chaining */
327f66d273dSizick 		soft_blowfish_ctx->blowfish_cbc =
328f66d273dSizick 		    (void *)blowfish_cbc_ctx_init(soft_blowfish_ctx->key_sched,
329f66d273dSizick 		    soft_blowfish_ctx->keysched_len,
330f66d273dSizick 		    soft_blowfish_ctx->ivec);
331f66d273dSizick 
332f66d273dSizick 		if (soft_blowfish_ctx->blowfish_cbc == NULL) {
333f66d273dSizick 			bzero(soft_blowfish_ctx->key_sched,
334f66d273dSizick 			    soft_blowfish_ctx->keysched_len);
335f66d273dSizick 			free(soft_blowfish_ctx->key_sched);
336f66d273dSizick 			free(session_p->encrypt.context);
337f66d273dSizick 			session_p->encrypt.context = NULL;
338f66d273dSizick 			rv = CKR_HOST_MEMORY;
339f66d273dSizick 		}
340f66d273dSizick 
341f66d273dSizick 		(void) pthread_mutex_unlock(&session_p->session_mutex);
342f66d273dSizick 
343f66d273dSizick 		return (rv);
344f66d273dSizick 	}
3457c478bd9Sstevel@tonic-gate 	default:
3467c478bd9Sstevel@tonic-gate 		return (CKR_MECHANISM_INVALID);
3477c478bd9Sstevel@tonic-gate 	}
3487c478bd9Sstevel@tonic-gate }
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate /*
3527c478bd9Sstevel@tonic-gate  * soft_encrypt_common()
3537c478bd9Sstevel@tonic-gate  *
3547c478bd9Sstevel@tonic-gate  * Arguments:
3557c478bd9Sstevel@tonic-gate  *      session_p:	pointer to soft_session_t struct
3567c478bd9Sstevel@tonic-gate  *	pData:		pointer to the input data to be encrypted
3577c478bd9Sstevel@tonic-gate  *	ulDataLen:	length of the input data
3587c478bd9Sstevel@tonic-gate  *	pEncrypted:	pointer to the output data after encryption
3597c478bd9Sstevel@tonic-gate  *	pulEncryptedLen: pointer to the length of the output data
3607c478bd9Sstevel@tonic-gate  *	update:		boolean flag indicates caller is soft_encrypt
3617c478bd9Sstevel@tonic-gate  *			or soft_encrypt_update
3627c478bd9Sstevel@tonic-gate  *
3637c478bd9Sstevel@tonic-gate  * Description:
3647c478bd9Sstevel@tonic-gate  *      This function calls the corresponding encrypt routine based
3657c478bd9Sstevel@tonic-gate  *	on the mechanism.
3667c478bd9Sstevel@tonic-gate  *
3677c478bd9Sstevel@tonic-gate  * Returns:
3687c478bd9Sstevel@tonic-gate  *	see corresponding encrypt routine.
3697c478bd9Sstevel@tonic-gate  */
3707c478bd9Sstevel@tonic-gate CK_RV
soft_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)3717c478bd9Sstevel@tonic-gate soft_encrypt_common(soft_session_t *session_p, CK_BYTE_PTR pData,
3727c478bd9Sstevel@tonic-gate     CK_ULONG ulDataLen, CK_BYTE_PTR pEncrypted,
3737c478bd9Sstevel@tonic-gate     CK_ULONG_PTR pulEncryptedLen, boolean_t update)
3747c478bd9Sstevel@tonic-gate {
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate 	CK_MECHANISM_TYPE mechanism = session_p->encrypt.mech.mechanism;
3777c478bd9Sstevel@tonic-gate 
3787c478bd9Sstevel@tonic-gate 	switch (mechanism) {
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate 	case CKM_DES_ECB:
3817c478bd9Sstevel@tonic-gate 	case CKM_DES_CBC:
3827c478bd9Sstevel@tonic-gate 	case CKM_DES3_ECB:
3837c478bd9Sstevel@tonic-gate 	case CKM_DES3_CBC:
38447c883c7Sdinak 
38547c883c7Sdinak 		if (ulDataLen == 0) {
38647c883c7Sdinak 			*pulEncryptedLen = 0;
38747c883c7Sdinak 			return (CKR_OK);
38847c883c7Sdinak 		}
38947c883c7Sdinak 		/* FALLTHROUGH */
39047c883c7Sdinak 
39147c883c7Sdinak 	case CKM_DES_CBC_PAD:
3927c478bd9Sstevel@tonic-gate 	case CKM_DES3_CBC_PAD:
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 		return (soft_des_encrypt_common(session_p, pData,
3957c478bd9Sstevel@tonic-gate 		    ulDataLen, pEncrypted, pulEncryptedLen, update));
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate 	case CKM_AES_ECB:
3987c478bd9Sstevel@tonic-gate 	case CKM_AES_CBC:
39923c57df7Smcpowers 	case CKM_AES_CTR:
40047c883c7Sdinak 
40147c883c7Sdinak 		if (ulDataLen == 0) {
40247c883c7Sdinak 			*pulEncryptedLen = 0;
40347c883c7Sdinak 			return (CKR_OK);
40447c883c7Sdinak 		}
40547c883c7Sdinak 		/* FALLTHROUGH */
40647c883c7Sdinak 
4077c478bd9Sstevel@tonic-gate 	case CKM_AES_CBC_PAD:
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate 		return (soft_aes_encrypt_common(session_p, pData,
4107c478bd9Sstevel@tonic-gate 		    ulDataLen, pEncrypted, pulEncryptedLen, update));
4117c478bd9Sstevel@tonic-gate 
412f66d273dSizick 	case CKM_BLOWFISH_CBC:
413f66d273dSizick 
41447c883c7Sdinak 		if (ulDataLen == 0) {
41547c883c7Sdinak 			*pulEncryptedLen = 0;
41647c883c7Sdinak 			return (CKR_OK);
41747c883c7Sdinak 		}
41847c883c7Sdinak 
419f66d273dSizick 		return (soft_blowfish_encrypt_common(session_p, pData,
420f66d273dSizick 		    ulDataLen, pEncrypted, pulEncryptedLen, update));
421f66d273dSizick 
4227c478bd9Sstevel@tonic-gate 	case CKM_RC4:
4237c478bd9Sstevel@tonic-gate 
42447c883c7Sdinak 		if (ulDataLen == 0) {
42547c883c7Sdinak 			*pulEncryptedLen = 0;
42647c883c7Sdinak 			return (CKR_OK);
4277c478bd9Sstevel@tonic-gate 		}
42847c883c7Sdinak 
42947c883c7Sdinak 		return (soft_arcfour_crypt(&(session_p->encrypt), pData,
43047c883c7Sdinak 		    ulDataLen, pEncrypted, pulEncryptedLen));
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate 	case CKM_RSA_X_509:
4337c478bd9Sstevel@tonic-gate 	case CKM_RSA_PKCS:
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate 		return (soft_rsa_encrypt_common(session_p, pData,
4367c478bd9Sstevel@tonic-gate 		    ulDataLen, pEncrypted, pulEncryptedLen, mechanism));
4377c478bd9Sstevel@tonic-gate 
4387c478bd9Sstevel@tonic-gate 	default:
4397c478bd9Sstevel@tonic-gate 		return (CKR_MECHANISM_INVALID);
4407c478bd9Sstevel@tonic-gate 	}
4417c478bd9Sstevel@tonic-gate }
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate 
4447c478bd9Sstevel@tonic-gate /*
4457c478bd9Sstevel@tonic-gate  * soft_encrypt()
4467c478bd9Sstevel@tonic-gate  *
4477c478bd9Sstevel@tonic-gate  * Arguments:
4487c478bd9Sstevel@tonic-gate  *      session_p:	pointer to soft_session_t struct
4497c478bd9Sstevel@tonic-gate  *	pData:		pointer to the input data to be encrypted
4507c478bd9Sstevel@tonic-gate  *	ulDataLen:	length of the input data
4517c478bd9Sstevel@tonic-gate  *	pEncryptedData:	pointer to the output data after encryption
4527c478bd9Sstevel@tonic-gate  *	pulEncryptedDataLen: pointer to the length of the output data
4537c478bd9Sstevel@tonic-gate  *
4547c478bd9Sstevel@tonic-gate  * Description:
4557c478bd9Sstevel@tonic-gate  *      called by C_Encrypt(). This function calls the soft_encrypt_common
4567c478bd9Sstevel@tonic-gate  *	routine.
4577c478bd9Sstevel@tonic-gate  *
4587c478bd9Sstevel@tonic-gate  * Returns:
4597c478bd9Sstevel@tonic-gate  *	see soft_encrypt_common().
4607c478bd9Sstevel@tonic-gate  */
4617c478bd9Sstevel@tonic-gate CK_RV
soft_encrypt(soft_session_t * session_p,CK_BYTE_PTR pData,CK_ULONG ulDataLen,CK_BYTE_PTR pEncryptedData,CK_ULONG_PTR pulEncryptedDataLen)4627c478bd9Sstevel@tonic-gate soft_encrypt(soft_session_t *session_p, CK_BYTE_PTR pData,
4637c478bd9Sstevel@tonic-gate     CK_ULONG ulDataLen, CK_BYTE_PTR pEncryptedData,
4647c478bd9Sstevel@tonic-gate     CK_ULONG_PTR pulEncryptedDataLen)
4657c478bd9Sstevel@tonic-gate {
4667c478bd9Sstevel@tonic-gate 
4677c478bd9Sstevel@tonic-gate 	return (soft_encrypt_common(session_p, pData, ulDataLen,
4687c478bd9Sstevel@tonic-gate 	    pEncryptedData, pulEncryptedDataLen, B_FALSE));
4697c478bd9Sstevel@tonic-gate }
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate /*
4737c478bd9Sstevel@tonic-gate  * soft_encrypt_update()
4747c478bd9Sstevel@tonic-gate  *
4757c478bd9Sstevel@tonic-gate  * Arguments:
4767c478bd9Sstevel@tonic-gate  *      session_p:	pointer to soft_session_t struct
4777c478bd9Sstevel@tonic-gate  *      pPart:		pointer to the input data to be digested
4787c478bd9Sstevel@tonic-gate  *      ulPartLen:	length of the input data
4797c478bd9Sstevel@tonic-gate  *	pEncryptedPart:	pointer to the ciphertext
4807c478bd9Sstevel@tonic-gate  *	pulEncryptedPartLen: pointer to the length of the ciphertext
4817c478bd9Sstevel@tonic-gate  *
4827c478bd9Sstevel@tonic-gate  * Description:
4837c478bd9Sstevel@tonic-gate  *      called by C_EncryptUpdate(). This function calls the
4847c478bd9Sstevel@tonic-gate  *	soft_encrypt_common routine (with update flag on).
4857c478bd9Sstevel@tonic-gate  *
4867c478bd9Sstevel@tonic-gate  * Returns:
4877c478bd9Sstevel@tonic-gate  *	see soft_encrypt_common().
4887c478bd9Sstevel@tonic-gate  */
4897c478bd9Sstevel@tonic-gate CK_RV
soft_encrypt_update(soft_session_t * session_p,CK_BYTE_PTR pPart,CK_ULONG ulPartLen,CK_BYTE_PTR pEncryptedPart,CK_ULONG_PTR pulEncryptedPartLen)4907c478bd9Sstevel@tonic-gate soft_encrypt_update(soft_session_t *session_p, CK_BYTE_PTR pPart,
4917c478bd9Sstevel@tonic-gate 	CK_ULONG ulPartLen, CK_BYTE_PTR pEncryptedPart,
4927c478bd9Sstevel@tonic-gate 	CK_ULONG_PTR pulEncryptedPartLen)
4937c478bd9Sstevel@tonic-gate {
4947c478bd9Sstevel@tonic-gate 
4957c478bd9Sstevel@tonic-gate 	CK_MECHANISM_TYPE mechanism = session_p->encrypt.mech.mechanism;
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 	switch (mechanism) {
4987c478bd9Sstevel@tonic-gate 
4997c478bd9Sstevel@tonic-gate 	case CKM_DES_ECB:
5007c478bd9Sstevel@tonic-gate 	case CKM_DES_CBC:
5017c478bd9Sstevel@tonic-gate 	case CKM_DES_CBC_PAD:
5027c478bd9Sstevel@tonic-gate 	case CKM_DES3_ECB:
5037c478bd9Sstevel@tonic-gate 	case CKM_DES3_CBC:
5047c478bd9Sstevel@tonic-gate 	case CKM_DES3_CBC_PAD:
5057c478bd9Sstevel@tonic-gate 	case CKM_AES_ECB:
5067c478bd9Sstevel@tonic-gate 	case CKM_AES_CBC:
5077c478bd9Sstevel@tonic-gate 	case CKM_AES_CBC_PAD:
50823c57df7Smcpowers 	case CKM_AES_CTR:
509f66d273dSizick 	case CKM_BLOWFISH_CBC:
51047c883c7Sdinak 	case CKM_RC4:
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate 		return (soft_encrypt_common(session_p, pPart, ulPartLen,
5137c478bd9Sstevel@tonic-gate 		    pEncryptedPart, pulEncryptedPartLen, B_TRUE));
5147c478bd9Sstevel@tonic-gate 
5157c478bd9Sstevel@tonic-gate 	default:
5167c478bd9Sstevel@tonic-gate 		/* PKCS11: The mechanism only supports single-part operation. */
5177c478bd9Sstevel@tonic-gate 		return (CKR_MECHANISM_INVALID);
5187c478bd9Sstevel@tonic-gate 	}
5197c478bd9Sstevel@tonic-gate }
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate /*
5237c478bd9Sstevel@tonic-gate  * soft_encrypt_final()
5247c478bd9Sstevel@tonic-gate  *
5257c478bd9Sstevel@tonic-gate  * Arguments:
5267c478bd9Sstevel@tonic-gate  *      session_p:		pointer to soft_session_t struct
5277c478bd9Sstevel@tonic-gate  *      pLastEncryptedPart:	pointer to the last encrypted data part
5287c478bd9Sstevel@tonic-gate  *      pulLastEncryptedPartLen: pointer to the length of the last
5297c478bd9Sstevel@tonic-gate  *				encrypted data part
5307c478bd9Sstevel@tonic-gate  *
5317c478bd9Sstevel@tonic-gate  * Description:
5327c478bd9Sstevel@tonic-gate  *      called by C_EncryptFinal().
5337c478bd9Sstevel@tonic-gate  *
5347c478bd9Sstevel@tonic-gate  * Returns:
5357c478bd9Sstevel@tonic-gate  *	CKR_OK: success
5367c478bd9Sstevel@tonic-gate  *	CKR_FUNCTION_FAILED: encrypt final function failed
5377c478bd9Sstevel@tonic-gate  *	CKR_DATA_LEN_RANGE: remaining buffer contains bad length
5387c478bd9Sstevel@tonic-gate  */
5397c478bd9Sstevel@tonic-gate CK_RV
soft_encrypt_final(soft_session_t * session_p,CK_BYTE_PTR pLastEncryptedPart,CK_ULONG_PTR pulLastEncryptedPartLen)5407c478bd9Sstevel@tonic-gate soft_encrypt_final(soft_session_t *session_p, CK_BYTE_PTR pLastEncryptedPart,
5417c478bd9Sstevel@tonic-gate 	CK_ULONG_PTR pulLastEncryptedPartLen)
5427c478bd9Sstevel@tonic-gate {
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate 	CK_MECHANISM_TYPE mechanism = session_p->encrypt.mech.mechanism;
5457c478bd9Sstevel@tonic-gate 	CK_ULONG out_len;
5467c478bd9Sstevel@tonic-gate 	CK_RV rv = CKR_OK;
5477c478bd9Sstevel@tonic-gate 	int rc;
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&session_p->session_mutex);
5507c478bd9Sstevel@tonic-gate 
5517c478bd9Sstevel@tonic-gate 	if (session_p->encrypt.context == NULL) {
5527c478bd9Sstevel@tonic-gate 		rv = CKR_OPERATION_NOT_INITIALIZED;
5537c478bd9Sstevel@tonic-gate 		*pulLastEncryptedPartLen = 0;
5547c478bd9Sstevel@tonic-gate 		goto clean1;
5557c478bd9Sstevel@tonic-gate 	}
5567c478bd9Sstevel@tonic-gate 	switch (mechanism) {
5577c478bd9Sstevel@tonic-gate 
5587c478bd9Sstevel@tonic-gate 	case CKM_DES_CBC_PAD:
5597c478bd9Sstevel@tonic-gate 	case CKM_DES3_CBC_PAD:
5607c478bd9Sstevel@tonic-gate 	{
5617c478bd9Sstevel@tonic-gate 		soft_des_ctx_t *soft_des_ctx;
5627c478bd9Sstevel@tonic-gate 
5637c478bd9Sstevel@tonic-gate 		soft_des_ctx = (soft_des_ctx_t *)session_p->encrypt.context;
5647c478bd9Sstevel@tonic-gate 		/*
5657c478bd9Sstevel@tonic-gate 		 * For CKM_DES_CBC_PAD, compute output length with
5667c478bd9Sstevel@tonic-gate 		 * padding. If the remaining buffer has one block
5677c478bd9Sstevel@tonic-gate 		 * of data, then output length will be two blocksize of
5687c478bd9Sstevel@tonic-gate 		 * ciphertext. If the remaining buffer has less than
5697c478bd9Sstevel@tonic-gate 		 * one block of data, then output length will be
5707c478bd9Sstevel@tonic-gate 		 * one blocksize.
5717c478bd9Sstevel@tonic-gate 		 */
5727c478bd9Sstevel@tonic-gate 		if (soft_des_ctx->remain_len == DES_BLOCK_LEN)
5737c478bd9Sstevel@tonic-gate 			out_len = 2 * DES_BLOCK_LEN;
5747c478bd9Sstevel@tonic-gate 		else
5757c478bd9Sstevel@tonic-gate 			out_len = DES_BLOCK_LEN;
5767c478bd9Sstevel@tonic-gate 
5777c478bd9Sstevel@tonic-gate 		if (pLastEncryptedPart == NULL) {
5787c478bd9Sstevel@tonic-gate 			/*
5797c478bd9Sstevel@tonic-gate 			 * Application asks for the length of the output
5807c478bd9Sstevel@tonic-gate 			 * buffer to hold the ciphertext.
5817c478bd9Sstevel@tonic-gate 			 */
5827c478bd9Sstevel@tonic-gate 			*pulLastEncryptedPartLen = out_len;
5837c478bd9Sstevel@tonic-gate 			goto clean1;
5847c478bd9Sstevel@tonic-gate 		} else {
5857c478bd9Sstevel@tonic-gate 			crypto_data_t out;
5867c478bd9Sstevel@tonic-gate 
5877c478bd9Sstevel@tonic-gate 			/* Copy remaining data to the output buffer. */
5887c478bd9Sstevel@tonic-gate 			(void) memcpy(pLastEncryptedPart, soft_des_ctx->data,
5897c478bd9Sstevel@tonic-gate 			    soft_des_ctx->remain_len);
5907c478bd9Sstevel@tonic-gate 
5917c478bd9Sstevel@tonic-gate 			/*
5927c478bd9Sstevel@tonic-gate 			 * Add padding bytes prior to encrypt final.
5937c478bd9Sstevel@tonic-gate 			 */
5947c478bd9Sstevel@tonic-gate 			soft_add_pkcs7_padding(pLastEncryptedPart +
5957c478bd9Sstevel@tonic-gate 			    soft_des_ctx->remain_len, DES_BLOCK_LEN,
5967c478bd9Sstevel@tonic-gate 			    soft_des_ctx->remain_len);
5977c478bd9Sstevel@tonic-gate 
5987c478bd9Sstevel@tonic-gate 			out.cd_format = CRYPTO_DATA_RAW;
5997c478bd9Sstevel@tonic-gate 			out.cd_offset = 0;
6007c478bd9Sstevel@tonic-gate 			out.cd_length = out_len;
6017c478bd9Sstevel@tonic-gate 			out.cd_raw.iov_base = (char *)pLastEncryptedPart;
6027c478bd9Sstevel@tonic-gate 			out.cd_raw.iov_len = out_len;
6037c478bd9Sstevel@tonic-gate 
6047c478bd9Sstevel@tonic-gate 			/* Encrypt multiple blocks of data. */
6057c478bd9Sstevel@tonic-gate 			rc = des_encrypt_contiguous_blocks(
6067c478bd9Sstevel@tonic-gate 			    (des_ctx_t *)soft_des_ctx->des_cbc,
6077c478bd9Sstevel@tonic-gate 			    (char *)pLastEncryptedPart, out_len, &out);
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate 			if (rc == 0) {
6107c478bd9Sstevel@tonic-gate 				*pulLastEncryptedPartLen = out_len;
6117c478bd9Sstevel@tonic-gate 			} else {
6127c478bd9Sstevel@tonic-gate 				*pulLastEncryptedPartLen = 0;
6137c478bd9Sstevel@tonic-gate 				rv = CKR_FUNCTION_FAILED;
6147c478bd9Sstevel@tonic-gate 			}
6157c478bd9Sstevel@tonic-gate 
6167c478bd9Sstevel@tonic-gate 			/* Cleanup memory space. */
6177c478bd9Sstevel@tonic-gate 			free(soft_des_ctx->des_cbc);
6187c478bd9Sstevel@tonic-gate 			bzero(soft_des_ctx->key_sched,
6197c478bd9Sstevel@tonic-gate 			    soft_des_ctx->keysched_len);
6207c478bd9Sstevel@tonic-gate 			free(soft_des_ctx->key_sched);
6217c478bd9Sstevel@tonic-gate 		}
6227c478bd9Sstevel@tonic-gate 
6237c478bd9Sstevel@tonic-gate 		break;
6247c478bd9Sstevel@tonic-gate 	}
6257c478bd9Sstevel@tonic-gate 	case CKM_DES_CBC:
6267c478bd9Sstevel@tonic-gate 	case CKM_DES_ECB:
6277c478bd9Sstevel@tonic-gate 	case CKM_DES3_CBC:
6287c478bd9Sstevel@tonic-gate 	case CKM_DES3_ECB:
6297c478bd9Sstevel@tonic-gate 	{
6307c478bd9Sstevel@tonic-gate 
6317c478bd9Sstevel@tonic-gate 		soft_des_ctx_t *soft_des_ctx;
6327c478bd9Sstevel@tonic-gate 
6337c478bd9Sstevel@tonic-gate 		soft_des_ctx = (soft_des_ctx_t *)session_p->encrypt.context;
6347c478bd9Sstevel@tonic-gate 		/*
6357c478bd9Sstevel@tonic-gate 		 * CKM_DES_CBC and CKM_DES_ECB does not do any padding,
6367c478bd9Sstevel@tonic-gate 		 * so when the final is called, the remaining buffer
6377c478bd9Sstevel@tonic-gate 		 * should not contain any more data.
6387c478bd9Sstevel@tonic-gate 		 */
6397c478bd9Sstevel@tonic-gate 		*pulLastEncryptedPartLen = 0;
6407c478bd9Sstevel@tonic-gate 		if (soft_des_ctx->remain_len != 0) {
6417c478bd9Sstevel@tonic-gate 			rv = CKR_DATA_LEN_RANGE;
6427c478bd9Sstevel@tonic-gate 		} else {
6437c478bd9Sstevel@tonic-gate 			if (pLastEncryptedPart == NULL)
6447c478bd9Sstevel@tonic-gate 				goto clean1;
6457c478bd9Sstevel@tonic-gate 		}
6467c478bd9Sstevel@tonic-gate 
6477c478bd9Sstevel@tonic-gate 		/* Cleanup memory space. */
6487c478bd9Sstevel@tonic-gate 		free(soft_des_ctx->des_cbc);
6497c478bd9Sstevel@tonic-gate 		bzero(soft_des_ctx->key_sched, soft_des_ctx->keysched_len);
6507c478bd9Sstevel@tonic-gate 		free(soft_des_ctx->key_sched);
6517c478bd9Sstevel@tonic-gate 
6527c478bd9Sstevel@tonic-gate 		break;
6537c478bd9Sstevel@tonic-gate 	}
6547c478bd9Sstevel@tonic-gate 	case CKM_AES_CBC_PAD:
6557c478bd9Sstevel@tonic-gate 	{
6567c478bd9Sstevel@tonic-gate 		soft_aes_ctx_t *soft_aes_ctx;
6577c478bd9Sstevel@tonic-gate 
6587c478bd9Sstevel@tonic-gate 		soft_aes_ctx = (soft_aes_ctx_t *)session_p->encrypt.context;
6597c478bd9Sstevel@tonic-gate 		/*
6607c478bd9Sstevel@tonic-gate 		 * For CKM_AES_CBC_PAD, compute output length with
6617c478bd9Sstevel@tonic-gate 		 * padding. If the remaining buffer has one block
6627c478bd9Sstevel@tonic-gate 		 * of data, then output length will be two blocksize of
6637c478bd9Sstevel@tonic-gate 		 * ciphertext. If the remaining buffer has less than
6647c478bd9Sstevel@tonic-gate 		 * one block of data, then output length will be
6657c478bd9Sstevel@tonic-gate 		 * one blocksize.
6667c478bd9Sstevel@tonic-gate 		 */
6677c478bd9Sstevel@tonic-gate 		if (soft_aes_ctx->remain_len == AES_BLOCK_LEN)
6687c478bd9Sstevel@tonic-gate 			out_len = 2 * AES_BLOCK_LEN;
6697c478bd9Sstevel@tonic-gate 		else
6707c478bd9Sstevel@tonic-gate 			out_len = AES_BLOCK_LEN;
6717c478bd9Sstevel@tonic-gate 
6727c478bd9Sstevel@tonic-gate 		if (pLastEncryptedPart == NULL) {
6737c478bd9Sstevel@tonic-gate 			/*
6747c478bd9Sstevel@tonic-gate 			 * Application asks for the length of the output
6757c478bd9Sstevel@tonic-gate 			 * buffer to hold the ciphertext.
6767c478bd9Sstevel@tonic-gate 			 */
6777c478bd9Sstevel@tonic-gate 			*pulLastEncryptedPartLen = out_len;
6787c478bd9Sstevel@tonic-gate 			goto clean1;
6797c478bd9Sstevel@tonic-gate 		} else {
6807c478bd9Sstevel@tonic-gate 			crypto_data_t out;
6817c478bd9Sstevel@tonic-gate 
6827c478bd9Sstevel@tonic-gate 			/* Copy remaining data to the output buffer. */
6837c478bd9Sstevel@tonic-gate 			(void) memcpy(pLastEncryptedPart, soft_aes_ctx->data,
6847c478bd9Sstevel@tonic-gate 			    soft_aes_ctx->remain_len);
6857c478bd9Sstevel@tonic-gate 
6867c478bd9Sstevel@tonic-gate 			/*
6877c478bd9Sstevel@tonic-gate 			 * Add padding bytes prior to encrypt final.
6887c478bd9Sstevel@tonic-gate 			 */
6897c478bd9Sstevel@tonic-gate 			soft_add_pkcs7_padding(pLastEncryptedPart +
6907c478bd9Sstevel@tonic-gate 			    soft_aes_ctx->remain_len, AES_BLOCK_LEN,
6917c478bd9Sstevel@tonic-gate 			    soft_aes_ctx->remain_len);
6927c478bd9Sstevel@tonic-gate 
6937c478bd9Sstevel@tonic-gate 			out.cd_format = CRYPTO_DATA_RAW;
6947c478bd9Sstevel@tonic-gate 			out.cd_offset = 0;
6957c478bd9Sstevel@tonic-gate 			out.cd_length = out_len;
6967c478bd9Sstevel@tonic-gate 			out.cd_raw.iov_base = (char *)pLastEncryptedPart;
6977c478bd9Sstevel@tonic-gate 			out.cd_raw.iov_len = out_len;
6987c478bd9Sstevel@tonic-gate 
6997c478bd9Sstevel@tonic-gate 			/* Encrypt multiple blocks of data. */
7007c478bd9Sstevel@tonic-gate 			rc = aes_encrypt_contiguous_blocks(
7017c478bd9Sstevel@tonic-gate 			    (aes_ctx_t *)soft_aes_ctx->aes_cbc,
7027c478bd9Sstevel@tonic-gate 			    (char *)pLastEncryptedPart, out_len, &out);
7037c478bd9Sstevel@tonic-gate 
7047c478bd9Sstevel@tonic-gate 			if (rc == 0) {
7057c478bd9Sstevel@tonic-gate 				*pulLastEncryptedPartLen = out_len;
7067c478bd9Sstevel@tonic-gate 			} else {
7077c478bd9Sstevel@tonic-gate 				*pulLastEncryptedPartLen = 0;
7087c478bd9Sstevel@tonic-gate 				rv = CKR_FUNCTION_FAILED;
7097c478bd9Sstevel@tonic-gate 			}
7107c478bd9Sstevel@tonic-gate 
7117c478bd9Sstevel@tonic-gate 			/* Cleanup memory space. */
7127c478bd9Sstevel@tonic-gate 			free(soft_aes_ctx->aes_cbc);
7137c478bd9Sstevel@tonic-gate 			bzero(soft_aes_ctx->key_sched,
7147c478bd9Sstevel@tonic-gate 			    soft_aes_ctx->keysched_len);
7157c478bd9Sstevel@tonic-gate 			free(soft_aes_ctx->key_sched);
7167c478bd9Sstevel@tonic-gate 		}
7177c478bd9Sstevel@tonic-gate 
7187c478bd9Sstevel@tonic-gate 		break;
7197c478bd9Sstevel@tonic-gate 	}
7207c478bd9Sstevel@tonic-gate 	case CKM_AES_CBC:
7217c478bd9Sstevel@tonic-gate 	case CKM_AES_ECB:
7227c478bd9Sstevel@tonic-gate 	{
7237c478bd9Sstevel@tonic-gate 		soft_aes_ctx_t *soft_aes_ctx;
7247c478bd9Sstevel@tonic-gate 
7257c478bd9Sstevel@tonic-gate 		soft_aes_ctx = (soft_aes_ctx_t *)session_p->encrypt.context;
7267c478bd9Sstevel@tonic-gate 		/*
7277c478bd9Sstevel@tonic-gate 		 * CKM_AES_CBC and CKM_AES_ECB does not do any padding,
7287c478bd9Sstevel@tonic-gate 		 * so when the final is called, the remaining buffer
7297c478bd9Sstevel@tonic-gate 		 * should not contain any more data.
7307c478bd9Sstevel@tonic-gate 		 */
7317c478bd9Sstevel@tonic-gate 		*pulLastEncryptedPartLen = 0;
7327c478bd9Sstevel@tonic-gate 		if (soft_aes_ctx->remain_len != 0) {
7337c478bd9Sstevel@tonic-gate 			rv = CKR_DATA_LEN_RANGE;
7347c478bd9Sstevel@tonic-gate 		} else {
7357c478bd9Sstevel@tonic-gate 			if (pLastEncryptedPart == NULL)
7367c478bd9Sstevel@tonic-gate 				goto clean1;
7377c478bd9Sstevel@tonic-gate 		}
7387c478bd9Sstevel@tonic-gate 
7397c478bd9Sstevel@tonic-gate 		/* Cleanup memory space. */
7407c478bd9Sstevel@tonic-gate 		free(soft_aes_ctx->aes_cbc);
7417c478bd9Sstevel@tonic-gate 		bzero(soft_aes_ctx->key_sched, soft_aes_ctx->keysched_len);
7427c478bd9Sstevel@tonic-gate 		free(soft_aes_ctx->key_sched);
7437c478bd9Sstevel@tonic-gate 
7447c478bd9Sstevel@tonic-gate 		break;
7457c478bd9Sstevel@tonic-gate 	}
74623c57df7Smcpowers 	case CKM_AES_CTR:
74723c57df7Smcpowers 	{
74823c57df7Smcpowers 		crypto_data_t out;
74923c57df7Smcpowers 		soft_aes_ctx_t *soft_aes_ctx;
75023c57df7Smcpowers 		ctr_ctx_t *ctr_ctx;
75123c57df7Smcpowers 		size_t len;
7527c478bd9Sstevel@tonic-gate 
75323c57df7Smcpowers 		soft_aes_ctx = (soft_aes_ctx_t *)session_p->encrypt.context;
75423c57df7Smcpowers 		ctr_ctx = soft_aes_ctx->aes_cbc;
75523c57df7Smcpowers 		len = ctr_ctx->ctr_remainder_len;
75623c57df7Smcpowers 
75723c57df7Smcpowers 		if (pLastEncryptedPart == NULL) {
75823c57df7Smcpowers 			*pulLastEncryptedPartLen = len;
75923c57df7Smcpowers 			goto clean1;
76023c57df7Smcpowers 		}
76123c57df7Smcpowers 		if (len > 0) {
76223c57df7Smcpowers 			out.cd_format = CRYPTO_DATA_RAW;
76323c57df7Smcpowers 			out.cd_offset = 0;
76423c57df7Smcpowers 			out.cd_length = len;
76523c57df7Smcpowers 			out.cd_raw.iov_base = (char *)pLastEncryptedPart;
76623c57df7Smcpowers 			out.cd_raw.iov_len = len;
76723c57df7Smcpowers 
76823c57df7Smcpowers 			rv = ctr_mode_final(ctr_ctx, &out, aes_encrypt_block);
76923c57df7Smcpowers 		}
77023c57df7Smcpowers 		if (rv == CRYPTO_BUFFER_TOO_SMALL) {
77123c57df7Smcpowers 			*pulLastEncryptedPartLen = len;
77223c57df7Smcpowers 			goto clean1;
77323c57df7Smcpowers 		}
77423c57df7Smcpowers 
77523c57df7Smcpowers 		/* Cleanup memory space. */
77623c57df7Smcpowers 		free(ctr_ctx);
77723c57df7Smcpowers 		bzero(soft_aes_ctx->key_sched, soft_aes_ctx->keysched_len);
77823c57df7Smcpowers 		free(soft_aes_ctx->key_sched);
77923c57df7Smcpowers 
78023c57df7Smcpowers 		break;
78123c57df7Smcpowers 	}
782f66d273dSizick 	case CKM_BLOWFISH_CBC:
783f66d273dSizick 	{
784f66d273dSizick 		soft_blowfish_ctx_t *soft_blowfish_ctx;
785f66d273dSizick 
786f66d273dSizick 		soft_blowfish_ctx =
787f66d273dSizick 		    (soft_blowfish_ctx_t *)session_p->encrypt.context;
788f66d273dSizick 		/*
789f66d273dSizick 		 * CKM_BLOWFISH_CBC does not do any padding, so when the
790f66d273dSizick 		 * final is called, the remaining buffer should not contain
791f66d273dSizick 		 * any more data
792f66d273dSizick 		 */
793f66d273dSizick 		*pulLastEncryptedPartLen = 0;
794f66d273dSizick 		if (soft_blowfish_ctx->remain_len != 0)
795f66d273dSizick 			rv = CKR_DATA_LEN_RANGE;
796f66d273dSizick 		else {
797f66d273dSizick 			if (pLastEncryptedPart == NULL)
798f66d273dSizick 				goto clean1;
799f66d273dSizick 		}
800f66d273dSizick 
801f66d273dSizick 		free(soft_blowfish_ctx->blowfish_cbc);
802f66d273dSizick 		bzero(soft_blowfish_ctx->key_sched,
803f66d273dSizick 		    soft_blowfish_ctx->keysched_len);
804f66d273dSizick 		free(soft_blowfish_ctx->key_sched);
805f66d273dSizick 		break;
806f66d273dSizick 	}
807f66d273dSizick 
8087c478bd9Sstevel@tonic-gate 	case CKM_RC4:
8097c478bd9Sstevel@tonic-gate 	{
8107c478bd9Sstevel@tonic-gate 		ARCFour_key *key = (ARCFour_key *)session_p->encrypt.context;
811c00745c7SZdenek Kotala 		/* Remaining data size is always zero for RC4. */
8127c478bd9Sstevel@tonic-gate 		*pulLastEncryptedPartLen = 0;
813c00745c7SZdenek Kotala 		if (pLastEncryptedPart == NULL)
814c00745c7SZdenek Kotala 			goto clean1;
815c00745c7SZdenek Kotala 		bzero(key, sizeof (*key));
8167c478bd9Sstevel@tonic-gate 		break;
8177c478bd9Sstevel@tonic-gate 	}
8187c478bd9Sstevel@tonic-gate 	default:
8197c478bd9Sstevel@tonic-gate 		/* PKCS11: The mechanism only supports single-part operation. */
8207c478bd9Sstevel@tonic-gate 		rv = CKR_MECHANISM_INVALID;
8217c478bd9Sstevel@tonic-gate 		break;
8227c478bd9Sstevel@tonic-gate 	}
8237c478bd9Sstevel@tonic-gate 
8247c478bd9Sstevel@tonic-gate 	free(session_p->encrypt.context);
8257c478bd9Sstevel@tonic-gate 	session_p->encrypt.context = NULL;
8267c478bd9Sstevel@tonic-gate clean1:
8277c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&session_p->session_mutex);
8287c478bd9Sstevel@tonic-gate 
8297c478bd9Sstevel@tonic-gate 	return (rv);
8307c478bd9Sstevel@tonic-gate }
8317c478bd9Sstevel@tonic-gate 
8327c478bd9Sstevel@tonic-gate /*
8337c478bd9Sstevel@tonic-gate  * This function frees the allocated active crypto context and the
8347c478bd9Sstevel@tonic-gate  * lower level of allocated struct as needed.
8357c478bd9Sstevel@tonic-gate  * This function is called by the 1st tier of encrypt/decrypt routines
8367c478bd9Sstevel@tonic-gate  * or by the 2nd tier of session close routine. Since the 1st tier
8377c478bd9Sstevel@tonic-gate  * caller will always call this function without locking the session
8387c478bd9Sstevel@tonic-gate  * mutex and the 2nd tier caller will call with the lock, we add the
839*726fad2aSDina K Nimeh  * third parameter "lock_held" to distinguish this case.
8407c478bd9Sstevel@tonic-gate  */
8417c478bd9Sstevel@tonic-gate void
soft_crypt_cleanup(soft_session_t * session_p,boolean_t encrypt,boolean_t lock_held)8427c478bd9Sstevel@tonic-gate soft_crypt_cleanup(soft_session_t *session_p, boolean_t encrypt,
8437c478bd9Sstevel@tonic-gate 	boolean_t lock_held)
8447c478bd9Sstevel@tonic-gate {
8457c478bd9Sstevel@tonic-gate 
8467c478bd9Sstevel@tonic-gate 	crypto_active_op_t *active_op;
8477c478bd9Sstevel@tonic-gate 	boolean_t lock_true = B_TRUE;
8487c478bd9Sstevel@tonic-gate 
8497c478bd9Sstevel@tonic-gate 	if (!lock_held)
8507c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_lock(&session_p->session_mutex);
8517c478bd9Sstevel@tonic-gate 
8527c478bd9Sstevel@tonic-gate 	active_op = (encrypt) ? &(session_p->encrypt) : &(session_p->decrypt);
8537c478bd9Sstevel@tonic-gate 
8547c478bd9Sstevel@tonic-gate 	switch (active_op->mech.mechanism) {
8557c478bd9Sstevel@tonic-gate 
8567c478bd9Sstevel@tonic-gate 	case CKM_DES_CBC_PAD:
8577c478bd9Sstevel@tonic-gate 	case CKM_DES3_CBC_PAD:
8587c478bd9Sstevel@tonic-gate 	case CKM_DES_CBC:
8597c478bd9Sstevel@tonic-gate 	case CKM_DES_ECB:
8607c478bd9Sstevel@tonic-gate 	case CKM_DES3_CBC:
8617c478bd9Sstevel@tonic-gate 	case CKM_DES3_ECB:
8627c478bd9Sstevel@tonic-gate 	{
8637c478bd9Sstevel@tonic-gate 
8647c478bd9Sstevel@tonic-gate 		soft_des_ctx_t *soft_des_ctx =
8657c478bd9Sstevel@tonic-gate 		    (soft_des_ctx_t *)active_op->context;
8667c478bd9Sstevel@tonic-gate 		des_ctx_t *des_ctx;
8677c478bd9Sstevel@tonic-gate 
8687c478bd9Sstevel@tonic-gate 		if (soft_des_ctx != NULL) {
8697c478bd9Sstevel@tonic-gate 			des_ctx = (des_ctx_t *)soft_des_ctx->des_cbc;
8707c478bd9Sstevel@tonic-gate 			if (des_ctx != NULL) {
8717c478bd9Sstevel@tonic-gate 				bzero(des_ctx->dc_keysched,
8727c478bd9Sstevel@tonic-gate 				    des_ctx->dc_keysched_len);
8737c478bd9Sstevel@tonic-gate 				free(soft_des_ctx->des_cbc);
8747c478bd9Sstevel@tonic-gate 			}
8757c478bd9Sstevel@tonic-gate 			bzero(soft_des_ctx->key_sched,
8767c478bd9Sstevel@tonic-gate 			    soft_des_ctx->keysched_len);
8777c478bd9Sstevel@tonic-gate 			free(soft_des_ctx->key_sched);
8787c478bd9Sstevel@tonic-gate 		}
8797c478bd9Sstevel@tonic-gate 		break;
8807c478bd9Sstevel@tonic-gate 	}
8817c478bd9Sstevel@tonic-gate 
8827c478bd9Sstevel@tonic-gate 	case CKM_AES_CBC_PAD:
8837c478bd9Sstevel@tonic-gate 	case CKM_AES_CBC:
8847c478bd9Sstevel@tonic-gate 	case CKM_AES_ECB:
8857c478bd9Sstevel@tonic-gate 	{
8867c478bd9Sstevel@tonic-gate 		soft_aes_ctx_t *soft_aes_ctx =
8877c478bd9Sstevel@tonic-gate 		    (soft_aes_ctx_t *)active_op->context;
8887c478bd9Sstevel@tonic-gate 		aes_ctx_t *aes_ctx;
8897c478bd9Sstevel@tonic-gate 
8907c478bd9Sstevel@tonic-gate 		if (soft_aes_ctx != NULL) {
8917c478bd9Sstevel@tonic-gate 			aes_ctx = (aes_ctx_t *)soft_aes_ctx->aes_cbc;
8927c478bd9Sstevel@tonic-gate 			if (aes_ctx != NULL) {
8937c478bd9Sstevel@tonic-gate 				bzero(aes_ctx->ac_keysched,
8947c478bd9Sstevel@tonic-gate 				    aes_ctx->ac_keysched_len);
8957c478bd9Sstevel@tonic-gate 				free(soft_aes_ctx->aes_cbc);
8967c478bd9Sstevel@tonic-gate 			}
8977c478bd9Sstevel@tonic-gate 			bzero(soft_aes_ctx->key_sched,
8987c478bd9Sstevel@tonic-gate 			    soft_aes_ctx->keysched_len);
8997c478bd9Sstevel@tonic-gate 			free(soft_aes_ctx->key_sched);
9007c478bd9Sstevel@tonic-gate 		}
9017c478bd9Sstevel@tonic-gate 		break;
9027c478bd9Sstevel@tonic-gate 	}
9037c478bd9Sstevel@tonic-gate 
904f66d273dSizick 	case CKM_BLOWFISH_CBC:
905f66d273dSizick 	{
906f66d273dSizick 		soft_blowfish_ctx_t *soft_blowfish_ctx =
907f66d273dSizick 		    (soft_blowfish_ctx_t *)active_op->context;
908f66d273dSizick 		blowfish_ctx_t *blowfish_ctx;
909f66d273dSizick 
910f66d273dSizick 		if (soft_blowfish_ctx != NULL) {
911f66d273dSizick 			blowfish_ctx =
912f66d273dSizick 			    (blowfish_ctx_t *)soft_blowfish_ctx->blowfish_cbc;
913f66d273dSizick 			if (blowfish_ctx != NULL) {
914f66d273dSizick 				bzero(blowfish_ctx->bc_keysched,
915f66d273dSizick 				    blowfish_ctx->bc_keysched_len);
916f66d273dSizick 				free(soft_blowfish_ctx->blowfish_cbc);
917f66d273dSizick 			}
918f66d273dSizick 
919f66d273dSizick 			bzero(soft_blowfish_ctx->key_sched,
920f66d273dSizick 			    soft_blowfish_ctx->keysched_len);
921f66d273dSizick 			free(soft_blowfish_ctx->key_sched);
922f66d273dSizick 		}
923f66d273dSizick 		break;
924f66d273dSizick 	}
925f66d273dSizick 
9267c478bd9Sstevel@tonic-gate 	case CKM_RC4:
9277c478bd9Sstevel@tonic-gate 	{
9287c478bd9Sstevel@tonic-gate 		ARCFour_key *key = (ARCFour_key *)active_op->context;
9297c478bd9Sstevel@tonic-gate 
9307c478bd9Sstevel@tonic-gate 		if (key != NULL)
9317c478bd9Sstevel@tonic-gate 			bzero(key, sizeof (*key));
9327c478bd9Sstevel@tonic-gate 		break;
9337c478bd9Sstevel@tonic-gate 	}
9347c478bd9Sstevel@tonic-gate 
9357c478bd9Sstevel@tonic-gate 	case CKM_RSA_X_509:
9367c478bd9Sstevel@tonic-gate 	case CKM_RSA_PKCS:
9374c21f043Sizick 	{
9384c21f043Sizick 		soft_rsa_ctx_t *rsa_ctx =
9394c21f043Sizick 		    (soft_rsa_ctx_t *)active_op->context;
9404c21f043Sizick 
9414c21f043Sizick 		if (rsa_ctx != NULL)
9424c21f043Sizick 			if (rsa_ctx->key != NULL) {
9434c21f043Sizick 				soft_cleanup_object(rsa_ctx->key);
9444c21f043Sizick 				free(rsa_ctx->key);
9454c21f043Sizick 			}
9464c21f043Sizick 
9477c478bd9Sstevel@tonic-gate 		break;
9484c21f043Sizick 	}
9497c478bd9Sstevel@tonic-gate 
9507c478bd9Sstevel@tonic-gate 	} /* switch */
9517c478bd9Sstevel@tonic-gate 
9527c478bd9Sstevel@tonic-gate 	if (active_op->context != NULL) {
9537c478bd9Sstevel@tonic-gate 		free(active_op->context);
9547c478bd9Sstevel@tonic-gate 		active_op->context = NULL;
9557c478bd9Sstevel@tonic-gate 	}
9567c478bd9Sstevel@tonic-gate 
9577c478bd9Sstevel@tonic-gate 	active_op->flags = 0;
9587c478bd9Sstevel@tonic-gate 
9597c478bd9Sstevel@tonic-gate 	if (!lock_held)
9607c478bd9Sstevel@tonic-gate 		SES_REFRELE(session_p, lock_true);
9617c478bd9Sstevel@tonic-gate }
962