xref: /onnv-gate/usr/src/uts/common/crypto/io/aes.c (revision 9339:7c09601804ed)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
52530Spwernau  * Common Development and Distribution License (the "License").
62530Spwernau  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*9339SMark.Powers@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate /*
270Sstevel@tonic-gate  * AES provider for the Kernel Cryptographic Framework (KCF)
280Sstevel@tonic-gate  */
290Sstevel@tonic-gate 
300Sstevel@tonic-gate #include <sys/types.h>
310Sstevel@tonic-gate #include <sys/systm.h>
320Sstevel@tonic-gate #include <sys/modctl.h>
330Sstevel@tonic-gate #include <sys/cmn_err.h>
340Sstevel@tonic-gate #include <sys/ddi.h>
350Sstevel@tonic-gate #include <sys/crypto/common.h>
367188Smcpowers #include <sys/crypto/impl.h>
370Sstevel@tonic-gate #include <sys/crypto/spi.h>
380Sstevel@tonic-gate #include <sys/sysmacros.h>
390Sstevel@tonic-gate #include <sys/strsun.h>
407188Smcpowers #include <modes/modes.h>
417188Smcpowers #include <aes/aes_impl.h>
420Sstevel@tonic-gate 
430Sstevel@tonic-gate extern struct mod_ops mod_cryptoops;
440Sstevel@tonic-gate 
450Sstevel@tonic-gate /*
460Sstevel@tonic-gate  * Module linkage information for the kernel.
470Sstevel@tonic-gate  */
480Sstevel@tonic-gate static struct modlcrypto modlcrypto = {
490Sstevel@tonic-gate 	&mod_cryptoops,
505072Smcpowers 	"AES Kernel SW Provider"
510Sstevel@tonic-gate };
520Sstevel@tonic-gate 
530Sstevel@tonic-gate static struct modlinkage modlinkage = {
540Sstevel@tonic-gate 	MODREV_1,
550Sstevel@tonic-gate 	(void *)&modlcrypto,
560Sstevel@tonic-gate 	NULL
570Sstevel@tonic-gate };
580Sstevel@tonic-gate 
590Sstevel@tonic-gate /*
600Sstevel@tonic-gate  * CSPI information (entry points, provider info, etc.)
610Sstevel@tonic-gate  */
620Sstevel@tonic-gate typedef enum aes_mech_type {
630Sstevel@tonic-gate 	AES_ECB_MECH_INFO_TYPE,		/* SUN_CKM_AES_ECB */
640Sstevel@tonic-gate 	AES_CBC_MECH_INFO_TYPE,		/* SUN_CKM_AES_CBC */
65904Smcpowers 	AES_CBC_PAD_MECH_INFO_TYPE,	/* SUN_CKM_AES_CBC_PAD */
664486Sktung 	AES_CTR_MECH_INFO_TYPE,		/* SUN_CKM_AES_CTR */
678005SMark.Powers@Sun.COM 	AES_CCM_MECH_INFO_TYPE,		/* SUN_CKM_AES_CCM */
68*9339SMark.Powers@Sun.COM 	AES_GCM_MECH_INFO_TYPE,		/* SUN_CKM_AES_GCM */
69*9339SMark.Powers@Sun.COM 	AES_GMAC_MECH_INFO_TYPE		/* SUN_CKM_AES_GMAC */
700Sstevel@tonic-gate } aes_mech_type_t;
710Sstevel@tonic-gate 
720Sstevel@tonic-gate /*
730Sstevel@tonic-gate  * The following definitions are to keep EXPORT_SRC happy.
740Sstevel@tonic-gate  */
752530Spwernau #ifndef AES_MIN_KEY_BYTES
762530Spwernau #define	AES_MIN_KEY_BYTES		0
770Sstevel@tonic-gate #endif
780Sstevel@tonic-gate 
792530Spwernau #ifndef AES_MAX_KEY_BYTES
802530Spwernau #define	AES_MAX_KEY_BYTES		0
810Sstevel@tonic-gate #endif
820Sstevel@tonic-gate 
830Sstevel@tonic-gate /*
840Sstevel@tonic-gate  * Mechanism info structure passed to KCF during registration.
850Sstevel@tonic-gate  */
860Sstevel@tonic-gate static crypto_mech_info_t aes_mech_info_tab[] = {
870Sstevel@tonic-gate 	/* AES_ECB */
880Sstevel@tonic-gate 	{SUN_CKM_AES_ECB, AES_ECB_MECH_INFO_TYPE,
890Sstevel@tonic-gate 	    CRYPTO_FG_ENCRYPT | CRYPTO_FG_ENCRYPT_ATOMIC |
900Sstevel@tonic-gate 	    CRYPTO_FG_DECRYPT | CRYPTO_FG_DECRYPT_ATOMIC,
912530Spwernau 	    AES_MIN_KEY_BYTES, AES_MAX_KEY_BYTES, CRYPTO_KEYSIZE_UNIT_IN_BYTES},
920Sstevel@tonic-gate 	/* AES_CBC */
930Sstevel@tonic-gate 	{SUN_CKM_AES_CBC, AES_CBC_MECH_INFO_TYPE,
940Sstevel@tonic-gate 	    CRYPTO_FG_ENCRYPT | CRYPTO_FG_ENCRYPT_ATOMIC |
950Sstevel@tonic-gate 	    CRYPTO_FG_DECRYPT | CRYPTO_FG_DECRYPT_ATOMIC,
962530Spwernau 	    AES_MIN_KEY_BYTES, AES_MAX_KEY_BYTES, CRYPTO_KEYSIZE_UNIT_IN_BYTES},
97904Smcpowers 	/* AES_CTR */
98904Smcpowers 	{SUN_CKM_AES_CTR, AES_CTR_MECH_INFO_TYPE,
99904Smcpowers 	    CRYPTO_FG_ENCRYPT | CRYPTO_FG_ENCRYPT_ATOMIC |
100904Smcpowers 	    CRYPTO_FG_DECRYPT | CRYPTO_FG_DECRYPT_ATOMIC,
1014486Sktung 	    AES_MIN_KEY_BYTES, AES_MAX_KEY_BYTES, CRYPTO_KEYSIZE_UNIT_IN_BYTES},
1024486Sktung 	/* AES_CCM */
1034486Sktung 	{SUN_CKM_AES_CCM, AES_CCM_MECH_INFO_TYPE,
1044486Sktung 	    CRYPTO_FG_ENCRYPT | CRYPTO_FG_ENCRYPT_ATOMIC |
1054486Sktung 	    CRYPTO_FG_DECRYPT | CRYPTO_FG_DECRYPT_ATOMIC,
1068005SMark.Powers@Sun.COM 	    AES_MIN_KEY_BYTES, AES_MAX_KEY_BYTES, CRYPTO_KEYSIZE_UNIT_IN_BYTES},
1078005SMark.Powers@Sun.COM 	/* AES_GCM */
1088005SMark.Powers@Sun.COM 	{SUN_CKM_AES_GCM, AES_GCM_MECH_INFO_TYPE,
1098005SMark.Powers@Sun.COM 	    CRYPTO_FG_ENCRYPT | CRYPTO_FG_ENCRYPT_ATOMIC |
1108005SMark.Powers@Sun.COM 	    CRYPTO_FG_DECRYPT | CRYPTO_FG_DECRYPT_ATOMIC,
111*9339SMark.Powers@Sun.COM 	    AES_MIN_KEY_BYTES, AES_MAX_KEY_BYTES, CRYPTO_KEYSIZE_UNIT_IN_BYTES},
112*9339SMark.Powers@Sun.COM 	/* AES_GMAC */
113*9339SMark.Powers@Sun.COM 	{SUN_CKM_AES_GMAC, AES_GMAC_MECH_INFO_TYPE,
114*9339SMark.Powers@Sun.COM 	    CRYPTO_FG_ENCRYPT | CRYPTO_FG_ENCRYPT_ATOMIC |
115*9339SMark.Powers@Sun.COM 	    CRYPTO_FG_DECRYPT | CRYPTO_FG_DECRYPT_ATOMIC |
116*9339SMark.Powers@Sun.COM 	    CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC |
117*9339SMark.Powers@Sun.COM 	    CRYPTO_FG_SIGN | CRYPTO_FG_SIGN_ATOMIC |
118*9339SMark.Powers@Sun.COM 	    CRYPTO_FG_VERIFY | CRYPTO_FG_VERIFY_ATOMIC,
1192530Spwernau 	    AES_MIN_KEY_BYTES, AES_MAX_KEY_BYTES, CRYPTO_KEYSIZE_UNIT_IN_BYTES}
1200Sstevel@tonic-gate };
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate /* operations are in-place if the output buffer is NULL */
1230Sstevel@tonic-gate #define	AES_ARG_INPLACE(input, output)				\
1240Sstevel@tonic-gate 	if ((output) == NULL)					\
1250Sstevel@tonic-gate 		(output) = (input);
1260Sstevel@tonic-gate 
1270Sstevel@tonic-gate static void aes_provider_status(crypto_provider_handle_t, uint_t *);
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate static crypto_control_ops_t aes_control_ops = {
1300Sstevel@tonic-gate 	aes_provider_status
1310Sstevel@tonic-gate };
1320Sstevel@tonic-gate 
1334486Sktung static int aes_encrypt_init(crypto_ctx_t *, crypto_mechanism_t *,
1344486Sktung     crypto_key_t *, crypto_spi_ctx_template_t, crypto_req_handle_t);
1354486Sktung static int aes_decrypt_init(crypto_ctx_t *, crypto_mechanism_t *,
1360Sstevel@tonic-gate     crypto_key_t *, crypto_spi_ctx_template_t, crypto_req_handle_t);
1374486Sktung static int aes_common_init(crypto_ctx_t *, crypto_mechanism_t *,
1384486Sktung     crypto_key_t *, crypto_spi_ctx_template_t, crypto_req_handle_t, boolean_t);
1390Sstevel@tonic-gate static int aes_common_init_ctx(aes_ctx_t *, crypto_spi_ctx_template_t *,
1404486Sktung     crypto_mechanism_t *, crypto_key_t *, int, boolean_t);
1410Sstevel@tonic-gate static int aes_encrypt_final(crypto_ctx_t *, crypto_data_t *,
1420Sstevel@tonic-gate     crypto_req_handle_t);
1430Sstevel@tonic-gate static int aes_decrypt_final(crypto_ctx_t *, crypto_data_t *,
1440Sstevel@tonic-gate     crypto_req_handle_t);
1450Sstevel@tonic-gate 
1460Sstevel@tonic-gate static int aes_encrypt(crypto_ctx_t *, crypto_data_t *, crypto_data_t *,
1470Sstevel@tonic-gate     crypto_req_handle_t);
1480Sstevel@tonic-gate static int aes_encrypt_update(crypto_ctx_t *, crypto_data_t *,
1490Sstevel@tonic-gate     crypto_data_t *, crypto_req_handle_t);
1500Sstevel@tonic-gate static int aes_encrypt_atomic(crypto_provider_handle_t, crypto_session_id_t,
1510Sstevel@tonic-gate     crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
1520Sstevel@tonic-gate     crypto_data_t *, crypto_spi_ctx_template_t, crypto_req_handle_t);
1530Sstevel@tonic-gate 
1540Sstevel@tonic-gate static int aes_decrypt(crypto_ctx_t *, crypto_data_t *, crypto_data_t *,
1550Sstevel@tonic-gate     crypto_req_handle_t);
1560Sstevel@tonic-gate static int aes_decrypt_update(crypto_ctx_t *, crypto_data_t *,
1570Sstevel@tonic-gate     crypto_data_t *, crypto_req_handle_t);
1580Sstevel@tonic-gate static int aes_decrypt_atomic(crypto_provider_handle_t, crypto_session_id_t,
1590Sstevel@tonic-gate     crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
1600Sstevel@tonic-gate     crypto_data_t *, crypto_spi_ctx_template_t, crypto_req_handle_t);
1610Sstevel@tonic-gate 
1620Sstevel@tonic-gate static crypto_cipher_ops_t aes_cipher_ops = {
1634486Sktung 	aes_encrypt_init,
1640Sstevel@tonic-gate 	aes_encrypt,
1650Sstevel@tonic-gate 	aes_encrypt_update,
1660Sstevel@tonic-gate 	aes_encrypt_final,
1670Sstevel@tonic-gate 	aes_encrypt_atomic,
1684486Sktung 	aes_decrypt_init,
1690Sstevel@tonic-gate 	aes_decrypt,
1700Sstevel@tonic-gate 	aes_decrypt_update,
1710Sstevel@tonic-gate 	aes_decrypt_final,
1720Sstevel@tonic-gate 	aes_decrypt_atomic
1730Sstevel@tonic-gate };
1740Sstevel@tonic-gate 
175*9339SMark.Powers@Sun.COM static int aes_mac_atomic(crypto_provider_handle_t, crypto_session_id_t,
176*9339SMark.Powers@Sun.COM     crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, crypto_data_t *,
177*9339SMark.Powers@Sun.COM     crypto_spi_ctx_template_t, crypto_req_handle_t);
178*9339SMark.Powers@Sun.COM static int aes_mac_verify_atomic(crypto_provider_handle_t, crypto_session_id_t,
179*9339SMark.Powers@Sun.COM     crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, crypto_data_t *,
180*9339SMark.Powers@Sun.COM     crypto_spi_ctx_template_t, crypto_req_handle_t);
181*9339SMark.Powers@Sun.COM 
182*9339SMark.Powers@Sun.COM static crypto_mac_ops_t aes_mac_ops = {
183*9339SMark.Powers@Sun.COM 	NULL,
184*9339SMark.Powers@Sun.COM 	NULL,
185*9339SMark.Powers@Sun.COM 	NULL,
186*9339SMark.Powers@Sun.COM 	NULL,
187*9339SMark.Powers@Sun.COM 	aes_mac_atomic,
188*9339SMark.Powers@Sun.COM 	aes_mac_verify_atomic
189*9339SMark.Powers@Sun.COM };
190*9339SMark.Powers@Sun.COM 
1910Sstevel@tonic-gate static int aes_create_ctx_template(crypto_provider_handle_t,
1920Sstevel@tonic-gate     crypto_mechanism_t *, crypto_key_t *, crypto_spi_ctx_template_t *,
1930Sstevel@tonic-gate     size_t *, crypto_req_handle_t);
1940Sstevel@tonic-gate static int aes_free_context(crypto_ctx_t *);
1950Sstevel@tonic-gate 
1960Sstevel@tonic-gate static crypto_ctx_ops_t aes_ctx_ops = {
1970Sstevel@tonic-gate 	aes_create_ctx_template,
1980Sstevel@tonic-gate 	aes_free_context
1990Sstevel@tonic-gate };
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate static crypto_ops_t aes_crypto_ops = {
2020Sstevel@tonic-gate 	&aes_control_ops,
2030Sstevel@tonic-gate 	NULL,
2040Sstevel@tonic-gate 	&aes_cipher_ops,
205*9339SMark.Powers@Sun.COM 	&aes_mac_ops,
2060Sstevel@tonic-gate 	NULL,
2070Sstevel@tonic-gate 	NULL,
2080Sstevel@tonic-gate 	NULL,
2090Sstevel@tonic-gate 	NULL,
2100Sstevel@tonic-gate 	NULL,
2110Sstevel@tonic-gate 	NULL,
2120Sstevel@tonic-gate 	NULL,
2130Sstevel@tonic-gate 	NULL,
2140Sstevel@tonic-gate 	NULL,
2150Sstevel@tonic-gate 	&aes_ctx_ops
2160Sstevel@tonic-gate };
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate static crypto_provider_info_t aes_prov_info = {
2190Sstevel@tonic-gate 	CRYPTO_SPI_VERSION_1,
2200Sstevel@tonic-gate 	"AES Software Provider",
2210Sstevel@tonic-gate 	CRYPTO_SW_PROVIDER,
2220Sstevel@tonic-gate 	{&modlinkage},
2230Sstevel@tonic-gate 	NULL,
2240Sstevel@tonic-gate 	&aes_crypto_ops,
2250Sstevel@tonic-gate 	sizeof (aes_mech_info_tab)/sizeof (crypto_mech_info_t),
2260Sstevel@tonic-gate 	aes_mech_info_tab
2270Sstevel@tonic-gate };
2280Sstevel@tonic-gate 
2290Sstevel@tonic-gate static crypto_kcf_provider_handle_t aes_prov_handle = NULL;
230*9339SMark.Powers@Sun.COM static crypto_data_t null_crypto_data = { CRYPTO_DATA_RAW };
2310Sstevel@tonic-gate 
2320Sstevel@tonic-gate int
2330Sstevel@tonic-gate _init(void)
2340Sstevel@tonic-gate {
2350Sstevel@tonic-gate 	int ret;
2360Sstevel@tonic-gate 
2370Sstevel@tonic-gate 	/*
2380Sstevel@tonic-gate 	 * Register with KCF. If the registration fails, return error.
2390Sstevel@tonic-gate 	 */
2400Sstevel@tonic-gate 	if ((ret = crypto_register_provider(&aes_prov_info,
2410Sstevel@tonic-gate 	    &aes_prov_handle)) != CRYPTO_SUCCESS) {
2420Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s _init: crypto_register_provider()"
2430Sstevel@tonic-gate 		    "failed (0x%x)", CRYPTO_PROVIDER_NAME, ret);
2440Sstevel@tonic-gate 		return (EACCES);
2450Sstevel@tonic-gate 	}
2460Sstevel@tonic-gate 
2470Sstevel@tonic-gate 	if ((ret = mod_install(&modlinkage)) != 0) {
2480Sstevel@tonic-gate 		int rv;
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate 		ASSERT(aes_prov_handle != NULL);
2510Sstevel@tonic-gate 		/* We should not return if the unregister returns busy. */
2520Sstevel@tonic-gate 		while ((rv = crypto_unregister_provider(aes_prov_handle))
2530Sstevel@tonic-gate 		    == CRYPTO_BUSY) {
2540Sstevel@tonic-gate 			cmn_err(CE_WARN,
2550Sstevel@tonic-gate 			    "%s _init: crypto_unregister_provider() "
2560Sstevel@tonic-gate 			    "failed (0x%x). Retrying.",
2570Sstevel@tonic-gate 			    CRYPTO_PROVIDER_NAME, rv);
2580Sstevel@tonic-gate 			/* wait 10 seconds and try again. */
2590Sstevel@tonic-gate 			delay(10 * drv_usectohz(1000000));
2600Sstevel@tonic-gate 		}
2610Sstevel@tonic-gate 	}
2620Sstevel@tonic-gate 
2630Sstevel@tonic-gate 	return (ret);
2640Sstevel@tonic-gate }
2650Sstevel@tonic-gate 
2660Sstevel@tonic-gate int
2670Sstevel@tonic-gate _fini(void)
2680Sstevel@tonic-gate {
2690Sstevel@tonic-gate 	int ret;
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate 	/*
2720Sstevel@tonic-gate 	 * Unregister from KCF if previous registration succeeded.
2730Sstevel@tonic-gate 	 */
2740Sstevel@tonic-gate 	if (aes_prov_handle != NULL) {
2750Sstevel@tonic-gate 		if ((ret = crypto_unregister_provider(aes_prov_handle)) !=
2760Sstevel@tonic-gate 		    CRYPTO_SUCCESS) {
2770Sstevel@tonic-gate 			cmn_err(CE_WARN,
2780Sstevel@tonic-gate 			    "%s _fini: crypto_unregister_provider() "
2790Sstevel@tonic-gate 			    "failed (0x%x)", CRYPTO_PROVIDER_NAME, ret);
2800Sstevel@tonic-gate 			return (EBUSY);
2810Sstevel@tonic-gate 		}
2820Sstevel@tonic-gate 		aes_prov_handle = NULL;
2830Sstevel@tonic-gate 	}
2840Sstevel@tonic-gate 
2850Sstevel@tonic-gate 	return (mod_remove(&modlinkage));
2860Sstevel@tonic-gate }
2870Sstevel@tonic-gate 
2880Sstevel@tonic-gate int
2890Sstevel@tonic-gate _info(struct modinfo *modinfop)
2900Sstevel@tonic-gate {
2910Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
2920Sstevel@tonic-gate }
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate 
295991Smcpowers static int
2967188Smcpowers aes_check_mech_param(crypto_mechanism_t *mechanism, aes_ctx_t **ctx, int kmflag)
297991Smcpowers {
2987188Smcpowers 	void *p = NULL;
299*9339SMark.Powers@Sun.COM 	boolean_t param_required = B_TRUE;
300*9339SMark.Powers@Sun.COM 	size_t param_len;
301*9339SMark.Powers@Sun.COM 	void *(*alloc_fun)(int);
302991Smcpowers 	int rv = CRYPTO_SUCCESS;
303991Smcpowers 
304991Smcpowers 	switch (mechanism->cm_type) {
305991Smcpowers 	case AES_ECB_MECH_INFO_TYPE:
306*9339SMark.Powers@Sun.COM 		param_required = B_FALSE;
307*9339SMark.Powers@Sun.COM 		alloc_fun = ecb_alloc_ctx;
308991Smcpowers 		break;
309991Smcpowers 	case AES_CBC_MECH_INFO_TYPE:
310*9339SMark.Powers@Sun.COM 		param_len = AES_BLOCK_LEN;
311*9339SMark.Powers@Sun.COM 		alloc_fun = cbc_alloc_ctx;
312991Smcpowers 		break;
313991Smcpowers 	case AES_CTR_MECH_INFO_TYPE:
314*9339SMark.Powers@Sun.COM 		param_len = sizeof (CK_AES_CTR_PARAMS);
315*9339SMark.Powers@Sun.COM 		alloc_fun = ctr_alloc_ctx;
316991Smcpowers 		break;
3174486Sktung 	case AES_CCM_MECH_INFO_TYPE:
318*9339SMark.Powers@Sun.COM 		param_len = sizeof (CK_AES_CCM_PARAMS);
319*9339SMark.Powers@Sun.COM 		alloc_fun = ccm_alloc_ctx;
3204486Sktung 		break;
3218005SMark.Powers@Sun.COM 	case AES_GCM_MECH_INFO_TYPE:
322*9339SMark.Powers@Sun.COM 		param_len = sizeof (CK_AES_GCM_PARAMS);
323*9339SMark.Powers@Sun.COM 		alloc_fun = gcm_alloc_ctx;
324*9339SMark.Powers@Sun.COM 		break;
325*9339SMark.Powers@Sun.COM 	case AES_GMAC_MECH_INFO_TYPE:
326*9339SMark.Powers@Sun.COM 		param_len = sizeof (CK_AES_GMAC_PARAMS);
327*9339SMark.Powers@Sun.COM 		alloc_fun = gmac_alloc_ctx;
3288005SMark.Powers@Sun.COM 		break;
329991Smcpowers 	default:
330991Smcpowers 		rv = CRYPTO_MECHANISM_INVALID;
331991Smcpowers 	}
332*9339SMark.Powers@Sun.COM 	if (param_required && mechanism->cm_param != NULL &&
333*9339SMark.Powers@Sun.COM 	    mechanism->cm_param_len != param_len) {
334*9339SMark.Powers@Sun.COM 		rv = CRYPTO_MECHANISM_PARAM_INVALID;
335*9339SMark.Powers@Sun.COM 	}
336*9339SMark.Powers@Sun.COM 	if (ctx != NULL) {
337*9339SMark.Powers@Sun.COM 		p = (alloc_fun)(kmflag);
3387188Smcpowers 		*ctx = p;
339*9339SMark.Powers@Sun.COM 	}
340991Smcpowers 	return (rv);
341991Smcpowers }
342991Smcpowers 
3431010Smcpowers /* EXPORT DELETE START */
3441010Smcpowers 
3450Sstevel@tonic-gate /*
3460Sstevel@tonic-gate  * Initialize key schedules for AES
3470Sstevel@tonic-gate  */
3480Sstevel@tonic-gate static int
3490Sstevel@tonic-gate init_keysched(crypto_key_t *key, void *newbie)
3500Sstevel@tonic-gate {
3510Sstevel@tonic-gate 	/*
3520Sstevel@tonic-gate 	 * Only keys by value are supported by this module.
3530Sstevel@tonic-gate 	 */
3540Sstevel@tonic-gate 	switch (key->ck_format) {
3550Sstevel@tonic-gate 	case CRYPTO_KEY_RAW:
3560Sstevel@tonic-gate 		if (key->ck_length < AES_MINBITS ||
3570Sstevel@tonic-gate 		    key->ck_length > AES_MAXBITS) {
3580Sstevel@tonic-gate 			return (CRYPTO_KEY_SIZE_RANGE);
3590Sstevel@tonic-gate 		}
3600Sstevel@tonic-gate 
3610Sstevel@tonic-gate 		/* key length must be either 128, 192, or 256 */
3620Sstevel@tonic-gate 		if ((key->ck_length & 63) != 0)
3630Sstevel@tonic-gate 			return (CRYPTO_KEY_SIZE_RANGE);
3640Sstevel@tonic-gate 		break;
3650Sstevel@tonic-gate 	default:
3660Sstevel@tonic-gate 		return (CRYPTO_KEY_TYPE_INCONSISTENT);
3670Sstevel@tonic-gate 	}
3680Sstevel@tonic-gate 
3690Sstevel@tonic-gate 	aes_init_keysched(key->ck_data, key->ck_length, newbie);
3700Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
3710Sstevel@tonic-gate }
3720Sstevel@tonic-gate 
3730Sstevel@tonic-gate /* EXPORT DELETE END */
3740Sstevel@tonic-gate 
3750Sstevel@tonic-gate /*
3760Sstevel@tonic-gate  * KCF software provider control entry points.
3770Sstevel@tonic-gate  */
3780Sstevel@tonic-gate /* ARGSUSED */
3790Sstevel@tonic-gate static void
3800Sstevel@tonic-gate aes_provider_status(crypto_provider_handle_t provider, uint_t *status)
3810Sstevel@tonic-gate {
3820Sstevel@tonic-gate 	*status = CRYPTO_PROVIDER_READY;
3830Sstevel@tonic-gate }
3840Sstevel@tonic-gate 
3854486Sktung static int
3864486Sktung aes_encrypt_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
3874486Sktung     crypto_key_t *key, crypto_spi_ctx_template_t template,
3884486Sktung     crypto_req_handle_t req) {
3894486Sktung 	return (aes_common_init(ctx, mechanism, key, template, req, B_TRUE));
3904486Sktung }
3914486Sktung 
3924486Sktung static int
3934486Sktung aes_decrypt_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
3944486Sktung     crypto_key_t *key, crypto_spi_ctx_template_t template,
3954486Sktung     crypto_req_handle_t req) {
3964486Sktung 	return (aes_common_init(ctx, mechanism, key, template, req, B_FALSE));
3974486Sktung }
3984486Sktung 
3994486Sktung 
4004486Sktung 
4010Sstevel@tonic-gate /*
4020Sstevel@tonic-gate  * KCF software provider encrypt entry points.
4030Sstevel@tonic-gate  */
4040Sstevel@tonic-gate static int
4050Sstevel@tonic-gate aes_common_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
4060Sstevel@tonic-gate     crypto_key_t *key, crypto_spi_ctx_template_t template,
4074486Sktung     crypto_req_handle_t req, boolean_t is_encrypt_init)
4080Sstevel@tonic-gate {
4090Sstevel@tonic-gate 
4100Sstevel@tonic-gate /* EXPORT DELETE START */
4110Sstevel@tonic-gate 
4120Sstevel@tonic-gate 	aes_ctx_t *aes_ctx;
4130Sstevel@tonic-gate 	int rv;
4140Sstevel@tonic-gate 	int kmflag;
4150Sstevel@tonic-gate 
4160Sstevel@tonic-gate 	/*
4170Sstevel@tonic-gate 	 * Only keys by value are supported by this module.
4180Sstevel@tonic-gate 	 */
4190Sstevel@tonic-gate 	if (key->ck_format != CRYPTO_KEY_RAW) {
4200Sstevel@tonic-gate 		return (CRYPTO_KEY_TYPE_INCONSISTENT);
4210Sstevel@tonic-gate 	}
4220Sstevel@tonic-gate 
4237188Smcpowers 	kmflag = crypto_kmflag(req);
4247188Smcpowers 	if ((rv = aes_check_mech_param(mechanism, &aes_ctx, kmflag))
4257188Smcpowers 	    != CRYPTO_SUCCESS)
426991Smcpowers 		return (rv);
4270Sstevel@tonic-gate 
4284486Sktung 	rv = aes_common_init_ctx(aes_ctx, template, mechanism, key, kmflag,
4294486Sktung 	    is_encrypt_init);
4300Sstevel@tonic-gate 	if (rv != CRYPTO_SUCCESS) {
4317188Smcpowers 		crypto_free_mode_ctx(aes_ctx);
4320Sstevel@tonic-gate 		return (rv);
4330Sstevel@tonic-gate 	}
4340Sstevel@tonic-gate 
4350Sstevel@tonic-gate 	ctx->cc_provider_private = aes_ctx;
4360Sstevel@tonic-gate 
4370Sstevel@tonic-gate /* EXPORT DELETE END */
4380Sstevel@tonic-gate 
4390Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
4400Sstevel@tonic-gate }
4410Sstevel@tonic-gate 
4427188Smcpowers static void
4437188Smcpowers aes_copy_block64(uint8_t *in, uint64_t *out)
4440Sstevel@tonic-gate {
4457188Smcpowers 	if (IS_P2ALIGNED(in, sizeof (uint64_t))) {
4467188Smcpowers 		/* LINTED: pointer alignment */
4477188Smcpowers 		out[0] = *(uint64_t *)&in[0];
4487188Smcpowers 		/* LINTED: pointer alignment */
4497188Smcpowers 		out[1] = *(uint64_t *)&in[8];
4507188Smcpowers 	} else {
4517188Smcpowers 		uint8_t *iv8 = (uint8_t *)&out[0];
4520Sstevel@tonic-gate 
4537188Smcpowers 		AES_COPY_BLOCK(in, iv8);
4540Sstevel@tonic-gate 	}
4550Sstevel@tonic-gate }
4560Sstevel@tonic-gate 
4570Sstevel@tonic-gate /* ARGSUSED */
4580Sstevel@tonic-gate static int
4590Sstevel@tonic-gate aes_encrypt(crypto_ctx_t *ctx, crypto_data_t *plaintext,
4600Sstevel@tonic-gate     crypto_data_t *ciphertext, crypto_req_handle_t req)
4610Sstevel@tonic-gate {
4620Sstevel@tonic-gate 	int ret = CRYPTO_FAILED;
4630Sstevel@tonic-gate 
4640Sstevel@tonic-gate /* EXPORT DELETE START */
4650Sstevel@tonic-gate 
4660Sstevel@tonic-gate 	aes_ctx_t *aes_ctx;
4674486Sktung 	size_t saved_length, saved_offset, length_needed;
4680Sstevel@tonic-gate 
4690Sstevel@tonic-gate 	ASSERT(ctx->cc_provider_private != NULL);
4700Sstevel@tonic-gate 	aes_ctx = ctx->cc_provider_private;
4710Sstevel@tonic-gate 
472904Smcpowers 	/*
473904Smcpowers 	 * For block ciphers, plaintext must be a multiple of AES block size.
474904Smcpowers 	 * This test is only valid for ciphers whose blocksize is a power of 2.
475904Smcpowers 	 */
476*9339SMark.Powers@Sun.COM 	if (((aes_ctx->ac_flags & (CTR_MODE|CCM_MODE|GCM_MODE|GMAC_MODE))
477*9339SMark.Powers@Sun.COM 	    == 0) && (plaintext->cd_length & (AES_BLOCK_LEN - 1)) != 0)
478904Smcpowers 		return (CRYPTO_DATA_LEN_RANGE);
479904Smcpowers 
4800Sstevel@tonic-gate 	AES_ARG_INPLACE(plaintext, ciphertext);
4810Sstevel@tonic-gate 
4820Sstevel@tonic-gate 	/*
4830Sstevel@tonic-gate 	 * We need to just return the length needed to store the output.
4840Sstevel@tonic-gate 	 * We should not destroy the context for the following case.
4850Sstevel@tonic-gate 	 */
486*9339SMark.Powers@Sun.COM 	switch (aes_ctx->ac_flags & (CCM_MODE|GCM_MODE|GMAC_MODE)) {
487*9339SMark.Powers@Sun.COM 	case CCM_MODE:
4887188Smcpowers 		length_needed = plaintext->cd_length + aes_ctx->ac_mac_len;
489*9339SMark.Powers@Sun.COM 		break;
490*9339SMark.Powers@Sun.COM 	case GCM_MODE:
4918195SMark.Powers@Sun.COM 		length_needed = plaintext->cd_length + aes_ctx->ac_tag_len;
492*9339SMark.Powers@Sun.COM 		break;
493*9339SMark.Powers@Sun.COM 	case GMAC_MODE:
494*9339SMark.Powers@Sun.COM 		if (plaintext->cd_length != 0)
495*9339SMark.Powers@Sun.COM 			return (CRYPTO_ARGUMENTS_BAD);
496*9339SMark.Powers@Sun.COM 
497*9339SMark.Powers@Sun.COM 		length_needed = aes_ctx->ac_tag_len;
498*9339SMark.Powers@Sun.COM 		break;
499*9339SMark.Powers@Sun.COM 	default:
5004486Sktung 		length_needed = plaintext->cd_length;
5014486Sktung 	}
5024486Sktung 
5034486Sktung 	if (ciphertext->cd_length < length_needed) {
5044486Sktung 		ciphertext->cd_length = length_needed;
5050Sstevel@tonic-gate 		return (CRYPTO_BUFFER_TOO_SMALL);
5060Sstevel@tonic-gate 	}
5070Sstevel@tonic-gate 
5084486Sktung 	saved_length = ciphertext->cd_length;
5094486Sktung 	saved_offset = ciphertext->cd_offset;
5104486Sktung 
5110Sstevel@tonic-gate 	/*
5120Sstevel@tonic-gate 	 * Do an update on the specified input data.
5130Sstevel@tonic-gate 	 */
5140Sstevel@tonic-gate 	ret = aes_encrypt_update(ctx, plaintext, ciphertext, req);
5154486Sktung 	if (ret != CRYPTO_SUCCESS) {
5164486Sktung 		return (ret);
5174486Sktung 	}
5184486Sktung 
5194486Sktung 	/*
5204486Sktung 	 * For CCM mode, aes_ccm_encrypt_final() will take care of any
5214486Sktung 	 * left-over unprocessed data, and compute the MAC
5224486Sktung 	 */
5237188Smcpowers 	if (aes_ctx->ac_flags & CCM_MODE) {
5244486Sktung 		/*
5258005SMark.Powers@Sun.COM 		 * ccm_encrypt_final() will compute the MAC and append
5264486Sktung 		 * it to existing ciphertext. So, need to adjust the left over
5274486Sktung 		 * length value accordingly
5284486Sktung 		 */
5294486Sktung 
5304486Sktung 		/* order of following 2 lines MUST not be reversed */
5314486Sktung 		ciphertext->cd_offset = ciphertext->cd_length;
5324486Sktung 		ciphertext->cd_length = saved_length - ciphertext->cd_length;
5337188Smcpowers 		ret = ccm_encrypt_final((ccm_ctx_t *)aes_ctx, ciphertext,
5347188Smcpowers 		    AES_BLOCK_LEN, aes_encrypt_block, aes_xor_block);
5354486Sktung 		if (ret != CRYPTO_SUCCESS) {
5364486Sktung 			return (ret);
5374486Sktung 		}
5384486Sktung 
5394486Sktung 		if (plaintext != ciphertext) {
5404486Sktung 			ciphertext->cd_length =
5414486Sktung 			    ciphertext->cd_offset - saved_offset;
5424486Sktung 		}
5434486Sktung 		ciphertext->cd_offset = saved_offset;
544*9339SMark.Powers@Sun.COM 	} else if (aes_ctx->ac_flags & (GCM_MODE|GMAC_MODE)) {
5458005SMark.Powers@Sun.COM 		/*
5468005SMark.Powers@Sun.COM 		 * gcm_encrypt_final() will compute the MAC and append
5478005SMark.Powers@Sun.COM 		 * it to existing ciphertext. So, need to adjust the left over
5488005SMark.Powers@Sun.COM 		 * length value accordingly
5498005SMark.Powers@Sun.COM 		 */
5508005SMark.Powers@Sun.COM 
5518005SMark.Powers@Sun.COM 		/* order of following 2 lines MUST not be reversed */
5528005SMark.Powers@Sun.COM 		ciphertext->cd_offset = ciphertext->cd_length;
5538005SMark.Powers@Sun.COM 		ciphertext->cd_length = saved_length - ciphertext->cd_length;
5548005SMark.Powers@Sun.COM 		ret = gcm_encrypt_final((gcm_ctx_t *)aes_ctx, ciphertext,
5558005SMark.Powers@Sun.COM 		    AES_BLOCK_LEN, aes_encrypt_block, aes_copy_block,
5568005SMark.Powers@Sun.COM 		    aes_xor_block);
5578005SMark.Powers@Sun.COM 		if (ret != CRYPTO_SUCCESS) {
5588005SMark.Powers@Sun.COM 			return (ret);
5598005SMark.Powers@Sun.COM 		}
5608005SMark.Powers@Sun.COM 
5618005SMark.Powers@Sun.COM 		if (plaintext != ciphertext) {
5628005SMark.Powers@Sun.COM 			ciphertext->cd_length =
5638005SMark.Powers@Sun.COM 			    ciphertext->cd_offset - saved_offset;
5648005SMark.Powers@Sun.COM 		}
5658005SMark.Powers@Sun.COM 		ciphertext->cd_offset = saved_offset;
5664486Sktung 	}
5674486Sktung 
5680Sstevel@tonic-gate 	ASSERT(aes_ctx->ac_remainder_len == 0);
5690Sstevel@tonic-gate 	(void) aes_free_context(ctx);
5700Sstevel@tonic-gate 
5710Sstevel@tonic-gate /* EXPORT DELETE END */
5720Sstevel@tonic-gate 
5730Sstevel@tonic-gate 	/* LINTED */
5740Sstevel@tonic-gate 	return (ret);
5750Sstevel@tonic-gate }
5760Sstevel@tonic-gate 
5770Sstevel@tonic-gate /* ARGSUSED */
5780Sstevel@tonic-gate static int
5790Sstevel@tonic-gate aes_decrypt(crypto_ctx_t *ctx, crypto_data_t *ciphertext,
5800Sstevel@tonic-gate     crypto_data_t *plaintext, crypto_req_handle_t req)
5810Sstevel@tonic-gate {
5820Sstevel@tonic-gate 	int ret = CRYPTO_FAILED;
5830Sstevel@tonic-gate 
5840Sstevel@tonic-gate /* EXPORT DELETE START */
5850Sstevel@tonic-gate 
5860Sstevel@tonic-gate 	aes_ctx_t *aes_ctx;
5874486Sktung 	off_t saved_offset;
588*9339SMark.Powers@Sun.COM 	size_t saved_length, length_needed;
5890Sstevel@tonic-gate 
5900Sstevel@tonic-gate 	ASSERT(ctx->cc_provider_private != NULL);
5910Sstevel@tonic-gate 	aes_ctx = ctx->cc_provider_private;
5920Sstevel@tonic-gate 
593904Smcpowers 	/*
5944486Sktung 	 * For block ciphers, plaintext must be a multiple of AES block size.
595904Smcpowers 	 * This test is only valid for ciphers whose blocksize is a power of 2.
596904Smcpowers 	 */
597*9339SMark.Powers@Sun.COM 	if (((aes_ctx->ac_flags & (CTR_MODE|CCM_MODE|GCM_MODE|GMAC_MODE))
598*9339SMark.Powers@Sun.COM 	    == 0) && (ciphertext->cd_length & (AES_BLOCK_LEN - 1)) != 0) {
5994558Sktung 		return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE);
6004558Sktung 	}
601904Smcpowers 
6020Sstevel@tonic-gate 	AES_ARG_INPLACE(ciphertext, plaintext);
6030Sstevel@tonic-gate 
6040Sstevel@tonic-gate 	/*
605*9339SMark.Powers@Sun.COM 	 * Return length needed to store the output.
606*9339SMark.Powers@Sun.COM 	 * Do not destroy context when plaintext buffer is too small.
6074486Sktung 	 *
608*9339SMark.Powers@Sun.COM 	 * CCM:  plaintext is MAC len smaller than cipher text
609*9339SMark.Powers@Sun.COM 	 * GCM:  plaintext is TAG len smaller than cipher text
610*9339SMark.Powers@Sun.COM 	 * GMAC: plaintext length must be zero
6110Sstevel@tonic-gate 	 */
612*9339SMark.Powers@Sun.COM 	switch (aes_ctx->ac_flags & (CCM_MODE|GCM_MODE|GMAC_MODE)) {
613*9339SMark.Powers@Sun.COM 	case CCM_MODE:
614*9339SMark.Powers@Sun.COM 		length_needed = aes_ctx->ac_processed_data_len;
615*9339SMark.Powers@Sun.COM 		break;
616*9339SMark.Powers@Sun.COM 	case GCM_MODE:
617*9339SMark.Powers@Sun.COM 		length_needed = ciphertext->cd_length - aes_ctx->ac_tag_len;
618*9339SMark.Powers@Sun.COM 		break;
619*9339SMark.Powers@Sun.COM 	case GMAC_MODE:
620*9339SMark.Powers@Sun.COM 		if (plaintext->cd_length != 0)
621*9339SMark.Powers@Sun.COM 			return (CRYPTO_ARGUMENTS_BAD);
6228005SMark.Powers@Sun.COM 
623*9339SMark.Powers@Sun.COM 		length_needed = 0;
624*9339SMark.Powers@Sun.COM 		break;
625*9339SMark.Powers@Sun.COM 	default:
626*9339SMark.Powers@Sun.COM 		length_needed = ciphertext->cd_length;
627*9339SMark.Powers@Sun.COM 	}
628*9339SMark.Powers@Sun.COM 
629*9339SMark.Powers@Sun.COM 	if (plaintext->cd_length < length_needed) {
630*9339SMark.Powers@Sun.COM 		plaintext->cd_length = length_needed;
6310Sstevel@tonic-gate 		return (CRYPTO_BUFFER_TOO_SMALL);
6320Sstevel@tonic-gate 	}
6330Sstevel@tonic-gate 
634*9339SMark.Powers@Sun.COM 	saved_offset = plaintext->cd_offset;
635*9339SMark.Powers@Sun.COM 	saved_length = plaintext->cd_length;
636*9339SMark.Powers@Sun.COM 
6370Sstevel@tonic-gate 	/*
6380Sstevel@tonic-gate 	 * Do an update on the specified input data.
6390Sstevel@tonic-gate 	 */
6400Sstevel@tonic-gate 	ret = aes_decrypt_update(ctx, ciphertext, plaintext, req);
6414486Sktung 	if (ret != CRYPTO_SUCCESS) {
6424486Sktung 		goto cleanup;
6434486Sktung 	}
6444486Sktung 
6457188Smcpowers 	if (aes_ctx->ac_flags & CCM_MODE) {
6467188Smcpowers 		ASSERT(aes_ctx->ac_processed_data_len == aes_ctx->ac_data_len);
6477188Smcpowers 		ASSERT(aes_ctx->ac_processed_mac_len == aes_ctx->ac_mac_len);
6484486Sktung 
6494486Sktung 		/* order of following 2 lines MUST not be reversed */
6504486Sktung 		plaintext->cd_offset = plaintext->cd_length;
6514486Sktung 		plaintext->cd_length = saved_length - plaintext->cd_length;
6524486Sktung 
6537188Smcpowers 		ret = ccm_decrypt_final((ccm_ctx_t *)aes_ctx, plaintext,
6547188Smcpowers 		    AES_BLOCK_LEN, aes_encrypt_block, aes_copy_block,
6557188Smcpowers 		    aes_xor_block);
6564486Sktung 		if (ret == CRYPTO_SUCCESS) {
6574486Sktung 			if (plaintext != ciphertext) {
6584486Sktung 				plaintext->cd_length =
6594486Sktung 				    plaintext->cd_offset - saved_offset;
6604486Sktung 			}
6614486Sktung 		} else {
6624486Sktung 			plaintext->cd_length = saved_length;
6634486Sktung 		}
6644486Sktung 
6654486Sktung 		plaintext->cd_offset = saved_offset;
666*9339SMark.Powers@Sun.COM 	} else if (aes_ctx->ac_flags & (GCM_MODE|GMAC_MODE)) {
6678005SMark.Powers@Sun.COM 		/* order of following 2 lines MUST not be reversed */
6688005SMark.Powers@Sun.COM 		plaintext->cd_offset = plaintext->cd_length;
6698005SMark.Powers@Sun.COM 		plaintext->cd_length = saved_length - plaintext->cd_length;
6708005SMark.Powers@Sun.COM 
6718005SMark.Powers@Sun.COM 		ret = gcm_decrypt_final((gcm_ctx_t *)aes_ctx, plaintext,
6728005SMark.Powers@Sun.COM 		    AES_BLOCK_LEN, aes_encrypt_block, aes_xor_block);
6738005SMark.Powers@Sun.COM 		if (ret == CRYPTO_SUCCESS) {
6748005SMark.Powers@Sun.COM 			if (plaintext != ciphertext) {
6758005SMark.Powers@Sun.COM 				plaintext->cd_length =
6768005SMark.Powers@Sun.COM 				    plaintext->cd_offset - saved_offset;
6778005SMark.Powers@Sun.COM 			}
6788005SMark.Powers@Sun.COM 		} else {
6798005SMark.Powers@Sun.COM 			plaintext->cd_length = saved_length;
6808005SMark.Powers@Sun.COM 		}
6818005SMark.Powers@Sun.COM 
6828005SMark.Powers@Sun.COM 		plaintext->cd_offset = saved_offset;
6834486Sktung 	}
6844486Sktung 
6850Sstevel@tonic-gate 	ASSERT(aes_ctx->ac_remainder_len == 0);
6864486Sktung 
6874486Sktung cleanup:
6880Sstevel@tonic-gate 	(void) aes_free_context(ctx);
6890Sstevel@tonic-gate 
6900Sstevel@tonic-gate /* EXPORT DELETE END */
6910Sstevel@tonic-gate 
6920Sstevel@tonic-gate 	/* LINTED */
6930Sstevel@tonic-gate 	return (ret);
6940Sstevel@tonic-gate }
6950Sstevel@tonic-gate 
6960Sstevel@tonic-gate /* ARGSUSED */
6970Sstevel@tonic-gate static int
6980Sstevel@tonic-gate aes_encrypt_update(crypto_ctx_t *ctx, crypto_data_t *plaintext,
6990Sstevel@tonic-gate     crypto_data_t *ciphertext, crypto_req_handle_t req)
7000Sstevel@tonic-gate {
7010Sstevel@tonic-gate 	off_t saved_offset;
7020Sstevel@tonic-gate 	size_t saved_length, out_len;
7030Sstevel@tonic-gate 	int ret = CRYPTO_SUCCESS;
704904Smcpowers 	aes_ctx_t *aes_ctx;
7050Sstevel@tonic-gate 
7060Sstevel@tonic-gate 	ASSERT(ctx->cc_provider_private != NULL);
7077188Smcpowers 	aes_ctx = ctx->cc_provider_private;
7080Sstevel@tonic-gate 
7090Sstevel@tonic-gate 	AES_ARG_INPLACE(plaintext, ciphertext);
7100Sstevel@tonic-gate 
7110Sstevel@tonic-gate 	/* compute number of bytes that will hold the ciphertext */
7127188Smcpowers 	out_len = aes_ctx->ac_remainder_len;
7130Sstevel@tonic-gate 	out_len += plaintext->cd_length;
7140Sstevel@tonic-gate 	out_len &= ~(AES_BLOCK_LEN - 1);
7150Sstevel@tonic-gate 
7160Sstevel@tonic-gate 	/* return length needed to store the output */
7170Sstevel@tonic-gate 	if (ciphertext->cd_length < out_len) {
7180Sstevel@tonic-gate 		ciphertext->cd_length = out_len;
7190Sstevel@tonic-gate 		return (CRYPTO_BUFFER_TOO_SMALL);
7200Sstevel@tonic-gate 	}
7210Sstevel@tonic-gate 
7220Sstevel@tonic-gate 	saved_offset = ciphertext->cd_offset;
7230Sstevel@tonic-gate 	saved_length = ciphertext->cd_length;
7240Sstevel@tonic-gate 
7250Sstevel@tonic-gate 	/*
7260Sstevel@tonic-gate 	 * Do the AES update on the specified input data.
7270Sstevel@tonic-gate 	 */
7280Sstevel@tonic-gate 	switch (plaintext->cd_format) {
7290Sstevel@tonic-gate 	case CRYPTO_DATA_RAW:
7307188Smcpowers 		ret = crypto_update_iov(ctx->cc_provider_private,
7317188Smcpowers 		    plaintext, ciphertext, aes_encrypt_contiguous_blocks,
7327188Smcpowers 		    aes_copy_block64);
7330Sstevel@tonic-gate 		break;
7340Sstevel@tonic-gate 	case CRYPTO_DATA_UIO:
7357188Smcpowers 		ret = crypto_update_uio(ctx->cc_provider_private,
7367188Smcpowers 		    plaintext, ciphertext, aes_encrypt_contiguous_blocks,
7377188Smcpowers 		    aes_copy_block64);
7380Sstevel@tonic-gate 		break;
7390Sstevel@tonic-gate 	case CRYPTO_DATA_MBLK:
7407188Smcpowers 		ret = crypto_update_mp(ctx->cc_provider_private,
7417188Smcpowers 		    plaintext, ciphertext, aes_encrypt_contiguous_blocks,
7427188Smcpowers 		    aes_copy_block64);
7430Sstevel@tonic-gate 		break;
7440Sstevel@tonic-gate 	default:
7450Sstevel@tonic-gate 		ret = CRYPTO_ARGUMENTS_BAD;
7460Sstevel@tonic-gate 	}
7470Sstevel@tonic-gate 
748904Smcpowers 	/*
749904Smcpowers 	 * Since AES counter mode is a stream cipher, we call
7507188Smcpowers 	 * ctr_mode_final() to pick up any remaining bytes.
751904Smcpowers 	 * It is an internal function that does not destroy
752904Smcpowers 	 * the context like *normal* final routines.
753904Smcpowers 	 */
7547188Smcpowers 	if ((aes_ctx->ac_flags & CTR_MODE) && (aes_ctx->ac_remainder_len > 0)) {
7557188Smcpowers 		ret = ctr_mode_final((ctr_ctx_t *)aes_ctx,
7567188Smcpowers 		    ciphertext, aes_encrypt_block);
757904Smcpowers 	}
758904Smcpowers 
7590Sstevel@tonic-gate 	if (ret == CRYPTO_SUCCESS) {
7600Sstevel@tonic-gate 		if (plaintext != ciphertext)
7610Sstevel@tonic-gate 			ciphertext->cd_length =
7620Sstevel@tonic-gate 			    ciphertext->cd_offset - saved_offset;
7630Sstevel@tonic-gate 	} else {
7640Sstevel@tonic-gate 		ciphertext->cd_length = saved_length;
7650Sstevel@tonic-gate 	}
7660Sstevel@tonic-gate 	ciphertext->cd_offset = saved_offset;
7670Sstevel@tonic-gate 
7680Sstevel@tonic-gate 	return (ret);
7690Sstevel@tonic-gate }
7700Sstevel@tonic-gate 
7710Sstevel@tonic-gate /* ARGSUSED */
7720Sstevel@tonic-gate static int
7730Sstevel@tonic-gate aes_decrypt_update(crypto_ctx_t *ctx, crypto_data_t *ciphertext,
7740Sstevel@tonic-gate     crypto_data_t *plaintext, crypto_req_handle_t req)
7750Sstevel@tonic-gate {
7760Sstevel@tonic-gate 	off_t saved_offset;
7770Sstevel@tonic-gate 	size_t saved_length, out_len;
7780Sstevel@tonic-gate 	int ret = CRYPTO_SUCCESS;
779904Smcpowers 	aes_ctx_t *aes_ctx;
7800Sstevel@tonic-gate 
7810Sstevel@tonic-gate 	ASSERT(ctx->cc_provider_private != NULL);
7827188Smcpowers 	aes_ctx = ctx->cc_provider_private;
7830Sstevel@tonic-gate 
7840Sstevel@tonic-gate 	AES_ARG_INPLACE(ciphertext, plaintext);
7850Sstevel@tonic-gate 
7868005SMark.Powers@Sun.COM 	/*
7878005SMark.Powers@Sun.COM 	 * Compute number of bytes that will hold the plaintext.
788*9339SMark.Powers@Sun.COM 	 * This is not necessary for CCM, GCM, and GMAC since these
789*9339SMark.Powers@Sun.COM 	 * mechanisms never return plaintext for update operations.
7908005SMark.Powers@Sun.COM 	 */
791*9339SMark.Powers@Sun.COM 	if ((aes_ctx->ac_flags & (CCM_MODE|GCM_MODE|GMAC_MODE)) == 0) {
7928005SMark.Powers@Sun.COM 		out_len = aes_ctx->ac_remainder_len;
7938005SMark.Powers@Sun.COM 		out_len += ciphertext->cd_length;
7948005SMark.Powers@Sun.COM 		out_len &= ~(AES_BLOCK_LEN - 1);
7950Sstevel@tonic-gate 
7968005SMark.Powers@Sun.COM 		/* return length needed to store the output */
7978005SMark.Powers@Sun.COM 		if (plaintext->cd_length < out_len) {
7988005SMark.Powers@Sun.COM 			plaintext->cd_length = out_len;
7998005SMark.Powers@Sun.COM 			return (CRYPTO_BUFFER_TOO_SMALL);
8008005SMark.Powers@Sun.COM 		}
8010Sstevel@tonic-gate 	}
8020Sstevel@tonic-gate 
8030Sstevel@tonic-gate 	saved_offset = plaintext->cd_offset;
8040Sstevel@tonic-gate 	saved_length = plaintext->cd_length;
8050Sstevel@tonic-gate 
806*9339SMark.Powers@Sun.COM 	if (aes_ctx->ac_flags & (GCM_MODE|GMAC_MODE))
8078005SMark.Powers@Sun.COM 		gcm_set_kmflag((gcm_ctx_t *)aes_ctx, crypto_kmflag(req));
8088005SMark.Powers@Sun.COM 
8090Sstevel@tonic-gate 	/*
8100Sstevel@tonic-gate 	 * Do the AES update on the specified input data.
8110Sstevel@tonic-gate 	 */
8120Sstevel@tonic-gate 	switch (ciphertext->cd_format) {
8130Sstevel@tonic-gate 	case CRYPTO_DATA_RAW:
8147188Smcpowers 		ret = crypto_update_iov(ctx->cc_provider_private,
8157188Smcpowers 		    ciphertext, plaintext, aes_decrypt_contiguous_blocks,
8167188Smcpowers 		    aes_copy_block64);
8170Sstevel@tonic-gate 		break;
8180Sstevel@tonic-gate 	case CRYPTO_DATA_UIO:
8197188Smcpowers 		ret = crypto_update_uio(ctx->cc_provider_private,
8207188Smcpowers 		    ciphertext, plaintext, aes_decrypt_contiguous_blocks,
8217188Smcpowers 		    aes_copy_block64);
8220Sstevel@tonic-gate 		break;
8230Sstevel@tonic-gate 	case CRYPTO_DATA_MBLK:
8247188Smcpowers 		ret = crypto_update_mp(ctx->cc_provider_private,
8257188Smcpowers 		    ciphertext, plaintext, aes_decrypt_contiguous_blocks,
8267188Smcpowers 		    aes_copy_block64);
8270Sstevel@tonic-gate 		break;
8280Sstevel@tonic-gate 	default:
8290Sstevel@tonic-gate 		ret = CRYPTO_ARGUMENTS_BAD;
8300Sstevel@tonic-gate 	}
8310Sstevel@tonic-gate 
832904Smcpowers 	/*
833904Smcpowers 	 * Since AES counter mode is a stream cipher, we call
8347188Smcpowers 	 * ctr_mode_final() to pick up any remaining bytes.
835904Smcpowers 	 * It is an internal function that does not destroy
836904Smcpowers 	 * the context like *normal* final routines.
837904Smcpowers 	 */
8387188Smcpowers 	if ((aes_ctx->ac_flags & CTR_MODE) && (aes_ctx->ac_remainder_len > 0)) {
8397188Smcpowers 		ret = ctr_mode_final((ctr_ctx_t *)aes_ctx, plaintext,
8407188Smcpowers 		    aes_encrypt_block);
8417188Smcpowers 		if (ret == CRYPTO_DATA_LEN_RANGE)
8427188Smcpowers 			ret = CRYPTO_ENCRYPTED_DATA_LEN_RANGE;
843904Smcpowers 	}
844904Smcpowers 
8450Sstevel@tonic-gate 	if (ret == CRYPTO_SUCCESS) {
8460Sstevel@tonic-gate 		if (ciphertext != plaintext)
8470Sstevel@tonic-gate 			plaintext->cd_length =
8480Sstevel@tonic-gate 			    plaintext->cd_offset - saved_offset;
8490Sstevel@tonic-gate 	} else {
8500Sstevel@tonic-gate 		plaintext->cd_length = saved_length;
8510Sstevel@tonic-gate 	}
8520Sstevel@tonic-gate 	plaintext->cd_offset = saved_offset;
8530Sstevel@tonic-gate 
854904Smcpowers 
8550Sstevel@tonic-gate 	return (ret);
8560Sstevel@tonic-gate }
8570Sstevel@tonic-gate 
8580Sstevel@tonic-gate /* ARGSUSED */
8590Sstevel@tonic-gate static int
8600Sstevel@tonic-gate aes_encrypt_final(crypto_ctx_t *ctx, crypto_data_t *data,
8610Sstevel@tonic-gate     crypto_req_handle_t req)
8620Sstevel@tonic-gate {
8630Sstevel@tonic-gate 
8640Sstevel@tonic-gate /* EXPORT DELETE START */
8650Sstevel@tonic-gate 
8660Sstevel@tonic-gate 	aes_ctx_t *aes_ctx;
867904Smcpowers 	int ret;
8680Sstevel@tonic-gate 
8690Sstevel@tonic-gate 	ASSERT(ctx->cc_provider_private != NULL);
8700Sstevel@tonic-gate 	aes_ctx = ctx->cc_provider_private;
8710Sstevel@tonic-gate 
872904Smcpowers 	if (data->cd_format != CRYPTO_DATA_RAW &&
873904Smcpowers 	    data->cd_format != CRYPTO_DATA_UIO &&
874904Smcpowers 	    data->cd_format != CRYPTO_DATA_MBLK) {
875904Smcpowers 		return (CRYPTO_ARGUMENTS_BAD);
876904Smcpowers 	}
877904Smcpowers 
8787188Smcpowers 	if (aes_ctx->ac_flags & CTR_MODE) {
8794486Sktung 		if (aes_ctx->ac_remainder_len > 0) {
8807188Smcpowers 			ret = ctr_mode_final((ctr_ctx_t *)aes_ctx, data,
8817188Smcpowers 			    aes_encrypt_block);
882904Smcpowers 			if (ret != CRYPTO_SUCCESS)
883904Smcpowers 				return (ret);
884904Smcpowers 		}
8857188Smcpowers 	} else if (aes_ctx->ac_flags & CCM_MODE) {
8867188Smcpowers 		ret = ccm_encrypt_final((ccm_ctx_t *)aes_ctx, data,
8877188Smcpowers 		    AES_BLOCK_LEN, aes_encrypt_block, aes_xor_block);
8884486Sktung 		if (ret != CRYPTO_SUCCESS) {
8894486Sktung 			return (ret);
8904486Sktung 		}
891*9339SMark.Powers@Sun.COM 	} else if (aes_ctx->ac_flags & (GCM_MODE|GMAC_MODE)) {
8928005SMark.Powers@Sun.COM 		size_t saved_offset = data->cd_offset;
8938005SMark.Powers@Sun.COM 
8948005SMark.Powers@Sun.COM 		ret = gcm_encrypt_final((gcm_ctx_t *)aes_ctx, data,
8958005SMark.Powers@Sun.COM 		    AES_BLOCK_LEN, aes_encrypt_block, aes_copy_block,
8968005SMark.Powers@Sun.COM 		    aes_xor_block);
8978005SMark.Powers@Sun.COM 		if (ret != CRYPTO_SUCCESS) {
8988005SMark.Powers@Sun.COM 			return (ret);
8998005SMark.Powers@Sun.COM 		}
9008005SMark.Powers@Sun.COM 		data->cd_length = data->cd_offset - saved_offset;
9018005SMark.Powers@Sun.COM 		data->cd_offset = saved_offset;
9024486Sktung 	} else {
9034486Sktung 		/*
9044486Sktung 		 * There must be no unprocessed plaintext.
9054486Sktung 		 * This happens if the length of the last data is
9064486Sktung 		 * not a multiple of the AES block length.
9074486Sktung 		 */
9084486Sktung 		if (aes_ctx->ac_remainder_len > 0) {
9094486Sktung 			return (CRYPTO_DATA_LEN_RANGE);
9104486Sktung 		}
9114558Sktung 		data->cd_length = 0;
912904Smcpowers 	}
913904Smcpowers 
9140Sstevel@tonic-gate 	(void) aes_free_context(ctx);
9150Sstevel@tonic-gate 
9160Sstevel@tonic-gate /* EXPORT DELETE END */
9170Sstevel@tonic-gate 
9180Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
9190Sstevel@tonic-gate }
9200Sstevel@tonic-gate 
9210Sstevel@tonic-gate /* ARGSUSED */
9220Sstevel@tonic-gate static int
9230Sstevel@tonic-gate aes_decrypt_final(crypto_ctx_t *ctx, crypto_data_t *data,
9240Sstevel@tonic-gate     crypto_req_handle_t req)
9250Sstevel@tonic-gate {
9260Sstevel@tonic-gate 
9270Sstevel@tonic-gate /* EXPORT DELETE START */
9280Sstevel@tonic-gate 
9290Sstevel@tonic-gate 	aes_ctx_t *aes_ctx;
930904Smcpowers 	int ret;
9314486Sktung 	off_t saved_offset;
9324486Sktung 	size_t saved_length;
9330Sstevel@tonic-gate 
9340Sstevel@tonic-gate 	ASSERT(ctx->cc_provider_private != NULL);
9350Sstevel@tonic-gate 	aes_ctx = ctx->cc_provider_private;
9360Sstevel@tonic-gate 
937904Smcpowers 	if (data->cd_format != CRYPTO_DATA_RAW &&
938904Smcpowers 	    data->cd_format != CRYPTO_DATA_UIO &&
939904Smcpowers 	    data->cd_format != CRYPTO_DATA_MBLK) {
940904Smcpowers 		return (CRYPTO_ARGUMENTS_BAD);
941904Smcpowers 	}
942904Smcpowers 
9430Sstevel@tonic-gate 	/*
9440Sstevel@tonic-gate 	 * There must be no unprocessed ciphertext.
9450Sstevel@tonic-gate 	 * This happens if the length of the last ciphertext is
9460Sstevel@tonic-gate 	 * not a multiple of the AES block length.
9470Sstevel@tonic-gate 	 */
948904Smcpowers 	if (aes_ctx->ac_remainder_len > 0) {
9497188Smcpowers 		if ((aes_ctx->ac_flags & CTR_MODE) == 0)
950904Smcpowers 			return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE);
951904Smcpowers 		else {
9527188Smcpowers 			ret = ctr_mode_final((ctr_ctx_t *)aes_ctx, data,
9537188Smcpowers 			    aes_encrypt_block);
9547188Smcpowers 			if (ret == CRYPTO_DATA_LEN_RANGE)
9557188Smcpowers 				ret = CRYPTO_ENCRYPTED_DATA_LEN_RANGE;
956904Smcpowers 			if (ret != CRYPTO_SUCCESS)
957904Smcpowers 				return (ret);
958904Smcpowers 		}
959904Smcpowers 	}
960904Smcpowers 
9617188Smcpowers 	if (aes_ctx->ac_flags & CCM_MODE) {
9624486Sktung 		/*
9634486Sktung 		 * This is where all the plaintext is returned, make sure
9644486Sktung 		 * the plaintext buffer is big enough
9654486Sktung 		 */
9667188Smcpowers 		size_t pt_len = aes_ctx->ac_data_len;
9674486Sktung 		if (data->cd_length < pt_len) {
9684486Sktung 			data->cd_length = pt_len;
9694486Sktung 			return (CRYPTO_BUFFER_TOO_SMALL);
9704486Sktung 		}
9714486Sktung 
9727188Smcpowers 		ASSERT(aes_ctx->ac_processed_data_len == pt_len);
9737188Smcpowers 		ASSERT(aes_ctx->ac_processed_mac_len == aes_ctx->ac_mac_len);
9744486Sktung 		saved_offset = data->cd_offset;
9754486Sktung 		saved_length = data->cd_length;
9767188Smcpowers 		ret = ccm_decrypt_final((ccm_ctx_t *)aes_ctx, data,
9777188Smcpowers 		    AES_BLOCK_LEN, aes_encrypt_block, aes_copy_block,
9787188Smcpowers 		    aes_xor_block);
9794486Sktung 		if (ret == CRYPTO_SUCCESS) {
9804486Sktung 			data->cd_length = data->cd_offset - saved_offset;
9814486Sktung 		} else {
9824486Sktung 			data->cd_length = saved_length;
9834486Sktung 		}
9844486Sktung 
9854486Sktung 		data->cd_offset = saved_offset;
9864486Sktung 		if (ret != CRYPTO_SUCCESS) {
9874486Sktung 			return (ret);
9884486Sktung 		}
989*9339SMark.Powers@Sun.COM 	} else if (aes_ctx->ac_flags & (GCM_MODE|GMAC_MODE)) {
9908005SMark.Powers@Sun.COM 		/*
9918005SMark.Powers@Sun.COM 		 * This is where all the plaintext is returned, make sure
9928005SMark.Powers@Sun.COM 		 * the plaintext buffer is big enough
9938005SMark.Powers@Sun.COM 		 */
9948005SMark.Powers@Sun.COM 		gcm_ctx_t *ctx = (gcm_ctx_t *)aes_ctx;
9958005SMark.Powers@Sun.COM 		size_t pt_len = ctx->gcm_processed_data_len - ctx->gcm_tag_len;
9968005SMark.Powers@Sun.COM 
9978005SMark.Powers@Sun.COM 		if (data->cd_length < pt_len) {
9988005SMark.Powers@Sun.COM 			data->cd_length = pt_len;
9998005SMark.Powers@Sun.COM 			return (CRYPTO_BUFFER_TOO_SMALL);
10008005SMark.Powers@Sun.COM 		}
10018005SMark.Powers@Sun.COM 
10028005SMark.Powers@Sun.COM 		saved_offset = data->cd_offset;
10038005SMark.Powers@Sun.COM 		saved_length = data->cd_length;
10048005SMark.Powers@Sun.COM 		ret = gcm_decrypt_final((gcm_ctx_t *)aes_ctx, data,
10058005SMark.Powers@Sun.COM 		    AES_BLOCK_LEN, aes_encrypt_block, aes_xor_block);
10068005SMark.Powers@Sun.COM 		if (ret == CRYPTO_SUCCESS) {
10078005SMark.Powers@Sun.COM 			data->cd_length = data->cd_offset - saved_offset;
10088005SMark.Powers@Sun.COM 		} else {
10098005SMark.Powers@Sun.COM 			data->cd_length = saved_length;
10108005SMark.Powers@Sun.COM 		}
10118005SMark.Powers@Sun.COM 
10128005SMark.Powers@Sun.COM 		data->cd_offset = saved_offset;
10138005SMark.Powers@Sun.COM 		if (ret != CRYPTO_SUCCESS) {
10148005SMark.Powers@Sun.COM 			return (ret);
10158005SMark.Powers@Sun.COM 		}
10164486Sktung 	}
10174486Sktung 
10184486Sktung 
1019*9339SMark.Powers@Sun.COM 	if ((aes_ctx->ac_flags & (CTR_MODE|CCM_MODE|GCM_MODE|GMAC_MODE)) == 0) {
1020904Smcpowers 		data->cd_length = 0;
10214558Sktung 	}
10220Sstevel@tonic-gate 
10230Sstevel@tonic-gate 	(void) aes_free_context(ctx);
10240Sstevel@tonic-gate 
10250Sstevel@tonic-gate /* EXPORT DELETE END */
10260Sstevel@tonic-gate 
10270Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
10280Sstevel@tonic-gate }
10290Sstevel@tonic-gate 
10300Sstevel@tonic-gate /* ARGSUSED */
10310Sstevel@tonic-gate static int
10320Sstevel@tonic-gate aes_encrypt_atomic(crypto_provider_handle_t provider,
10330Sstevel@tonic-gate     crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
10340Sstevel@tonic-gate     crypto_key_t *key, crypto_data_t *plaintext, crypto_data_t *ciphertext,
10350Sstevel@tonic-gate     crypto_spi_ctx_template_t template, crypto_req_handle_t req)
10360Sstevel@tonic-gate {
10370Sstevel@tonic-gate 	aes_ctx_t aes_ctx;	/* on the stack */
10380Sstevel@tonic-gate 	off_t saved_offset;
10390Sstevel@tonic-gate 	size_t saved_length;
10408195SMark.Powers@Sun.COM 	size_t length_needed;
10410Sstevel@tonic-gate 	int ret;
10420Sstevel@tonic-gate 
10430Sstevel@tonic-gate 	AES_ARG_INPLACE(plaintext, ciphertext);
10440Sstevel@tonic-gate 
10458195SMark.Powers@Sun.COM 	/*
1046*9339SMark.Powers@Sun.COM 	 * CTR, CCM, GCM, and GMAC modes do not require that plaintext
10478195SMark.Powers@Sun.COM 	 * be a multiple of AES block size.
10488195SMark.Powers@Sun.COM 	 */
10498195SMark.Powers@Sun.COM 	switch (mechanism->cm_type) {
10508195SMark.Powers@Sun.COM 	case AES_CTR_MECH_INFO_TYPE:
10518195SMark.Powers@Sun.COM 	case AES_CCM_MECH_INFO_TYPE:
10528195SMark.Powers@Sun.COM 	case AES_GCM_MECH_INFO_TYPE:
1053*9339SMark.Powers@Sun.COM 	case AES_GMAC_MECH_INFO_TYPE:
10548195SMark.Powers@Sun.COM 		break;
10558195SMark.Powers@Sun.COM 	default:
1056904Smcpowers 		if ((plaintext->cd_length & (AES_BLOCK_LEN - 1)) != 0)
1057904Smcpowers 			return (CRYPTO_DATA_LEN_RANGE);
1058904Smcpowers 	}
10590Sstevel@tonic-gate 
10607188Smcpowers 	if ((ret = aes_check_mech_param(mechanism, NULL, 0)) != CRYPTO_SUCCESS)
1061991Smcpowers 		return (ret);
10620Sstevel@tonic-gate 
10630Sstevel@tonic-gate 	bzero(&aes_ctx, sizeof (aes_ctx_t));
10640Sstevel@tonic-gate 
10650Sstevel@tonic-gate 	ret = aes_common_init_ctx(&aes_ctx, template, mechanism, key,
10664486Sktung 	    crypto_kmflag(req), B_TRUE);
10670Sstevel@tonic-gate 	if (ret != CRYPTO_SUCCESS)
10680Sstevel@tonic-gate 		return (ret);
10690Sstevel@tonic-gate 
10708195SMark.Powers@Sun.COM 	switch (mechanism->cm_type) {
10718195SMark.Powers@Sun.COM 	case AES_CCM_MECH_INFO_TYPE:
10728195SMark.Powers@Sun.COM 		length_needed = plaintext->cd_length + aes_ctx.ac_mac_len;
10738195SMark.Powers@Sun.COM 		break;
1074*9339SMark.Powers@Sun.COM 	case AES_GMAC_MECH_INFO_TYPE:
1075*9339SMark.Powers@Sun.COM 		if (plaintext->cd_length != 0)
1076*9339SMark.Powers@Sun.COM 			return (CRYPTO_ARGUMENTS_BAD);
1077*9339SMark.Powers@Sun.COM 		/* FALLTHRU */
10788195SMark.Powers@Sun.COM 	case AES_GCM_MECH_INFO_TYPE:
10798195SMark.Powers@Sun.COM 		length_needed = plaintext->cd_length + aes_ctx.ac_tag_len;
10808195SMark.Powers@Sun.COM 		break;
10818195SMark.Powers@Sun.COM 	default:
10828195SMark.Powers@Sun.COM 		length_needed = plaintext->cd_length;
10834486Sktung 	}
10844486Sktung 
10858195SMark.Powers@Sun.COM 	/* return size of buffer needed to store output */
10868195SMark.Powers@Sun.COM 	if (ciphertext->cd_length < length_needed) {
10878195SMark.Powers@Sun.COM 		ciphertext->cd_length = length_needed;
10888195SMark.Powers@Sun.COM 		ret = CRYPTO_BUFFER_TOO_SMALL;
10898195SMark.Powers@Sun.COM 		goto out;
10908195SMark.Powers@Sun.COM 	}
10914486Sktung 
10920Sstevel@tonic-gate 	saved_offset = ciphertext->cd_offset;
10930Sstevel@tonic-gate 	saved_length = ciphertext->cd_length;
10940Sstevel@tonic-gate 
10950Sstevel@tonic-gate 	/*
10960Sstevel@tonic-gate 	 * Do an update on the specified input data.
10970Sstevel@tonic-gate 	 */
10980Sstevel@tonic-gate 	switch (plaintext->cd_format) {
10990Sstevel@tonic-gate 	case CRYPTO_DATA_RAW:
11007188Smcpowers 		ret = crypto_update_iov(&aes_ctx, plaintext, ciphertext,
11017188Smcpowers 		    aes_encrypt_contiguous_blocks, aes_copy_block64);
11020Sstevel@tonic-gate 		break;
11030Sstevel@tonic-gate 	case CRYPTO_DATA_UIO:
11047188Smcpowers 		ret = crypto_update_uio(&aes_ctx, plaintext, ciphertext,
11057188Smcpowers 		    aes_encrypt_contiguous_blocks, aes_copy_block64);
11060Sstevel@tonic-gate 		break;
11070Sstevel@tonic-gate 	case CRYPTO_DATA_MBLK:
11087188Smcpowers 		ret = crypto_update_mp(&aes_ctx, plaintext, ciphertext,
11097188Smcpowers 		    aes_encrypt_contiguous_blocks, aes_copy_block64);
11100Sstevel@tonic-gate 		break;
11110Sstevel@tonic-gate 	default:
11120Sstevel@tonic-gate 		ret = CRYPTO_ARGUMENTS_BAD;
11130Sstevel@tonic-gate 	}
11140Sstevel@tonic-gate 
1115904Smcpowers 	if (ret == CRYPTO_SUCCESS) {
11164486Sktung 		if (mechanism->cm_type == AES_CCM_MECH_INFO_TYPE) {
11177188Smcpowers 			ret = ccm_encrypt_final((ccm_ctx_t *)&aes_ctx,
11187188Smcpowers 			    ciphertext, AES_BLOCK_LEN, aes_encrypt_block,
11197188Smcpowers 			    aes_xor_block);
11204486Sktung 			if (ret != CRYPTO_SUCCESS)
11214486Sktung 				goto out;
1122904Smcpowers 			ASSERT(aes_ctx.ac_remainder_len == 0);
1123*9339SMark.Powers@Sun.COM 		} else if (mechanism->cm_type == AES_GCM_MECH_INFO_TYPE ||
1124*9339SMark.Powers@Sun.COM 		    mechanism->cm_type == AES_GMAC_MECH_INFO_TYPE) {
11258005SMark.Powers@Sun.COM 			ret = gcm_encrypt_final((gcm_ctx_t *)&aes_ctx,
11268005SMark.Powers@Sun.COM 			    ciphertext, AES_BLOCK_LEN, aes_encrypt_block,
11278005SMark.Powers@Sun.COM 			    aes_copy_block, aes_xor_block);
11288005SMark.Powers@Sun.COM 			if (ret != CRYPTO_SUCCESS)
11298005SMark.Powers@Sun.COM 				goto out;
11308005SMark.Powers@Sun.COM 			ASSERT(aes_ctx.ac_remainder_len == 0);
11314486Sktung 		} else if (mechanism->cm_type == AES_CTR_MECH_INFO_TYPE) {
1132904Smcpowers 			if (aes_ctx.ac_remainder_len > 0) {
11337188Smcpowers 				ret = ctr_mode_final((ctr_ctx_t *)&aes_ctx,
11347188Smcpowers 				    ciphertext, aes_encrypt_block);
1135904Smcpowers 				if (ret != CRYPTO_SUCCESS)
1136904Smcpowers 					goto out;
1137904Smcpowers 			}
11384486Sktung 		} else {
11394486Sktung 			ASSERT(aes_ctx.ac_remainder_len == 0);
11404486Sktung 		}
11414486Sktung 
11424486Sktung 		if (plaintext != ciphertext) {
11434486Sktung 			ciphertext->cd_length =
11444486Sktung 			    ciphertext->cd_offset - saved_offset;
1145904Smcpowers 		}
1146904Smcpowers 	} else {
1147904Smcpowers 		ciphertext->cd_length = saved_length;
1148904Smcpowers 	}
1149904Smcpowers 	ciphertext->cd_offset = saved_offset;
1150904Smcpowers 
1151904Smcpowers out:
11527188Smcpowers 	if (aes_ctx.ac_flags & PROVIDER_OWNS_KEY_SCHEDULE) {
11530Sstevel@tonic-gate 		bzero(aes_ctx.ac_keysched, aes_ctx.ac_keysched_len);
11540Sstevel@tonic-gate 		kmem_free(aes_ctx.ac_keysched, aes_ctx.ac_keysched_len);
11550Sstevel@tonic-gate 	}
11560Sstevel@tonic-gate 
11570Sstevel@tonic-gate 	return (ret);
11580Sstevel@tonic-gate }
11590Sstevel@tonic-gate 
11600Sstevel@tonic-gate /* ARGSUSED */
11610Sstevel@tonic-gate static int
11620Sstevel@tonic-gate aes_decrypt_atomic(crypto_provider_handle_t provider,
11630Sstevel@tonic-gate     crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
11640Sstevel@tonic-gate     crypto_key_t *key, crypto_data_t *ciphertext, crypto_data_t *plaintext,
11650Sstevel@tonic-gate     crypto_spi_ctx_template_t template, crypto_req_handle_t req)
11660Sstevel@tonic-gate {
11670Sstevel@tonic-gate 	aes_ctx_t aes_ctx;	/* on the stack */
11680Sstevel@tonic-gate 	off_t saved_offset;
11690Sstevel@tonic-gate 	size_t saved_length;
11708195SMark.Powers@Sun.COM 	size_t length_needed;
11710Sstevel@tonic-gate 	int ret;
11720Sstevel@tonic-gate 
11730Sstevel@tonic-gate 	AES_ARG_INPLACE(ciphertext, plaintext);
11740Sstevel@tonic-gate 
11754486Sktung 	/*
1176*9339SMark.Powers@Sun.COM 	 * CCM, GCM, CTR, and GMAC modes do not require that ciphertext
11778195SMark.Powers@Sun.COM 	 * be a multiple of AES block size.
11784486Sktung 	 */
11798195SMark.Powers@Sun.COM 	switch (mechanism->cm_type) {
11808195SMark.Powers@Sun.COM 	case AES_CTR_MECH_INFO_TYPE:
11818195SMark.Powers@Sun.COM 	case AES_CCM_MECH_INFO_TYPE:
11828195SMark.Powers@Sun.COM 	case AES_GCM_MECH_INFO_TYPE:
1183*9339SMark.Powers@Sun.COM 	case AES_GMAC_MECH_INFO_TYPE:
11848195SMark.Powers@Sun.COM 		break;
11858195SMark.Powers@Sun.COM 	default:
11868195SMark.Powers@Sun.COM 		if ((ciphertext->cd_length & (AES_BLOCK_LEN - 1)) != 0)
11878195SMark.Powers@Sun.COM 			return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE);
11880Sstevel@tonic-gate 	}
11890Sstevel@tonic-gate 
11907188Smcpowers 	if ((ret = aes_check_mech_param(mechanism, NULL, 0)) != CRYPTO_SUCCESS)
1191991Smcpowers 		return (ret);
11920Sstevel@tonic-gate 
11930Sstevel@tonic-gate 	bzero(&aes_ctx, sizeof (aes_ctx_t));
11940Sstevel@tonic-gate 
11950Sstevel@tonic-gate 	ret = aes_common_init_ctx(&aes_ctx, template, mechanism, key,
11964486Sktung 	    crypto_kmflag(req), B_FALSE);
11970Sstevel@tonic-gate 	if (ret != CRYPTO_SUCCESS)
11980Sstevel@tonic-gate 		return (ret);
11990Sstevel@tonic-gate 
12008195SMark.Powers@Sun.COM 	switch (mechanism->cm_type) {
12018195SMark.Powers@Sun.COM 	case AES_CCM_MECH_INFO_TYPE:
12028195SMark.Powers@Sun.COM 		length_needed = aes_ctx.ac_data_len;
12038195SMark.Powers@Sun.COM 		break;
12048195SMark.Powers@Sun.COM 	case AES_GCM_MECH_INFO_TYPE:
12058195SMark.Powers@Sun.COM 		length_needed = ciphertext->cd_length - aes_ctx.ac_tag_len;
12068195SMark.Powers@Sun.COM 		break;
1207*9339SMark.Powers@Sun.COM 	case AES_GMAC_MECH_INFO_TYPE:
1208*9339SMark.Powers@Sun.COM 		if (plaintext->cd_length != 0)
1209*9339SMark.Powers@Sun.COM 			return (CRYPTO_ARGUMENTS_BAD);
1210*9339SMark.Powers@Sun.COM 		length_needed = 0;
1211*9339SMark.Powers@Sun.COM 		break;
12128195SMark.Powers@Sun.COM 	default:
12138195SMark.Powers@Sun.COM 		length_needed = ciphertext->cd_length;
12148195SMark.Powers@Sun.COM 	}
12158195SMark.Powers@Sun.COM 
12168195SMark.Powers@Sun.COM 	/* return size of buffer needed to store output */
12178195SMark.Powers@Sun.COM 	if (plaintext->cd_length < length_needed) {
12188195SMark.Powers@Sun.COM 		plaintext->cd_length = length_needed;
12198195SMark.Powers@Sun.COM 		ret = CRYPTO_BUFFER_TOO_SMALL;
12208195SMark.Powers@Sun.COM 		goto out;
12214486Sktung 	}
12224486Sktung 
12230Sstevel@tonic-gate 	saved_offset = plaintext->cd_offset;
12240Sstevel@tonic-gate 	saved_length = plaintext->cd_length;
12250Sstevel@tonic-gate 
1226*9339SMark.Powers@Sun.COM 	if (mechanism->cm_type == AES_GCM_MECH_INFO_TYPE ||
1227*9339SMark.Powers@Sun.COM 	    mechanism->cm_type == AES_GMAC_MECH_INFO_TYPE)
12288005SMark.Powers@Sun.COM 		gcm_set_kmflag((gcm_ctx_t *)&aes_ctx, crypto_kmflag(req));
12298005SMark.Powers@Sun.COM 
12300Sstevel@tonic-gate 	/*
12310Sstevel@tonic-gate 	 * Do an update on the specified input data.
12320Sstevel@tonic-gate 	 */
12330Sstevel@tonic-gate 	switch (ciphertext->cd_format) {
12340Sstevel@tonic-gate 	case CRYPTO_DATA_RAW:
12357188Smcpowers 		ret = crypto_update_iov(&aes_ctx, ciphertext, plaintext,
12367188Smcpowers 		    aes_decrypt_contiguous_blocks, aes_copy_block64);
12370Sstevel@tonic-gate 		break;
12380Sstevel@tonic-gate 	case CRYPTO_DATA_UIO:
12397188Smcpowers 		ret = crypto_update_uio(&aes_ctx, ciphertext, plaintext,
12407188Smcpowers 		    aes_decrypt_contiguous_blocks, aes_copy_block64);
12410Sstevel@tonic-gate 		break;
12420Sstevel@tonic-gate 	case CRYPTO_DATA_MBLK:
12437188Smcpowers 		ret = crypto_update_mp(&aes_ctx, ciphertext, plaintext,
12447188Smcpowers 		    aes_decrypt_contiguous_blocks, aes_copy_block64);
12450Sstevel@tonic-gate 		break;
12460Sstevel@tonic-gate 	default:
12470Sstevel@tonic-gate 		ret = CRYPTO_ARGUMENTS_BAD;
12480Sstevel@tonic-gate 	}
12490Sstevel@tonic-gate 
1250904Smcpowers 	if (ret == CRYPTO_SUCCESS) {
12514486Sktung 		if (mechanism->cm_type == AES_CCM_MECH_INFO_TYPE) {
12527188Smcpowers 			ASSERT(aes_ctx.ac_processed_data_len
12537188Smcpowers 			    == aes_ctx.ac_data_len);
12547188Smcpowers 			ASSERT(aes_ctx.ac_processed_mac_len
12557188Smcpowers 			    == aes_ctx.ac_mac_len);
12567188Smcpowers 			ret = ccm_decrypt_final((ccm_ctx_t *)&aes_ctx,
12577188Smcpowers 			    plaintext, AES_BLOCK_LEN, aes_encrypt_block,
12587188Smcpowers 			    aes_copy_block, aes_xor_block);
12594486Sktung 			ASSERT(aes_ctx.ac_remainder_len == 0);
12604486Sktung 			if ((ret == CRYPTO_SUCCESS) &&
12614486Sktung 			    (ciphertext != plaintext)) {
12624486Sktung 				plaintext->cd_length =
12634486Sktung 				    plaintext->cd_offset - saved_offset;
12644486Sktung 			} else {
12654486Sktung 				plaintext->cd_length = saved_length;
12664486Sktung 			}
1267*9339SMark.Powers@Sun.COM 		} else if (mechanism->cm_type == AES_GCM_MECH_INFO_TYPE ||
1268*9339SMark.Powers@Sun.COM 		    mechanism->cm_type == AES_GMAC_MECH_INFO_TYPE) {
12698005SMark.Powers@Sun.COM 			ret = gcm_decrypt_final((gcm_ctx_t *)&aes_ctx,
12708005SMark.Powers@Sun.COM 			    plaintext, AES_BLOCK_LEN, aes_encrypt_block,
12718005SMark.Powers@Sun.COM 			    aes_xor_block);
12728005SMark.Powers@Sun.COM 			ASSERT(aes_ctx.ac_remainder_len == 0);
12738005SMark.Powers@Sun.COM 			if ((ret == CRYPTO_SUCCESS) &&
12748005SMark.Powers@Sun.COM 			    (ciphertext != plaintext)) {
12758005SMark.Powers@Sun.COM 				plaintext->cd_length =
12768005SMark.Powers@Sun.COM 				    plaintext->cd_offset - saved_offset;
12778005SMark.Powers@Sun.COM 			} else {
12788005SMark.Powers@Sun.COM 				plaintext->cd_length = saved_length;
12798005SMark.Powers@Sun.COM 			}
12804486Sktung 		} else if (mechanism->cm_type != AES_CTR_MECH_INFO_TYPE) {
1281904Smcpowers 			ASSERT(aes_ctx.ac_remainder_len == 0);
1282904Smcpowers 			if (ciphertext != plaintext)
1283904Smcpowers 				plaintext->cd_length =
1284904Smcpowers 				    plaintext->cd_offset - saved_offset;
1285904Smcpowers 		} else {
1286904Smcpowers 			if (aes_ctx.ac_remainder_len > 0) {
12877188Smcpowers 				ret = ctr_mode_final((ctr_ctx_t *)&aes_ctx,
12887188Smcpowers 				    plaintext, aes_encrypt_block);
12897188Smcpowers 				if (ret == CRYPTO_DATA_LEN_RANGE)
12907188Smcpowers 					ret = CRYPTO_ENCRYPTED_DATA_LEN_RANGE;
1291904Smcpowers 				if (ret != CRYPTO_SUCCESS)
1292904Smcpowers 					goto out;
1293904Smcpowers 			}
1294904Smcpowers 			if (ciphertext != plaintext)
1295904Smcpowers 				plaintext->cd_length =
1296904Smcpowers 				    plaintext->cd_offset - saved_offset;
1297904Smcpowers 		}
1298904Smcpowers 	} else {
1299904Smcpowers 		plaintext->cd_length = saved_length;
1300904Smcpowers 	}
1301904Smcpowers 	plaintext->cd_offset = saved_offset;
1302904Smcpowers 
1303904Smcpowers out:
13047188Smcpowers 	if (aes_ctx.ac_flags & PROVIDER_OWNS_KEY_SCHEDULE) {
13050Sstevel@tonic-gate 		bzero(aes_ctx.ac_keysched, aes_ctx.ac_keysched_len);
13060Sstevel@tonic-gate 		kmem_free(aes_ctx.ac_keysched, aes_ctx.ac_keysched_len);
13070Sstevel@tonic-gate 	}
13080Sstevel@tonic-gate 
13097188Smcpowers 	if (aes_ctx.ac_flags & CCM_MODE) {
13107188Smcpowers 		if (aes_ctx.ac_pt_buf != NULL) {
13117188Smcpowers 			kmem_free(aes_ctx.ac_pt_buf, aes_ctx.ac_data_len);
13127188Smcpowers 		}
1313*9339SMark.Powers@Sun.COM 	} else if (aes_ctx.ac_flags & (GCM_MODE|GMAC_MODE)) {
13148005SMark.Powers@Sun.COM 		if (((gcm_ctx_t *)&aes_ctx)->gcm_pt_buf != NULL) {
13158005SMark.Powers@Sun.COM 			kmem_free(((gcm_ctx_t *)&aes_ctx)->gcm_pt_buf,
13168005SMark.Powers@Sun.COM 			    ((gcm_ctx_t *)&aes_ctx)->gcm_pt_buf_len);
13178005SMark.Powers@Sun.COM 		}
13184486Sktung 	}
13194486Sktung 
13200Sstevel@tonic-gate 	return (ret);
13210Sstevel@tonic-gate }
13220Sstevel@tonic-gate 
13230Sstevel@tonic-gate /*
13240Sstevel@tonic-gate  * KCF software provider context template entry points.
13250Sstevel@tonic-gate  */
13260Sstevel@tonic-gate /* ARGSUSED */
13270Sstevel@tonic-gate static int
13280Sstevel@tonic-gate aes_create_ctx_template(crypto_provider_handle_t provider,
13290Sstevel@tonic-gate     crypto_mechanism_t *mechanism, crypto_key_t *key,
13300Sstevel@tonic-gate     crypto_spi_ctx_template_t *tmpl, size_t *tmpl_size, crypto_req_handle_t req)
13310Sstevel@tonic-gate {
13320Sstevel@tonic-gate 
13330Sstevel@tonic-gate /* EXPORT DELETE START */
13340Sstevel@tonic-gate 
13350Sstevel@tonic-gate 	void *keysched;
13360Sstevel@tonic-gate 	size_t size;
13370Sstevel@tonic-gate 	int rv;
13380Sstevel@tonic-gate 
1339991Smcpowers 	if (mechanism->cm_type != AES_ECB_MECH_INFO_TYPE &&
1340991Smcpowers 	    mechanism->cm_type != AES_CBC_MECH_INFO_TYPE &&
13414486Sktung 	    mechanism->cm_type != AES_CTR_MECH_INFO_TYPE &&
1342*9339SMark.Powers@Sun.COM 	    mechanism->cm_type != AES_CCM_MECH_INFO_TYPE &&
1343*9339SMark.Powers@Sun.COM 	    mechanism->cm_type != AES_GCM_MECH_INFO_TYPE &&
1344*9339SMark.Powers@Sun.COM 	    mechanism->cm_type != AES_GMAC_MECH_INFO_TYPE)
13450Sstevel@tonic-gate 		return (CRYPTO_MECHANISM_INVALID);
13460Sstevel@tonic-gate 
13470Sstevel@tonic-gate 	if ((keysched = aes_alloc_keysched(&size,
13480Sstevel@tonic-gate 	    crypto_kmflag(req))) == NULL) {
13490Sstevel@tonic-gate 		return (CRYPTO_HOST_MEMORY);
13500Sstevel@tonic-gate 	}
13510Sstevel@tonic-gate 
13520Sstevel@tonic-gate 	/*
13530Sstevel@tonic-gate 	 * Initialize key schedule.  Key length information is stored
13540Sstevel@tonic-gate 	 * in the key.
13550Sstevel@tonic-gate 	 */
13560Sstevel@tonic-gate 	if ((rv = init_keysched(key, keysched)) != CRYPTO_SUCCESS) {
13570Sstevel@tonic-gate 		bzero(keysched, size);
13580Sstevel@tonic-gate 		kmem_free(keysched, size);
13590Sstevel@tonic-gate 		return (rv);
13600Sstevel@tonic-gate 	}
13610Sstevel@tonic-gate 
13620Sstevel@tonic-gate 	*tmpl = keysched;
13630Sstevel@tonic-gate 	*tmpl_size = size;
13640Sstevel@tonic-gate 
13650Sstevel@tonic-gate /* EXPORT DELETE END */
13660Sstevel@tonic-gate 
13670Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
13680Sstevel@tonic-gate }
13690Sstevel@tonic-gate 
13700Sstevel@tonic-gate /* ARGSUSED */
13710Sstevel@tonic-gate static int
13720Sstevel@tonic-gate aes_free_context(crypto_ctx_t *ctx)
13730Sstevel@tonic-gate {
13740Sstevel@tonic-gate 
13750Sstevel@tonic-gate /* EXPORT DELETE START */
13760Sstevel@tonic-gate 
13770Sstevel@tonic-gate 	aes_ctx_t *aes_ctx = ctx->cc_provider_private;
13780Sstevel@tonic-gate 
13790Sstevel@tonic-gate 	if (aes_ctx != NULL) {
13807188Smcpowers 		if (aes_ctx->ac_flags & PROVIDER_OWNS_KEY_SCHEDULE) {
13810Sstevel@tonic-gate 			ASSERT(aes_ctx->ac_keysched_len != 0);
13820Sstevel@tonic-gate 			bzero(aes_ctx->ac_keysched, aes_ctx->ac_keysched_len);
13830Sstevel@tonic-gate 			kmem_free(aes_ctx->ac_keysched,
13840Sstevel@tonic-gate 			    aes_ctx->ac_keysched_len);
13850Sstevel@tonic-gate 		}
13867188Smcpowers 		crypto_free_mode_ctx(aes_ctx);
13870Sstevel@tonic-gate 		ctx->cc_provider_private = NULL;
13880Sstevel@tonic-gate 	}
13890Sstevel@tonic-gate 
13900Sstevel@tonic-gate /* EXPORT DELETE END */
13910Sstevel@tonic-gate 
13920Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
13930Sstevel@tonic-gate }
13940Sstevel@tonic-gate 
13950Sstevel@tonic-gate /* ARGSUSED */
13960Sstevel@tonic-gate static int
13970Sstevel@tonic-gate aes_common_init_ctx(aes_ctx_t *aes_ctx, crypto_spi_ctx_template_t *template,
13984486Sktung     crypto_mechanism_t *mechanism, crypto_key_t *key, int kmflag,
13994486Sktung     boolean_t is_encrypt_init)
14000Sstevel@tonic-gate {
14010Sstevel@tonic-gate 	int rv = CRYPTO_SUCCESS;
14020Sstevel@tonic-gate 
14030Sstevel@tonic-gate /* EXPORT DELETE START */
14040Sstevel@tonic-gate 
14050Sstevel@tonic-gate 	void *keysched;
14060Sstevel@tonic-gate 	size_t size;
1407904Smcpowers 
1408904Smcpowers 	if (template == NULL) {
1409904Smcpowers 		if ((keysched = aes_alloc_keysched(&size, kmflag)) == NULL)
1410904Smcpowers 			return (CRYPTO_HOST_MEMORY);
1411904Smcpowers 		/*
1412904Smcpowers 		 * Initialize key schedule.
1413904Smcpowers 		 * Key length is stored in the key.
1414904Smcpowers 		 */
14154486Sktung 		if ((rv = init_keysched(key, keysched)) != CRYPTO_SUCCESS) {
1416904Smcpowers 			kmem_free(keysched, size);
14174486Sktung 			return (rv);
14184486Sktung 		}
1419904Smcpowers 
14207188Smcpowers 		aes_ctx->ac_flags |= PROVIDER_OWNS_KEY_SCHEDULE;
1421904Smcpowers 		aes_ctx->ac_keysched_len = size;
1422904Smcpowers 	} else {
1423904Smcpowers 		keysched = template;
14240Sstevel@tonic-gate 	}
14250Sstevel@tonic-gate 	aes_ctx->ac_keysched = keysched;
14260Sstevel@tonic-gate 
14277188Smcpowers 	switch (mechanism->cm_type) {
14287188Smcpowers 	case AES_CBC_MECH_INFO_TYPE:
14297188Smcpowers 		rv = cbc_init_ctx((cbc_ctx_t *)aes_ctx, mechanism->cm_param,
14307188Smcpowers 		    mechanism->cm_param_len, AES_BLOCK_LEN, aes_copy_block64);
14317188Smcpowers 		break;
14327188Smcpowers 	case AES_CTR_MECH_INFO_TYPE: {
14337188Smcpowers 		CK_AES_CTR_PARAMS *pp;
14347188Smcpowers 
14357188Smcpowers 		if (mechanism->cm_param == NULL ||
14367188Smcpowers 		    mechanism->cm_param_len != sizeof (CK_AES_CTR_PARAMS)) {
14374486Sktung 			return (CRYPTO_MECHANISM_PARAM_INVALID);
14384486Sktung 		}
14397188Smcpowers 		pp = (CK_AES_CTR_PARAMS *)mechanism->cm_param;
14407188Smcpowers 		rv = ctr_init_ctx((ctr_ctx_t *)aes_ctx, pp->ulCounterBits,
14417188Smcpowers 		    pp->cb, aes_copy_block);
14427188Smcpowers 		break;
14437188Smcpowers 	}
14447188Smcpowers 	case AES_CCM_MECH_INFO_TYPE:
14457188Smcpowers 		if (mechanism->cm_param == NULL ||
14467188Smcpowers 		    mechanism->cm_param_len != sizeof (CK_AES_CCM_PARAMS)) {
14477188Smcpowers 			return (CRYPTO_MECHANISM_PARAM_INVALID);
14487188Smcpowers 		}
14497188Smcpowers 		rv = ccm_init_ctx((ccm_ctx_t *)aes_ctx, mechanism->cm_param,
14507188Smcpowers 		    kmflag, is_encrypt_init, AES_BLOCK_LEN, aes_encrypt_block,
14517188Smcpowers 		    aes_xor_block);
14527188Smcpowers 		break;
14538005SMark.Powers@Sun.COM 	case AES_GCM_MECH_INFO_TYPE:
14548005SMark.Powers@Sun.COM 		if (mechanism->cm_param == NULL ||
14558005SMark.Powers@Sun.COM 		    mechanism->cm_param_len != sizeof (CK_AES_GCM_PARAMS)) {
14568005SMark.Powers@Sun.COM 			return (CRYPTO_MECHANISM_PARAM_INVALID);
14578005SMark.Powers@Sun.COM 		}
14588005SMark.Powers@Sun.COM 		rv = gcm_init_ctx((gcm_ctx_t *)aes_ctx, mechanism->cm_param,
14598005SMark.Powers@Sun.COM 		    AES_BLOCK_LEN, aes_encrypt_block, aes_copy_block,
14608005SMark.Powers@Sun.COM 		    aes_xor_block);
14618005SMark.Powers@Sun.COM 		break;
1462*9339SMark.Powers@Sun.COM 	case AES_GMAC_MECH_INFO_TYPE:
1463*9339SMark.Powers@Sun.COM 		if (mechanism->cm_param == NULL ||
1464*9339SMark.Powers@Sun.COM 		    mechanism->cm_param_len != sizeof (CK_AES_GMAC_PARAMS)) {
1465*9339SMark.Powers@Sun.COM 			return (CRYPTO_MECHANISM_PARAM_INVALID);
1466*9339SMark.Powers@Sun.COM 		}
1467*9339SMark.Powers@Sun.COM 		rv = gmac_init_ctx((gcm_ctx_t *)aes_ctx, mechanism->cm_param,
1468*9339SMark.Powers@Sun.COM 		    AES_BLOCK_LEN, aes_encrypt_block, aes_copy_block,
1469*9339SMark.Powers@Sun.COM 		    aes_xor_block);
1470*9339SMark.Powers@Sun.COM 		break;
14717188Smcpowers 	case AES_ECB_MECH_INFO_TYPE:
14727188Smcpowers 		aes_ctx->ac_flags |= ECB_MODE;
14737188Smcpowers 	}
14747188Smcpowers 
14757188Smcpowers 	if (rv != CRYPTO_SUCCESS) {
14767188Smcpowers 		if (aes_ctx->ac_flags & PROVIDER_OWNS_KEY_SCHEDULE) {
14777188Smcpowers 			bzero(keysched, size);
14787188Smcpowers 			kmem_free(keysched, size);
14794486Sktung 		}
14804486Sktung 	}
14814486Sktung 
14820Sstevel@tonic-gate /* EXPORT DELETE END */
14830Sstevel@tonic-gate 
14840Sstevel@tonic-gate 	return (rv);
14850Sstevel@tonic-gate }
1486*9339SMark.Powers@Sun.COM 
1487*9339SMark.Powers@Sun.COM static int
1488*9339SMark.Powers@Sun.COM process_gmac_mech(crypto_mechanism_t *mech, crypto_data_t *data,
1489*9339SMark.Powers@Sun.COM     CK_AES_GCM_PARAMS *gcm_params)
1490*9339SMark.Powers@Sun.COM {
1491*9339SMark.Powers@Sun.COM 	/* LINTED: pointer alignment */
1492*9339SMark.Powers@Sun.COM 	CK_AES_GMAC_PARAMS *params = (CK_AES_GMAC_PARAMS *)mech->cm_param;
1493*9339SMark.Powers@Sun.COM 
1494*9339SMark.Powers@Sun.COM 	if (mech->cm_type != AES_GMAC_MECH_INFO_TYPE)
1495*9339SMark.Powers@Sun.COM 		return (CRYPTO_MECHANISM_INVALID);
1496*9339SMark.Powers@Sun.COM 
1497*9339SMark.Powers@Sun.COM 	if (mech->cm_param_len != sizeof (CK_AES_GMAC_PARAMS))
1498*9339SMark.Powers@Sun.COM 		return (CRYPTO_MECHANISM_PARAM_INVALID);
1499*9339SMark.Powers@Sun.COM 
1500*9339SMark.Powers@Sun.COM 	if (params->pIv == NULL)
1501*9339SMark.Powers@Sun.COM 		return (CRYPTO_MECHANISM_PARAM_INVALID);
1502*9339SMark.Powers@Sun.COM 
1503*9339SMark.Powers@Sun.COM 	gcm_params->pIv = params->pIv;
1504*9339SMark.Powers@Sun.COM 	gcm_params->ulIvLen = AES_GMAC_IV_LEN;
1505*9339SMark.Powers@Sun.COM 	gcm_params->ulTagBits = AES_GMAC_TAG_BITS;
1506*9339SMark.Powers@Sun.COM 
1507*9339SMark.Powers@Sun.COM 	if (data == NULL)
1508*9339SMark.Powers@Sun.COM 		return (CRYPTO_SUCCESS);
1509*9339SMark.Powers@Sun.COM 
1510*9339SMark.Powers@Sun.COM 	if (data->cd_format != CRYPTO_DATA_RAW)
1511*9339SMark.Powers@Sun.COM 		return (CRYPTO_ARGUMENTS_BAD);
1512*9339SMark.Powers@Sun.COM 
1513*9339SMark.Powers@Sun.COM 	gcm_params->pAAD = (uchar_t *)data->cd_raw.iov_base;
1514*9339SMark.Powers@Sun.COM 	gcm_params->ulAADLen = data->cd_length;
1515*9339SMark.Powers@Sun.COM 	return (CRYPTO_SUCCESS);
1516*9339SMark.Powers@Sun.COM }
1517*9339SMark.Powers@Sun.COM 
1518*9339SMark.Powers@Sun.COM static int
1519*9339SMark.Powers@Sun.COM aes_mac_atomic(crypto_provider_handle_t provider,
1520*9339SMark.Powers@Sun.COM     crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
1521*9339SMark.Powers@Sun.COM     crypto_key_t *key, crypto_data_t *data, crypto_data_t *mac,
1522*9339SMark.Powers@Sun.COM     crypto_spi_ctx_template_t template, crypto_req_handle_t req)
1523*9339SMark.Powers@Sun.COM {
1524*9339SMark.Powers@Sun.COM 	CK_AES_GCM_PARAMS gcm_params;
1525*9339SMark.Powers@Sun.COM 	crypto_mechanism_t gcm_mech;
1526*9339SMark.Powers@Sun.COM 	int rv;
1527*9339SMark.Powers@Sun.COM 
1528*9339SMark.Powers@Sun.COM 	if ((rv = process_gmac_mech(mechanism, data, &gcm_params))
1529*9339SMark.Powers@Sun.COM 	    != CRYPTO_SUCCESS)
1530*9339SMark.Powers@Sun.COM 		return (rv);
1531*9339SMark.Powers@Sun.COM 
1532*9339SMark.Powers@Sun.COM 	gcm_mech.cm_type = AES_GCM_MECH_INFO_TYPE;
1533*9339SMark.Powers@Sun.COM 	gcm_mech.cm_param_len = sizeof (CK_AES_GCM_PARAMS);
1534*9339SMark.Powers@Sun.COM 	gcm_mech.cm_param = (char *)&gcm_params;
1535*9339SMark.Powers@Sun.COM 
1536*9339SMark.Powers@Sun.COM 	return (aes_encrypt_atomic(provider, session_id, &gcm_mech,
1537*9339SMark.Powers@Sun.COM 	    key, &null_crypto_data, mac, template, req));
1538*9339SMark.Powers@Sun.COM }
1539*9339SMark.Powers@Sun.COM 
1540*9339SMark.Powers@Sun.COM static int
1541*9339SMark.Powers@Sun.COM aes_mac_verify_atomic(crypto_provider_handle_t provider,
1542*9339SMark.Powers@Sun.COM     crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
1543*9339SMark.Powers@Sun.COM     crypto_key_t *key, crypto_data_t *data, crypto_data_t *mac,
1544*9339SMark.Powers@Sun.COM     crypto_spi_ctx_template_t template, crypto_req_handle_t req)
1545*9339SMark.Powers@Sun.COM {
1546*9339SMark.Powers@Sun.COM 	CK_AES_GCM_PARAMS gcm_params;
1547*9339SMark.Powers@Sun.COM 	crypto_mechanism_t gcm_mech;
1548*9339SMark.Powers@Sun.COM 	int rv;
1549*9339SMark.Powers@Sun.COM 
1550*9339SMark.Powers@Sun.COM 	if ((rv = process_gmac_mech(mechanism, data, &gcm_params))
1551*9339SMark.Powers@Sun.COM 	    != CRYPTO_SUCCESS)
1552*9339SMark.Powers@Sun.COM 		return (rv);
1553*9339SMark.Powers@Sun.COM 
1554*9339SMark.Powers@Sun.COM 	gcm_mech.cm_type = AES_GCM_MECH_INFO_TYPE;
1555*9339SMark.Powers@Sun.COM 	gcm_mech.cm_param_len = sizeof (CK_AES_GCM_PARAMS);
1556*9339SMark.Powers@Sun.COM 	gcm_mech.cm_param = (char *)&gcm_params;
1557*9339SMark.Powers@Sun.COM 
1558*9339SMark.Powers@Sun.COM 	return (aes_decrypt_atomic(provider, session_id, &gcm_mech,
1559*9339SMark.Powers@Sun.COM 	    key, mac, &null_crypto_data, template, req));
1560*9339SMark.Powers@Sun.COM }
1561