xref: /onnv-gate/usr/src/uts/common/crypto/io/aes.c (revision 12856:2377353d2b97)
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*12856SZdenek.Kotala@Sun.COM  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate  */
240Sstevel@tonic-gate 
250Sstevel@tonic-gate /*
260Sstevel@tonic-gate  * AES provider for the Kernel Cryptographic Framework (KCF)
270Sstevel@tonic-gate  */
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #include <sys/types.h>
300Sstevel@tonic-gate #include <sys/systm.h>
310Sstevel@tonic-gate #include <sys/modctl.h>
320Sstevel@tonic-gate #include <sys/cmn_err.h>
330Sstevel@tonic-gate #include <sys/ddi.h>
340Sstevel@tonic-gate #include <sys/crypto/common.h>
357188Smcpowers #include <sys/crypto/impl.h>
360Sstevel@tonic-gate #include <sys/crypto/spi.h>
370Sstevel@tonic-gate #include <sys/sysmacros.h>
380Sstevel@tonic-gate #include <sys/strsun.h>
397188Smcpowers #include <modes/modes.h>
4010500SHai-May.Chao@Sun.COM #define	_AES_FIPS_POST
4110500SHai-May.Chao@Sun.COM #define	_AES_IMPL
427188Smcpowers #include <aes/aes_impl.h>
430Sstevel@tonic-gate 
440Sstevel@tonic-gate extern struct mod_ops mod_cryptoops;
450Sstevel@tonic-gate 
460Sstevel@tonic-gate /*
470Sstevel@tonic-gate  * Module linkage information for the kernel.
480Sstevel@tonic-gate  */
490Sstevel@tonic-gate static struct modlcrypto modlcrypto = {
500Sstevel@tonic-gate 	&mod_cryptoops,
515072Smcpowers 	"AES Kernel SW Provider"
520Sstevel@tonic-gate };
530Sstevel@tonic-gate 
540Sstevel@tonic-gate static struct modlinkage modlinkage = {
550Sstevel@tonic-gate 	MODREV_1,
560Sstevel@tonic-gate 	(void *)&modlcrypto,
570Sstevel@tonic-gate 	NULL
580Sstevel@tonic-gate };
590Sstevel@tonic-gate 
600Sstevel@tonic-gate /*
610Sstevel@tonic-gate  * The following definitions are to keep EXPORT_SRC happy.
620Sstevel@tonic-gate  */
632530Spwernau #ifndef AES_MIN_KEY_BYTES
642530Spwernau #define	AES_MIN_KEY_BYTES		0
650Sstevel@tonic-gate #endif
660Sstevel@tonic-gate 
672530Spwernau #ifndef AES_MAX_KEY_BYTES
682530Spwernau #define	AES_MAX_KEY_BYTES		0
690Sstevel@tonic-gate #endif
700Sstevel@tonic-gate 
710Sstevel@tonic-gate /*
720Sstevel@tonic-gate  * Mechanism info structure passed to KCF during registration.
730Sstevel@tonic-gate  */
740Sstevel@tonic-gate static crypto_mech_info_t aes_mech_info_tab[] = {
750Sstevel@tonic-gate 	/* AES_ECB */
760Sstevel@tonic-gate 	{SUN_CKM_AES_ECB, AES_ECB_MECH_INFO_TYPE,
770Sstevel@tonic-gate 	    CRYPTO_FG_ENCRYPT | CRYPTO_FG_ENCRYPT_ATOMIC |
780Sstevel@tonic-gate 	    CRYPTO_FG_DECRYPT | CRYPTO_FG_DECRYPT_ATOMIC,
792530Spwernau 	    AES_MIN_KEY_BYTES, AES_MAX_KEY_BYTES, CRYPTO_KEYSIZE_UNIT_IN_BYTES},
800Sstevel@tonic-gate 	/* AES_CBC */
810Sstevel@tonic-gate 	{SUN_CKM_AES_CBC, AES_CBC_MECH_INFO_TYPE,
820Sstevel@tonic-gate 	    CRYPTO_FG_ENCRYPT | CRYPTO_FG_ENCRYPT_ATOMIC |
830Sstevel@tonic-gate 	    CRYPTO_FG_DECRYPT | CRYPTO_FG_DECRYPT_ATOMIC,
842530Spwernau 	    AES_MIN_KEY_BYTES, AES_MAX_KEY_BYTES, CRYPTO_KEYSIZE_UNIT_IN_BYTES},
85904Smcpowers 	/* AES_CTR */
86904Smcpowers 	{SUN_CKM_AES_CTR, AES_CTR_MECH_INFO_TYPE,
87904Smcpowers 	    CRYPTO_FG_ENCRYPT | CRYPTO_FG_ENCRYPT_ATOMIC |
88904Smcpowers 	    CRYPTO_FG_DECRYPT | CRYPTO_FG_DECRYPT_ATOMIC,
894486Sktung 	    AES_MIN_KEY_BYTES, AES_MAX_KEY_BYTES, CRYPTO_KEYSIZE_UNIT_IN_BYTES},
904486Sktung 	/* AES_CCM */
914486Sktung 	{SUN_CKM_AES_CCM, AES_CCM_MECH_INFO_TYPE,
924486Sktung 	    CRYPTO_FG_ENCRYPT | CRYPTO_FG_ENCRYPT_ATOMIC |
934486Sktung 	    CRYPTO_FG_DECRYPT | CRYPTO_FG_DECRYPT_ATOMIC,
948005SMark.Powers@Sun.COM 	    AES_MIN_KEY_BYTES, AES_MAX_KEY_BYTES, CRYPTO_KEYSIZE_UNIT_IN_BYTES},
958005SMark.Powers@Sun.COM 	/* AES_GCM */
968005SMark.Powers@Sun.COM 	{SUN_CKM_AES_GCM, AES_GCM_MECH_INFO_TYPE,
978005SMark.Powers@Sun.COM 	    CRYPTO_FG_ENCRYPT | CRYPTO_FG_ENCRYPT_ATOMIC |
988005SMark.Powers@Sun.COM 	    CRYPTO_FG_DECRYPT | CRYPTO_FG_DECRYPT_ATOMIC,
999339SMark.Powers@Sun.COM 	    AES_MIN_KEY_BYTES, AES_MAX_KEY_BYTES, CRYPTO_KEYSIZE_UNIT_IN_BYTES},
1009339SMark.Powers@Sun.COM 	/* AES_GMAC */
1019339SMark.Powers@Sun.COM 	{SUN_CKM_AES_GMAC, AES_GMAC_MECH_INFO_TYPE,
1029339SMark.Powers@Sun.COM 	    CRYPTO_FG_ENCRYPT | CRYPTO_FG_ENCRYPT_ATOMIC |
1039339SMark.Powers@Sun.COM 	    CRYPTO_FG_DECRYPT | CRYPTO_FG_DECRYPT_ATOMIC |
1049339SMark.Powers@Sun.COM 	    CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC |
1059339SMark.Powers@Sun.COM 	    CRYPTO_FG_SIGN | CRYPTO_FG_SIGN_ATOMIC |
1069339SMark.Powers@Sun.COM 	    CRYPTO_FG_VERIFY | CRYPTO_FG_VERIFY_ATOMIC,
1072530Spwernau 	    AES_MIN_KEY_BYTES, AES_MAX_KEY_BYTES, CRYPTO_KEYSIZE_UNIT_IN_BYTES}
1080Sstevel@tonic-gate };
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate /* operations are in-place if the output buffer is NULL */
1110Sstevel@tonic-gate #define	AES_ARG_INPLACE(input, output)				\
1120Sstevel@tonic-gate 	if ((output) == NULL)					\
1130Sstevel@tonic-gate 		(output) = (input);
1140Sstevel@tonic-gate 
1150Sstevel@tonic-gate static void aes_provider_status(crypto_provider_handle_t, uint_t *);
1160Sstevel@tonic-gate 
1170Sstevel@tonic-gate static crypto_control_ops_t aes_control_ops = {
1180Sstevel@tonic-gate 	aes_provider_status
1190Sstevel@tonic-gate };
1200Sstevel@tonic-gate 
1214486Sktung static int aes_encrypt_init(crypto_ctx_t *, crypto_mechanism_t *,
1224486Sktung     crypto_key_t *, crypto_spi_ctx_template_t, crypto_req_handle_t);
1234486Sktung static int aes_decrypt_init(crypto_ctx_t *, crypto_mechanism_t *,
1240Sstevel@tonic-gate     crypto_key_t *, crypto_spi_ctx_template_t, crypto_req_handle_t);
1254486Sktung static int aes_common_init(crypto_ctx_t *, crypto_mechanism_t *,
1264486Sktung     crypto_key_t *, crypto_spi_ctx_template_t, crypto_req_handle_t, boolean_t);
1270Sstevel@tonic-gate static int aes_common_init_ctx(aes_ctx_t *, crypto_spi_ctx_template_t *,
1284486Sktung     crypto_mechanism_t *, crypto_key_t *, int, boolean_t);
1290Sstevel@tonic-gate static int aes_encrypt_final(crypto_ctx_t *, crypto_data_t *,
1300Sstevel@tonic-gate     crypto_req_handle_t);
1310Sstevel@tonic-gate static int aes_decrypt_final(crypto_ctx_t *, crypto_data_t *,
1320Sstevel@tonic-gate     crypto_req_handle_t);
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate static int aes_encrypt(crypto_ctx_t *, crypto_data_t *, crypto_data_t *,
1350Sstevel@tonic-gate     crypto_req_handle_t);
1360Sstevel@tonic-gate static int aes_encrypt_update(crypto_ctx_t *, crypto_data_t *,
1370Sstevel@tonic-gate     crypto_data_t *, crypto_req_handle_t);
1380Sstevel@tonic-gate static int aes_encrypt_atomic(crypto_provider_handle_t, crypto_session_id_t,
1390Sstevel@tonic-gate     crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
1400Sstevel@tonic-gate     crypto_data_t *, crypto_spi_ctx_template_t, crypto_req_handle_t);
1410Sstevel@tonic-gate 
1420Sstevel@tonic-gate static int aes_decrypt(crypto_ctx_t *, crypto_data_t *, crypto_data_t *,
1430Sstevel@tonic-gate     crypto_req_handle_t);
1440Sstevel@tonic-gate static int aes_decrypt_update(crypto_ctx_t *, crypto_data_t *,
1450Sstevel@tonic-gate     crypto_data_t *, crypto_req_handle_t);
1460Sstevel@tonic-gate static int aes_decrypt_atomic(crypto_provider_handle_t, crypto_session_id_t,
1470Sstevel@tonic-gate     crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
1480Sstevel@tonic-gate     crypto_data_t *, crypto_spi_ctx_template_t, crypto_req_handle_t);
1490Sstevel@tonic-gate 
1500Sstevel@tonic-gate static crypto_cipher_ops_t aes_cipher_ops = {
1514486Sktung 	aes_encrypt_init,
1520Sstevel@tonic-gate 	aes_encrypt,
1530Sstevel@tonic-gate 	aes_encrypt_update,
1540Sstevel@tonic-gate 	aes_encrypt_final,
1550Sstevel@tonic-gate 	aes_encrypt_atomic,
1564486Sktung 	aes_decrypt_init,
1570Sstevel@tonic-gate 	aes_decrypt,
1580Sstevel@tonic-gate 	aes_decrypt_update,
1590Sstevel@tonic-gate 	aes_decrypt_final,
1600Sstevel@tonic-gate 	aes_decrypt_atomic
1610Sstevel@tonic-gate };
1620Sstevel@tonic-gate 
1639339SMark.Powers@Sun.COM static int aes_mac_atomic(crypto_provider_handle_t, crypto_session_id_t,
1649339SMark.Powers@Sun.COM     crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, crypto_data_t *,
1659339SMark.Powers@Sun.COM     crypto_spi_ctx_template_t, crypto_req_handle_t);
1669339SMark.Powers@Sun.COM static int aes_mac_verify_atomic(crypto_provider_handle_t, crypto_session_id_t,
1679339SMark.Powers@Sun.COM     crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, crypto_data_t *,
1689339SMark.Powers@Sun.COM     crypto_spi_ctx_template_t, crypto_req_handle_t);
1699339SMark.Powers@Sun.COM 
1709339SMark.Powers@Sun.COM static crypto_mac_ops_t aes_mac_ops = {
1719339SMark.Powers@Sun.COM 	NULL,
1729339SMark.Powers@Sun.COM 	NULL,
1739339SMark.Powers@Sun.COM 	NULL,
1749339SMark.Powers@Sun.COM 	NULL,
1759339SMark.Powers@Sun.COM 	aes_mac_atomic,
1769339SMark.Powers@Sun.COM 	aes_mac_verify_atomic
1779339SMark.Powers@Sun.COM };
1789339SMark.Powers@Sun.COM 
1790Sstevel@tonic-gate static int aes_create_ctx_template(crypto_provider_handle_t,
1800Sstevel@tonic-gate     crypto_mechanism_t *, crypto_key_t *, crypto_spi_ctx_template_t *,
1810Sstevel@tonic-gate     size_t *, crypto_req_handle_t);
1820Sstevel@tonic-gate static int aes_free_context(crypto_ctx_t *);
1830Sstevel@tonic-gate 
1840Sstevel@tonic-gate static crypto_ctx_ops_t aes_ctx_ops = {
1850Sstevel@tonic-gate 	aes_create_ctx_template,
1860Sstevel@tonic-gate 	aes_free_context
1870Sstevel@tonic-gate };
1880Sstevel@tonic-gate 
18910732SAnthony.Scarpino@Sun.COM static void aes_POST(int *);
19010732SAnthony.Scarpino@Sun.COM 
19110732SAnthony.Scarpino@Sun.COM static crypto_fips140_ops_t aes_fips140_ops = {
19210732SAnthony.Scarpino@Sun.COM 	aes_POST
19310732SAnthony.Scarpino@Sun.COM };
19410732SAnthony.Scarpino@Sun.COM 
1950Sstevel@tonic-gate static crypto_ops_t aes_crypto_ops = {
1960Sstevel@tonic-gate 	&aes_control_ops,
1970Sstevel@tonic-gate 	NULL,
1980Sstevel@tonic-gate 	&aes_cipher_ops,
1999339SMark.Powers@Sun.COM 	&aes_mac_ops,
2000Sstevel@tonic-gate 	NULL,
2010Sstevel@tonic-gate 	NULL,
2020Sstevel@tonic-gate 	NULL,
2030Sstevel@tonic-gate 	NULL,
2040Sstevel@tonic-gate 	NULL,
2050Sstevel@tonic-gate 	NULL,
2060Sstevel@tonic-gate 	NULL,
2070Sstevel@tonic-gate 	NULL,
2080Sstevel@tonic-gate 	NULL,
20910732SAnthony.Scarpino@Sun.COM 	&aes_ctx_ops,
21010732SAnthony.Scarpino@Sun.COM 	NULL,
21110732SAnthony.Scarpino@Sun.COM 	NULL,
21210732SAnthony.Scarpino@Sun.COM 	&aes_fips140_ops
2130Sstevel@tonic-gate };
2140Sstevel@tonic-gate 
2150Sstevel@tonic-gate static crypto_provider_info_t aes_prov_info = {
21610732SAnthony.Scarpino@Sun.COM 	CRYPTO_SPI_VERSION_4,
2170Sstevel@tonic-gate 	"AES Software Provider",
2180Sstevel@tonic-gate 	CRYPTO_SW_PROVIDER,
2190Sstevel@tonic-gate 	{&modlinkage},
2200Sstevel@tonic-gate 	NULL,
2210Sstevel@tonic-gate 	&aes_crypto_ops,
2220Sstevel@tonic-gate 	sizeof (aes_mech_info_tab)/sizeof (crypto_mech_info_t),
2230Sstevel@tonic-gate 	aes_mech_info_tab
2240Sstevel@tonic-gate };
2250Sstevel@tonic-gate 
2260Sstevel@tonic-gate static crypto_kcf_provider_handle_t aes_prov_handle = NULL;
2279339SMark.Powers@Sun.COM static crypto_data_t null_crypto_data = { CRYPTO_DATA_RAW };
2280Sstevel@tonic-gate 
2290Sstevel@tonic-gate int
_init(void)2300Sstevel@tonic-gate _init(void)
2310Sstevel@tonic-gate {
2320Sstevel@tonic-gate 	int ret;
2330Sstevel@tonic-gate 
23411751SAnthony.Scarpino@Sun.COM 	if ((ret = mod_install(&modlinkage)) != 0)
23511751SAnthony.Scarpino@Sun.COM 		return (ret);
23611751SAnthony.Scarpino@Sun.COM 
23711751SAnthony.Scarpino@Sun.COM 	/* Register with KCF.  If the registration fails, remove the module. */
23811751SAnthony.Scarpino@Sun.COM 	if (crypto_register_provider(&aes_prov_info, &aes_prov_handle)) {
23911751SAnthony.Scarpino@Sun.COM 		(void) mod_remove(&modlinkage);
2400Sstevel@tonic-gate 		return (EACCES);
2410Sstevel@tonic-gate 	}
2420Sstevel@tonic-gate 
24311751SAnthony.Scarpino@Sun.COM 	return (0);
2440Sstevel@tonic-gate }
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate int
_fini(void)2470Sstevel@tonic-gate _fini(void)
2480Sstevel@tonic-gate {
24911751SAnthony.Scarpino@Sun.COM 	/* Unregister from KCF if module is registered */
2500Sstevel@tonic-gate 	if (aes_prov_handle != NULL) {
25111751SAnthony.Scarpino@Sun.COM 		if (crypto_unregister_provider(aes_prov_handle))
2520Sstevel@tonic-gate 			return (EBUSY);
25311751SAnthony.Scarpino@Sun.COM 
2540Sstevel@tonic-gate 		aes_prov_handle = NULL;
2550Sstevel@tonic-gate 	}
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate 	return (mod_remove(&modlinkage));
2580Sstevel@tonic-gate }
2590Sstevel@tonic-gate 
2600Sstevel@tonic-gate int
_info(struct modinfo * modinfop)2610Sstevel@tonic-gate _info(struct modinfo *modinfop)
2620Sstevel@tonic-gate {
2630Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
2640Sstevel@tonic-gate }
2650Sstevel@tonic-gate 
2660Sstevel@tonic-gate 
267991Smcpowers static int
aes_check_mech_param(crypto_mechanism_t * mechanism,aes_ctx_t ** ctx,int kmflag)2687188Smcpowers aes_check_mech_param(crypto_mechanism_t *mechanism, aes_ctx_t **ctx, int kmflag)
269991Smcpowers {
2707188Smcpowers 	void *p = NULL;
2719339SMark.Powers@Sun.COM 	boolean_t param_required = B_TRUE;
2729339SMark.Powers@Sun.COM 	size_t param_len;
2739339SMark.Powers@Sun.COM 	void *(*alloc_fun)(int);
274991Smcpowers 	int rv = CRYPTO_SUCCESS;
275991Smcpowers 
276991Smcpowers 	switch (mechanism->cm_type) {
277991Smcpowers 	case AES_ECB_MECH_INFO_TYPE:
2789339SMark.Powers@Sun.COM 		param_required = B_FALSE;
2799339SMark.Powers@Sun.COM 		alloc_fun = ecb_alloc_ctx;
280991Smcpowers 		break;
281991Smcpowers 	case AES_CBC_MECH_INFO_TYPE:
2829339SMark.Powers@Sun.COM 		param_len = AES_BLOCK_LEN;
2839339SMark.Powers@Sun.COM 		alloc_fun = cbc_alloc_ctx;
284991Smcpowers 		break;
285991Smcpowers 	case AES_CTR_MECH_INFO_TYPE:
2869339SMark.Powers@Sun.COM 		param_len = sizeof (CK_AES_CTR_PARAMS);
2879339SMark.Powers@Sun.COM 		alloc_fun = ctr_alloc_ctx;
288991Smcpowers 		break;
2894486Sktung 	case AES_CCM_MECH_INFO_TYPE:
2909339SMark.Powers@Sun.COM 		param_len = sizeof (CK_AES_CCM_PARAMS);
2919339SMark.Powers@Sun.COM 		alloc_fun = ccm_alloc_ctx;
2924486Sktung 		break;
2938005SMark.Powers@Sun.COM 	case AES_GCM_MECH_INFO_TYPE:
2949339SMark.Powers@Sun.COM 		param_len = sizeof (CK_AES_GCM_PARAMS);
2959339SMark.Powers@Sun.COM 		alloc_fun = gcm_alloc_ctx;
2969339SMark.Powers@Sun.COM 		break;
2979339SMark.Powers@Sun.COM 	case AES_GMAC_MECH_INFO_TYPE:
2989339SMark.Powers@Sun.COM 		param_len = sizeof (CK_AES_GMAC_PARAMS);
2999339SMark.Powers@Sun.COM 		alloc_fun = gmac_alloc_ctx;
3008005SMark.Powers@Sun.COM 		break;
301991Smcpowers 	default:
302991Smcpowers 		rv = CRYPTO_MECHANISM_INVALID;
303*12856SZdenek.Kotala@Sun.COM 		return (rv);
304991Smcpowers 	}
3059339SMark.Powers@Sun.COM 	if (param_required && mechanism->cm_param != NULL &&
3069339SMark.Powers@Sun.COM 	    mechanism->cm_param_len != param_len) {
3079339SMark.Powers@Sun.COM 		rv = CRYPTO_MECHANISM_PARAM_INVALID;
3089339SMark.Powers@Sun.COM 	}
3099339SMark.Powers@Sun.COM 	if (ctx != NULL) {
3109339SMark.Powers@Sun.COM 		p = (alloc_fun)(kmflag);
3117188Smcpowers 		*ctx = p;
3129339SMark.Powers@Sun.COM 	}
313991Smcpowers 	return (rv);
314991Smcpowers }
315991Smcpowers 
3161010Smcpowers /* EXPORT DELETE START */
3171010Smcpowers 
3180Sstevel@tonic-gate /*
3190Sstevel@tonic-gate  * Initialize key schedules for AES
3200Sstevel@tonic-gate  */
3210Sstevel@tonic-gate static int
init_keysched(crypto_key_t * key,void * newbie)3220Sstevel@tonic-gate init_keysched(crypto_key_t *key, void *newbie)
3230Sstevel@tonic-gate {
3240Sstevel@tonic-gate 	/*
3250Sstevel@tonic-gate 	 * Only keys by value are supported by this module.
3260Sstevel@tonic-gate 	 */
3270Sstevel@tonic-gate 	switch (key->ck_format) {
3280Sstevel@tonic-gate 	case CRYPTO_KEY_RAW:
3290Sstevel@tonic-gate 		if (key->ck_length < AES_MINBITS ||
3300Sstevel@tonic-gate 		    key->ck_length > AES_MAXBITS) {
3310Sstevel@tonic-gate 			return (CRYPTO_KEY_SIZE_RANGE);
3320Sstevel@tonic-gate 		}
3330Sstevel@tonic-gate 
3340Sstevel@tonic-gate 		/* key length must be either 128, 192, or 256 */
3350Sstevel@tonic-gate 		if ((key->ck_length & 63) != 0)
3360Sstevel@tonic-gate 			return (CRYPTO_KEY_SIZE_RANGE);
3370Sstevel@tonic-gate 		break;
3380Sstevel@tonic-gate 	default:
3390Sstevel@tonic-gate 		return (CRYPTO_KEY_TYPE_INCONSISTENT);
3400Sstevel@tonic-gate 	}
3410Sstevel@tonic-gate 
3420Sstevel@tonic-gate 	aes_init_keysched(key->ck_data, key->ck_length, newbie);
3430Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
3440Sstevel@tonic-gate }
3450Sstevel@tonic-gate 
3460Sstevel@tonic-gate /* EXPORT DELETE END */
3470Sstevel@tonic-gate 
3480Sstevel@tonic-gate /*
3490Sstevel@tonic-gate  * KCF software provider control entry points.
3500Sstevel@tonic-gate  */
3510Sstevel@tonic-gate /* ARGSUSED */
3520Sstevel@tonic-gate static void
aes_provider_status(crypto_provider_handle_t provider,uint_t * status)3530Sstevel@tonic-gate aes_provider_status(crypto_provider_handle_t provider, uint_t *status)
3540Sstevel@tonic-gate {
3550Sstevel@tonic-gate 	*status = CRYPTO_PROVIDER_READY;
3560Sstevel@tonic-gate }
3570Sstevel@tonic-gate 
3584486Sktung static int
aes_encrypt_init(crypto_ctx_t * ctx,crypto_mechanism_t * mechanism,crypto_key_t * key,crypto_spi_ctx_template_t template,crypto_req_handle_t req)3594486Sktung aes_encrypt_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
3604486Sktung     crypto_key_t *key, crypto_spi_ctx_template_t template,
3614486Sktung     crypto_req_handle_t req) {
3624486Sktung 	return (aes_common_init(ctx, mechanism, key, template, req, B_TRUE));
3634486Sktung }
3644486Sktung 
3654486Sktung static int
aes_decrypt_init(crypto_ctx_t * ctx,crypto_mechanism_t * mechanism,crypto_key_t * key,crypto_spi_ctx_template_t template,crypto_req_handle_t req)3664486Sktung aes_decrypt_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
3674486Sktung     crypto_key_t *key, crypto_spi_ctx_template_t template,
3684486Sktung     crypto_req_handle_t req) {
3694486Sktung 	return (aes_common_init(ctx, mechanism, key, template, req, B_FALSE));
3704486Sktung }
3714486Sktung 
3724486Sktung 
3734486Sktung 
3740Sstevel@tonic-gate /*
3750Sstevel@tonic-gate  * KCF software provider encrypt entry points.
3760Sstevel@tonic-gate  */
3770Sstevel@tonic-gate static int
aes_common_init(crypto_ctx_t * ctx,crypto_mechanism_t * mechanism,crypto_key_t * key,crypto_spi_ctx_template_t template,crypto_req_handle_t req,boolean_t is_encrypt_init)3780Sstevel@tonic-gate aes_common_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
3790Sstevel@tonic-gate     crypto_key_t *key, crypto_spi_ctx_template_t template,
3804486Sktung     crypto_req_handle_t req, boolean_t is_encrypt_init)
3810Sstevel@tonic-gate {
3820Sstevel@tonic-gate 
3830Sstevel@tonic-gate /* EXPORT DELETE START */
3840Sstevel@tonic-gate 
3850Sstevel@tonic-gate 	aes_ctx_t *aes_ctx;
3860Sstevel@tonic-gate 	int rv;
3870Sstevel@tonic-gate 	int kmflag;
3880Sstevel@tonic-gate 
3890Sstevel@tonic-gate 	/*
3900Sstevel@tonic-gate 	 * Only keys by value are supported by this module.
3910Sstevel@tonic-gate 	 */
3920Sstevel@tonic-gate 	if (key->ck_format != CRYPTO_KEY_RAW) {
3930Sstevel@tonic-gate 		return (CRYPTO_KEY_TYPE_INCONSISTENT);
3940Sstevel@tonic-gate 	}
3950Sstevel@tonic-gate 
3967188Smcpowers 	kmflag = crypto_kmflag(req);
3977188Smcpowers 	if ((rv = aes_check_mech_param(mechanism, &aes_ctx, kmflag))
3987188Smcpowers 	    != CRYPTO_SUCCESS)
399991Smcpowers 		return (rv);
4000Sstevel@tonic-gate 
4014486Sktung 	rv = aes_common_init_ctx(aes_ctx, template, mechanism, key, kmflag,
4024486Sktung 	    is_encrypt_init);
4030Sstevel@tonic-gate 	if (rv != CRYPTO_SUCCESS) {
4047188Smcpowers 		crypto_free_mode_ctx(aes_ctx);
4050Sstevel@tonic-gate 		return (rv);
4060Sstevel@tonic-gate 	}
4070Sstevel@tonic-gate 
4080Sstevel@tonic-gate 	ctx->cc_provider_private = aes_ctx;
4090Sstevel@tonic-gate 
4100Sstevel@tonic-gate /* EXPORT DELETE END */
4110Sstevel@tonic-gate 
4120Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
4130Sstevel@tonic-gate }
4140Sstevel@tonic-gate 
4157188Smcpowers static void
aes_copy_block64(uint8_t * in,uint64_t * out)4167188Smcpowers aes_copy_block64(uint8_t *in, uint64_t *out)
4170Sstevel@tonic-gate {
4187188Smcpowers 	if (IS_P2ALIGNED(in, sizeof (uint64_t))) {
4197188Smcpowers 		/* LINTED: pointer alignment */
4207188Smcpowers 		out[0] = *(uint64_t *)&in[0];
4217188Smcpowers 		/* LINTED: pointer alignment */
4227188Smcpowers 		out[1] = *(uint64_t *)&in[8];
4237188Smcpowers 	} else {
4247188Smcpowers 		uint8_t *iv8 = (uint8_t *)&out[0];
4250Sstevel@tonic-gate 
4267188Smcpowers 		AES_COPY_BLOCK(in, iv8);
4270Sstevel@tonic-gate 	}
4280Sstevel@tonic-gate }
4290Sstevel@tonic-gate 
4309392Sopensolaris@drydog.com 
4310Sstevel@tonic-gate static int
aes_encrypt(crypto_ctx_t * ctx,crypto_data_t * plaintext,crypto_data_t * ciphertext,crypto_req_handle_t req)4320Sstevel@tonic-gate aes_encrypt(crypto_ctx_t *ctx, crypto_data_t *plaintext,
4330Sstevel@tonic-gate     crypto_data_t *ciphertext, crypto_req_handle_t req)
4340Sstevel@tonic-gate {
4350Sstevel@tonic-gate 	int ret = CRYPTO_FAILED;
4360Sstevel@tonic-gate 
4370Sstevel@tonic-gate /* EXPORT DELETE START */
4380Sstevel@tonic-gate 
4390Sstevel@tonic-gate 	aes_ctx_t *aes_ctx;
4404486Sktung 	size_t saved_length, saved_offset, length_needed;
4410Sstevel@tonic-gate 
4420Sstevel@tonic-gate 	ASSERT(ctx->cc_provider_private != NULL);
4430Sstevel@tonic-gate 	aes_ctx = ctx->cc_provider_private;
4440Sstevel@tonic-gate 
445904Smcpowers 	/*
446904Smcpowers 	 * For block ciphers, plaintext must be a multiple of AES block size.
447904Smcpowers 	 * This test is only valid for ciphers whose blocksize is a power of 2.
448904Smcpowers 	 */
4499339SMark.Powers@Sun.COM 	if (((aes_ctx->ac_flags & (CTR_MODE|CCM_MODE|GCM_MODE|GMAC_MODE))
4509339SMark.Powers@Sun.COM 	    == 0) && (plaintext->cd_length & (AES_BLOCK_LEN - 1)) != 0)
451904Smcpowers 		return (CRYPTO_DATA_LEN_RANGE);
452904Smcpowers 
4530Sstevel@tonic-gate 	AES_ARG_INPLACE(plaintext, ciphertext);
4540Sstevel@tonic-gate 
4550Sstevel@tonic-gate 	/*
4560Sstevel@tonic-gate 	 * We need to just return the length needed to store the output.
4570Sstevel@tonic-gate 	 * We should not destroy the context for the following case.
4580Sstevel@tonic-gate 	 */
4599339SMark.Powers@Sun.COM 	switch (aes_ctx->ac_flags & (CCM_MODE|GCM_MODE|GMAC_MODE)) {
4609339SMark.Powers@Sun.COM 	case CCM_MODE:
4617188Smcpowers 		length_needed = plaintext->cd_length + aes_ctx->ac_mac_len;
4629339SMark.Powers@Sun.COM 		break;
4639339SMark.Powers@Sun.COM 	case GCM_MODE:
4648195SMark.Powers@Sun.COM 		length_needed = plaintext->cd_length + aes_ctx->ac_tag_len;
4659339SMark.Powers@Sun.COM 		break;
4669339SMark.Powers@Sun.COM 	case GMAC_MODE:
4679339SMark.Powers@Sun.COM 		if (plaintext->cd_length != 0)
4689339SMark.Powers@Sun.COM 			return (CRYPTO_ARGUMENTS_BAD);
4699339SMark.Powers@Sun.COM 
4709339SMark.Powers@Sun.COM 		length_needed = aes_ctx->ac_tag_len;
4719339SMark.Powers@Sun.COM 		break;
4729339SMark.Powers@Sun.COM 	default:
4734486Sktung 		length_needed = plaintext->cd_length;
4744486Sktung 	}
4754486Sktung 
4764486Sktung 	if (ciphertext->cd_length < length_needed) {
4774486Sktung 		ciphertext->cd_length = length_needed;
4780Sstevel@tonic-gate 		return (CRYPTO_BUFFER_TOO_SMALL);
4790Sstevel@tonic-gate 	}
4800Sstevel@tonic-gate 
4814486Sktung 	saved_length = ciphertext->cd_length;
4824486Sktung 	saved_offset = ciphertext->cd_offset;
4834486Sktung 
4840Sstevel@tonic-gate 	/*
4850Sstevel@tonic-gate 	 * Do an update on the specified input data.
4860Sstevel@tonic-gate 	 */
4870Sstevel@tonic-gate 	ret = aes_encrypt_update(ctx, plaintext, ciphertext, req);
4884486Sktung 	if (ret != CRYPTO_SUCCESS) {
4894486Sktung 		return (ret);
4904486Sktung 	}
4914486Sktung 
4924486Sktung 	/*
4934486Sktung 	 * For CCM mode, aes_ccm_encrypt_final() will take care of any
4944486Sktung 	 * left-over unprocessed data, and compute the MAC
4954486Sktung 	 */
4967188Smcpowers 	if (aes_ctx->ac_flags & CCM_MODE) {
4974486Sktung 		/*
4988005SMark.Powers@Sun.COM 		 * ccm_encrypt_final() will compute the MAC and append
4994486Sktung 		 * it to existing ciphertext. So, need to adjust the left over
5004486Sktung 		 * length value accordingly
5014486Sktung 		 */
5024486Sktung 
5034486Sktung 		/* order of following 2 lines MUST not be reversed */
5044486Sktung 		ciphertext->cd_offset = ciphertext->cd_length;
5054486Sktung 		ciphertext->cd_length = saved_length - ciphertext->cd_length;
5067188Smcpowers 		ret = ccm_encrypt_final((ccm_ctx_t *)aes_ctx, ciphertext,
5077188Smcpowers 		    AES_BLOCK_LEN, aes_encrypt_block, aes_xor_block);
5084486Sktung 		if (ret != CRYPTO_SUCCESS) {
5094486Sktung 			return (ret);
5104486Sktung 		}
5114486Sktung 
5124486Sktung 		if (plaintext != ciphertext) {
5134486Sktung 			ciphertext->cd_length =
5144486Sktung 			    ciphertext->cd_offset - saved_offset;
5154486Sktung 		}
5164486Sktung 		ciphertext->cd_offset = saved_offset;
5179339SMark.Powers@Sun.COM 	} else if (aes_ctx->ac_flags & (GCM_MODE|GMAC_MODE)) {
5188005SMark.Powers@Sun.COM 		/*
5198005SMark.Powers@Sun.COM 		 * gcm_encrypt_final() will compute the MAC and append
5208005SMark.Powers@Sun.COM 		 * it to existing ciphertext. So, need to adjust the left over
5218005SMark.Powers@Sun.COM 		 * length value accordingly
5228005SMark.Powers@Sun.COM 		 */
5238005SMark.Powers@Sun.COM 
5248005SMark.Powers@Sun.COM 		/* order of following 2 lines MUST not be reversed */
5258005SMark.Powers@Sun.COM 		ciphertext->cd_offset = ciphertext->cd_length;
5268005SMark.Powers@Sun.COM 		ciphertext->cd_length = saved_length - ciphertext->cd_length;
5278005SMark.Powers@Sun.COM 		ret = gcm_encrypt_final((gcm_ctx_t *)aes_ctx, ciphertext,
5288005SMark.Powers@Sun.COM 		    AES_BLOCK_LEN, aes_encrypt_block, aes_copy_block,
5298005SMark.Powers@Sun.COM 		    aes_xor_block);
5308005SMark.Powers@Sun.COM 		if (ret != CRYPTO_SUCCESS) {
5318005SMark.Powers@Sun.COM 			return (ret);
5328005SMark.Powers@Sun.COM 		}
5338005SMark.Powers@Sun.COM 
5348005SMark.Powers@Sun.COM 		if (plaintext != ciphertext) {
5358005SMark.Powers@Sun.COM 			ciphertext->cd_length =
5368005SMark.Powers@Sun.COM 			    ciphertext->cd_offset - saved_offset;
5378005SMark.Powers@Sun.COM 		}
5388005SMark.Powers@Sun.COM 		ciphertext->cd_offset = saved_offset;
5394486Sktung 	}
5404486Sktung 
5410Sstevel@tonic-gate 	ASSERT(aes_ctx->ac_remainder_len == 0);
5420Sstevel@tonic-gate 	(void) aes_free_context(ctx);
5430Sstevel@tonic-gate 
5440Sstevel@tonic-gate /* EXPORT DELETE END */
5450Sstevel@tonic-gate 
5460Sstevel@tonic-gate 	return (ret);
5470Sstevel@tonic-gate }
5480Sstevel@tonic-gate 
5499392Sopensolaris@drydog.com 
5500Sstevel@tonic-gate static int
aes_decrypt(crypto_ctx_t * ctx,crypto_data_t * ciphertext,crypto_data_t * plaintext,crypto_req_handle_t req)5510Sstevel@tonic-gate aes_decrypt(crypto_ctx_t *ctx, crypto_data_t *ciphertext,
5520Sstevel@tonic-gate     crypto_data_t *plaintext, crypto_req_handle_t req)
5530Sstevel@tonic-gate {
5540Sstevel@tonic-gate 	int ret = CRYPTO_FAILED;
5550Sstevel@tonic-gate 
5560Sstevel@tonic-gate /* EXPORT DELETE START */
5570Sstevel@tonic-gate 
5580Sstevel@tonic-gate 	aes_ctx_t *aes_ctx;
5594486Sktung 	off_t saved_offset;
5609339SMark.Powers@Sun.COM 	size_t saved_length, length_needed;
5610Sstevel@tonic-gate 
5620Sstevel@tonic-gate 	ASSERT(ctx->cc_provider_private != NULL);
5630Sstevel@tonic-gate 	aes_ctx = ctx->cc_provider_private;
5640Sstevel@tonic-gate 
565904Smcpowers 	/*
5664486Sktung 	 * For block ciphers, plaintext must be a multiple of AES block size.
567904Smcpowers 	 * This test is only valid for ciphers whose blocksize is a power of 2.
568904Smcpowers 	 */
5699339SMark.Powers@Sun.COM 	if (((aes_ctx->ac_flags & (CTR_MODE|CCM_MODE|GCM_MODE|GMAC_MODE))
5709339SMark.Powers@Sun.COM 	    == 0) && (ciphertext->cd_length & (AES_BLOCK_LEN - 1)) != 0) {
5714558Sktung 		return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE);
5724558Sktung 	}
573904Smcpowers 
5740Sstevel@tonic-gate 	AES_ARG_INPLACE(ciphertext, plaintext);
5750Sstevel@tonic-gate 
5760Sstevel@tonic-gate 	/*
5779339SMark.Powers@Sun.COM 	 * Return length needed to store the output.
5789339SMark.Powers@Sun.COM 	 * Do not destroy context when plaintext buffer is too small.
5794486Sktung 	 *
5809339SMark.Powers@Sun.COM 	 * CCM:  plaintext is MAC len smaller than cipher text
5819339SMark.Powers@Sun.COM 	 * GCM:  plaintext is TAG len smaller than cipher text
5829339SMark.Powers@Sun.COM 	 * GMAC: plaintext length must be zero
5830Sstevel@tonic-gate 	 */
5849339SMark.Powers@Sun.COM 	switch (aes_ctx->ac_flags & (CCM_MODE|GCM_MODE|GMAC_MODE)) {
5859339SMark.Powers@Sun.COM 	case CCM_MODE:
5869339SMark.Powers@Sun.COM 		length_needed = aes_ctx->ac_processed_data_len;
5879339SMark.Powers@Sun.COM 		break;
5889339SMark.Powers@Sun.COM 	case GCM_MODE:
5899339SMark.Powers@Sun.COM 		length_needed = ciphertext->cd_length - aes_ctx->ac_tag_len;
5909339SMark.Powers@Sun.COM 		break;
5919339SMark.Powers@Sun.COM 	case GMAC_MODE:
5929339SMark.Powers@Sun.COM 		if (plaintext->cd_length != 0)
5939339SMark.Powers@Sun.COM 			return (CRYPTO_ARGUMENTS_BAD);
5948005SMark.Powers@Sun.COM 
5959339SMark.Powers@Sun.COM 		length_needed = 0;
5969339SMark.Powers@Sun.COM 		break;
5979339SMark.Powers@Sun.COM 	default:
5989339SMark.Powers@Sun.COM 		length_needed = ciphertext->cd_length;
5999339SMark.Powers@Sun.COM 	}
6009339SMark.Powers@Sun.COM 
6019339SMark.Powers@Sun.COM 	if (plaintext->cd_length < length_needed) {
6029339SMark.Powers@Sun.COM 		plaintext->cd_length = length_needed;
6030Sstevel@tonic-gate 		return (CRYPTO_BUFFER_TOO_SMALL);
6040Sstevel@tonic-gate 	}
6050Sstevel@tonic-gate 
6069339SMark.Powers@Sun.COM 	saved_offset = plaintext->cd_offset;
6079339SMark.Powers@Sun.COM 	saved_length = plaintext->cd_length;
6089339SMark.Powers@Sun.COM 
6090Sstevel@tonic-gate 	/*
6100Sstevel@tonic-gate 	 * Do an update on the specified input data.
6110Sstevel@tonic-gate 	 */
6120Sstevel@tonic-gate 	ret = aes_decrypt_update(ctx, ciphertext, plaintext, req);
6134486Sktung 	if (ret != CRYPTO_SUCCESS) {
6144486Sktung 		goto cleanup;
6154486Sktung 	}
6164486Sktung 
6177188Smcpowers 	if (aes_ctx->ac_flags & CCM_MODE) {
6187188Smcpowers 		ASSERT(aes_ctx->ac_processed_data_len == aes_ctx->ac_data_len);
6197188Smcpowers 		ASSERT(aes_ctx->ac_processed_mac_len == aes_ctx->ac_mac_len);
6204486Sktung 
6214486Sktung 		/* order of following 2 lines MUST not be reversed */
6224486Sktung 		plaintext->cd_offset = plaintext->cd_length;
6234486Sktung 		plaintext->cd_length = saved_length - plaintext->cd_length;
6244486Sktung 
6257188Smcpowers 		ret = ccm_decrypt_final((ccm_ctx_t *)aes_ctx, plaintext,
6267188Smcpowers 		    AES_BLOCK_LEN, aes_encrypt_block, aes_copy_block,
6277188Smcpowers 		    aes_xor_block);
6284486Sktung 		if (ret == CRYPTO_SUCCESS) {
6294486Sktung 			if (plaintext != ciphertext) {
6304486Sktung 				plaintext->cd_length =
6314486Sktung 				    plaintext->cd_offset - saved_offset;
6324486Sktung 			}
6334486Sktung 		} else {
6344486Sktung 			plaintext->cd_length = saved_length;
6354486Sktung 		}
6364486Sktung 
6374486Sktung 		plaintext->cd_offset = saved_offset;
6389339SMark.Powers@Sun.COM 	} else if (aes_ctx->ac_flags & (GCM_MODE|GMAC_MODE)) {
6398005SMark.Powers@Sun.COM 		/* order of following 2 lines MUST not be reversed */
6408005SMark.Powers@Sun.COM 		plaintext->cd_offset = plaintext->cd_length;
6418005SMark.Powers@Sun.COM 		plaintext->cd_length = saved_length - plaintext->cd_length;
6428005SMark.Powers@Sun.COM 
6438005SMark.Powers@Sun.COM 		ret = gcm_decrypt_final((gcm_ctx_t *)aes_ctx, plaintext,
6448005SMark.Powers@Sun.COM 		    AES_BLOCK_LEN, aes_encrypt_block, aes_xor_block);
6458005SMark.Powers@Sun.COM 		if (ret == CRYPTO_SUCCESS) {
6468005SMark.Powers@Sun.COM 			if (plaintext != ciphertext) {
6478005SMark.Powers@Sun.COM 				plaintext->cd_length =
6488005SMark.Powers@Sun.COM 				    plaintext->cd_offset - saved_offset;
6498005SMark.Powers@Sun.COM 			}
6508005SMark.Powers@Sun.COM 		} else {
6518005SMark.Powers@Sun.COM 			plaintext->cd_length = saved_length;
6528005SMark.Powers@Sun.COM 		}
6538005SMark.Powers@Sun.COM 
6548005SMark.Powers@Sun.COM 		plaintext->cd_offset = saved_offset;
6554486Sktung 	}
6564486Sktung 
6570Sstevel@tonic-gate 	ASSERT(aes_ctx->ac_remainder_len == 0);
6584486Sktung 
6594486Sktung cleanup:
6600Sstevel@tonic-gate 	(void) aes_free_context(ctx);
6610Sstevel@tonic-gate 
6620Sstevel@tonic-gate /* EXPORT DELETE END */
6630Sstevel@tonic-gate 
6640Sstevel@tonic-gate 	return (ret);
6650Sstevel@tonic-gate }
6660Sstevel@tonic-gate 
6679392Sopensolaris@drydog.com 
6680Sstevel@tonic-gate /* ARGSUSED */
6690Sstevel@tonic-gate static int
aes_encrypt_update(crypto_ctx_t * ctx,crypto_data_t * plaintext,crypto_data_t * ciphertext,crypto_req_handle_t req)6700Sstevel@tonic-gate aes_encrypt_update(crypto_ctx_t *ctx, crypto_data_t *plaintext,
6710Sstevel@tonic-gate     crypto_data_t *ciphertext, crypto_req_handle_t req)
6720Sstevel@tonic-gate {
6730Sstevel@tonic-gate 	off_t saved_offset;
6740Sstevel@tonic-gate 	size_t saved_length, out_len;
6750Sstevel@tonic-gate 	int ret = CRYPTO_SUCCESS;
676904Smcpowers 	aes_ctx_t *aes_ctx;
6770Sstevel@tonic-gate 
6780Sstevel@tonic-gate 	ASSERT(ctx->cc_provider_private != NULL);
6797188Smcpowers 	aes_ctx = ctx->cc_provider_private;
6800Sstevel@tonic-gate 
6810Sstevel@tonic-gate 	AES_ARG_INPLACE(plaintext, ciphertext);
6820Sstevel@tonic-gate 
6830Sstevel@tonic-gate 	/* compute number of bytes that will hold the ciphertext */
6847188Smcpowers 	out_len = aes_ctx->ac_remainder_len;
6850Sstevel@tonic-gate 	out_len += plaintext->cd_length;
6860Sstevel@tonic-gate 	out_len &= ~(AES_BLOCK_LEN - 1);
6870Sstevel@tonic-gate 
6880Sstevel@tonic-gate 	/* return length needed to store the output */
6890Sstevel@tonic-gate 	if (ciphertext->cd_length < out_len) {
6900Sstevel@tonic-gate 		ciphertext->cd_length = out_len;
6910Sstevel@tonic-gate 		return (CRYPTO_BUFFER_TOO_SMALL);
6920Sstevel@tonic-gate 	}
6930Sstevel@tonic-gate 
6940Sstevel@tonic-gate 	saved_offset = ciphertext->cd_offset;
6950Sstevel@tonic-gate 	saved_length = ciphertext->cd_length;
6960Sstevel@tonic-gate 
6970Sstevel@tonic-gate 	/*
6980Sstevel@tonic-gate 	 * Do the AES update on the specified input data.
6990Sstevel@tonic-gate 	 */
7000Sstevel@tonic-gate 	switch (plaintext->cd_format) {
7010Sstevel@tonic-gate 	case CRYPTO_DATA_RAW:
7027188Smcpowers 		ret = crypto_update_iov(ctx->cc_provider_private,
7037188Smcpowers 		    plaintext, ciphertext, aes_encrypt_contiguous_blocks,
7047188Smcpowers 		    aes_copy_block64);
7050Sstevel@tonic-gate 		break;
7060Sstevel@tonic-gate 	case CRYPTO_DATA_UIO:
7077188Smcpowers 		ret = crypto_update_uio(ctx->cc_provider_private,
7087188Smcpowers 		    plaintext, ciphertext, aes_encrypt_contiguous_blocks,
7097188Smcpowers 		    aes_copy_block64);
7100Sstevel@tonic-gate 		break;
7110Sstevel@tonic-gate 	case CRYPTO_DATA_MBLK:
7127188Smcpowers 		ret = crypto_update_mp(ctx->cc_provider_private,
7137188Smcpowers 		    plaintext, ciphertext, aes_encrypt_contiguous_blocks,
7147188Smcpowers 		    aes_copy_block64);
7150Sstevel@tonic-gate 		break;
7160Sstevel@tonic-gate 	default:
7170Sstevel@tonic-gate 		ret = CRYPTO_ARGUMENTS_BAD;
7180Sstevel@tonic-gate 	}
7190Sstevel@tonic-gate 
720904Smcpowers 	/*
721904Smcpowers 	 * Since AES counter mode is a stream cipher, we call
7227188Smcpowers 	 * ctr_mode_final() to pick up any remaining bytes.
723904Smcpowers 	 * It is an internal function that does not destroy
724904Smcpowers 	 * the context like *normal* final routines.
725904Smcpowers 	 */
7267188Smcpowers 	if ((aes_ctx->ac_flags & CTR_MODE) && (aes_ctx->ac_remainder_len > 0)) {
7277188Smcpowers 		ret = ctr_mode_final((ctr_ctx_t *)aes_ctx,
7287188Smcpowers 		    ciphertext, aes_encrypt_block);
729904Smcpowers 	}
730904Smcpowers 
7310Sstevel@tonic-gate 	if (ret == CRYPTO_SUCCESS) {
7320Sstevel@tonic-gate 		if (plaintext != ciphertext)
7330Sstevel@tonic-gate 			ciphertext->cd_length =
7340Sstevel@tonic-gate 			    ciphertext->cd_offset - saved_offset;
7350Sstevel@tonic-gate 	} else {
7360Sstevel@tonic-gate 		ciphertext->cd_length = saved_length;
7370Sstevel@tonic-gate 	}
7380Sstevel@tonic-gate 	ciphertext->cd_offset = saved_offset;
7390Sstevel@tonic-gate 
7400Sstevel@tonic-gate 	return (ret);
7410Sstevel@tonic-gate }
7420Sstevel@tonic-gate 
7439392Sopensolaris@drydog.com 
7440Sstevel@tonic-gate static int
aes_decrypt_update(crypto_ctx_t * ctx,crypto_data_t * ciphertext,crypto_data_t * plaintext,crypto_req_handle_t req)7450Sstevel@tonic-gate aes_decrypt_update(crypto_ctx_t *ctx, crypto_data_t *ciphertext,
7460Sstevel@tonic-gate     crypto_data_t *plaintext, crypto_req_handle_t req)
7470Sstevel@tonic-gate {
7480Sstevel@tonic-gate 	off_t saved_offset;
7490Sstevel@tonic-gate 	size_t saved_length, out_len;
7500Sstevel@tonic-gate 	int ret = CRYPTO_SUCCESS;
751904Smcpowers 	aes_ctx_t *aes_ctx;
7520Sstevel@tonic-gate 
7530Sstevel@tonic-gate 	ASSERT(ctx->cc_provider_private != NULL);
7547188Smcpowers 	aes_ctx = ctx->cc_provider_private;
7550Sstevel@tonic-gate 
7560Sstevel@tonic-gate 	AES_ARG_INPLACE(ciphertext, plaintext);
7570Sstevel@tonic-gate 
7588005SMark.Powers@Sun.COM 	/*
7598005SMark.Powers@Sun.COM 	 * Compute number of bytes that will hold the plaintext.
7609339SMark.Powers@Sun.COM 	 * This is not necessary for CCM, GCM, and GMAC since these
7619339SMark.Powers@Sun.COM 	 * mechanisms never return plaintext for update operations.
7628005SMark.Powers@Sun.COM 	 */
7639339SMark.Powers@Sun.COM 	if ((aes_ctx->ac_flags & (CCM_MODE|GCM_MODE|GMAC_MODE)) == 0) {
7648005SMark.Powers@Sun.COM 		out_len = aes_ctx->ac_remainder_len;
7658005SMark.Powers@Sun.COM 		out_len += ciphertext->cd_length;
7668005SMark.Powers@Sun.COM 		out_len &= ~(AES_BLOCK_LEN - 1);
7670Sstevel@tonic-gate 
7688005SMark.Powers@Sun.COM 		/* return length needed to store the output */
7698005SMark.Powers@Sun.COM 		if (plaintext->cd_length < out_len) {
7708005SMark.Powers@Sun.COM 			plaintext->cd_length = out_len;
7718005SMark.Powers@Sun.COM 			return (CRYPTO_BUFFER_TOO_SMALL);
7728005SMark.Powers@Sun.COM 		}
7730Sstevel@tonic-gate 	}
7740Sstevel@tonic-gate 
7750Sstevel@tonic-gate 	saved_offset = plaintext->cd_offset;
7760Sstevel@tonic-gate 	saved_length = plaintext->cd_length;
7770Sstevel@tonic-gate 
7789339SMark.Powers@Sun.COM 	if (aes_ctx->ac_flags & (GCM_MODE|GMAC_MODE))
7798005SMark.Powers@Sun.COM 		gcm_set_kmflag((gcm_ctx_t *)aes_ctx, crypto_kmflag(req));
7808005SMark.Powers@Sun.COM 
7810Sstevel@tonic-gate 	/*
7820Sstevel@tonic-gate 	 * Do the AES update on the specified input data.
7830Sstevel@tonic-gate 	 */
7840Sstevel@tonic-gate 	switch (ciphertext->cd_format) {
7850Sstevel@tonic-gate 	case CRYPTO_DATA_RAW:
7867188Smcpowers 		ret = crypto_update_iov(ctx->cc_provider_private,
7877188Smcpowers 		    ciphertext, plaintext, aes_decrypt_contiguous_blocks,
7887188Smcpowers 		    aes_copy_block64);
7890Sstevel@tonic-gate 		break;
7900Sstevel@tonic-gate 	case CRYPTO_DATA_UIO:
7917188Smcpowers 		ret = crypto_update_uio(ctx->cc_provider_private,
7927188Smcpowers 		    ciphertext, plaintext, aes_decrypt_contiguous_blocks,
7937188Smcpowers 		    aes_copy_block64);
7940Sstevel@tonic-gate 		break;
7950Sstevel@tonic-gate 	case CRYPTO_DATA_MBLK:
7967188Smcpowers 		ret = crypto_update_mp(ctx->cc_provider_private,
7977188Smcpowers 		    ciphertext, plaintext, aes_decrypt_contiguous_blocks,
7987188Smcpowers 		    aes_copy_block64);
7990Sstevel@tonic-gate 		break;
8000Sstevel@tonic-gate 	default:
8010Sstevel@tonic-gate 		ret = CRYPTO_ARGUMENTS_BAD;
8020Sstevel@tonic-gate 	}
8030Sstevel@tonic-gate 
804904Smcpowers 	/*
805904Smcpowers 	 * Since AES counter mode is a stream cipher, we call
8067188Smcpowers 	 * ctr_mode_final() to pick up any remaining bytes.
807904Smcpowers 	 * It is an internal function that does not destroy
808904Smcpowers 	 * the context like *normal* final routines.
809904Smcpowers 	 */
8107188Smcpowers 	if ((aes_ctx->ac_flags & CTR_MODE) && (aes_ctx->ac_remainder_len > 0)) {
8117188Smcpowers 		ret = ctr_mode_final((ctr_ctx_t *)aes_ctx, plaintext,
8127188Smcpowers 		    aes_encrypt_block);
8137188Smcpowers 		if (ret == CRYPTO_DATA_LEN_RANGE)
8147188Smcpowers 			ret = CRYPTO_ENCRYPTED_DATA_LEN_RANGE;
815904Smcpowers 	}
816904Smcpowers 
8170Sstevel@tonic-gate 	if (ret == CRYPTO_SUCCESS) {
8180Sstevel@tonic-gate 		if (ciphertext != plaintext)
8190Sstevel@tonic-gate 			plaintext->cd_length =
8200Sstevel@tonic-gate 			    plaintext->cd_offset - saved_offset;
8210Sstevel@tonic-gate 	} else {
8220Sstevel@tonic-gate 		plaintext->cd_length = saved_length;
8230Sstevel@tonic-gate 	}
8240Sstevel@tonic-gate 	plaintext->cd_offset = saved_offset;
8250Sstevel@tonic-gate 
826904Smcpowers 
8270Sstevel@tonic-gate 	return (ret);
8280Sstevel@tonic-gate }
8290Sstevel@tonic-gate 
8300Sstevel@tonic-gate /* ARGSUSED */
8310Sstevel@tonic-gate static int
aes_encrypt_final(crypto_ctx_t * ctx,crypto_data_t * data,crypto_req_handle_t req)8320Sstevel@tonic-gate aes_encrypt_final(crypto_ctx_t *ctx, crypto_data_t *data,
8330Sstevel@tonic-gate     crypto_req_handle_t req)
8340Sstevel@tonic-gate {
8350Sstevel@tonic-gate 
8360Sstevel@tonic-gate /* EXPORT DELETE START */
8370Sstevel@tonic-gate 
8380Sstevel@tonic-gate 	aes_ctx_t *aes_ctx;
839904Smcpowers 	int ret;
8400Sstevel@tonic-gate 
8410Sstevel@tonic-gate 	ASSERT(ctx->cc_provider_private != NULL);
8420Sstevel@tonic-gate 	aes_ctx = ctx->cc_provider_private;
8430Sstevel@tonic-gate 
844904Smcpowers 	if (data->cd_format != CRYPTO_DATA_RAW &&
845904Smcpowers 	    data->cd_format != CRYPTO_DATA_UIO &&
846904Smcpowers 	    data->cd_format != CRYPTO_DATA_MBLK) {
847904Smcpowers 		return (CRYPTO_ARGUMENTS_BAD);
848904Smcpowers 	}
849904Smcpowers 
8507188Smcpowers 	if (aes_ctx->ac_flags & CTR_MODE) {
8514486Sktung 		if (aes_ctx->ac_remainder_len > 0) {
8527188Smcpowers 			ret = ctr_mode_final((ctr_ctx_t *)aes_ctx, data,
8537188Smcpowers 			    aes_encrypt_block);
854904Smcpowers 			if (ret != CRYPTO_SUCCESS)
855904Smcpowers 				return (ret);
856904Smcpowers 		}
8577188Smcpowers 	} else if (aes_ctx->ac_flags & CCM_MODE) {
8587188Smcpowers 		ret = ccm_encrypt_final((ccm_ctx_t *)aes_ctx, data,
8597188Smcpowers 		    AES_BLOCK_LEN, aes_encrypt_block, aes_xor_block);
8604486Sktung 		if (ret != CRYPTO_SUCCESS) {
8614486Sktung 			return (ret);
8624486Sktung 		}
8639339SMark.Powers@Sun.COM 	} else if (aes_ctx->ac_flags & (GCM_MODE|GMAC_MODE)) {
8648005SMark.Powers@Sun.COM 		size_t saved_offset = data->cd_offset;
8658005SMark.Powers@Sun.COM 
8668005SMark.Powers@Sun.COM 		ret = gcm_encrypt_final((gcm_ctx_t *)aes_ctx, data,
8678005SMark.Powers@Sun.COM 		    AES_BLOCK_LEN, aes_encrypt_block, aes_copy_block,
8688005SMark.Powers@Sun.COM 		    aes_xor_block);
8698005SMark.Powers@Sun.COM 		if (ret != CRYPTO_SUCCESS) {
8708005SMark.Powers@Sun.COM 			return (ret);
8718005SMark.Powers@Sun.COM 		}
8728005SMark.Powers@Sun.COM 		data->cd_length = data->cd_offset - saved_offset;
8738005SMark.Powers@Sun.COM 		data->cd_offset = saved_offset;
8744486Sktung 	} else {
8754486Sktung 		/*
8764486Sktung 		 * There must be no unprocessed plaintext.
8774486Sktung 		 * This happens if the length of the last data is
8784486Sktung 		 * not a multiple of the AES block length.
8794486Sktung 		 */
8804486Sktung 		if (aes_ctx->ac_remainder_len > 0) {
8814486Sktung 			return (CRYPTO_DATA_LEN_RANGE);
8824486Sktung 		}
8834558Sktung 		data->cd_length = 0;
884904Smcpowers 	}
885904Smcpowers 
8860Sstevel@tonic-gate 	(void) aes_free_context(ctx);
8870Sstevel@tonic-gate 
8880Sstevel@tonic-gate /* EXPORT DELETE END */
8890Sstevel@tonic-gate 
8900Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
8910Sstevel@tonic-gate }
8920Sstevel@tonic-gate 
8930Sstevel@tonic-gate /* ARGSUSED */
8940Sstevel@tonic-gate static int
aes_decrypt_final(crypto_ctx_t * ctx,crypto_data_t * data,crypto_req_handle_t req)8950Sstevel@tonic-gate aes_decrypt_final(crypto_ctx_t *ctx, crypto_data_t *data,
8960Sstevel@tonic-gate     crypto_req_handle_t req)
8970Sstevel@tonic-gate {
8980Sstevel@tonic-gate 
8990Sstevel@tonic-gate /* EXPORT DELETE START */
9000Sstevel@tonic-gate 
9010Sstevel@tonic-gate 	aes_ctx_t *aes_ctx;
902904Smcpowers 	int ret;
9034486Sktung 	off_t saved_offset;
9044486Sktung 	size_t saved_length;
9050Sstevel@tonic-gate 
9060Sstevel@tonic-gate 	ASSERT(ctx->cc_provider_private != NULL);
9070Sstevel@tonic-gate 	aes_ctx = ctx->cc_provider_private;
9080Sstevel@tonic-gate 
909904Smcpowers 	if (data->cd_format != CRYPTO_DATA_RAW &&
910904Smcpowers 	    data->cd_format != CRYPTO_DATA_UIO &&
911904Smcpowers 	    data->cd_format != CRYPTO_DATA_MBLK) {
912904Smcpowers 		return (CRYPTO_ARGUMENTS_BAD);
913904Smcpowers 	}
914904Smcpowers 
9150Sstevel@tonic-gate 	/*
9160Sstevel@tonic-gate 	 * There must be no unprocessed ciphertext.
9170Sstevel@tonic-gate 	 * This happens if the length of the last ciphertext is
9180Sstevel@tonic-gate 	 * not a multiple of the AES block length.
9190Sstevel@tonic-gate 	 */
920904Smcpowers 	if (aes_ctx->ac_remainder_len > 0) {
9217188Smcpowers 		if ((aes_ctx->ac_flags & CTR_MODE) == 0)
922904Smcpowers 			return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE);
923904Smcpowers 		else {
9247188Smcpowers 			ret = ctr_mode_final((ctr_ctx_t *)aes_ctx, data,
9257188Smcpowers 			    aes_encrypt_block);
9267188Smcpowers 			if (ret == CRYPTO_DATA_LEN_RANGE)
9277188Smcpowers 				ret = CRYPTO_ENCRYPTED_DATA_LEN_RANGE;
928904Smcpowers 			if (ret != CRYPTO_SUCCESS)
929904Smcpowers 				return (ret);
930904Smcpowers 		}
931904Smcpowers 	}
932904Smcpowers 
9337188Smcpowers 	if (aes_ctx->ac_flags & CCM_MODE) {
9344486Sktung 		/*
9354486Sktung 		 * This is where all the plaintext is returned, make sure
9364486Sktung 		 * the plaintext buffer is big enough
9374486Sktung 		 */
9387188Smcpowers 		size_t pt_len = aes_ctx->ac_data_len;
9394486Sktung 		if (data->cd_length < pt_len) {
9404486Sktung 			data->cd_length = pt_len;
9414486Sktung 			return (CRYPTO_BUFFER_TOO_SMALL);
9424486Sktung 		}
9434486Sktung 
9447188Smcpowers 		ASSERT(aes_ctx->ac_processed_data_len == pt_len);
9457188Smcpowers 		ASSERT(aes_ctx->ac_processed_mac_len == aes_ctx->ac_mac_len);
9464486Sktung 		saved_offset = data->cd_offset;
9474486Sktung 		saved_length = data->cd_length;
9487188Smcpowers 		ret = ccm_decrypt_final((ccm_ctx_t *)aes_ctx, data,
9497188Smcpowers 		    AES_BLOCK_LEN, aes_encrypt_block, aes_copy_block,
9507188Smcpowers 		    aes_xor_block);
9514486Sktung 		if (ret == CRYPTO_SUCCESS) {
9524486Sktung 			data->cd_length = data->cd_offset - saved_offset;
9534486Sktung 		} else {
9544486Sktung 			data->cd_length = saved_length;
9554486Sktung 		}
9564486Sktung 
9574486Sktung 		data->cd_offset = saved_offset;
9584486Sktung 		if (ret != CRYPTO_SUCCESS) {
9594486Sktung 			return (ret);
9604486Sktung 		}
9619339SMark.Powers@Sun.COM 	} else if (aes_ctx->ac_flags & (GCM_MODE|GMAC_MODE)) {
9628005SMark.Powers@Sun.COM 		/*
9638005SMark.Powers@Sun.COM 		 * This is where all the plaintext is returned, make sure
9648005SMark.Powers@Sun.COM 		 * the plaintext buffer is big enough
9658005SMark.Powers@Sun.COM 		 */
9668005SMark.Powers@Sun.COM 		gcm_ctx_t *ctx = (gcm_ctx_t *)aes_ctx;
9678005SMark.Powers@Sun.COM 		size_t pt_len = ctx->gcm_processed_data_len - ctx->gcm_tag_len;
9688005SMark.Powers@Sun.COM 
9698005SMark.Powers@Sun.COM 		if (data->cd_length < pt_len) {
9708005SMark.Powers@Sun.COM 			data->cd_length = pt_len;
9718005SMark.Powers@Sun.COM 			return (CRYPTO_BUFFER_TOO_SMALL);
9728005SMark.Powers@Sun.COM 		}
9738005SMark.Powers@Sun.COM 
9748005SMark.Powers@Sun.COM 		saved_offset = data->cd_offset;
9758005SMark.Powers@Sun.COM 		saved_length = data->cd_length;
9768005SMark.Powers@Sun.COM 		ret = gcm_decrypt_final((gcm_ctx_t *)aes_ctx, data,
9778005SMark.Powers@Sun.COM 		    AES_BLOCK_LEN, aes_encrypt_block, aes_xor_block);
9788005SMark.Powers@Sun.COM 		if (ret == CRYPTO_SUCCESS) {
9798005SMark.Powers@Sun.COM 			data->cd_length = data->cd_offset - saved_offset;
9808005SMark.Powers@Sun.COM 		} else {
9818005SMark.Powers@Sun.COM 			data->cd_length = saved_length;
9828005SMark.Powers@Sun.COM 		}
9838005SMark.Powers@Sun.COM 
9848005SMark.Powers@Sun.COM 		data->cd_offset = saved_offset;
9858005SMark.Powers@Sun.COM 		if (ret != CRYPTO_SUCCESS) {
9868005SMark.Powers@Sun.COM 			return (ret);
9878005SMark.Powers@Sun.COM 		}
9884486Sktung 	}
9894486Sktung 
9904486Sktung 
9919339SMark.Powers@Sun.COM 	if ((aes_ctx->ac_flags & (CTR_MODE|CCM_MODE|GCM_MODE|GMAC_MODE)) == 0) {
992904Smcpowers 		data->cd_length = 0;
9934558Sktung 	}
9940Sstevel@tonic-gate 
9950Sstevel@tonic-gate 	(void) aes_free_context(ctx);
9960Sstevel@tonic-gate 
9970Sstevel@tonic-gate /* EXPORT DELETE END */
9980Sstevel@tonic-gate 
9990Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
10000Sstevel@tonic-gate }
10010Sstevel@tonic-gate 
10020Sstevel@tonic-gate /* ARGSUSED */
10030Sstevel@tonic-gate static int
aes_encrypt_atomic(crypto_provider_handle_t provider,crypto_session_id_t session_id,crypto_mechanism_t * mechanism,crypto_key_t * key,crypto_data_t * plaintext,crypto_data_t * ciphertext,crypto_spi_ctx_template_t template,crypto_req_handle_t req)10040Sstevel@tonic-gate aes_encrypt_atomic(crypto_provider_handle_t provider,
10050Sstevel@tonic-gate     crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
10060Sstevel@tonic-gate     crypto_key_t *key, crypto_data_t *plaintext, crypto_data_t *ciphertext,
10070Sstevel@tonic-gate     crypto_spi_ctx_template_t template, crypto_req_handle_t req)
10080Sstevel@tonic-gate {
10090Sstevel@tonic-gate 	aes_ctx_t aes_ctx;	/* on the stack */
10100Sstevel@tonic-gate 	off_t saved_offset;
10110Sstevel@tonic-gate 	size_t saved_length;
10128195SMark.Powers@Sun.COM 	size_t length_needed;
10130Sstevel@tonic-gate 	int ret;
10140Sstevel@tonic-gate 
10150Sstevel@tonic-gate 	AES_ARG_INPLACE(plaintext, ciphertext);
10160Sstevel@tonic-gate 
10178195SMark.Powers@Sun.COM 	/*
10189339SMark.Powers@Sun.COM 	 * CTR, CCM, GCM, and GMAC modes do not require that plaintext
10198195SMark.Powers@Sun.COM 	 * be a multiple of AES block size.
10208195SMark.Powers@Sun.COM 	 */
10218195SMark.Powers@Sun.COM 	switch (mechanism->cm_type) {
10228195SMark.Powers@Sun.COM 	case AES_CTR_MECH_INFO_TYPE:
10238195SMark.Powers@Sun.COM 	case AES_CCM_MECH_INFO_TYPE:
10248195SMark.Powers@Sun.COM 	case AES_GCM_MECH_INFO_TYPE:
10259339SMark.Powers@Sun.COM 	case AES_GMAC_MECH_INFO_TYPE:
10268195SMark.Powers@Sun.COM 		break;
10278195SMark.Powers@Sun.COM 	default:
1028904Smcpowers 		if ((plaintext->cd_length & (AES_BLOCK_LEN - 1)) != 0)
1029904Smcpowers 			return (CRYPTO_DATA_LEN_RANGE);
1030904Smcpowers 	}
10310Sstevel@tonic-gate 
10327188Smcpowers 	if ((ret = aes_check_mech_param(mechanism, NULL, 0)) != CRYPTO_SUCCESS)
1033991Smcpowers 		return (ret);
10340Sstevel@tonic-gate 
10350Sstevel@tonic-gate 	bzero(&aes_ctx, sizeof (aes_ctx_t));
10360Sstevel@tonic-gate 
10370Sstevel@tonic-gate 	ret = aes_common_init_ctx(&aes_ctx, template, mechanism, key,
10384486Sktung 	    crypto_kmflag(req), B_TRUE);
10390Sstevel@tonic-gate 	if (ret != CRYPTO_SUCCESS)
10400Sstevel@tonic-gate 		return (ret);
10410Sstevel@tonic-gate 
10428195SMark.Powers@Sun.COM 	switch (mechanism->cm_type) {
10438195SMark.Powers@Sun.COM 	case AES_CCM_MECH_INFO_TYPE:
10448195SMark.Powers@Sun.COM 		length_needed = plaintext->cd_length + aes_ctx.ac_mac_len;
10458195SMark.Powers@Sun.COM 		break;
10469339SMark.Powers@Sun.COM 	case AES_GMAC_MECH_INFO_TYPE:
10479339SMark.Powers@Sun.COM 		if (plaintext->cd_length != 0)
10489339SMark.Powers@Sun.COM 			return (CRYPTO_ARGUMENTS_BAD);
10499339SMark.Powers@Sun.COM 		/* FALLTHRU */
10508195SMark.Powers@Sun.COM 	case AES_GCM_MECH_INFO_TYPE:
10518195SMark.Powers@Sun.COM 		length_needed = plaintext->cd_length + aes_ctx.ac_tag_len;
10528195SMark.Powers@Sun.COM 		break;
10538195SMark.Powers@Sun.COM 	default:
10548195SMark.Powers@Sun.COM 		length_needed = plaintext->cd_length;
10554486Sktung 	}
10564486Sktung 
10578195SMark.Powers@Sun.COM 	/* return size of buffer needed to store output */
10588195SMark.Powers@Sun.COM 	if (ciphertext->cd_length < length_needed) {
10598195SMark.Powers@Sun.COM 		ciphertext->cd_length = length_needed;
10608195SMark.Powers@Sun.COM 		ret = CRYPTO_BUFFER_TOO_SMALL;
10618195SMark.Powers@Sun.COM 		goto out;
10628195SMark.Powers@Sun.COM 	}
10634486Sktung 
10640Sstevel@tonic-gate 	saved_offset = ciphertext->cd_offset;
10650Sstevel@tonic-gate 	saved_length = ciphertext->cd_length;
10660Sstevel@tonic-gate 
10670Sstevel@tonic-gate 	/*
10680Sstevel@tonic-gate 	 * Do an update on the specified input data.
10690Sstevel@tonic-gate 	 */
10700Sstevel@tonic-gate 	switch (plaintext->cd_format) {
10710Sstevel@tonic-gate 	case CRYPTO_DATA_RAW:
10727188Smcpowers 		ret = crypto_update_iov(&aes_ctx, plaintext, ciphertext,
10737188Smcpowers 		    aes_encrypt_contiguous_blocks, aes_copy_block64);
10740Sstevel@tonic-gate 		break;
10750Sstevel@tonic-gate 	case CRYPTO_DATA_UIO:
10767188Smcpowers 		ret = crypto_update_uio(&aes_ctx, plaintext, ciphertext,
10777188Smcpowers 		    aes_encrypt_contiguous_blocks, aes_copy_block64);
10780Sstevel@tonic-gate 		break;
10790Sstevel@tonic-gate 	case CRYPTO_DATA_MBLK:
10807188Smcpowers 		ret = crypto_update_mp(&aes_ctx, plaintext, ciphertext,
10817188Smcpowers 		    aes_encrypt_contiguous_blocks, aes_copy_block64);
10820Sstevel@tonic-gate 		break;
10830Sstevel@tonic-gate 	default:
10840Sstevel@tonic-gate 		ret = CRYPTO_ARGUMENTS_BAD;
10850Sstevel@tonic-gate 	}
10860Sstevel@tonic-gate 
1087904Smcpowers 	if (ret == CRYPTO_SUCCESS) {
10884486Sktung 		if (mechanism->cm_type == AES_CCM_MECH_INFO_TYPE) {
10897188Smcpowers 			ret = ccm_encrypt_final((ccm_ctx_t *)&aes_ctx,
10907188Smcpowers 			    ciphertext, AES_BLOCK_LEN, aes_encrypt_block,
10917188Smcpowers 			    aes_xor_block);
10924486Sktung 			if (ret != CRYPTO_SUCCESS)
10934486Sktung 				goto out;
1094904Smcpowers 			ASSERT(aes_ctx.ac_remainder_len == 0);
10959339SMark.Powers@Sun.COM 		} else if (mechanism->cm_type == AES_GCM_MECH_INFO_TYPE ||
10969339SMark.Powers@Sun.COM 		    mechanism->cm_type == AES_GMAC_MECH_INFO_TYPE) {
10978005SMark.Powers@Sun.COM 			ret = gcm_encrypt_final((gcm_ctx_t *)&aes_ctx,
10988005SMark.Powers@Sun.COM 			    ciphertext, AES_BLOCK_LEN, aes_encrypt_block,
10998005SMark.Powers@Sun.COM 			    aes_copy_block, aes_xor_block);
11008005SMark.Powers@Sun.COM 			if (ret != CRYPTO_SUCCESS)
11018005SMark.Powers@Sun.COM 				goto out;
11028005SMark.Powers@Sun.COM 			ASSERT(aes_ctx.ac_remainder_len == 0);
11034486Sktung 		} else if (mechanism->cm_type == AES_CTR_MECH_INFO_TYPE) {
1104904Smcpowers 			if (aes_ctx.ac_remainder_len > 0) {
11057188Smcpowers 				ret = ctr_mode_final((ctr_ctx_t *)&aes_ctx,
11067188Smcpowers 				    ciphertext, aes_encrypt_block);
1107904Smcpowers 				if (ret != CRYPTO_SUCCESS)
1108904Smcpowers 					goto out;
1109904Smcpowers 			}
11104486Sktung 		} else {
11114486Sktung 			ASSERT(aes_ctx.ac_remainder_len == 0);
11124486Sktung 		}
11134486Sktung 
11144486Sktung 		if (plaintext != ciphertext) {
11154486Sktung 			ciphertext->cd_length =
11164486Sktung 			    ciphertext->cd_offset - saved_offset;
1117904Smcpowers 		}
1118904Smcpowers 	} else {
1119904Smcpowers 		ciphertext->cd_length = saved_length;
1120904Smcpowers 	}
1121904Smcpowers 	ciphertext->cd_offset = saved_offset;
1122904Smcpowers 
1123904Smcpowers out:
11247188Smcpowers 	if (aes_ctx.ac_flags & PROVIDER_OWNS_KEY_SCHEDULE) {
11250Sstevel@tonic-gate 		bzero(aes_ctx.ac_keysched, aes_ctx.ac_keysched_len);
11260Sstevel@tonic-gate 		kmem_free(aes_ctx.ac_keysched, aes_ctx.ac_keysched_len);
11270Sstevel@tonic-gate 	}
11280Sstevel@tonic-gate 
11290Sstevel@tonic-gate 	return (ret);
11300Sstevel@tonic-gate }
11310Sstevel@tonic-gate 
11320Sstevel@tonic-gate /* ARGSUSED */
11330Sstevel@tonic-gate static int
aes_decrypt_atomic(crypto_provider_handle_t provider,crypto_session_id_t session_id,crypto_mechanism_t * mechanism,crypto_key_t * key,crypto_data_t * ciphertext,crypto_data_t * plaintext,crypto_spi_ctx_template_t template,crypto_req_handle_t req)11340Sstevel@tonic-gate aes_decrypt_atomic(crypto_provider_handle_t provider,
11350Sstevel@tonic-gate     crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
11360Sstevel@tonic-gate     crypto_key_t *key, crypto_data_t *ciphertext, crypto_data_t *plaintext,
11370Sstevel@tonic-gate     crypto_spi_ctx_template_t template, crypto_req_handle_t req)
11380Sstevel@tonic-gate {
11390Sstevel@tonic-gate 	aes_ctx_t aes_ctx;	/* on the stack */
11400Sstevel@tonic-gate 	off_t saved_offset;
11410Sstevel@tonic-gate 	size_t saved_length;
11428195SMark.Powers@Sun.COM 	size_t length_needed;
11430Sstevel@tonic-gate 	int ret;
11440Sstevel@tonic-gate 
11450Sstevel@tonic-gate 	AES_ARG_INPLACE(ciphertext, plaintext);
11460Sstevel@tonic-gate 
11474486Sktung 	/*
11489339SMark.Powers@Sun.COM 	 * CCM, GCM, CTR, and GMAC modes do not require that ciphertext
11498195SMark.Powers@Sun.COM 	 * be a multiple of AES block size.
11504486Sktung 	 */
11518195SMark.Powers@Sun.COM 	switch (mechanism->cm_type) {
11528195SMark.Powers@Sun.COM 	case AES_CTR_MECH_INFO_TYPE:
11538195SMark.Powers@Sun.COM 	case AES_CCM_MECH_INFO_TYPE:
11548195SMark.Powers@Sun.COM 	case AES_GCM_MECH_INFO_TYPE:
11559339SMark.Powers@Sun.COM 	case AES_GMAC_MECH_INFO_TYPE:
11568195SMark.Powers@Sun.COM 		break;
11578195SMark.Powers@Sun.COM 	default:
11588195SMark.Powers@Sun.COM 		if ((ciphertext->cd_length & (AES_BLOCK_LEN - 1)) != 0)
11598195SMark.Powers@Sun.COM 			return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE);
11600Sstevel@tonic-gate 	}
11610Sstevel@tonic-gate 
11627188Smcpowers 	if ((ret = aes_check_mech_param(mechanism, NULL, 0)) != CRYPTO_SUCCESS)
1163991Smcpowers 		return (ret);
11640Sstevel@tonic-gate 
11650Sstevel@tonic-gate 	bzero(&aes_ctx, sizeof (aes_ctx_t));
11660Sstevel@tonic-gate 
11670Sstevel@tonic-gate 	ret = aes_common_init_ctx(&aes_ctx, template, mechanism, key,
11684486Sktung 	    crypto_kmflag(req), B_FALSE);
11690Sstevel@tonic-gate 	if (ret != CRYPTO_SUCCESS)
11700Sstevel@tonic-gate 		return (ret);
11710Sstevel@tonic-gate 
11728195SMark.Powers@Sun.COM 	switch (mechanism->cm_type) {
11738195SMark.Powers@Sun.COM 	case AES_CCM_MECH_INFO_TYPE:
11748195SMark.Powers@Sun.COM 		length_needed = aes_ctx.ac_data_len;
11758195SMark.Powers@Sun.COM 		break;
11768195SMark.Powers@Sun.COM 	case AES_GCM_MECH_INFO_TYPE:
11778195SMark.Powers@Sun.COM 		length_needed = ciphertext->cd_length - aes_ctx.ac_tag_len;
11788195SMark.Powers@Sun.COM 		break;
11799339SMark.Powers@Sun.COM 	case AES_GMAC_MECH_INFO_TYPE:
11809339SMark.Powers@Sun.COM 		if (plaintext->cd_length != 0)
11819339SMark.Powers@Sun.COM 			return (CRYPTO_ARGUMENTS_BAD);
11829339SMark.Powers@Sun.COM 		length_needed = 0;
11839339SMark.Powers@Sun.COM 		break;
11848195SMark.Powers@Sun.COM 	default:
11858195SMark.Powers@Sun.COM 		length_needed = ciphertext->cd_length;
11868195SMark.Powers@Sun.COM 	}
11878195SMark.Powers@Sun.COM 
11888195SMark.Powers@Sun.COM 	/* return size of buffer needed to store output */
11898195SMark.Powers@Sun.COM 	if (plaintext->cd_length < length_needed) {
11908195SMark.Powers@Sun.COM 		plaintext->cd_length = length_needed;
11918195SMark.Powers@Sun.COM 		ret = CRYPTO_BUFFER_TOO_SMALL;
11928195SMark.Powers@Sun.COM 		goto out;
11934486Sktung 	}
11944486Sktung 
11950Sstevel@tonic-gate 	saved_offset = plaintext->cd_offset;
11960Sstevel@tonic-gate 	saved_length = plaintext->cd_length;
11970Sstevel@tonic-gate 
11989339SMark.Powers@Sun.COM 	if (mechanism->cm_type == AES_GCM_MECH_INFO_TYPE ||
11999339SMark.Powers@Sun.COM 	    mechanism->cm_type == AES_GMAC_MECH_INFO_TYPE)
12008005SMark.Powers@Sun.COM 		gcm_set_kmflag((gcm_ctx_t *)&aes_ctx, crypto_kmflag(req));
12018005SMark.Powers@Sun.COM 
12020Sstevel@tonic-gate 	/*
12030Sstevel@tonic-gate 	 * Do an update on the specified input data.
12040Sstevel@tonic-gate 	 */
12050Sstevel@tonic-gate 	switch (ciphertext->cd_format) {
12060Sstevel@tonic-gate 	case CRYPTO_DATA_RAW:
12077188Smcpowers 		ret = crypto_update_iov(&aes_ctx, ciphertext, plaintext,
12087188Smcpowers 		    aes_decrypt_contiguous_blocks, aes_copy_block64);
12090Sstevel@tonic-gate 		break;
12100Sstevel@tonic-gate 	case CRYPTO_DATA_UIO:
12117188Smcpowers 		ret = crypto_update_uio(&aes_ctx, ciphertext, plaintext,
12127188Smcpowers 		    aes_decrypt_contiguous_blocks, aes_copy_block64);
12130Sstevel@tonic-gate 		break;
12140Sstevel@tonic-gate 	case CRYPTO_DATA_MBLK:
12157188Smcpowers 		ret = crypto_update_mp(&aes_ctx, ciphertext, plaintext,
12167188Smcpowers 		    aes_decrypt_contiguous_blocks, aes_copy_block64);
12170Sstevel@tonic-gate 		break;
12180Sstevel@tonic-gate 	default:
12190Sstevel@tonic-gate 		ret = CRYPTO_ARGUMENTS_BAD;
12200Sstevel@tonic-gate 	}
12210Sstevel@tonic-gate 
1222904Smcpowers 	if (ret == CRYPTO_SUCCESS) {
12234486Sktung 		if (mechanism->cm_type == AES_CCM_MECH_INFO_TYPE) {
12247188Smcpowers 			ASSERT(aes_ctx.ac_processed_data_len
12257188Smcpowers 			    == aes_ctx.ac_data_len);
12267188Smcpowers 			ASSERT(aes_ctx.ac_processed_mac_len
12277188Smcpowers 			    == aes_ctx.ac_mac_len);
12287188Smcpowers 			ret = ccm_decrypt_final((ccm_ctx_t *)&aes_ctx,
12297188Smcpowers 			    plaintext, AES_BLOCK_LEN, aes_encrypt_block,
12307188Smcpowers 			    aes_copy_block, aes_xor_block);
12314486Sktung 			ASSERT(aes_ctx.ac_remainder_len == 0);
12324486Sktung 			if ((ret == CRYPTO_SUCCESS) &&
12334486Sktung 			    (ciphertext != plaintext)) {
12344486Sktung 				plaintext->cd_length =
12354486Sktung 				    plaintext->cd_offset - saved_offset;
12364486Sktung 			} else {
12374486Sktung 				plaintext->cd_length = saved_length;
12384486Sktung 			}
12399339SMark.Powers@Sun.COM 		} else if (mechanism->cm_type == AES_GCM_MECH_INFO_TYPE ||
12409339SMark.Powers@Sun.COM 		    mechanism->cm_type == AES_GMAC_MECH_INFO_TYPE) {
12418005SMark.Powers@Sun.COM 			ret = gcm_decrypt_final((gcm_ctx_t *)&aes_ctx,
12428005SMark.Powers@Sun.COM 			    plaintext, AES_BLOCK_LEN, aes_encrypt_block,
12438005SMark.Powers@Sun.COM 			    aes_xor_block);
12448005SMark.Powers@Sun.COM 			ASSERT(aes_ctx.ac_remainder_len == 0);
12458005SMark.Powers@Sun.COM 			if ((ret == CRYPTO_SUCCESS) &&
12468005SMark.Powers@Sun.COM 			    (ciphertext != plaintext)) {
12478005SMark.Powers@Sun.COM 				plaintext->cd_length =
12488005SMark.Powers@Sun.COM 				    plaintext->cd_offset - saved_offset;
12498005SMark.Powers@Sun.COM 			} else {
12508005SMark.Powers@Sun.COM 				plaintext->cd_length = saved_length;
12518005SMark.Powers@Sun.COM 			}
12524486Sktung 		} else if (mechanism->cm_type != AES_CTR_MECH_INFO_TYPE) {
1253904Smcpowers 			ASSERT(aes_ctx.ac_remainder_len == 0);
1254904Smcpowers 			if (ciphertext != plaintext)
1255904Smcpowers 				plaintext->cd_length =
1256904Smcpowers 				    plaintext->cd_offset - saved_offset;
1257904Smcpowers 		} else {
1258904Smcpowers 			if (aes_ctx.ac_remainder_len > 0) {
12597188Smcpowers 				ret = ctr_mode_final((ctr_ctx_t *)&aes_ctx,
12607188Smcpowers 				    plaintext, aes_encrypt_block);
12617188Smcpowers 				if (ret == CRYPTO_DATA_LEN_RANGE)
12627188Smcpowers 					ret = CRYPTO_ENCRYPTED_DATA_LEN_RANGE;
1263904Smcpowers 				if (ret != CRYPTO_SUCCESS)
1264904Smcpowers 					goto out;
1265904Smcpowers 			}
1266904Smcpowers 			if (ciphertext != plaintext)
1267904Smcpowers 				plaintext->cd_length =
1268904Smcpowers 				    plaintext->cd_offset - saved_offset;
1269904Smcpowers 		}
1270904Smcpowers 	} else {
1271904Smcpowers 		plaintext->cd_length = saved_length;
1272904Smcpowers 	}
1273904Smcpowers 	plaintext->cd_offset = saved_offset;
1274904Smcpowers 
1275904Smcpowers out:
12767188Smcpowers 	if (aes_ctx.ac_flags & PROVIDER_OWNS_KEY_SCHEDULE) {
12770Sstevel@tonic-gate 		bzero(aes_ctx.ac_keysched, aes_ctx.ac_keysched_len);
12780Sstevel@tonic-gate 		kmem_free(aes_ctx.ac_keysched, aes_ctx.ac_keysched_len);
12790Sstevel@tonic-gate 	}
12800Sstevel@tonic-gate 
12817188Smcpowers 	if (aes_ctx.ac_flags & CCM_MODE) {
12827188Smcpowers 		if (aes_ctx.ac_pt_buf != NULL) {
12837188Smcpowers 			kmem_free(aes_ctx.ac_pt_buf, aes_ctx.ac_data_len);
12847188Smcpowers 		}
12859339SMark.Powers@Sun.COM 	} else if (aes_ctx.ac_flags & (GCM_MODE|GMAC_MODE)) {
12868005SMark.Powers@Sun.COM 		if (((gcm_ctx_t *)&aes_ctx)->gcm_pt_buf != NULL) {
12878005SMark.Powers@Sun.COM 			kmem_free(((gcm_ctx_t *)&aes_ctx)->gcm_pt_buf,
12888005SMark.Powers@Sun.COM 			    ((gcm_ctx_t *)&aes_ctx)->gcm_pt_buf_len);
12898005SMark.Powers@Sun.COM 		}
12904486Sktung 	}
12914486Sktung 
12920Sstevel@tonic-gate 	return (ret);
12930Sstevel@tonic-gate }
12940Sstevel@tonic-gate 
12950Sstevel@tonic-gate /*
12960Sstevel@tonic-gate  * KCF software provider context template entry points.
12970Sstevel@tonic-gate  */
12980Sstevel@tonic-gate /* ARGSUSED */
12990Sstevel@tonic-gate static int
aes_create_ctx_template(crypto_provider_handle_t provider,crypto_mechanism_t * mechanism,crypto_key_t * key,crypto_spi_ctx_template_t * tmpl,size_t * tmpl_size,crypto_req_handle_t req)13000Sstevel@tonic-gate aes_create_ctx_template(crypto_provider_handle_t provider,
13010Sstevel@tonic-gate     crypto_mechanism_t *mechanism, crypto_key_t *key,
13020Sstevel@tonic-gate     crypto_spi_ctx_template_t *tmpl, size_t *tmpl_size, crypto_req_handle_t req)
13030Sstevel@tonic-gate {
13040Sstevel@tonic-gate 
13050Sstevel@tonic-gate /* EXPORT DELETE START */
13060Sstevel@tonic-gate 
13070Sstevel@tonic-gate 	void *keysched;
13080Sstevel@tonic-gate 	size_t size;
13090Sstevel@tonic-gate 	int rv;
13100Sstevel@tonic-gate 
1311991Smcpowers 	if (mechanism->cm_type != AES_ECB_MECH_INFO_TYPE &&
1312991Smcpowers 	    mechanism->cm_type != AES_CBC_MECH_INFO_TYPE &&
13134486Sktung 	    mechanism->cm_type != AES_CTR_MECH_INFO_TYPE &&
13149339SMark.Powers@Sun.COM 	    mechanism->cm_type != AES_CCM_MECH_INFO_TYPE &&
13159339SMark.Powers@Sun.COM 	    mechanism->cm_type != AES_GCM_MECH_INFO_TYPE &&
13169339SMark.Powers@Sun.COM 	    mechanism->cm_type != AES_GMAC_MECH_INFO_TYPE)
13170Sstevel@tonic-gate 		return (CRYPTO_MECHANISM_INVALID);
13180Sstevel@tonic-gate 
13190Sstevel@tonic-gate 	if ((keysched = aes_alloc_keysched(&size,
13200Sstevel@tonic-gate 	    crypto_kmflag(req))) == NULL) {
13210Sstevel@tonic-gate 		return (CRYPTO_HOST_MEMORY);
13220Sstevel@tonic-gate 	}
13230Sstevel@tonic-gate 
13240Sstevel@tonic-gate 	/*
13250Sstevel@tonic-gate 	 * Initialize key schedule.  Key length information is stored
13260Sstevel@tonic-gate 	 * in the key.
13270Sstevel@tonic-gate 	 */
13280Sstevel@tonic-gate 	if ((rv = init_keysched(key, keysched)) != CRYPTO_SUCCESS) {
13290Sstevel@tonic-gate 		bzero(keysched, size);
13300Sstevel@tonic-gate 		kmem_free(keysched, size);
13310Sstevel@tonic-gate 		return (rv);
13320Sstevel@tonic-gate 	}
13330Sstevel@tonic-gate 
13340Sstevel@tonic-gate 	*tmpl = keysched;
13350Sstevel@tonic-gate 	*tmpl_size = size;
13360Sstevel@tonic-gate 
13370Sstevel@tonic-gate /* EXPORT DELETE END */
13380Sstevel@tonic-gate 
13390Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
13400Sstevel@tonic-gate }
13410Sstevel@tonic-gate 
13429392Sopensolaris@drydog.com 
13430Sstevel@tonic-gate static int
aes_free_context(crypto_ctx_t * ctx)13440Sstevel@tonic-gate aes_free_context(crypto_ctx_t *ctx)
13450Sstevel@tonic-gate {
13460Sstevel@tonic-gate 
13470Sstevel@tonic-gate /* EXPORT DELETE START */
13480Sstevel@tonic-gate 
13490Sstevel@tonic-gate 	aes_ctx_t *aes_ctx = ctx->cc_provider_private;
13500Sstevel@tonic-gate 
13510Sstevel@tonic-gate 	if (aes_ctx != NULL) {
13527188Smcpowers 		if (aes_ctx->ac_flags & PROVIDER_OWNS_KEY_SCHEDULE) {
13530Sstevel@tonic-gate 			ASSERT(aes_ctx->ac_keysched_len != 0);
13540Sstevel@tonic-gate 			bzero(aes_ctx->ac_keysched, aes_ctx->ac_keysched_len);
13550Sstevel@tonic-gate 			kmem_free(aes_ctx->ac_keysched,
13560Sstevel@tonic-gate 			    aes_ctx->ac_keysched_len);
13570Sstevel@tonic-gate 		}
13587188Smcpowers 		crypto_free_mode_ctx(aes_ctx);
13590Sstevel@tonic-gate 		ctx->cc_provider_private = NULL;
13600Sstevel@tonic-gate 	}
13610Sstevel@tonic-gate 
13620Sstevel@tonic-gate /* EXPORT DELETE END */
13630Sstevel@tonic-gate 
13640Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
13650Sstevel@tonic-gate }
13660Sstevel@tonic-gate 
13679392Sopensolaris@drydog.com 
13680Sstevel@tonic-gate static int
aes_common_init_ctx(aes_ctx_t * aes_ctx,crypto_spi_ctx_template_t * template,crypto_mechanism_t * mechanism,crypto_key_t * key,int kmflag,boolean_t is_encrypt_init)13690Sstevel@tonic-gate aes_common_init_ctx(aes_ctx_t *aes_ctx, crypto_spi_ctx_template_t *template,
13704486Sktung     crypto_mechanism_t *mechanism, crypto_key_t *key, int kmflag,
13714486Sktung     boolean_t is_encrypt_init)
13720Sstevel@tonic-gate {
13730Sstevel@tonic-gate 	int rv = CRYPTO_SUCCESS;
13740Sstevel@tonic-gate 
13750Sstevel@tonic-gate /* EXPORT DELETE START */
13760Sstevel@tonic-gate 
13770Sstevel@tonic-gate 	void *keysched;
13780Sstevel@tonic-gate 	size_t size;
1379904Smcpowers 
1380904Smcpowers 	if (template == NULL) {
1381904Smcpowers 		if ((keysched = aes_alloc_keysched(&size, kmflag)) == NULL)
1382904Smcpowers 			return (CRYPTO_HOST_MEMORY);
1383904Smcpowers 		/*
1384904Smcpowers 		 * Initialize key schedule.
1385904Smcpowers 		 * Key length is stored in the key.
1386904Smcpowers 		 */
13874486Sktung 		if ((rv = init_keysched(key, keysched)) != CRYPTO_SUCCESS) {
1388904Smcpowers 			kmem_free(keysched, size);
13894486Sktung 			return (rv);
13904486Sktung 		}
1391904Smcpowers 
13927188Smcpowers 		aes_ctx->ac_flags |= PROVIDER_OWNS_KEY_SCHEDULE;
1393904Smcpowers 		aes_ctx->ac_keysched_len = size;
1394904Smcpowers 	} else {
1395904Smcpowers 		keysched = template;
13960Sstevel@tonic-gate 	}
13970Sstevel@tonic-gate 	aes_ctx->ac_keysched = keysched;
13980Sstevel@tonic-gate 
13997188Smcpowers 	switch (mechanism->cm_type) {
14007188Smcpowers 	case AES_CBC_MECH_INFO_TYPE:
14017188Smcpowers 		rv = cbc_init_ctx((cbc_ctx_t *)aes_ctx, mechanism->cm_param,
14027188Smcpowers 		    mechanism->cm_param_len, AES_BLOCK_LEN, aes_copy_block64);
14037188Smcpowers 		break;
14047188Smcpowers 	case AES_CTR_MECH_INFO_TYPE: {
14057188Smcpowers 		CK_AES_CTR_PARAMS *pp;
14067188Smcpowers 
14077188Smcpowers 		if (mechanism->cm_param == NULL ||
14087188Smcpowers 		    mechanism->cm_param_len != sizeof (CK_AES_CTR_PARAMS)) {
14094486Sktung 			return (CRYPTO_MECHANISM_PARAM_INVALID);
14104486Sktung 		}
14119392Sopensolaris@drydog.com 		pp = (CK_AES_CTR_PARAMS *)(void *)mechanism->cm_param;
14127188Smcpowers 		rv = ctr_init_ctx((ctr_ctx_t *)aes_ctx, pp->ulCounterBits,
14137188Smcpowers 		    pp->cb, aes_copy_block);
14147188Smcpowers 		break;
14157188Smcpowers 	}
14167188Smcpowers 	case AES_CCM_MECH_INFO_TYPE:
14177188Smcpowers 		if (mechanism->cm_param == NULL ||
14187188Smcpowers 		    mechanism->cm_param_len != sizeof (CK_AES_CCM_PARAMS)) {
14197188Smcpowers 			return (CRYPTO_MECHANISM_PARAM_INVALID);
14207188Smcpowers 		}
14217188Smcpowers 		rv = ccm_init_ctx((ccm_ctx_t *)aes_ctx, mechanism->cm_param,
14227188Smcpowers 		    kmflag, is_encrypt_init, AES_BLOCK_LEN, aes_encrypt_block,
14237188Smcpowers 		    aes_xor_block);
14247188Smcpowers 		break;
14258005SMark.Powers@Sun.COM 	case AES_GCM_MECH_INFO_TYPE:
14268005SMark.Powers@Sun.COM 		if (mechanism->cm_param == NULL ||
14278005SMark.Powers@Sun.COM 		    mechanism->cm_param_len != sizeof (CK_AES_GCM_PARAMS)) {
14288005SMark.Powers@Sun.COM 			return (CRYPTO_MECHANISM_PARAM_INVALID);
14298005SMark.Powers@Sun.COM 		}
14308005SMark.Powers@Sun.COM 		rv = gcm_init_ctx((gcm_ctx_t *)aes_ctx, mechanism->cm_param,
14318005SMark.Powers@Sun.COM 		    AES_BLOCK_LEN, aes_encrypt_block, aes_copy_block,
14328005SMark.Powers@Sun.COM 		    aes_xor_block);
14338005SMark.Powers@Sun.COM 		break;
14349339SMark.Powers@Sun.COM 	case AES_GMAC_MECH_INFO_TYPE:
14359339SMark.Powers@Sun.COM 		if (mechanism->cm_param == NULL ||
14369339SMark.Powers@Sun.COM 		    mechanism->cm_param_len != sizeof (CK_AES_GMAC_PARAMS)) {
14379339SMark.Powers@Sun.COM 			return (CRYPTO_MECHANISM_PARAM_INVALID);
14389339SMark.Powers@Sun.COM 		}
14399339SMark.Powers@Sun.COM 		rv = gmac_init_ctx((gcm_ctx_t *)aes_ctx, mechanism->cm_param,
14409339SMark.Powers@Sun.COM 		    AES_BLOCK_LEN, aes_encrypt_block, aes_copy_block,
14419339SMark.Powers@Sun.COM 		    aes_xor_block);
14429339SMark.Powers@Sun.COM 		break;
14437188Smcpowers 	case AES_ECB_MECH_INFO_TYPE:
14447188Smcpowers 		aes_ctx->ac_flags |= ECB_MODE;
14457188Smcpowers 	}
14467188Smcpowers 
14477188Smcpowers 	if (rv != CRYPTO_SUCCESS) {
14487188Smcpowers 		if (aes_ctx->ac_flags & PROVIDER_OWNS_KEY_SCHEDULE) {
14497188Smcpowers 			bzero(keysched, size);
14507188Smcpowers 			kmem_free(keysched, size);
14514486Sktung 		}
14524486Sktung 	}
14534486Sktung 
14540Sstevel@tonic-gate /* EXPORT DELETE END */
14550Sstevel@tonic-gate 
14560Sstevel@tonic-gate 	return (rv);
14570Sstevel@tonic-gate }
14589339SMark.Powers@Sun.COM 
14599339SMark.Powers@Sun.COM static int
process_gmac_mech(crypto_mechanism_t * mech,crypto_data_t * data,CK_AES_GCM_PARAMS * gcm_params)14609339SMark.Powers@Sun.COM process_gmac_mech(crypto_mechanism_t *mech, crypto_data_t *data,
14619339SMark.Powers@Sun.COM     CK_AES_GCM_PARAMS *gcm_params)
14629339SMark.Powers@Sun.COM {
14639339SMark.Powers@Sun.COM 	/* LINTED: pointer alignment */
14649339SMark.Powers@Sun.COM 	CK_AES_GMAC_PARAMS *params = (CK_AES_GMAC_PARAMS *)mech->cm_param;
14659339SMark.Powers@Sun.COM 
14669339SMark.Powers@Sun.COM 	if (mech->cm_type != AES_GMAC_MECH_INFO_TYPE)
14679339SMark.Powers@Sun.COM 		return (CRYPTO_MECHANISM_INVALID);
14689339SMark.Powers@Sun.COM 
14699339SMark.Powers@Sun.COM 	if (mech->cm_param_len != sizeof (CK_AES_GMAC_PARAMS))
14709339SMark.Powers@Sun.COM 		return (CRYPTO_MECHANISM_PARAM_INVALID);
14719339SMark.Powers@Sun.COM 
14729339SMark.Powers@Sun.COM 	if (params->pIv == NULL)
14739339SMark.Powers@Sun.COM 		return (CRYPTO_MECHANISM_PARAM_INVALID);
14749339SMark.Powers@Sun.COM 
14759339SMark.Powers@Sun.COM 	gcm_params->pIv = params->pIv;
14769339SMark.Powers@Sun.COM 	gcm_params->ulIvLen = AES_GMAC_IV_LEN;
14779339SMark.Powers@Sun.COM 	gcm_params->ulTagBits = AES_GMAC_TAG_BITS;
14789339SMark.Powers@Sun.COM 
14799339SMark.Powers@Sun.COM 	if (data == NULL)
14809339SMark.Powers@Sun.COM 		return (CRYPTO_SUCCESS);
14819339SMark.Powers@Sun.COM 
14829339SMark.Powers@Sun.COM 	if (data->cd_format != CRYPTO_DATA_RAW)
14839339SMark.Powers@Sun.COM 		return (CRYPTO_ARGUMENTS_BAD);
14849339SMark.Powers@Sun.COM 
14859339SMark.Powers@Sun.COM 	gcm_params->pAAD = (uchar_t *)data->cd_raw.iov_base;
14869339SMark.Powers@Sun.COM 	gcm_params->ulAADLen = data->cd_length;
14879339SMark.Powers@Sun.COM 	return (CRYPTO_SUCCESS);
14889339SMark.Powers@Sun.COM }
14899339SMark.Powers@Sun.COM 
14909339SMark.Powers@Sun.COM static int
aes_mac_atomic(crypto_provider_handle_t provider,crypto_session_id_t session_id,crypto_mechanism_t * mechanism,crypto_key_t * key,crypto_data_t * data,crypto_data_t * mac,crypto_spi_ctx_template_t template,crypto_req_handle_t req)14919339SMark.Powers@Sun.COM aes_mac_atomic(crypto_provider_handle_t provider,
14929339SMark.Powers@Sun.COM     crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
14939339SMark.Powers@Sun.COM     crypto_key_t *key, crypto_data_t *data, crypto_data_t *mac,
14949339SMark.Powers@Sun.COM     crypto_spi_ctx_template_t template, crypto_req_handle_t req)
14959339SMark.Powers@Sun.COM {
14969339SMark.Powers@Sun.COM 	CK_AES_GCM_PARAMS gcm_params;
14979339SMark.Powers@Sun.COM 	crypto_mechanism_t gcm_mech;
14989339SMark.Powers@Sun.COM 	int rv;
14999339SMark.Powers@Sun.COM 
15009339SMark.Powers@Sun.COM 	if ((rv = process_gmac_mech(mechanism, data, &gcm_params))
15019339SMark.Powers@Sun.COM 	    != CRYPTO_SUCCESS)
15029339SMark.Powers@Sun.COM 		return (rv);
15039339SMark.Powers@Sun.COM 
15049339SMark.Powers@Sun.COM 	gcm_mech.cm_type = AES_GCM_MECH_INFO_TYPE;
15059339SMark.Powers@Sun.COM 	gcm_mech.cm_param_len = sizeof (CK_AES_GCM_PARAMS);
15069339SMark.Powers@Sun.COM 	gcm_mech.cm_param = (char *)&gcm_params;
15079339SMark.Powers@Sun.COM 
15089339SMark.Powers@Sun.COM 	return (aes_encrypt_atomic(provider, session_id, &gcm_mech,
15099339SMark.Powers@Sun.COM 	    key, &null_crypto_data, mac, template, req));
15109339SMark.Powers@Sun.COM }
15119339SMark.Powers@Sun.COM 
15129339SMark.Powers@Sun.COM static int
aes_mac_verify_atomic(crypto_provider_handle_t provider,crypto_session_id_t session_id,crypto_mechanism_t * mechanism,crypto_key_t * key,crypto_data_t * data,crypto_data_t * mac,crypto_spi_ctx_template_t template,crypto_req_handle_t req)15139339SMark.Powers@Sun.COM aes_mac_verify_atomic(crypto_provider_handle_t provider,
15149339SMark.Powers@Sun.COM     crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
15159339SMark.Powers@Sun.COM     crypto_key_t *key, crypto_data_t *data, crypto_data_t *mac,
15169339SMark.Powers@Sun.COM     crypto_spi_ctx_template_t template, crypto_req_handle_t req)
15179339SMark.Powers@Sun.COM {
15189339SMark.Powers@Sun.COM 	CK_AES_GCM_PARAMS gcm_params;
15199339SMark.Powers@Sun.COM 	crypto_mechanism_t gcm_mech;
15209339SMark.Powers@Sun.COM 	int rv;
15219339SMark.Powers@Sun.COM 
15229339SMark.Powers@Sun.COM 	if ((rv = process_gmac_mech(mechanism, data, &gcm_params))
15239339SMark.Powers@Sun.COM 	    != CRYPTO_SUCCESS)
15249339SMark.Powers@Sun.COM 		return (rv);
15259339SMark.Powers@Sun.COM 
15269339SMark.Powers@Sun.COM 	gcm_mech.cm_type = AES_GCM_MECH_INFO_TYPE;
15279339SMark.Powers@Sun.COM 	gcm_mech.cm_param_len = sizeof (CK_AES_GCM_PARAMS);
15289339SMark.Powers@Sun.COM 	gcm_mech.cm_param = (char *)&gcm_params;
15299339SMark.Powers@Sun.COM 
15309339SMark.Powers@Sun.COM 	return (aes_decrypt_atomic(provider, session_id, &gcm_mech,
15319339SMark.Powers@Sun.COM 	    key, mac, &null_crypto_data, template, req));
15329339SMark.Powers@Sun.COM }
153310500SHai-May.Chao@Sun.COM 
153410500SHai-May.Chao@Sun.COM /*
153510500SHai-May.Chao@Sun.COM  * AES Power-Up Self-Test
153610500SHai-May.Chao@Sun.COM  */
153710500SHai-May.Chao@Sun.COM void
aes_POST(int * rc)153810500SHai-May.Chao@Sun.COM aes_POST(int *rc)
153910500SHai-May.Chao@Sun.COM {
154010500SHai-May.Chao@Sun.COM 
154110500SHai-May.Chao@Sun.COM 	int ret;
154210500SHai-May.Chao@Sun.COM 
154310500SHai-May.Chao@Sun.COM 	/* AES Power-Up Self-Test for 128-bit key. */
154410500SHai-May.Chao@Sun.COM 	ret = fips_aes_post(FIPS_AES_128_KEY_SIZE);
154510500SHai-May.Chao@Sun.COM 
154610500SHai-May.Chao@Sun.COM 	if (ret != CRYPTO_SUCCESS)
154710500SHai-May.Chao@Sun.COM 		goto out;
154810500SHai-May.Chao@Sun.COM 
154910500SHai-May.Chao@Sun.COM 	/* AES Power-Up Self-Test for 192-bit key. */
155010500SHai-May.Chao@Sun.COM 	ret = fips_aes_post(FIPS_AES_192_KEY_SIZE);
155110500SHai-May.Chao@Sun.COM 
155210500SHai-May.Chao@Sun.COM 	if (ret != CRYPTO_SUCCESS)
155310500SHai-May.Chao@Sun.COM 		goto out;
155410500SHai-May.Chao@Sun.COM 
155510500SHai-May.Chao@Sun.COM 	/* AES Power-Up Self-Test for 256-bit key. */
155610500SHai-May.Chao@Sun.COM 	ret = fips_aes_post(FIPS_AES_256_KEY_SIZE);
155710500SHai-May.Chao@Sun.COM 
155810500SHai-May.Chao@Sun.COM out:
155910500SHai-May.Chao@Sun.COM 	*rc = ret;
156010500SHai-May.Chao@Sun.COM 
156110500SHai-May.Chao@Sun.COM }
1562