xref: /onnv-gate/usr/src/uts/common/crypto/io/aes.c (revision 9392:7b19cd0bbccc)
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 /*
229339SMark.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 */
689339SMark.Powers@Sun.COM 	AES_GCM_MECH_INFO_TYPE,		/* SUN_CKM_AES_GCM */
699339SMark.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,
1119339SMark.Powers@Sun.COM 	    AES_MIN_KEY_BYTES, AES_MAX_KEY_BYTES, CRYPTO_KEYSIZE_UNIT_IN_BYTES},
1129339SMark.Powers@Sun.COM 	/* AES_GMAC */
1139339SMark.Powers@Sun.COM 	{SUN_CKM_AES_GMAC, AES_GMAC_MECH_INFO_TYPE,
1149339SMark.Powers@Sun.COM 	    CRYPTO_FG_ENCRYPT | CRYPTO_FG_ENCRYPT_ATOMIC |
1159339SMark.Powers@Sun.COM 	    CRYPTO_FG_DECRYPT | CRYPTO_FG_DECRYPT_ATOMIC |
1169339SMark.Powers@Sun.COM 	    CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC |
1179339SMark.Powers@Sun.COM 	    CRYPTO_FG_SIGN | CRYPTO_FG_SIGN_ATOMIC |
1189339SMark.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 
1759339SMark.Powers@Sun.COM static int aes_mac_atomic(crypto_provider_handle_t, crypto_session_id_t,
1769339SMark.Powers@Sun.COM     crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, crypto_data_t *,
1779339SMark.Powers@Sun.COM     crypto_spi_ctx_template_t, crypto_req_handle_t);
1789339SMark.Powers@Sun.COM static int aes_mac_verify_atomic(crypto_provider_handle_t, crypto_session_id_t,
1799339SMark.Powers@Sun.COM     crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, crypto_data_t *,
1809339SMark.Powers@Sun.COM     crypto_spi_ctx_template_t, crypto_req_handle_t);
1819339SMark.Powers@Sun.COM 
1829339SMark.Powers@Sun.COM static crypto_mac_ops_t aes_mac_ops = {
1839339SMark.Powers@Sun.COM 	NULL,
1849339SMark.Powers@Sun.COM 	NULL,
1859339SMark.Powers@Sun.COM 	NULL,
1869339SMark.Powers@Sun.COM 	NULL,
1879339SMark.Powers@Sun.COM 	aes_mac_atomic,
1889339SMark.Powers@Sun.COM 	aes_mac_verify_atomic
1899339SMark.Powers@Sun.COM };
1909339SMark.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,
2059339SMark.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;
2309339SMark.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;
2999339SMark.Powers@Sun.COM 	boolean_t param_required = B_TRUE;
3009339SMark.Powers@Sun.COM 	size_t param_len;
3019339SMark.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:
3069339SMark.Powers@Sun.COM 		param_required = B_FALSE;
3079339SMark.Powers@Sun.COM 		alloc_fun = ecb_alloc_ctx;
308991Smcpowers 		break;
309991Smcpowers 	case AES_CBC_MECH_INFO_TYPE:
3109339SMark.Powers@Sun.COM 		param_len = AES_BLOCK_LEN;
3119339SMark.Powers@Sun.COM 		alloc_fun = cbc_alloc_ctx;
312991Smcpowers 		break;
313991Smcpowers 	case AES_CTR_MECH_INFO_TYPE:
3149339SMark.Powers@Sun.COM 		param_len = sizeof (CK_AES_CTR_PARAMS);
3159339SMark.Powers@Sun.COM 		alloc_fun = ctr_alloc_ctx;
316991Smcpowers 		break;
3174486Sktung 	case AES_CCM_MECH_INFO_TYPE:
3189339SMark.Powers@Sun.COM 		param_len = sizeof (CK_AES_CCM_PARAMS);
3199339SMark.Powers@Sun.COM 		alloc_fun = ccm_alloc_ctx;
3204486Sktung 		break;
3218005SMark.Powers@Sun.COM 	case AES_GCM_MECH_INFO_TYPE:
3229339SMark.Powers@Sun.COM 		param_len = sizeof (CK_AES_GCM_PARAMS);
3239339SMark.Powers@Sun.COM 		alloc_fun = gcm_alloc_ctx;
3249339SMark.Powers@Sun.COM 		break;
3259339SMark.Powers@Sun.COM 	case AES_GMAC_MECH_INFO_TYPE:
3269339SMark.Powers@Sun.COM 		param_len = sizeof (CK_AES_GMAC_PARAMS);
3279339SMark.Powers@Sun.COM 		alloc_fun = gmac_alloc_ctx;
3288005SMark.Powers@Sun.COM 		break;
329991Smcpowers 	default:
330991Smcpowers 		rv = CRYPTO_MECHANISM_INVALID;
331991Smcpowers 	}
3329339SMark.Powers@Sun.COM 	if (param_required && mechanism->cm_param != NULL &&
3339339SMark.Powers@Sun.COM 	    mechanism->cm_param_len != param_len) {
3349339SMark.Powers@Sun.COM 		rv = CRYPTO_MECHANISM_PARAM_INVALID;
3359339SMark.Powers@Sun.COM 	}
3369339SMark.Powers@Sun.COM 	if (ctx != NULL) {
3379339SMark.Powers@Sun.COM 		p = (alloc_fun)(kmflag);
3387188Smcpowers 		*ctx = p;
3399339SMark.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 
457*9392Sopensolaris@drydog.com 
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 	 */
4769339SMark.Powers@Sun.COM 	if (((aes_ctx->ac_flags & (CTR_MODE|CCM_MODE|GCM_MODE|GMAC_MODE))
4779339SMark.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 	 */
4869339SMark.Powers@Sun.COM 	switch (aes_ctx->ac_flags & (CCM_MODE|GCM_MODE|GMAC_MODE)) {
4879339SMark.Powers@Sun.COM 	case CCM_MODE:
4887188Smcpowers 		length_needed = plaintext->cd_length + aes_ctx->ac_mac_len;
4899339SMark.Powers@Sun.COM 		break;
4909339SMark.Powers@Sun.COM 	case GCM_MODE:
4918195SMark.Powers@Sun.COM 		length_needed = plaintext->cd_length + aes_ctx->ac_tag_len;
4929339SMark.Powers@Sun.COM 		break;
4939339SMark.Powers@Sun.COM 	case GMAC_MODE:
4949339SMark.Powers@Sun.COM 		if (plaintext->cd_length != 0)
4959339SMark.Powers@Sun.COM 			return (CRYPTO_ARGUMENTS_BAD);
4969339SMark.Powers@Sun.COM 
4979339SMark.Powers@Sun.COM 		length_needed = aes_ctx->ac_tag_len;
4989339SMark.Powers@Sun.COM 		break;
4999339SMark.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;
5449339SMark.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 	return (ret);
5740Sstevel@tonic-gate }
5750Sstevel@tonic-gate 
576*9392Sopensolaris@drydog.com 
5770Sstevel@tonic-gate static int
5780Sstevel@tonic-gate aes_decrypt(crypto_ctx_t *ctx, crypto_data_t *ciphertext,
5790Sstevel@tonic-gate     crypto_data_t *plaintext, crypto_req_handle_t req)
5800Sstevel@tonic-gate {
5810Sstevel@tonic-gate 	int ret = CRYPTO_FAILED;
5820Sstevel@tonic-gate 
5830Sstevel@tonic-gate /* EXPORT DELETE START */
5840Sstevel@tonic-gate 
5850Sstevel@tonic-gate 	aes_ctx_t *aes_ctx;
5864486Sktung 	off_t saved_offset;
5879339SMark.Powers@Sun.COM 	size_t saved_length, length_needed;
5880Sstevel@tonic-gate 
5890Sstevel@tonic-gate 	ASSERT(ctx->cc_provider_private != NULL);
5900Sstevel@tonic-gate 	aes_ctx = ctx->cc_provider_private;
5910Sstevel@tonic-gate 
592904Smcpowers 	/*
5934486Sktung 	 * For block ciphers, plaintext must be a multiple of AES block size.
594904Smcpowers 	 * This test is only valid for ciphers whose blocksize is a power of 2.
595904Smcpowers 	 */
5969339SMark.Powers@Sun.COM 	if (((aes_ctx->ac_flags & (CTR_MODE|CCM_MODE|GCM_MODE|GMAC_MODE))
5979339SMark.Powers@Sun.COM 	    == 0) && (ciphertext->cd_length & (AES_BLOCK_LEN - 1)) != 0) {
5984558Sktung 		return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE);
5994558Sktung 	}
600904Smcpowers 
6010Sstevel@tonic-gate 	AES_ARG_INPLACE(ciphertext, plaintext);
6020Sstevel@tonic-gate 
6030Sstevel@tonic-gate 	/*
6049339SMark.Powers@Sun.COM 	 * Return length needed to store the output.
6059339SMark.Powers@Sun.COM 	 * Do not destroy context when plaintext buffer is too small.
6064486Sktung 	 *
6079339SMark.Powers@Sun.COM 	 * CCM:  plaintext is MAC len smaller than cipher text
6089339SMark.Powers@Sun.COM 	 * GCM:  plaintext is TAG len smaller than cipher text
6099339SMark.Powers@Sun.COM 	 * GMAC: plaintext length must be zero
6100Sstevel@tonic-gate 	 */
6119339SMark.Powers@Sun.COM 	switch (aes_ctx->ac_flags & (CCM_MODE|GCM_MODE|GMAC_MODE)) {
6129339SMark.Powers@Sun.COM 	case CCM_MODE:
6139339SMark.Powers@Sun.COM 		length_needed = aes_ctx->ac_processed_data_len;
6149339SMark.Powers@Sun.COM 		break;
6159339SMark.Powers@Sun.COM 	case GCM_MODE:
6169339SMark.Powers@Sun.COM 		length_needed = ciphertext->cd_length - aes_ctx->ac_tag_len;
6179339SMark.Powers@Sun.COM 		break;
6189339SMark.Powers@Sun.COM 	case GMAC_MODE:
6199339SMark.Powers@Sun.COM 		if (plaintext->cd_length != 0)
6209339SMark.Powers@Sun.COM 			return (CRYPTO_ARGUMENTS_BAD);
6218005SMark.Powers@Sun.COM 
6229339SMark.Powers@Sun.COM 		length_needed = 0;
6239339SMark.Powers@Sun.COM 		break;
6249339SMark.Powers@Sun.COM 	default:
6259339SMark.Powers@Sun.COM 		length_needed = ciphertext->cd_length;
6269339SMark.Powers@Sun.COM 	}
6279339SMark.Powers@Sun.COM 
6289339SMark.Powers@Sun.COM 	if (plaintext->cd_length < length_needed) {
6299339SMark.Powers@Sun.COM 		plaintext->cd_length = length_needed;
6300Sstevel@tonic-gate 		return (CRYPTO_BUFFER_TOO_SMALL);
6310Sstevel@tonic-gate 	}
6320Sstevel@tonic-gate 
6339339SMark.Powers@Sun.COM 	saved_offset = plaintext->cd_offset;
6349339SMark.Powers@Sun.COM 	saved_length = plaintext->cd_length;
6359339SMark.Powers@Sun.COM 
6360Sstevel@tonic-gate 	/*
6370Sstevel@tonic-gate 	 * Do an update on the specified input data.
6380Sstevel@tonic-gate 	 */
6390Sstevel@tonic-gate 	ret = aes_decrypt_update(ctx, ciphertext, plaintext, req);
6404486Sktung 	if (ret != CRYPTO_SUCCESS) {
6414486Sktung 		goto cleanup;
6424486Sktung 	}
6434486Sktung 
6447188Smcpowers 	if (aes_ctx->ac_flags & CCM_MODE) {
6457188Smcpowers 		ASSERT(aes_ctx->ac_processed_data_len == aes_ctx->ac_data_len);
6467188Smcpowers 		ASSERT(aes_ctx->ac_processed_mac_len == aes_ctx->ac_mac_len);
6474486Sktung 
6484486Sktung 		/* order of following 2 lines MUST not be reversed */
6494486Sktung 		plaintext->cd_offset = plaintext->cd_length;
6504486Sktung 		plaintext->cd_length = saved_length - plaintext->cd_length;
6514486Sktung 
6527188Smcpowers 		ret = ccm_decrypt_final((ccm_ctx_t *)aes_ctx, plaintext,
6537188Smcpowers 		    AES_BLOCK_LEN, aes_encrypt_block, aes_copy_block,
6547188Smcpowers 		    aes_xor_block);
6554486Sktung 		if (ret == CRYPTO_SUCCESS) {
6564486Sktung 			if (plaintext != ciphertext) {
6574486Sktung 				plaintext->cd_length =
6584486Sktung 				    plaintext->cd_offset - saved_offset;
6594486Sktung 			}
6604486Sktung 		} else {
6614486Sktung 			plaintext->cd_length = saved_length;
6624486Sktung 		}
6634486Sktung 
6644486Sktung 		plaintext->cd_offset = saved_offset;
6659339SMark.Powers@Sun.COM 	} else if (aes_ctx->ac_flags & (GCM_MODE|GMAC_MODE)) {
6668005SMark.Powers@Sun.COM 		/* order of following 2 lines MUST not be reversed */
6678005SMark.Powers@Sun.COM 		plaintext->cd_offset = plaintext->cd_length;
6688005SMark.Powers@Sun.COM 		plaintext->cd_length = saved_length - plaintext->cd_length;
6698005SMark.Powers@Sun.COM 
6708005SMark.Powers@Sun.COM 		ret = gcm_decrypt_final((gcm_ctx_t *)aes_ctx, plaintext,
6718005SMark.Powers@Sun.COM 		    AES_BLOCK_LEN, aes_encrypt_block, aes_xor_block);
6728005SMark.Powers@Sun.COM 		if (ret == CRYPTO_SUCCESS) {
6738005SMark.Powers@Sun.COM 			if (plaintext != ciphertext) {
6748005SMark.Powers@Sun.COM 				plaintext->cd_length =
6758005SMark.Powers@Sun.COM 				    plaintext->cd_offset - saved_offset;
6768005SMark.Powers@Sun.COM 			}
6778005SMark.Powers@Sun.COM 		} else {
6788005SMark.Powers@Sun.COM 			plaintext->cd_length = saved_length;
6798005SMark.Powers@Sun.COM 		}
6808005SMark.Powers@Sun.COM 
6818005SMark.Powers@Sun.COM 		plaintext->cd_offset = saved_offset;
6824486Sktung 	}
6834486Sktung 
6840Sstevel@tonic-gate 	ASSERT(aes_ctx->ac_remainder_len == 0);
6854486Sktung 
6864486Sktung cleanup:
6870Sstevel@tonic-gate 	(void) aes_free_context(ctx);
6880Sstevel@tonic-gate 
6890Sstevel@tonic-gate /* EXPORT DELETE END */
6900Sstevel@tonic-gate 
6910Sstevel@tonic-gate 	return (ret);
6920Sstevel@tonic-gate }
6930Sstevel@tonic-gate 
694*9392Sopensolaris@drydog.com 
6950Sstevel@tonic-gate /* ARGSUSED */
6960Sstevel@tonic-gate static int
6970Sstevel@tonic-gate aes_encrypt_update(crypto_ctx_t *ctx, crypto_data_t *plaintext,
6980Sstevel@tonic-gate     crypto_data_t *ciphertext, crypto_req_handle_t req)
6990Sstevel@tonic-gate {
7000Sstevel@tonic-gate 	off_t saved_offset;
7010Sstevel@tonic-gate 	size_t saved_length, out_len;
7020Sstevel@tonic-gate 	int ret = CRYPTO_SUCCESS;
703904Smcpowers 	aes_ctx_t *aes_ctx;
7040Sstevel@tonic-gate 
7050Sstevel@tonic-gate 	ASSERT(ctx->cc_provider_private != NULL);
7067188Smcpowers 	aes_ctx = ctx->cc_provider_private;
7070Sstevel@tonic-gate 
7080Sstevel@tonic-gate 	AES_ARG_INPLACE(plaintext, ciphertext);
7090Sstevel@tonic-gate 
7100Sstevel@tonic-gate 	/* compute number of bytes that will hold the ciphertext */
7117188Smcpowers 	out_len = aes_ctx->ac_remainder_len;
7120Sstevel@tonic-gate 	out_len += plaintext->cd_length;
7130Sstevel@tonic-gate 	out_len &= ~(AES_BLOCK_LEN - 1);
7140Sstevel@tonic-gate 
7150Sstevel@tonic-gate 	/* return length needed to store the output */
7160Sstevel@tonic-gate 	if (ciphertext->cd_length < out_len) {
7170Sstevel@tonic-gate 		ciphertext->cd_length = out_len;
7180Sstevel@tonic-gate 		return (CRYPTO_BUFFER_TOO_SMALL);
7190Sstevel@tonic-gate 	}
7200Sstevel@tonic-gate 
7210Sstevel@tonic-gate 	saved_offset = ciphertext->cd_offset;
7220Sstevel@tonic-gate 	saved_length = ciphertext->cd_length;
7230Sstevel@tonic-gate 
7240Sstevel@tonic-gate 	/*
7250Sstevel@tonic-gate 	 * Do the AES update on the specified input data.
7260Sstevel@tonic-gate 	 */
7270Sstevel@tonic-gate 	switch (plaintext->cd_format) {
7280Sstevel@tonic-gate 	case CRYPTO_DATA_RAW:
7297188Smcpowers 		ret = crypto_update_iov(ctx->cc_provider_private,
7307188Smcpowers 		    plaintext, ciphertext, aes_encrypt_contiguous_blocks,
7317188Smcpowers 		    aes_copy_block64);
7320Sstevel@tonic-gate 		break;
7330Sstevel@tonic-gate 	case CRYPTO_DATA_UIO:
7347188Smcpowers 		ret = crypto_update_uio(ctx->cc_provider_private,
7357188Smcpowers 		    plaintext, ciphertext, aes_encrypt_contiguous_blocks,
7367188Smcpowers 		    aes_copy_block64);
7370Sstevel@tonic-gate 		break;
7380Sstevel@tonic-gate 	case CRYPTO_DATA_MBLK:
7397188Smcpowers 		ret = crypto_update_mp(ctx->cc_provider_private,
7407188Smcpowers 		    plaintext, ciphertext, aes_encrypt_contiguous_blocks,
7417188Smcpowers 		    aes_copy_block64);
7420Sstevel@tonic-gate 		break;
7430Sstevel@tonic-gate 	default:
7440Sstevel@tonic-gate 		ret = CRYPTO_ARGUMENTS_BAD;
7450Sstevel@tonic-gate 	}
7460Sstevel@tonic-gate 
747904Smcpowers 	/*
748904Smcpowers 	 * Since AES counter mode is a stream cipher, we call
7497188Smcpowers 	 * ctr_mode_final() to pick up any remaining bytes.
750904Smcpowers 	 * It is an internal function that does not destroy
751904Smcpowers 	 * the context like *normal* final routines.
752904Smcpowers 	 */
7537188Smcpowers 	if ((aes_ctx->ac_flags & CTR_MODE) && (aes_ctx->ac_remainder_len > 0)) {
7547188Smcpowers 		ret = ctr_mode_final((ctr_ctx_t *)aes_ctx,
7557188Smcpowers 		    ciphertext, aes_encrypt_block);
756904Smcpowers 	}
757904Smcpowers 
7580Sstevel@tonic-gate 	if (ret == CRYPTO_SUCCESS) {
7590Sstevel@tonic-gate 		if (plaintext != ciphertext)
7600Sstevel@tonic-gate 			ciphertext->cd_length =
7610Sstevel@tonic-gate 			    ciphertext->cd_offset - saved_offset;
7620Sstevel@tonic-gate 	} else {
7630Sstevel@tonic-gate 		ciphertext->cd_length = saved_length;
7640Sstevel@tonic-gate 	}
7650Sstevel@tonic-gate 	ciphertext->cd_offset = saved_offset;
7660Sstevel@tonic-gate 
7670Sstevel@tonic-gate 	return (ret);
7680Sstevel@tonic-gate }
7690Sstevel@tonic-gate 
770*9392Sopensolaris@drydog.com 
7710Sstevel@tonic-gate static int
7720Sstevel@tonic-gate aes_decrypt_update(crypto_ctx_t *ctx, crypto_data_t *ciphertext,
7730Sstevel@tonic-gate     crypto_data_t *plaintext, crypto_req_handle_t req)
7740Sstevel@tonic-gate {
7750Sstevel@tonic-gate 	off_t saved_offset;
7760Sstevel@tonic-gate 	size_t saved_length, out_len;
7770Sstevel@tonic-gate 	int ret = CRYPTO_SUCCESS;
778904Smcpowers 	aes_ctx_t *aes_ctx;
7790Sstevel@tonic-gate 
7800Sstevel@tonic-gate 	ASSERT(ctx->cc_provider_private != NULL);
7817188Smcpowers 	aes_ctx = ctx->cc_provider_private;
7820Sstevel@tonic-gate 
7830Sstevel@tonic-gate 	AES_ARG_INPLACE(ciphertext, plaintext);
7840Sstevel@tonic-gate 
7858005SMark.Powers@Sun.COM 	/*
7868005SMark.Powers@Sun.COM 	 * Compute number of bytes that will hold the plaintext.
7879339SMark.Powers@Sun.COM 	 * This is not necessary for CCM, GCM, and GMAC since these
7889339SMark.Powers@Sun.COM 	 * mechanisms never return plaintext for update operations.
7898005SMark.Powers@Sun.COM 	 */
7909339SMark.Powers@Sun.COM 	if ((aes_ctx->ac_flags & (CCM_MODE|GCM_MODE|GMAC_MODE)) == 0) {
7918005SMark.Powers@Sun.COM 		out_len = aes_ctx->ac_remainder_len;
7928005SMark.Powers@Sun.COM 		out_len += ciphertext->cd_length;
7938005SMark.Powers@Sun.COM 		out_len &= ~(AES_BLOCK_LEN - 1);
7940Sstevel@tonic-gate 
7958005SMark.Powers@Sun.COM 		/* return length needed to store the output */
7968005SMark.Powers@Sun.COM 		if (plaintext->cd_length < out_len) {
7978005SMark.Powers@Sun.COM 			plaintext->cd_length = out_len;
7988005SMark.Powers@Sun.COM 			return (CRYPTO_BUFFER_TOO_SMALL);
7998005SMark.Powers@Sun.COM 		}
8000Sstevel@tonic-gate 	}
8010Sstevel@tonic-gate 
8020Sstevel@tonic-gate 	saved_offset = plaintext->cd_offset;
8030Sstevel@tonic-gate 	saved_length = plaintext->cd_length;
8040Sstevel@tonic-gate 
8059339SMark.Powers@Sun.COM 	if (aes_ctx->ac_flags & (GCM_MODE|GMAC_MODE))
8068005SMark.Powers@Sun.COM 		gcm_set_kmflag((gcm_ctx_t *)aes_ctx, crypto_kmflag(req));
8078005SMark.Powers@Sun.COM 
8080Sstevel@tonic-gate 	/*
8090Sstevel@tonic-gate 	 * Do the AES update on the specified input data.
8100Sstevel@tonic-gate 	 */
8110Sstevel@tonic-gate 	switch (ciphertext->cd_format) {
8120Sstevel@tonic-gate 	case CRYPTO_DATA_RAW:
8137188Smcpowers 		ret = crypto_update_iov(ctx->cc_provider_private,
8147188Smcpowers 		    ciphertext, plaintext, aes_decrypt_contiguous_blocks,
8157188Smcpowers 		    aes_copy_block64);
8160Sstevel@tonic-gate 		break;
8170Sstevel@tonic-gate 	case CRYPTO_DATA_UIO:
8187188Smcpowers 		ret = crypto_update_uio(ctx->cc_provider_private,
8197188Smcpowers 		    ciphertext, plaintext, aes_decrypt_contiguous_blocks,
8207188Smcpowers 		    aes_copy_block64);
8210Sstevel@tonic-gate 		break;
8220Sstevel@tonic-gate 	case CRYPTO_DATA_MBLK:
8237188Smcpowers 		ret = crypto_update_mp(ctx->cc_provider_private,
8247188Smcpowers 		    ciphertext, plaintext, aes_decrypt_contiguous_blocks,
8257188Smcpowers 		    aes_copy_block64);
8260Sstevel@tonic-gate 		break;
8270Sstevel@tonic-gate 	default:
8280Sstevel@tonic-gate 		ret = CRYPTO_ARGUMENTS_BAD;
8290Sstevel@tonic-gate 	}
8300Sstevel@tonic-gate 
831904Smcpowers 	/*
832904Smcpowers 	 * Since AES counter mode is a stream cipher, we call
8337188Smcpowers 	 * ctr_mode_final() to pick up any remaining bytes.
834904Smcpowers 	 * It is an internal function that does not destroy
835904Smcpowers 	 * the context like *normal* final routines.
836904Smcpowers 	 */
8377188Smcpowers 	if ((aes_ctx->ac_flags & CTR_MODE) && (aes_ctx->ac_remainder_len > 0)) {
8387188Smcpowers 		ret = ctr_mode_final((ctr_ctx_t *)aes_ctx, plaintext,
8397188Smcpowers 		    aes_encrypt_block);
8407188Smcpowers 		if (ret == CRYPTO_DATA_LEN_RANGE)
8417188Smcpowers 			ret = CRYPTO_ENCRYPTED_DATA_LEN_RANGE;
842904Smcpowers 	}
843904Smcpowers 
8440Sstevel@tonic-gate 	if (ret == CRYPTO_SUCCESS) {
8450Sstevel@tonic-gate 		if (ciphertext != plaintext)
8460Sstevel@tonic-gate 			plaintext->cd_length =
8470Sstevel@tonic-gate 			    plaintext->cd_offset - saved_offset;
8480Sstevel@tonic-gate 	} else {
8490Sstevel@tonic-gate 		plaintext->cd_length = saved_length;
8500Sstevel@tonic-gate 	}
8510Sstevel@tonic-gate 	plaintext->cd_offset = saved_offset;
8520Sstevel@tonic-gate 
853904Smcpowers 
8540Sstevel@tonic-gate 	return (ret);
8550Sstevel@tonic-gate }
8560Sstevel@tonic-gate 
8570Sstevel@tonic-gate /* ARGSUSED */
8580Sstevel@tonic-gate static int
8590Sstevel@tonic-gate aes_encrypt_final(crypto_ctx_t *ctx, crypto_data_t *data,
8600Sstevel@tonic-gate     crypto_req_handle_t req)
8610Sstevel@tonic-gate {
8620Sstevel@tonic-gate 
8630Sstevel@tonic-gate /* EXPORT DELETE START */
8640Sstevel@tonic-gate 
8650Sstevel@tonic-gate 	aes_ctx_t *aes_ctx;
866904Smcpowers 	int ret;
8670Sstevel@tonic-gate 
8680Sstevel@tonic-gate 	ASSERT(ctx->cc_provider_private != NULL);
8690Sstevel@tonic-gate 	aes_ctx = ctx->cc_provider_private;
8700Sstevel@tonic-gate 
871904Smcpowers 	if (data->cd_format != CRYPTO_DATA_RAW &&
872904Smcpowers 	    data->cd_format != CRYPTO_DATA_UIO &&
873904Smcpowers 	    data->cd_format != CRYPTO_DATA_MBLK) {
874904Smcpowers 		return (CRYPTO_ARGUMENTS_BAD);
875904Smcpowers 	}
876904Smcpowers 
8777188Smcpowers 	if (aes_ctx->ac_flags & CTR_MODE) {
8784486Sktung 		if (aes_ctx->ac_remainder_len > 0) {
8797188Smcpowers 			ret = ctr_mode_final((ctr_ctx_t *)aes_ctx, data,
8807188Smcpowers 			    aes_encrypt_block);
881904Smcpowers 			if (ret != CRYPTO_SUCCESS)
882904Smcpowers 				return (ret);
883904Smcpowers 		}
8847188Smcpowers 	} else if (aes_ctx->ac_flags & CCM_MODE) {
8857188Smcpowers 		ret = ccm_encrypt_final((ccm_ctx_t *)aes_ctx, data,
8867188Smcpowers 		    AES_BLOCK_LEN, aes_encrypt_block, aes_xor_block);
8874486Sktung 		if (ret != CRYPTO_SUCCESS) {
8884486Sktung 			return (ret);
8894486Sktung 		}
8909339SMark.Powers@Sun.COM 	} else if (aes_ctx->ac_flags & (GCM_MODE|GMAC_MODE)) {
8918005SMark.Powers@Sun.COM 		size_t saved_offset = data->cd_offset;
8928005SMark.Powers@Sun.COM 
8938005SMark.Powers@Sun.COM 		ret = gcm_encrypt_final((gcm_ctx_t *)aes_ctx, data,
8948005SMark.Powers@Sun.COM 		    AES_BLOCK_LEN, aes_encrypt_block, aes_copy_block,
8958005SMark.Powers@Sun.COM 		    aes_xor_block);
8968005SMark.Powers@Sun.COM 		if (ret != CRYPTO_SUCCESS) {
8978005SMark.Powers@Sun.COM 			return (ret);
8988005SMark.Powers@Sun.COM 		}
8998005SMark.Powers@Sun.COM 		data->cd_length = data->cd_offset - saved_offset;
9008005SMark.Powers@Sun.COM 		data->cd_offset = saved_offset;
9014486Sktung 	} else {
9024486Sktung 		/*
9034486Sktung 		 * There must be no unprocessed plaintext.
9044486Sktung 		 * This happens if the length of the last data is
9054486Sktung 		 * not a multiple of the AES block length.
9064486Sktung 		 */
9074486Sktung 		if (aes_ctx->ac_remainder_len > 0) {
9084486Sktung 			return (CRYPTO_DATA_LEN_RANGE);
9094486Sktung 		}
9104558Sktung 		data->cd_length = 0;
911904Smcpowers 	}
912904Smcpowers 
9130Sstevel@tonic-gate 	(void) aes_free_context(ctx);
9140Sstevel@tonic-gate 
9150Sstevel@tonic-gate /* EXPORT DELETE END */
9160Sstevel@tonic-gate 
9170Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
9180Sstevel@tonic-gate }
9190Sstevel@tonic-gate 
9200Sstevel@tonic-gate /* ARGSUSED */
9210Sstevel@tonic-gate static int
9220Sstevel@tonic-gate aes_decrypt_final(crypto_ctx_t *ctx, crypto_data_t *data,
9230Sstevel@tonic-gate     crypto_req_handle_t req)
9240Sstevel@tonic-gate {
9250Sstevel@tonic-gate 
9260Sstevel@tonic-gate /* EXPORT DELETE START */
9270Sstevel@tonic-gate 
9280Sstevel@tonic-gate 	aes_ctx_t *aes_ctx;
929904Smcpowers 	int ret;
9304486Sktung 	off_t saved_offset;
9314486Sktung 	size_t saved_length;
9320Sstevel@tonic-gate 
9330Sstevel@tonic-gate 	ASSERT(ctx->cc_provider_private != NULL);
9340Sstevel@tonic-gate 	aes_ctx = ctx->cc_provider_private;
9350Sstevel@tonic-gate 
936904Smcpowers 	if (data->cd_format != CRYPTO_DATA_RAW &&
937904Smcpowers 	    data->cd_format != CRYPTO_DATA_UIO &&
938904Smcpowers 	    data->cd_format != CRYPTO_DATA_MBLK) {
939904Smcpowers 		return (CRYPTO_ARGUMENTS_BAD);
940904Smcpowers 	}
941904Smcpowers 
9420Sstevel@tonic-gate 	/*
9430Sstevel@tonic-gate 	 * There must be no unprocessed ciphertext.
9440Sstevel@tonic-gate 	 * This happens if the length of the last ciphertext is
9450Sstevel@tonic-gate 	 * not a multiple of the AES block length.
9460Sstevel@tonic-gate 	 */
947904Smcpowers 	if (aes_ctx->ac_remainder_len > 0) {
9487188Smcpowers 		if ((aes_ctx->ac_flags & CTR_MODE) == 0)
949904Smcpowers 			return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE);
950904Smcpowers 		else {
9517188Smcpowers 			ret = ctr_mode_final((ctr_ctx_t *)aes_ctx, data,
9527188Smcpowers 			    aes_encrypt_block);
9537188Smcpowers 			if (ret == CRYPTO_DATA_LEN_RANGE)
9547188Smcpowers 				ret = CRYPTO_ENCRYPTED_DATA_LEN_RANGE;
955904Smcpowers 			if (ret != CRYPTO_SUCCESS)
956904Smcpowers 				return (ret);
957904Smcpowers 		}
958904Smcpowers 	}
959904Smcpowers 
9607188Smcpowers 	if (aes_ctx->ac_flags & CCM_MODE) {
9614486Sktung 		/*
9624486Sktung 		 * This is where all the plaintext is returned, make sure
9634486Sktung 		 * the plaintext buffer is big enough
9644486Sktung 		 */
9657188Smcpowers 		size_t pt_len = aes_ctx->ac_data_len;
9664486Sktung 		if (data->cd_length < pt_len) {
9674486Sktung 			data->cd_length = pt_len;
9684486Sktung 			return (CRYPTO_BUFFER_TOO_SMALL);
9694486Sktung 		}
9704486Sktung 
9717188Smcpowers 		ASSERT(aes_ctx->ac_processed_data_len == pt_len);
9727188Smcpowers 		ASSERT(aes_ctx->ac_processed_mac_len == aes_ctx->ac_mac_len);
9734486Sktung 		saved_offset = data->cd_offset;
9744486Sktung 		saved_length = data->cd_length;
9757188Smcpowers 		ret = ccm_decrypt_final((ccm_ctx_t *)aes_ctx, data,
9767188Smcpowers 		    AES_BLOCK_LEN, aes_encrypt_block, aes_copy_block,
9777188Smcpowers 		    aes_xor_block);
9784486Sktung 		if (ret == CRYPTO_SUCCESS) {
9794486Sktung 			data->cd_length = data->cd_offset - saved_offset;
9804486Sktung 		} else {
9814486Sktung 			data->cd_length = saved_length;
9824486Sktung 		}
9834486Sktung 
9844486Sktung 		data->cd_offset = saved_offset;
9854486Sktung 		if (ret != CRYPTO_SUCCESS) {
9864486Sktung 			return (ret);
9874486Sktung 		}
9889339SMark.Powers@Sun.COM 	} else if (aes_ctx->ac_flags & (GCM_MODE|GMAC_MODE)) {
9898005SMark.Powers@Sun.COM 		/*
9908005SMark.Powers@Sun.COM 		 * This is where all the plaintext is returned, make sure
9918005SMark.Powers@Sun.COM 		 * the plaintext buffer is big enough
9928005SMark.Powers@Sun.COM 		 */
9938005SMark.Powers@Sun.COM 		gcm_ctx_t *ctx = (gcm_ctx_t *)aes_ctx;
9948005SMark.Powers@Sun.COM 		size_t pt_len = ctx->gcm_processed_data_len - ctx->gcm_tag_len;
9958005SMark.Powers@Sun.COM 
9968005SMark.Powers@Sun.COM 		if (data->cd_length < pt_len) {
9978005SMark.Powers@Sun.COM 			data->cd_length = pt_len;
9988005SMark.Powers@Sun.COM 			return (CRYPTO_BUFFER_TOO_SMALL);
9998005SMark.Powers@Sun.COM 		}
10008005SMark.Powers@Sun.COM 
10018005SMark.Powers@Sun.COM 		saved_offset = data->cd_offset;
10028005SMark.Powers@Sun.COM 		saved_length = data->cd_length;
10038005SMark.Powers@Sun.COM 		ret = gcm_decrypt_final((gcm_ctx_t *)aes_ctx, data,
10048005SMark.Powers@Sun.COM 		    AES_BLOCK_LEN, aes_encrypt_block, aes_xor_block);
10058005SMark.Powers@Sun.COM 		if (ret == CRYPTO_SUCCESS) {
10068005SMark.Powers@Sun.COM 			data->cd_length = data->cd_offset - saved_offset;
10078005SMark.Powers@Sun.COM 		} else {
10088005SMark.Powers@Sun.COM 			data->cd_length = saved_length;
10098005SMark.Powers@Sun.COM 		}
10108005SMark.Powers@Sun.COM 
10118005SMark.Powers@Sun.COM 		data->cd_offset = saved_offset;
10128005SMark.Powers@Sun.COM 		if (ret != CRYPTO_SUCCESS) {
10138005SMark.Powers@Sun.COM 			return (ret);
10148005SMark.Powers@Sun.COM 		}
10154486Sktung 	}
10164486Sktung 
10174486Sktung 
10189339SMark.Powers@Sun.COM 	if ((aes_ctx->ac_flags & (CTR_MODE|CCM_MODE|GCM_MODE|GMAC_MODE)) == 0) {
1019904Smcpowers 		data->cd_length = 0;
10204558Sktung 	}
10210Sstevel@tonic-gate 
10220Sstevel@tonic-gate 	(void) aes_free_context(ctx);
10230Sstevel@tonic-gate 
10240Sstevel@tonic-gate /* EXPORT DELETE END */
10250Sstevel@tonic-gate 
10260Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
10270Sstevel@tonic-gate }
10280Sstevel@tonic-gate 
10290Sstevel@tonic-gate /* ARGSUSED */
10300Sstevel@tonic-gate static int
10310Sstevel@tonic-gate aes_encrypt_atomic(crypto_provider_handle_t provider,
10320Sstevel@tonic-gate     crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
10330Sstevel@tonic-gate     crypto_key_t *key, crypto_data_t *plaintext, crypto_data_t *ciphertext,
10340Sstevel@tonic-gate     crypto_spi_ctx_template_t template, crypto_req_handle_t req)
10350Sstevel@tonic-gate {
10360Sstevel@tonic-gate 	aes_ctx_t aes_ctx;	/* on the stack */
10370Sstevel@tonic-gate 	off_t saved_offset;
10380Sstevel@tonic-gate 	size_t saved_length;
10398195SMark.Powers@Sun.COM 	size_t length_needed;
10400Sstevel@tonic-gate 	int ret;
10410Sstevel@tonic-gate 
10420Sstevel@tonic-gate 	AES_ARG_INPLACE(plaintext, ciphertext);
10430Sstevel@tonic-gate 
10448195SMark.Powers@Sun.COM 	/*
10459339SMark.Powers@Sun.COM 	 * CTR, CCM, GCM, and GMAC modes do not require that plaintext
10468195SMark.Powers@Sun.COM 	 * be a multiple of AES block size.
10478195SMark.Powers@Sun.COM 	 */
10488195SMark.Powers@Sun.COM 	switch (mechanism->cm_type) {
10498195SMark.Powers@Sun.COM 	case AES_CTR_MECH_INFO_TYPE:
10508195SMark.Powers@Sun.COM 	case AES_CCM_MECH_INFO_TYPE:
10518195SMark.Powers@Sun.COM 	case AES_GCM_MECH_INFO_TYPE:
10529339SMark.Powers@Sun.COM 	case AES_GMAC_MECH_INFO_TYPE:
10538195SMark.Powers@Sun.COM 		break;
10548195SMark.Powers@Sun.COM 	default:
1055904Smcpowers 		if ((plaintext->cd_length & (AES_BLOCK_LEN - 1)) != 0)
1056904Smcpowers 			return (CRYPTO_DATA_LEN_RANGE);
1057904Smcpowers 	}
10580Sstevel@tonic-gate 
10597188Smcpowers 	if ((ret = aes_check_mech_param(mechanism, NULL, 0)) != CRYPTO_SUCCESS)
1060991Smcpowers 		return (ret);
10610Sstevel@tonic-gate 
10620Sstevel@tonic-gate 	bzero(&aes_ctx, sizeof (aes_ctx_t));
10630Sstevel@tonic-gate 
10640Sstevel@tonic-gate 	ret = aes_common_init_ctx(&aes_ctx, template, mechanism, key,
10654486Sktung 	    crypto_kmflag(req), B_TRUE);
10660Sstevel@tonic-gate 	if (ret != CRYPTO_SUCCESS)
10670Sstevel@tonic-gate 		return (ret);
10680Sstevel@tonic-gate 
10698195SMark.Powers@Sun.COM 	switch (mechanism->cm_type) {
10708195SMark.Powers@Sun.COM 	case AES_CCM_MECH_INFO_TYPE:
10718195SMark.Powers@Sun.COM 		length_needed = plaintext->cd_length + aes_ctx.ac_mac_len;
10728195SMark.Powers@Sun.COM 		break;
10739339SMark.Powers@Sun.COM 	case AES_GMAC_MECH_INFO_TYPE:
10749339SMark.Powers@Sun.COM 		if (plaintext->cd_length != 0)
10759339SMark.Powers@Sun.COM 			return (CRYPTO_ARGUMENTS_BAD);
10769339SMark.Powers@Sun.COM 		/* FALLTHRU */
10778195SMark.Powers@Sun.COM 	case AES_GCM_MECH_INFO_TYPE:
10788195SMark.Powers@Sun.COM 		length_needed = plaintext->cd_length + aes_ctx.ac_tag_len;
10798195SMark.Powers@Sun.COM 		break;
10808195SMark.Powers@Sun.COM 	default:
10818195SMark.Powers@Sun.COM 		length_needed = plaintext->cd_length;
10824486Sktung 	}
10834486Sktung 
10848195SMark.Powers@Sun.COM 	/* return size of buffer needed to store output */
10858195SMark.Powers@Sun.COM 	if (ciphertext->cd_length < length_needed) {
10868195SMark.Powers@Sun.COM 		ciphertext->cd_length = length_needed;
10878195SMark.Powers@Sun.COM 		ret = CRYPTO_BUFFER_TOO_SMALL;
10888195SMark.Powers@Sun.COM 		goto out;
10898195SMark.Powers@Sun.COM 	}
10904486Sktung 
10910Sstevel@tonic-gate 	saved_offset = ciphertext->cd_offset;
10920Sstevel@tonic-gate 	saved_length = ciphertext->cd_length;
10930Sstevel@tonic-gate 
10940Sstevel@tonic-gate 	/*
10950Sstevel@tonic-gate 	 * Do an update on the specified input data.
10960Sstevel@tonic-gate 	 */
10970Sstevel@tonic-gate 	switch (plaintext->cd_format) {
10980Sstevel@tonic-gate 	case CRYPTO_DATA_RAW:
10997188Smcpowers 		ret = crypto_update_iov(&aes_ctx, plaintext, ciphertext,
11007188Smcpowers 		    aes_encrypt_contiguous_blocks, aes_copy_block64);
11010Sstevel@tonic-gate 		break;
11020Sstevel@tonic-gate 	case CRYPTO_DATA_UIO:
11037188Smcpowers 		ret = crypto_update_uio(&aes_ctx, plaintext, ciphertext,
11047188Smcpowers 		    aes_encrypt_contiguous_blocks, aes_copy_block64);
11050Sstevel@tonic-gate 		break;
11060Sstevel@tonic-gate 	case CRYPTO_DATA_MBLK:
11077188Smcpowers 		ret = crypto_update_mp(&aes_ctx, plaintext, ciphertext,
11087188Smcpowers 		    aes_encrypt_contiguous_blocks, aes_copy_block64);
11090Sstevel@tonic-gate 		break;
11100Sstevel@tonic-gate 	default:
11110Sstevel@tonic-gate 		ret = CRYPTO_ARGUMENTS_BAD;
11120Sstevel@tonic-gate 	}
11130Sstevel@tonic-gate 
1114904Smcpowers 	if (ret == CRYPTO_SUCCESS) {
11154486Sktung 		if (mechanism->cm_type == AES_CCM_MECH_INFO_TYPE) {
11167188Smcpowers 			ret = ccm_encrypt_final((ccm_ctx_t *)&aes_ctx,
11177188Smcpowers 			    ciphertext, AES_BLOCK_LEN, aes_encrypt_block,
11187188Smcpowers 			    aes_xor_block);
11194486Sktung 			if (ret != CRYPTO_SUCCESS)
11204486Sktung 				goto out;
1121904Smcpowers 			ASSERT(aes_ctx.ac_remainder_len == 0);
11229339SMark.Powers@Sun.COM 		} else if (mechanism->cm_type == AES_GCM_MECH_INFO_TYPE ||
11239339SMark.Powers@Sun.COM 		    mechanism->cm_type == AES_GMAC_MECH_INFO_TYPE) {
11248005SMark.Powers@Sun.COM 			ret = gcm_encrypt_final((gcm_ctx_t *)&aes_ctx,
11258005SMark.Powers@Sun.COM 			    ciphertext, AES_BLOCK_LEN, aes_encrypt_block,
11268005SMark.Powers@Sun.COM 			    aes_copy_block, aes_xor_block);
11278005SMark.Powers@Sun.COM 			if (ret != CRYPTO_SUCCESS)
11288005SMark.Powers@Sun.COM 				goto out;
11298005SMark.Powers@Sun.COM 			ASSERT(aes_ctx.ac_remainder_len == 0);
11304486Sktung 		} else if (mechanism->cm_type == AES_CTR_MECH_INFO_TYPE) {
1131904Smcpowers 			if (aes_ctx.ac_remainder_len > 0) {
11327188Smcpowers 				ret = ctr_mode_final((ctr_ctx_t *)&aes_ctx,
11337188Smcpowers 				    ciphertext, aes_encrypt_block);
1134904Smcpowers 				if (ret != CRYPTO_SUCCESS)
1135904Smcpowers 					goto out;
1136904Smcpowers 			}
11374486Sktung 		} else {
11384486Sktung 			ASSERT(aes_ctx.ac_remainder_len == 0);
11394486Sktung 		}
11404486Sktung 
11414486Sktung 		if (plaintext != ciphertext) {
11424486Sktung 			ciphertext->cd_length =
11434486Sktung 			    ciphertext->cd_offset - saved_offset;
1144904Smcpowers 		}
1145904Smcpowers 	} else {
1146904Smcpowers 		ciphertext->cd_length = saved_length;
1147904Smcpowers 	}
1148904Smcpowers 	ciphertext->cd_offset = saved_offset;
1149904Smcpowers 
1150904Smcpowers out:
11517188Smcpowers 	if (aes_ctx.ac_flags & PROVIDER_OWNS_KEY_SCHEDULE) {
11520Sstevel@tonic-gate 		bzero(aes_ctx.ac_keysched, aes_ctx.ac_keysched_len);
11530Sstevel@tonic-gate 		kmem_free(aes_ctx.ac_keysched, aes_ctx.ac_keysched_len);
11540Sstevel@tonic-gate 	}
11550Sstevel@tonic-gate 
11560Sstevel@tonic-gate 	return (ret);
11570Sstevel@tonic-gate }
11580Sstevel@tonic-gate 
11590Sstevel@tonic-gate /* ARGSUSED */
11600Sstevel@tonic-gate static int
11610Sstevel@tonic-gate aes_decrypt_atomic(crypto_provider_handle_t provider,
11620Sstevel@tonic-gate     crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
11630Sstevel@tonic-gate     crypto_key_t *key, crypto_data_t *ciphertext, crypto_data_t *plaintext,
11640Sstevel@tonic-gate     crypto_spi_ctx_template_t template, crypto_req_handle_t req)
11650Sstevel@tonic-gate {
11660Sstevel@tonic-gate 	aes_ctx_t aes_ctx;	/* on the stack */
11670Sstevel@tonic-gate 	off_t saved_offset;
11680Sstevel@tonic-gate 	size_t saved_length;
11698195SMark.Powers@Sun.COM 	size_t length_needed;
11700Sstevel@tonic-gate 	int ret;
11710Sstevel@tonic-gate 
11720Sstevel@tonic-gate 	AES_ARG_INPLACE(ciphertext, plaintext);
11730Sstevel@tonic-gate 
11744486Sktung 	/*
11759339SMark.Powers@Sun.COM 	 * CCM, GCM, CTR, and GMAC modes do not require that ciphertext
11768195SMark.Powers@Sun.COM 	 * be a multiple of AES block size.
11774486Sktung 	 */
11788195SMark.Powers@Sun.COM 	switch (mechanism->cm_type) {
11798195SMark.Powers@Sun.COM 	case AES_CTR_MECH_INFO_TYPE:
11808195SMark.Powers@Sun.COM 	case AES_CCM_MECH_INFO_TYPE:
11818195SMark.Powers@Sun.COM 	case AES_GCM_MECH_INFO_TYPE:
11829339SMark.Powers@Sun.COM 	case AES_GMAC_MECH_INFO_TYPE:
11838195SMark.Powers@Sun.COM 		break;
11848195SMark.Powers@Sun.COM 	default:
11858195SMark.Powers@Sun.COM 		if ((ciphertext->cd_length & (AES_BLOCK_LEN - 1)) != 0)
11868195SMark.Powers@Sun.COM 			return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE);
11870Sstevel@tonic-gate 	}
11880Sstevel@tonic-gate 
11897188Smcpowers 	if ((ret = aes_check_mech_param(mechanism, NULL, 0)) != CRYPTO_SUCCESS)
1190991Smcpowers 		return (ret);
11910Sstevel@tonic-gate 
11920Sstevel@tonic-gate 	bzero(&aes_ctx, sizeof (aes_ctx_t));
11930Sstevel@tonic-gate 
11940Sstevel@tonic-gate 	ret = aes_common_init_ctx(&aes_ctx, template, mechanism, key,
11954486Sktung 	    crypto_kmflag(req), B_FALSE);
11960Sstevel@tonic-gate 	if (ret != CRYPTO_SUCCESS)
11970Sstevel@tonic-gate 		return (ret);
11980Sstevel@tonic-gate 
11998195SMark.Powers@Sun.COM 	switch (mechanism->cm_type) {
12008195SMark.Powers@Sun.COM 	case AES_CCM_MECH_INFO_TYPE:
12018195SMark.Powers@Sun.COM 		length_needed = aes_ctx.ac_data_len;
12028195SMark.Powers@Sun.COM 		break;
12038195SMark.Powers@Sun.COM 	case AES_GCM_MECH_INFO_TYPE:
12048195SMark.Powers@Sun.COM 		length_needed = ciphertext->cd_length - aes_ctx.ac_tag_len;
12058195SMark.Powers@Sun.COM 		break;
12069339SMark.Powers@Sun.COM 	case AES_GMAC_MECH_INFO_TYPE:
12079339SMark.Powers@Sun.COM 		if (plaintext->cd_length != 0)
12089339SMark.Powers@Sun.COM 			return (CRYPTO_ARGUMENTS_BAD);
12099339SMark.Powers@Sun.COM 		length_needed = 0;
12109339SMark.Powers@Sun.COM 		break;
12118195SMark.Powers@Sun.COM 	default:
12128195SMark.Powers@Sun.COM 		length_needed = ciphertext->cd_length;
12138195SMark.Powers@Sun.COM 	}
12148195SMark.Powers@Sun.COM 
12158195SMark.Powers@Sun.COM 	/* return size of buffer needed to store output */
12168195SMark.Powers@Sun.COM 	if (plaintext->cd_length < length_needed) {
12178195SMark.Powers@Sun.COM 		plaintext->cd_length = length_needed;
12188195SMark.Powers@Sun.COM 		ret = CRYPTO_BUFFER_TOO_SMALL;
12198195SMark.Powers@Sun.COM 		goto out;
12204486Sktung 	}
12214486Sktung 
12220Sstevel@tonic-gate 	saved_offset = plaintext->cd_offset;
12230Sstevel@tonic-gate 	saved_length = plaintext->cd_length;
12240Sstevel@tonic-gate 
12259339SMark.Powers@Sun.COM 	if (mechanism->cm_type == AES_GCM_MECH_INFO_TYPE ||
12269339SMark.Powers@Sun.COM 	    mechanism->cm_type == AES_GMAC_MECH_INFO_TYPE)
12278005SMark.Powers@Sun.COM 		gcm_set_kmflag((gcm_ctx_t *)&aes_ctx, crypto_kmflag(req));
12288005SMark.Powers@Sun.COM 
12290Sstevel@tonic-gate 	/*
12300Sstevel@tonic-gate 	 * Do an update on the specified input data.
12310Sstevel@tonic-gate 	 */
12320Sstevel@tonic-gate 	switch (ciphertext->cd_format) {
12330Sstevel@tonic-gate 	case CRYPTO_DATA_RAW:
12347188Smcpowers 		ret = crypto_update_iov(&aes_ctx, ciphertext, plaintext,
12357188Smcpowers 		    aes_decrypt_contiguous_blocks, aes_copy_block64);
12360Sstevel@tonic-gate 		break;
12370Sstevel@tonic-gate 	case CRYPTO_DATA_UIO:
12387188Smcpowers 		ret = crypto_update_uio(&aes_ctx, ciphertext, plaintext,
12397188Smcpowers 		    aes_decrypt_contiguous_blocks, aes_copy_block64);
12400Sstevel@tonic-gate 		break;
12410Sstevel@tonic-gate 	case CRYPTO_DATA_MBLK:
12427188Smcpowers 		ret = crypto_update_mp(&aes_ctx, ciphertext, plaintext,
12437188Smcpowers 		    aes_decrypt_contiguous_blocks, aes_copy_block64);
12440Sstevel@tonic-gate 		break;
12450Sstevel@tonic-gate 	default:
12460Sstevel@tonic-gate 		ret = CRYPTO_ARGUMENTS_BAD;
12470Sstevel@tonic-gate 	}
12480Sstevel@tonic-gate 
1249904Smcpowers 	if (ret == CRYPTO_SUCCESS) {
12504486Sktung 		if (mechanism->cm_type == AES_CCM_MECH_INFO_TYPE) {
12517188Smcpowers 			ASSERT(aes_ctx.ac_processed_data_len
12527188Smcpowers 			    == aes_ctx.ac_data_len);
12537188Smcpowers 			ASSERT(aes_ctx.ac_processed_mac_len
12547188Smcpowers 			    == aes_ctx.ac_mac_len);
12557188Smcpowers 			ret = ccm_decrypt_final((ccm_ctx_t *)&aes_ctx,
12567188Smcpowers 			    plaintext, AES_BLOCK_LEN, aes_encrypt_block,
12577188Smcpowers 			    aes_copy_block, aes_xor_block);
12584486Sktung 			ASSERT(aes_ctx.ac_remainder_len == 0);
12594486Sktung 			if ((ret == CRYPTO_SUCCESS) &&
12604486Sktung 			    (ciphertext != plaintext)) {
12614486Sktung 				plaintext->cd_length =
12624486Sktung 				    plaintext->cd_offset - saved_offset;
12634486Sktung 			} else {
12644486Sktung 				plaintext->cd_length = saved_length;
12654486Sktung 			}
12669339SMark.Powers@Sun.COM 		} else if (mechanism->cm_type == AES_GCM_MECH_INFO_TYPE ||
12679339SMark.Powers@Sun.COM 		    mechanism->cm_type == AES_GMAC_MECH_INFO_TYPE) {
12688005SMark.Powers@Sun.COM 			ret = gcm_decrypt_final((gcm_ctx_t *)&aes_ctx,
12698005SMark.Powers@Sun.COM 			    plaintext, AES_BLOCK_LEN, aes_encrypt_block,
12708005SMark.Powers@Sun.COM 			    aes_xor_block);
12718005SMark.Powers@Sun.COM 			ASSERT(aes_ctx.ac_remainder_len == 0);
12728005SMark.Powers@Sun.COM 			if ((ret == CRYPTO_SUCCESS) &&
12738005SMark.Powers@Sun.COM 			    (ciphertext != plaintext)) {
12748005SMark.Powers@Sun.COM 				plaintext->cd_length =
12758005SMark.Powers@Sun.COM 				    plaintext->cd_offset - saved_offset;
12768005SMark.Powers@Sun.COM 			} else {
12778005SMark.Powers@Sun.COM 				plaintext->cd_length = saved_length;
12788005SMark.Powers@Sun.COM 			}
12794486Sktung 		} else if (mechanism->cm_type != AES_CTR_MECH_INFO_TYPE) {
1280904Smcpowers 			ASSERT(aes_ctx.ac_remainder_len == 0);
1281904Smcpowers 			if (ciphertext != plaintext)
1282904Smcpowers 				plaintext->cd_length =
1283904Smcpowers 				    plaintext->cd_offset - saved_offset;
1284904Smcpowers 		} else {
1285904Smcpowers 			if (aes_ctx.ac_remainder_len > 0) {
12867188Smcpowers 				ret = ctr_mode_final((ctr_ctx_t *)&aes_ctx,
12877188Smcpowers 				    plaintext, aes_encrypt_block);
12887188Smcpowers 				if (ret == CRYPTO_DATA_LEN_RANGE)
12897188Smcpowers 					ret = CRYPTO_ENCRYPTED_DATA_LEN_RANGE;
1290904Smcpowers 				if (ret != CRYPTO_SUCCESS)
1291904Smcpowers 					goto out;
1292904Smcpowers 			}
1293904Smcpowers 			if (ciphertext != plaintext)
1294904Smcpowers 				plaintext->cd_length =
1295904Smcpowers 				    plaintext->cd_offset - saved_offset;
1296904Smcpowers 		}
1297904Smcpowers 	} else {
1298904Smcpowers 		plaintext->cd_length = saved_length;
1299904Smcpowers 	}
1300904Smcpowers 	plaintext->cd_offset = saved_offset;
1301904Smcpowers 
1302904Smcpowers out:
13037188Smcpowers 	if (aes_ctx.ac_flags & PROVIDER_OWNS_KEY_SCHEDULE) {
13040Sstevel@tonic-gate 		bzero(aes_ctx.ac_keysched, aes_ctx.ac_keysched_len);
13050Sstevel@tonic-gate 		kmem_free(aes_ctx.ac_keysched, aes_ctx.ac_keysched_len);
13060Sstevel@tonic-gate 	}
13070Sstevel@tonic-gate 
13087188Smcpowers 	if (aes_ctx.ac_flags & CCM_MODE) {
13097188Smcpowers 		if (aes_ctx.ac_pt_buf != NULL) {
13107188Smcpowers 			kmem_free(aes_ctx.ac_pt_buf, aes_ctx.ac_data_len);
13117188Smcpowers 		}
13129339SMark.Powers@Sun.COM 	} else if (aes_ctx.ac_flags & (GCM_MODE|GMAC_MODE)) {
13138005SMark.Powers@Sun.COM 		if (((gcm_ctx_t *)&aes_ctx)->gcm_pt_buf != NULL) {
13148005SMark.Powers@Sun.COM 			kmem_free(((gcm_ctx_t *)&aes_ctx)->gcm_pt_buf,
13158005SMark.Powers@Sun.COM 			    ((gcm_ctx_t *)&aes_ctx)->gcm_pt_buf_len);
13168005SMark.Powers@Sun.COM 		}
13174486Sktung 	}
13184486Sktung 
13190Sstevel@tonic-gate 	return (ret);
13200Sstevel@tonic-gate }
13210Sstevel@tonic-gate 
13220Sstevel@tonic-gate /*
13230Sstevel@tonic-gate  * KCF software provider context template entry points.
13240Sstevel@tonic-gate  */
13250Sstevel@tonic-gate /* ARGSUSED */
13260Sstevel@tonic-gate static int
13270Sstevel@tonic-gate aes_create_ctx_template(crypto_provider_handle_t provider,
13280Sstevel@tonic-gate     crypto_mechanism_t *mechanism, crypto_key_t *key,
13290Sstevel@tonic-gate     crypto_spi_ctx_template_t *tmpl, size_t *tmpl_size, crypto_req_handle_t req)
13300Sstevel@tonic-gate {
13310Sstevel@tonic-gate 
13320Sstevel@tonic-gate /* EXPORT DELETE START */
13330Sstevel@tonic-gate 
13340Sstevel@tonic-gate 	void *keysched;
13350Sstevel@tonic-gate 	size_t size;
13360Sstevel@tonic-gate 	int rv;
13370Sstevel@tonic-gate 
1338991Smcpowers 	if (mechanism->cm_type != AES_ECB_MECH_INFO_TYPE &&
1339991Smcpowers 	    mechanism->cm_type != AES_CBC_MECH_INFO_TYPE &&
13404486Sktung 	    mechanism->cm_type != AES_CTR_MECH_INFO_TYPE &&
13419339SMark.Powers@Sun.COM 	    mechanism->cm_type != AES_CCM_MECH_INFO_TYPE &&
13429339SMark.Powers@Sun.COM 	    mechanism->cm_type != AES_GCM_MECH_INFO_TYPE &&
13439339SMark.Powers@Sun.COM 	    mechanism->cm_type != AES_GMAC_MECH_INFO_TYPE)
13440Sstevel@tonic-gate 		return (CRYPTO_MECHANISM_INVALID);
13450Sstevel@tonic-gate 
13460Sstevel@tonic-gate 	if ((keysched = aes_alloc_keysched(&size,
13470Sstevel@tonic-gate 	    crypto_kmflag(req))) == NULL) {
13480Sstevel@tonic-gate 		return (CRYPTO_HOST_MEMORY);
13490Sstevel@tonic-gate 	}
13500Sstevel@tonic-gate 
13510Sstevel@tonic-gate 	/*
13520Sstevel@tonic-gate 	 * Initialize key schedule.  Key length information is stored
13530Sstevel@tonic-gate 	 * in the key.
13540Sstevel@tonic-gate 	 */
13550Sstevel@tonic-gate 	if ((rv = init_keysched(key, keysched)) != CRYPTO_SUCCESS) {
13560Sstevel@tonic-gate 		bzero(keysched, size);
13570Sstevel@tonic-gate 		kmem_free(keysched, size);
13580Sstevel@tonic-gate 		return (rv);
13590Sstevel@tonic-gate 	}
13600Sstevel@tonic-gate 
13610Sstevel@tonic-gate 	*tmpl = keysched;
13620Sstevel@tonic-gate 	*tmpl_size = size;
13630Sstevel@tonic-gate 
13640Sstevel@tonic-gate /* EXPORT DELETE END */
13650Sstevel@tonic-gate 
13660Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
13670Sstevel@tonic-gate }
13680Sstevel@tonic-gate 
1369*9392Sopensolaris@drydog.com 
13700Sstevel@tonic-gate static int
13710Sstevel@tonic-gate aes_free_context(crypto_ctx_t *ctx)
13720Sstevel@tonic-gate {
13730Sstevel@tonic-gate 
13740Sstevel@tonic-gate /* EXPORT DELETE START */
13750Sstevel@tonic-gate 
13760Sstevel@tonic-gate 	aes_ctx_t *aes_ctx = ctx->cc_provider_private;
13770Sstevel@tonic-gate 
13780Sstevel@tonic-gate 	if (aes_ctx != NULL) {
13797188Smcpowers 		if (aes_ctx->ac_flags & PROVIDER_OWNS_KEY_SCHEDULE) {
13800Sstevel@tonic-gate 			ASSERT(aes_ctx->ac_keysched_len != 0);
13810Sstevel@tonic-gate 			bzero(aes_ctx->ac_keysched, aes_ctx->ac_keysched_len);
13820Sstevel@tonic-gate 			kmem_free(aes_ctx->ac_keysched,
13830Sstevel@tonic-gate 			    aes_ctx->ac_keysched_len);
13840Sstevel@tonic-gate 		}
13857188Smcpowers 		crypto_free_mode_ctx(aes_ctx);
13860Sstevel@tonic-gate 		ctx->cc_provider_private = NULL;
13870Sstevel@tonic-gate 	}
13880Sstevel@tonic-gate 
13890Sstevel@tonic-gate /* EXPORT DELETE END */
13900Sstevel@tonic-gate 
13910Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
13920Sstevel@tonic-gate }
13930Sstevel@tonic-gate 
1394*9392Sopensolaris@drydog.com 
13950Sstevel@tonic-gate static int
13960Sstevel@tonic-gate aes_common_init_ctx(aes_ctx_t *aes_ctx, crypto_spi_ctx_template_t *template,
13974486Sktung     crypto_mechanism_t *mechanism, crypto_key_t *key, int kmflag,
13984486Sktung     boolean_t is_encrypt_init)
13990Sstevel@tonic-gate {
14000Sstevel@tonic-gate 	int rv = CRYPTO_SUCCESS;
14010Sstevel@tonic-gate 
14020Sstevel@tonic-gate /* EXPORT DELETE START */
14030Sstevel@tonic-gate 
14040Sstevel@tonic-gate 	void *keysched;
14050Sstevel@tonic-gate 	size_t size;
1406904Smcpowers 
1407904Smcpowers 	if (template == NULL) {
1408904Smcpowers 		if ((keysched = aes_alloc_keysched(&size, kmflag)) == NULL)
1409904Smcpowers 			return (CRYPTO_HOST_MEMORY);
1410904Smcpowers 		/*
1411904Smcpowers 		 * Initialize key schedule.
1412904Smcpowers 		 * Key length is stored in the key.
1413904Smcpowers 		 */
14144486Sktung 		if ((rv = init_keysched(key, keysched)) != CRYPTO_SUCCESS) {
1415904Smcpowers 			kmem_free(keysched, size);
14164486Sktung 			return (rv);
14174486Sktung 		}
1418904Smcpowers 
14197188Smcpowers 		aes_ctx->ac_flags |= PROVIDER_OWNS_KEY_SCHEDULE;
1420904Smcpowers 		aes_ctx->ac_keysched_len = size;
1421904Smcpowers 	} else {
1422904Smcpowers 		keysched = template;
14230Sstevel@tonic-gate 	}
14240Sstevel@tonic-gate 	aes_ctx->ac_keysched = keysched;
14250Sstevel@tonic-gate 
14267188Smcpowers 	switch (mechanism->cm_type) {
14277188Smcpowers 	case AES_CBC_MECH_INFO_TYPE:
14287188Smcpowers 		rv = cbc_init_ctx((cbc_ctx_t *)aes_ctx, mechanism->cm_param,
14297188Smcpowers 		    mechanism->cm_param_len, AES_BLOCK_LEN, aes_copy_block64);
14307188Smcpowers 		break;
14317188Smcpowers 	case AES_CTR_MECH_INFO_TYPE: {
14327188Smcpowers 		CK_AES_CTR_PARAMS *pp;
14337188Smcpowers 
14347188Smcpowers 		if (mechanism->cm_param == NULL ||
14357188Smcpowers 		    mechanism->cm_param_len != sizeof (CK_AES_CTR_PARAMS)) {
14364486Sktung 			return (CRYPTO_MECHANISM_PARAM_INVALID);
14374486Sktung 		}
1438*9392Sopensolaris@drydog.com 		pp = (CK_AES_CTR_PARAMS *)(void *)mechanism->cm_param;
14397188Smcpowers 		rv = ctr_init_ctx((ctr_ctx_t *)aes_ctx, pp->ulCounterBits,
14407188Smcpowers 		    pp->cb, aes_copy_block);
14417188Smcpowers 		break;
14427188Smcpowers 	}
14437188Smcpowers 	case AES_CCM_MECH_INFO_TYPE:
14447188Smcpowers 		if (mechanism->cm_param == NULL ||
14457188Smcpowers 		    mechanism->cm_param_len != sizeof (CK_AES_CCM_PARAMS)) {
14467188Smcpowers 			return (CRYPTO_MECHANISM_PARAM_INVALID);
14477188Smcpowers 		}
14487188Smcpowers 		rv = ccm_init_ctx((ccm_ctx_t *)aes_ctx, mechanism->cm_param,
14497188Smcpowers 		    kmflag, is_encrypt_init, AES_BLOCK_LEN, aes_encrypt_block,
14507188Smcpowers 		    aes_xor_block);
14517188Smcpowers 		break;
14528005SMark.Powers@Sun.COM 	case AES_GCM_MECH_INFO_TYPE:
14538005SMark.Powers@Sun.COM 		if (mechanism->cm_param == NULL ||
14548005SMark.Powers@Sun.COM 		    mechanism->cm_param_len != sizeof (CK_AES_GCM_PARAMS)) {
14558005SMark.Powers@Sun.COM 			return (CRYPTO_MECHANISM_PARAM_INVALID);
14568005SMark.Powers@Sun.COM 		}
14578005SMark.Powers@Sun.COM 		rv = gcm_init_ctx((gcm_ctx_t *)aes_ctx, mechanism->cm_param,
14588005SMark.Powers@Sun.COM 		    AES_BLOCK_LEN, aes_encrypt_block, aes_copy_block,
14598005SMark.Powers@Sun.COM 		    aes_xor_block);
14608005SMark.Powers@Sun.COM 		break;
14619339SMark.Powers@Sun.COM 	case AES_GMAC_MECH_INFO_TYPE:
14629339SMark.Powers@Sun.COM 		if (mechanism->cm_param == NULL ||
14639339SMark.Powers@Sun.COM 		    mechanism->cm_param_len != sizeof (CK_AES_GMAC_PARAMS)) {
14649339SMark.Powers@Sun.COM 			return (CRYPTO_MECHANISM_PARAM_INVALID);
14659339SMark.Powers@Sun.COM 		}
14669339SMark.Powers@Sun.COM 		rv = gmac_init_ctx((gcm_ctx_t *)aes_ctx, mechanism->cm_param,
14679339SMark.Powers@Sun.COM 		    AES_BLOCK_LEN, aes_encrypt_block, aes_copy_block,
14689339SMark.Powers@Sun.COM 		    aes_xor_block);
14699339SMark.Powers@Sun.COM 		break;
14707188Smcpowers 	case AES_ECB_MECH_INFO_TYPE:
14717188Smcpowers 		aes_ctx->ac_flags |= ECB_MODE;
14727188Smcpowers 	}
14737188Smcpowers 
14747188Smcpowers 	if (rv != CRYPTO_SUCCESS) {
14757188Smcpowers 		if (aes_ctx->ac_flags & PROVIDER_OWNS_KEY_SCHEDULE) {
14767188Smcpowers 			bzero(keysched, size);
14777188Smcpowers 			kmem_free(keysched, size);
14784486Sktung 		}
14794486Sktung 	}
14804486Sktung 
14810Sstevel@tonic-gate /* EXPORT DELETE END */
14820Sstevel@tonic-gate 
14830Sstevel@tonic-gate 	return (rv);
14840Sstevel@tonic-gate }
14859339SMark.Powers@Sun.COM 
14869339SMark.Powers@Sun.COM static int
14879339SMark.Powers@Sun.COM process_gmac_mech(crypto_mechanism_t *mech, crypto_data_t *data,
14889339SMark.Powers@Sun.COM     CK_AES_GCM_PARAMS *gcm_params)
14899339SMark.Powers@Sun.COM {
14909339SMark.Powers@Sun.COM 	/* LINTED: pointer alignment */
14919339SMark.Powers@Sun.COM 	CK_AES_GMAC_PARAMS *params = (CK_AES_GMAC_PARAMS *)mech->cm_param;
14929339SMark.Powers@Sun.COM 
14939339SMark.Powers@Sun.COM 	if (mech->cm_type != AES_GMAC_MECH_INFO_TYPE)
14949339SMark.Powers@Sun.COM 		return (CRYPTO_MECHANISM_INVALID);
14959339SMark.Powers@Sun.COM 
14969339SMark.Powers@Sun.COM 	if (mech->cm_param_len != sizeof (CK_AES_GMAC_PARAMS))
14979339SMark.Powers@Sun.COM 		return (CRYPTO_MECHANISM_PARAM_INVALID);
14989339SMark.Powers@Sun.COM 
14999339SMark.Powers@Sun.COM 	if (params->pIv == NULL)
15009339SMark.Powers@Sun.COM 		return (CRYPTO_MECHANISM_PARAM_INVALID);
15019339SMark.Powers@Sun.COM 
15029339SMark.Powers@Sun.COM 	gcm_params->pIv = params->pIv;
15039339SMark.Powers@Sun.COM 	gcm_params->ulIvLen = AES_GMAC_IV_LEN;
15049339SMark.Powers@Sun.COM 	gcm_params->ulTagBits = AES_GMAC_TAG_BITS;
15059339SMark.Powers@Sun.COM 
15069339SMark.Powers@Sun.COM 	if (data == NULL)
15079339SMark.Powers@Sun.COM 		return (CRYPTO_SUCCESS);
15089339SMark.Powers@Sun.COM 
15099339SMark.Powers@Sun.COM 	if (data->cd_format != CRYPTO_DATA_RAW)
15109339SMark.Powers@Sun.COM 		return (CRYPTO_ARGUMENTS_BAD);
15119339SMark.Powers@Sun.COM 
15129339SMark.Powers@Sun.COM 	gcm_params->pAAD = (uchar_t *)data->cd_raw.iov_base;
15139339SMark.Powers@Sun.COM 	gcm_params->ulAADLen = data->cd_length;
15149339SMark.Powers@Sun.COM 	return (CRYPTO_SUCCESS);
15159339SMark.Powers@Sun.COM }
15169339SMark.Powers@Sun.COM 
15179339SMark.Powers@Sun.COM static int
15189339SMark.Powers@Sun.COM aes_mac_atomic(crypto_provider_handle_t provider,
15199339SMark.Powers@Sun.COM     crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
15209339SMark.Powers@Sun.COM     crypto_key_t *key, crypto_data_t *data, crypto_data_t *mac,
15219339SMark.Powers@Sun.COM     crypto_spi_ctx_template_t template, crypto_req_handle_t req)
15229339SMark.Powers@Sun.COM {
15239339SMark.Powers@Sun.COM 	CK_AES_GCM_PARAMS gcm_params;
15249339SMark.Powers@Sun.COM 	crypto_mechanism_t gcm_mech;
15259339SMark.Powers@Sun.COM 	int rv;
15269339SMark.Powers@Sun.COM 
15279339SMark.Powers@Sun.COM 	if ((rv = process_gmac_mech(mechanism, data, &gcm_params))
15289339SMark.Powers@Sun.COM 	    != CRYPTO_SUCCESS)
15299339SMark.Powers@Sun.COM 		return (rv);
15309339SMark.Powers@Sun.COM 
15319339SMark.Powers@Sun.COM 	gcm_mech.cm_type = AES_GCM_MECH_INFO_TYPE;
15329339SMark.Powers@Sun.COM 	gcm_mech.cm_param_len = sizeof (CK_AES_GCM_PARAMS);
15339339SMark.Powers@Sun.COM 	gcm_mech.cm_param = (char *)&gcm_params;
15349339SMark.Powers@Sun.COM 
15359339SMark.Powers@Sun.COM 	return (aes_encrypt_atomic(provider, session_id, &gcm_mech,
15369339SMark.Powers@Sun.COM 	    key, &null_crypto_data, mac, template, req));
15379339SMark.Powers@Sun.COM }
15389339SMark.Powers@Sun.COM 
15399339SMark.Powers@Sun.COM static int
15409339SMark.Powers@Sun.COM aes_mac_verify_atomic(crypto_provider_handle_t provider,
15419339SMark.Powers@Sun.COM     crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
15429339SMark.Powers@Sun.COM     crypto_key_t *key, crypto_data_t *data, crypto_data_t *mac,
15439339SMark.Powers@Sun.COM     crypto_spi_ctx_template_t template, crypto_req_handle_t req)
15449339SMark.Powers@Sun.COM {
15459339SMark.Powers@Sun.COM 	CK_AES_GCM_PARAMS gcm_params;
15469339SMark.Powers@Sun.COM 	crypto_mechanism_t gcm_mech;
15479339SMark.Powers@Sun.COM 	int rv;
15489339SMark.Powers@Sun.COM 
15499339SMark.Powers@Sun.COM 	if ((rv = process_gmac_mech(mechanism, data, &gcm_params))
15509339SMark.Powers@Sun.COM 	    != CRYPTO_SUCCESS)
15519339SMark.Powers@Sun.COM 		return (rv);
15529339SMark.Powers@Sun.COM 
15539339SMark.Powers@Sun.COM 	gcm_mech.cm_type = AES_GCM_MECH_INFO_TYPE;
15549339SMark.Powers@Sun.COM 	gcm_mech.cm_param_len = sizeof (CK_AES_GCM_PARAMS);
15559339SMark.Powers@Sun.COM 	gcm_mech.cm_param = (char *)&gcm_params;
15569339SMark.Powers@Sun.COM 
15579339SMark.Powers@Sun.COM 	return (aes_decrypt_atomic(provider, session_id, &gcm_mech,
15589339SMark.Powers@Sun.COM 	    key, mac, &null_crypto_data, template, req));
15599339SMark.Powers@Sun.COM }
1560