17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 53fdb082fSpwernau * Common Development and Distribution License (the "License"). 63fdb082fSpwernau * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22e8ab7b17SZdenek Kotala * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. 237c478bd9Sstevel@tonic-gate */ 247c478bd9Sstevel@tonic-gate 257c478bd9Sstevel@tonic-gate /* 267c478bd9Sstevel@tonic-gate * AES provider for the Kernel Cryptographic Framework (KCF) 277c478bd9Sstevel@tonic-gate */ 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate #include <sys/types.h> 307c478bd9Sstevel@tonic-gate #include <sys/systm.h> 317c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 327c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 337c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 347c478bd9Sstevel@tonic-gate #include <sys/crypto/common.h> 3523c57df7Smcpowers #include <sys/crypto/impl.h> 367c478bd9Sstevel@tonic-gate #include <sys/crypto/spi.h> 377c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 387c478bd9Sstevel@tonic-gate #include <sys/strsun.h> 3923c57df7Smcpowers #include <modes/modes.h> 40b5a2d845SHai-May Chao #define _AES_IMPL 4123c57df7Smcpowers #include <aes/aes_impl.h> 427c478bd9Sstevel@tonic-gate 437c478bd9Sstevel@tonic-gate extern struct mod_ops mod_cryptoops; 447c478bd9Sstevel@tonic-gate 457c478bd9Sstevel@tonic-gate /* 467c478bd9Sstevel@tonic-gate * Module linkage information for the kernel. 477c478bd9Sstevel@tonic-gate */ 487c478bd9Sstevel@tonic-gate static struct modlcrypto modlcrypto = { 497c478bd9Sstevel@tonic-gate &mod_cryptoops, 50d2b32306Smcpowers "AES Kernel SW Provider" 517c478bd9Sstevel@tonic-gate }; 527c478bd9Sstevel@tonic-gate 537c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 547c478bd9Sstevel@tonic-gate MODREV_1, 557c478bd9Sstevel@tonic-gate (void *)&modlcrypto, 567c478bd9Sstevel@tonic-gate NULL 577c478bd9Sstevel@tonic-gate }; 587c478bd9Sstevel@tonic-gate 597c478bd9Sstevel@tonic-gate /* 607c478bd9Sstevel@tonic-gate * Mechanism info structure passed to KCF during registration. 617c478bd9Sstevel@tonic-gate */ 627c478bd9Sstevel@tonic-gate static crypto_mech_info_t aes_mech_info_tab[] = { 637c478bd9Sstevel@tonic-gate /* AES_ECB */ 647c478bd9Sstevel@tonic-gate {SUN_CKM_AES_ECB, AES_ECB_MECH_INFO_TYPE, 657c478bd9Sstevel@tonic-gate CRYPTO_FG_ENCRYPT | CRYPTO_FG_ENCRYPT_ATOMIC | 667c478bd9Sstevel@tonic-gate CRYPTO_FG_DECRYPT | CRYPTO_FG_DECRYPT_ATOMIC, 673fdb082fSpwernau AES_MIN_KEY_BYTES, AES_MAX_KEY_BYTES, CRYPTO_KEYSIZE_UNIT_IN_BYTES}, 687c478bd9Sstevel@tonic-gate /* AES_CBC */ 697c478bd9Sstevel@tonic-gate {SUN_CKM_AES_CBC, AES_CBC_MECH_INFO_TYPE, 707c478bd9Sstevel@tonic-gate CRYPTO_FG_ENCRYPT | CRYPTO_FG_ENCRYPT_ATOMIC | 717c478bd9Sstevel@tonic-gate CRYPTO_FG_DECRYPT | CRYPTO_FG_DECRYPT_ATOMIC, 723fdb082fSpwernau AES_MIN_KEY_BYTES, AES_MAX_KEY_BYTES, CRYPTO_KEYSIZE_UNIT_IN_BYTES}, 73894b2776Smcpowers /* AES_CTR */ 74894b2776Smcpowers {SUN_CKM_AES_CTR, AES_CTR_MECH_INFO_TYPE, 75894b2776Smcpowers CRYPTO_FG_ENCRYPT | CRYPTO_FG_ENCRYPT_ATOMIC | 76894b2776Smcpowers CRYPTO_FG_DECRYPT | CRYPTO_FG_DECRYPT_ATOMIC, 777fb8ff4bSktung AES_MIN_KEY_BYTES, AES_MAX_KEY_BYTES, CRYPTO_KEYSIZE_UNIT_IN_BYTES}, 787fb8ff4bSktung /* AES_CCM */ 797fb8ff4bSktung {SUN_CKM_AES_CCM, AES_CCM_MECH_INFO_TYPE, 807fb8ff4bSktung CRYPTO_FG_ENCRYPT | CRYPTO_FG_ENCRYPT_ATOMIC | 817fb8ff4bSktung CRYPTO_FG_DECRYPT | CRYPTO_FG_DECRYPT_ATOMIC, 824d703b5cSMark Powers AES_MIN_KEY_BYTES, AES_MAX_KEY_BYTES, CRYPTO_KEYSIZE_UNIT_IN_BYTES}, 834d703b5cSMark Powers /* AES_GCM */ 844d703b5cSMark Powers {SUN_CKM_AES_GCM, AES_GCM_MECH_INFO_TYPE, 854d703b5cSMark Powers CRYPTO_FG_ENCRYPT | CRYPTO_FG_ENCRYPT_ATOMIC | 864d703b5cSMark Powers CRYPTO_FG_DECRYPT | CRYPTO_FG_DECRYPT_ATOMIC, 87983a1033SMark Powers AES_MIN_KEY_BYTES, AES_MAX_KEY_BYTES, CRYPTO_KEYSIZE_UNIT_IN_BYTES}, 88983a1033SMark Powers /* AES_GMAC */ 89983a1033SMark Powers {SUN_CKM_AES_GMAC, AES_GMAC_MECH_INFO_TYPE, 90983a1033SMark Powers CRYPTO_FG_ENCRYPT | CRYPTO_FG_ENCRYPT_ATOMIC | 91983a1033SMark Powers CRYPTO_FG_DECRYPT | CRYPTO_FG_DECRYPT_ATOMIC | 92983a1033SMark Powers CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC | 93983a1033SMark Powers CRYPTO_FG_SIGN | CRYPTO_FG_SIGN_ATOMIC | 94983a1033SMark Powers CRYPTO_FG_VERIFY | CRYPTO_FG_VERIFY_ATOMIC, 953fdb082fSpwernau AES_MIN_KEY_BYTES, AES_MAX_KEY_BYTES, CRYPTO_KEYSIZE_UNIT_IN_BYTES} 967c478bd9Sstevel@tonic-gate }; 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate /* operations are in-place if the output buffer is NULL */ 997c478bd9Sstevel@tonic-gate #define AES_ARG_INPLACE(input, output) \ 1007c478bd9Sstevel@tonic-gate if ((output) == NULL) \ 1017c478bd9Sstevel@tonic-gate (output) = (input); 1027c478bd9Sstevel@tonic-gate 1037c478bd9Sstevel@tonic-gate static void aes_provider_status(crypto_provider_handle_t, uint_t *); 1047c478bd9Sstevel@tonic-gate 1057c478bd9Sstevel@tonic-gate static crypto_control_ops_t aes_control_ops = { 1067c478bd9Sstevel@tonic-gate aes_provider_status 1077c478bd9Sstevel@tonic-gate }; 1087c478bd9Sstevel@tonic-gate 1097fb8ff4bSktung static int aes_encrypt_init(crypto_ctx_t *, crypto_mechanism_t *, 1107c478bd9Sstevel@tonic-gate crypto_key_t *, crypto_spi_ctx_template_t, crypto_req_handle_t); 1117fb8ff4bSktung static int aes_decrypt_init(crypto_ctx_t *, crypto_mechanism_t *, 1127fb8ff4bSktung crypto_key_t *, crypto_spi_ctx_template_t, crypto_req_handle_t); 1137fb8ff4bSktung static int aes_common_init(crypto_ctx_t *, crypto_mechanism_t *, 1147fb8ff4bSktung crypto_key_t *, crypto_spi_ctx_template_t, crypto_req_handle_t, boolean_t); 1157c478bd9Sstevel@tonic-gate static int aes_common_init_ctx(aes_ctx_t *, crypto_spi_ctx_template_t *, 1167fb8ff4bSktung crypto_mechanism_t *, crypto_key_t *, int, boolean_t); 1177c478bd9Sstevel@tonic-gate static int aes_encrypt_final(crypto_ctx_t *, crypto_data_t *, 1187c478bd9Sstevel@tonic-gate crypto_req_handle_t); 1197c478bd9Sstevel@tonic-gate static int aes_decrypt_final(crypto_ctx_t *, crypto_data_t *, 1207c478bd9Sstevel@tonic-gate crypto_req_handle_t); 1217c478bd9Sstevel@tonic-gate 1227c478bd9Sstevel@tonic-gate static int aes_encrypt(crypto_ctx_t *, crypto_data_t *, crypto_data_t *, 1237c478bd9Sstevel@tonic-gate crypto_req_handle_t); 1247c478bd9Sstevel@tonic-gate static int aes_encrypt_update(crypto_ctx_t *, crypto_data_t *, 1257c478bd9Sstevel@tonic-gate crypto_data_t *, crypto_req_handle_t); 1267c478bd9Sstevel@tonic-gate static int aes_encrypt_atomic(crypto_provider_handle_t, crypto_session_id_t, 1277c478bd9Sstevel@tonic-gate crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, 1287c478bd9Sstevel@tonic-gate crypto_data_t *, crypto_spi_ctx_template_t, crypto_req_handle_t); 1297c478bd9Sstevel@tonic-gate 1307c478bd9Sstevel@tonic-gate static int aes_decrypt(crypto_ctx_t *, crypto_data_t *, crypto_data_t *, 1317c478bd9Sstevel@tonic-gate crypto_req_handle_t); 1327c478bd9Sstevel@tonic-gate static int aes_decrypt_update(crypto_ctx_t *, crypto_data_t *, 1337c478bd9Sstevel@tonic-gate crypto_data_t *, crypto_req_handle_t); 1347c478bd9Sstevel@tonic-gate static int aes_decrypt_atomic(crypto_provider_handle_t, crypto_session_id_t, 1357c478bd9Sstevel@tonic-gate crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, 1367c478bd9Sstevel@tonic-gate crypto_data_t *, crypto_spi_ctx_template_t, crypto_req_handle_t); 1377c478bd9Sstevel@tonic-gate 1387c478bd9Sstevel@tonic-gate static crypto_cipher_ops_t aes_cipher_ops = { 1397fb8ff4bSktung aes_encrypt_init, 1407c478bd9Sstevel@tonic-gate aes_encrypt, 1417c478bd9Sstevel@tonic-gate aes_encrypt_update, 1427c478bd9Sstevel@tonic-gate aes_encrypt_final, 1437c478bd9Sstevel@tonic-gate aes_encrypt_atomic, 1447fb8ff4bSktung aes_decrypt_init, 1457c478bd9Sstevel@tonic-gate aes_decrypt, 1467c478bd9Sstevel@tonic-gate aes_decrypt_update, 1477c478bd9Sstevel@tonic-gate aes_decrypt_final, 1487c478bd9Sstevel@tonic-gate aes_decrypt_atomic 1497c478bd9Sstevel@tonic-gate }; 1507c478bd9Sstevel@tonic-gate 151983a1033SMark Powers static int aes_mac_atomic(crypto_provider_handle_t, crypto_session_id_t, 152983a1033SMark Powers crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, crypto_data_t *, 153983a1033SMark Powers crypto_spi_ctx_template_t, crypto_req_handle_t); 154983a1033SMark Powers static int aes_mac_verify_atomic(crypto_provider_handle_t, crypto_session_id_t, 155983a1033SMark Powers crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, crypto_data_t *, 156983a1033SMark Powers crypto_spi_ctx_template_t, crypto_req_handle_t); 157983a1033SMark Powers 158983a1033SMark Powers static crypto_mac_ops_t aes_mac_ops = { 159983a1033SMark Powers NULL, 160983a1033SMark Powers NULL, 161983a1033SMark Powers NULL, 162983a1033SMark Powers NULL, 163983a1033SMark Powers aes_mac_atomic, 164983a1033SMark Powers aes_mac_verify_atomic 165983a1033SMark Powers }; 166983a1033SMark Powers 1677c478bd9Sstevel@tonic-gate static int aes_create_ctx_template(crypto_provider_handle_t, 1687c478bd9Sstevel@tonic-gate crypto_mechanism_t *, crypto_key_t *, crypto_spi_ctx_template_t *, 1697c478bd9Sstevel@tonic-gate size_t *, crypto_req_handle_t); 1707c478bd9Sstevel@tonic-gate static int aes_free_context(crypto_ctx_t *); 1717c478bd9Sstevel@tonic-gate 1727c478bd9Sstevel@tonic-gate static crypto_ctx_ops_t aes_ctx_ops = { 1737c478bd9Sstevel@tonic-gate aes_create_ctx_template, 1747c478bd9Sstevel@tonic-gate aes_free_context 1757c478bd9Sstevel@tonic-gate }; 1767c478bd9Sstevel@tonic-gate 1777c478bd9Sstevel@tonic-gate static crypto_ops_t aes_crypto_ops = { 1787c478bd9Sstevel@tonic-gate &aes_control_ops, 1797c478bd9Sstevel@tonic-gate NULL, 1807c478bd9Sstevel@tonic-gate &aes_cipher_ops, 181983a1033SMark Powers &aes_mac_ops, 1827c478bd9Sstevel@tonic-gate NULL, 1837c478bd9Sstevel@tonic-gate NULL, 1847c478bd9Sstevel@tonic-gate NULL, 1857c478bd9Sstevel@tonic-gate NULL, 1867c478bd9Sstevel@tonic-gate NULL, 1877c478bd9Sstevel@tonic-gate NULL, 1887c478bd9Sstevel@tonic-gate NULL, 1897c478bd9Sstevel@tonic-gate NULL, 1907c478bd9Sstevel@tonic-gate NULL, 19173556491SAnthony Scarpino &aes_ctx_ops, 19273556491SAnthony Scarpino NULL, 19373556491SAnthony Scarpino NULL, 194*6ea3c060SGarrett D'Amore NULL, 1957c478bd9Sstevel@tonic-gate }; 1967c478bd9Sstevel@tonic-gate 1977c478bd9Sstevel@tonic-gate static crypto_provider_info_t aes_prov_info = { 19873556491SAnthony Scarpino CRYPTO_SPI_VERSION_4, 1997c478bd9Sstevel@tonic-gate "AES Software Provider", 2007c478bd9Sstevel@tonic-gate CRYPTO_SW_PROVIDER, 2017c478bd9Sstevel@tonic-gate {&modlinkage}, 2027c478bd9Sstevel@tonic-gate NULL, 2037c478bd9Sstevel@tonic-gate &aes_crypto_ops, 2047c478bd9Sstevel@tonic-gate sizeof (aes_mech_info_tab)/sizeof (crypto_mech_info_t), 2057c478bd9Sstevel@tonic-gate aes_mech_info_tab 2067c478bd9Sstevel@tonic-gate }; 2077c478bd9Sstevel@tonic-gate 2087c478bd9Sstevel@tonic-gate static crypto_kcf_provider_handle_t aes_prov_handle = NULL; 209983a1033SMark Powers static crypto_data_t null_crypto_data = { CRYPTO_DATA_RAW }; 2107c478bd9Sstevel@tonic-gate 2117c478bd9Sstevel@tonic-gate int 2127c478bd9Sstevel@tonic-gate _init(void) 2137c478bd9Sstevel@tonic-gate { 2147c478bd9Sstevel@tonic-gate int ret; 2157c478bd9Sstevel@tonic-gate 216d3b2efc7SAnthony Scarpino if ((ret = mod_install(&modlinkage)) != 0) 217d3b2efc7SAnthony Scarpino return (ret); 218d3b2efc7SAnthony Scarpino 219d3b2efc7SAnthony Scarpino /* Register with KCF. If the registration fails, remove the module. */ 220d3b2efc7SAnthony Scarpino if (crypto_register_provider(&aes_prov_info, &aes_prov_handle)) { 221d3b2efc7SAnthony Scarpino (void) mod_remove(&modlinkage); 2227c478bd9Sstevel@tonic-gate return (EACCES); 2237c478bd9Sstevel@tonic-gate } 2247c478bd9Sstevel@tonic-gate 225d3b2efc7SAnthony Scarpino return (0); 2267c478bd9Sstevel@tonic-gate } 2277c478bd9Sstevel@tonic-gate 2287c478bd9Sstevel@tonic-gate int 2297c478bd9Sstevel@tonic-gate _fini(void) 2307c478bd9Sstevel@tonic-gate { 231d3b2efc7SAnthony Scarpino /* Unregister from KCF if module is registered */ 2327c478bd9Sstevel@tonic-gate if (aes_prov_handle != NULL) { 233d3b2efc7SAnthony Scarpino if (crypto_unregister_provider(aes_prov_handle)) 2347c478bd9Sstevel@tonic-gate return (EBUSY); 235d3b2efc7SAnthony Scarpino 2367c478bd9Sstevel@tonic-gate aes_prov_handle = NULL; 2377c478bd9Sstevel@tonic-gate } 2387c478bd9Sstevel@tonic-gate 2397c478bd9Sstevel@tonic-gate return (mod_remove(&modlinkage)); 2407c478bd9Sstevel@tonic-gate } 2417c478bd9Sstevel@tonic-gate 2427c478bd9Sstevel@tonic-gate int 2437c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 2447c478bd9Sstevel@tonic-gate { 2457c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 2467c478bd9Sstevel@tonic-gate } 2477c478bd9Sstevel@tonic-gate 2487c478bd9Sstevel@tonic-gate 249bbbb143bSmcpowers static int 25023c57df7Smcpowers aes_check_mech_param(crypto_mechanism_t *mechanism, aes_ctx_t **ctx, int kmflag) 251bbbb143bSmcpowers { 25223c57df7Smcpowers void *p = NULL; 253983a1033SMark Powers boolean_t param_required = B_TRUE; 254983a1033SMark Powers size_t param_len; 255983a1033SMark Powers void *(*alloc_fun)(int); 256bbbb143bSmcpowers int rv = CRYPTO_SUCCESS; 257bbbb143bSmcpowers 258bbbb143bSmcpowers switch (mechanism->cm_type) { 259bbbb143bSmcpowers case AES_ECB_MECH_INFO_TYPE: 260983a1033SMark Powers param_required = B_FALSE; 261983a1033SMark Powers alloc_fun = ecb_alloc_ctx; 262bbbb143bSmcpowers break; 263bbbb143bSmcpowers case AES_CBC_MECH_INFO_TYPE: 264983a1033SMark Powers param_len = AES_BLOCK_LEN; 265983a1033SMark Powers alloc_fun = cbc_alloc_ctx; 26623c57df7Smcpowers break; 267bbbb143bSmcpowers case AES_CTR_MECH_INFO_TYPE: 268983a1033SMark Powers param_len = sizeof (CK_AES_CTR_PARAMS); 269983a1033SMark Powers alloc_fun = ctr_alloc_ctx; 27023c57df7Smcpowers break; 2717fb8ff4bSktung case AES_CCM_MECH_INFO_TYPE: 272983a1033SMark Powers param_len = sizeof (CK_AES_CCM_PARAMS); 273983a1033SMark Powers alloc_fun = ccm_alloc_ctx; 27423c57df7Smcpowers break; 2754d703b5cSMark Powers case AES_GCM_MECH_INFO_TYPE: 276983a1033SMark Powers param_len = sizeof (CK_AES_GCM_PARAMS); 277983a1033SMark Powers alloc_fun = gcm_alloc_ctx; 2784d703b5cSMark Powers break; 279983a1033SMark Powers case AES_GMAC_MECH_INFO_TYPE: 280983a1033SMark Powers param_len = sizeof (CK_AES_GMAC_PARAMS); 281983a1033SMark Powers alloc_fun = gmac_alloc_ctx; 2824d703b5cSMark Powers break; 283bbbb143bSmcpowers default: 284bbbb143bSmcpowers rv = CRYPTO_MECHANISM_INVALID; 285e8ab7b17SZdenek Kotala return (rv); 286bbbb143bSmcpowers } 287983a1033SMark Powers if (param_required && mechanism->cm_param != NULL && 288983a1033SMark Powers mechanism->cm_param_len != param_len) { 289983a1033SMark Powers rv = CRYPTO_MECHANISM_PARAM_INVALID; 290983a1033SMark Powers } 291983a1033SMark Powers if (ctx != NULL) { 292983a1033SMark Powers p = (alloc_fun)(kmflag); 29323c57df7Smcpowers *ctx = p; 294983a1033SMark Powers } 295bbbb143bSmcpowers return (rv); 296bbbb143bSmcpowers } 297bbbb143bSmcpowers 2987c478bd9Sstevel@tonic-gate /* 2997c478bd9Sstevel@tonic-gate * Initialize key schedules for AES 3007c478bd9Sstevel@tonic-gate */ 3017c478bd9Sstevel@tonic-gate static int 3027c478bd9Sstevel@tonic-gate init_keysched(crypto_key_t *key, void *newbie) 3037c478bd9Sstevel@tonic-gate { 3047c478bd9Sstevel@tonic-gate /* 3057c478bd9Sstevel@tonic-gate * Only keys by value are supported by this module. 3067c478bd9Sstevel@tonic-gate */ 3077c478bd9Sstevel@tonic-gate switch (key->ck_format) { 3087c478bd9Sstevel@tonic-gate case CRYPTO_KEY_RAW: 3097c478bd9Sstevel@tonic-gate if (key->ck_length < AES_MINBITS || 3107c478bd9Sstevel@tonic-gate key->ck_length > AES_MAXBITS) { 3117c478bd9Sstevel@tonic-gate return (CRYPTO_KEY_SIZE_RANGE); 3127c478bd9Sstevel@tonic-gate } 3137c478bd9Sstevel@tonic-gate 3147c478bd9Sstevel@tonic-gate /* key length must be either 128, 192, or 256 */ 3157c478bd9Sstevel@tonic-gate if ((key->ck_length & 63) != 0) 3167c478bd9Sstevel@tonic-gate return (CRYPTO_KEY_SIZE_RANGE); 3177c478bd9Sstevel@tonic-gate break; 3187c478bd9Sstevel@tonic-gate default: 3197c478bd9Sstevel@tonic-gate return (CRYPTO_KEY_TYPE_INCONSISTENT); 3207c478bd9Sstevel@tonic-gate } 3217c478bd9Sstevel@tonic-gate 3227c478bd9Sstevel@tonic-gate aes_init_keysched(key->ck_data, key->ck_length, newbie); 3237c478bd9Sstevel@tonic-gate return (CRYPTO_SUCCESS); 3247c478bd9Sstevel@tonic-gate } 3257c478bd9Sstevel@tonic-gate 3267c478bd9Sstevel@tonic-gate /* 3277c478bd9Sstevel@tonic-gate * KCF software provider control entry points. 3287c478bd9Sstevel@tonic-gate */ 3297c478bd9Sstevel@tonic-gate /* ARGSUSED */ 3307c478bd9Sstevel@tonic-gate static void 3317c478bd9Sstevel@tonic-gate aes_provider_status(crypto_provider_handle_t provider, uint_t *status) 3327c478bd9Sstevel@tonic-gate { 3337c478bd9Sstevel@tonic-gate *status = CRYPTO_PROVIDER_READY; 3347c478bd9Sstevel@tonic-gate } 3357c478bd9Sstevel@tonic-gate 3367fb8ff4bSktung static int 3377fb8ff4bSktung aes_encrypt_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism, 3387fb8ff4bSktung crypto_key_t *key, crypto_spi_ctx_template_t template, 3397fb8ff4bSktung crypto_req_handle_t req) { 3407fb8ff4bSktung return (aes_common_init(ctx, mechanism, key, template, req, B_TRUE)); 3417fb8ff4bSktung } 3427fb8ff4bSktung 3437fb8ff4bSktung static int 3447fb8ff4bSktung aes_decrypt_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism, 3457fb8ff4bSktung crypto_key_t *key, crypto_spi_ctx_template_t template, 3467fb8ff4bSktung crypto_req_handle_t req) { 3477fb8ff4bSktung return (aes_common_init(ctx, mechanism, key, template, req, B_FALSE)); 3487fb8ff4bSktung } 3497fb8ff4bSktung 3507fb8ff4bSktung 3517fb8ff4bSktung 3527c478bd9Sstevel@tonic-gate /* 3537c478bd9Sstevel@tonic-gate * KCF software provider encrypt entry points. 3547c478bd9Sstevel@tonic-gate */ 3557c478bd9Sstevel@tonic-gate static int 3567c478bd9Sstevel@tonic-gate aes_common_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism, 3577c478bd9Sstevel@tonic-gate crypto_key_t *key, crypto_spi_ctx_template_t template, 3587fb8ff4bSktung crypto_req_handle_t req, boolean_t is_encrypt_init) 3597c478bd9Sstevel@tonic-gate { 3607c478bd9Sstevel@tonic-gate aes_ctx_t *aes_ctx; 3617c478bd9Sstevel@tonic-gate int rv; 3627c478bd9Sstevel@tonic-gate int kmflag; 3637c478bd9Sstevel@tonic-gate 3647c478bd9Sstevel@tonic-gate /* 3657c478bd9Sstevel@tonic-gate * Only keys by value are supported by this module. 3667c478bd9Sstevel@tonic-gate */ 3677c478bd9Sstevel@tonic-gate if (key->ck_format != CRYPTO_KEY_RAW) { 3687c478bd9Sstevel@tonic-gate return (CRYPTO_KEY_TYPE_INCONSISTENT); 3697c478bd9Sstevel@tonic-gate } 3707c478bd9Sstevel@tonic-gate 3717c478bd9Sstevel@tonic-gate kmflag = crypto_kmflag(req); 37223c57df7Smcpowers if ((rv = aes_check_mech_param(mechanism, &aes_ctx, kmflag)) 37323c57df7Smcpowers != CRYPTO_SUCCESS) 37423c57df7Smcpowers return (rv); 3757c478bd9Sstevel@tonic-gate 3767fb8ff4bSktung rv = aes_common_init_ctx(aes_ctx, template, mechanism, key, kmflag, 3777fb8ff4bSktung is_encrypt_init); 3787c478bd9Sstevel@tonic-gate if (rv != CRYPTO_SUCCESS) { 37923c57df7Smcpowers crypto_free_mode_ctx(aes_ctx); 3807c478bd9Sstevel@tonic-gate return (rv); 3817c478bd9Sstevel@tonic-gate } 3827c478bd9Sstevel@tonic-gate 3837c478bd9Sstevel@tonic-gate ctx->cc_provider_private = aes_ctx; 3847c478bd9Sstevel@tonic-gate 3857c478bd9Sstevel@tonic-gate return (CRYPTO_SUCCESS); 3867c478bd9Sstevel@tonic-gate } 3877c478bd9Sstevel@tonic-gate 38823c57df7Smcpowers static void 38923c57df7Smcpowers aes_copy_block64(uint8_t *in, uint64_t *out) 3907c478bd9Sstevel@tonic-gate { 39123c57df7Smcpowers if (IS_P2ALIGNED(in, sizeof (uint64_t))) { 3927c478bd9Sstevel@tonic-gate /* LINTED: pointer alignment */ 39323c57df7Smcpowers out[0] = *(uint64_t *)&in[0]; 3947c478bd9Sstevel@tonic-gate /* LINTED: pointer alignment */ 39523c57df7Smcpowers out[1] = *(uint64_t *)&in[8]; 3967c478bd9Sstevel@tonic-gate } else { 39723c57df7Smcpowers uint8_t *iv8 = (uint8_t *)&out[0]; 3987c478bd9Sstevel@tonic-gate 39923c57df7Smcpowers AES_COPY_BLOCK(in, iv8); 4007c478bd9Sstevel@tonic-gate } 4017c478bd9Sstevel@tonic-gate } 4027c478bd9Sstevel@tonic-gate 40354034eb2SDan OpenSolaris Anderson 4047c478bd9Sstevel@tonic-gate static int 4057c478bd9Sstevel@tonic-gate aes_encrypt(crypto_ctx_t *ctx, crypto_data_t *plaintext, 4067c478bd9Sstevel@tonic-gate crypto_data_t *ciphertext, crypto_req_handle_t req) 4077c478bd9Sstevel@tonic-gate { 4087c478bd9Sstevel@tonic-gate int ret = CRYPTO_FAILED; 4097c478bd9Sstevel@tonic-gate 4107c478bd9Sstevel@tonic-gate aes_ctx_t *aes_ctx; 4117fb8ff4bSktung size_t saved_length, saved_offset, length_needed; 4127c478bd9Sstevel@tonic-gate 4137c478bd9Sstevel@tonic-gate ASSERT(ctx->cc_provider_private != NULL); 4147c478bd9Sstevel@tonic-gate aes_ctx = ctx->cc_provider_private; 4157c478bd9Sstevel@tonic-gate 416894b2776Smcpowers /* 417894b2776Smcpowers * For block ciphers, plaintext must be a multiple of AES block size. 418894b2776Smcpowers * This test is only valid for ciphers whose blocksize is a power of 2. 419894b2776Smcpowers */ 420983a1033SMark Powers if (((aes_ctx->ac_flags & (CTR_MODE|CCM_MODE|GCM_MODE|GMAC_MODE)) 421983a1033SMark Powers == 0) && (plaintext->cd_length & (AES_BLOCK_LEN - 1)) != 0) 422894b2776Smcpowers return (CRYPTO_DATA_LEN_RANGE); 423894b2776Smcpowers 4247c478bd9Sstevel@tonic-gate AES_ARG_INPLACE(plaintext, ciphertext); 4257c478bd9Sstevel@tonic-gate 4267c478bd9Sstevel@tonic-gate /* 4277c478bd9Sstevel@tonic-gate * We need to just return the length needed to store the output. 4287c478bd9Sstevel@tonic-gate * We should not destroy the context for the following case. 4297c478bd9Sstevel@tonic-gate */ 430983a1033SMark Powers switch (aes_ctx->ac_flags & (CCM_MODE|GCM_MODE|GMAC_MODE)) { 431983a1033SMark Powers case CCM_MODE: 43223c57df7Smcpowers length_needed = plaintext->cd_length + aes_ctx->ac_mac_len; 433983a1033SMark Powers break; 434983a1033SMark Powers case GCM_MODE: 4351dcbfafdSMark Powers length_needed = plaintext->cd_length + aes_ctx->ac_tag_len; 436983a1033SMark Powers break; 437983a1033SMark Powers case GMAC_MODE: 438983a1033SMark Powers if (plaintext->cd_length != 0) 439983a1033SMark Powers return (CRYPTO_ARGUMENTS_BAD); 440983a1033SMark Powers 441983a1033SMark Powers length_needed = aes_ctx->ac_tag_len; 442983a1033SMark Powers break; 443983a1033SMark Powers default: 4447fb8ff4bSktung length_needed = plaintext->cd_length; 4457fb8ff4bSktung } 4467fb8ff4bSktung 4477fb8ff4bSktung if (ciphertext->cd_length < length_needed) { 4487fb8ff4bSktung ciphertext->cd_length = length_needed; 4497c478bd9Sstevel@tonic-gate return (CRYPTO_BUFFER_TOO_SMALL); 4507c478bd9Sstevel@tonic-gate } 4517c478bd9Sstevel@tonic-gate 4527fb8ff4bSktung saved_length = ciphertext->cd_length; 4537fb8ff4bSktung saved_offset = ciphertext->cd_offset; 4547fb8ff4bSktung 4557c478bd9Sstevel@tonic-gate /* 4567c478bd9Sstevel@tonic-gate * Do an update on the specified input data. 4577c478bd9Sstevel@tonic-gate */ 4587c478bd9Sstevel@tonic-gate ret = aes_encrypt_update(ctx, plaintext, ciphertext, req); 4597fb8ff4bSktung if (ret != CRYPTO_SUCCESS) { 4607fb8ff4bSktung return (ret); 4617fb8ff4bSktung } 4627fb8ff4bSktung 4637fb8ff4bSktung /* 4647fb8ff4bSktung * For CCM mode, aes_ccm_encrypt_final() will take care of any 4657fb8ff4bSktung * left-over unprocessed data, and compute the MAC 4667fb8ff4bSktung */ 46723c57df7Smcpowers if (aes_ctx->ac_flags & CCM_MODE) { 4687fb8ff4bSktung /* 4694d703b5cSMark Powers * ccm_encrypt_final() will compute the MAC and append 4707fb8ff4bSktung * it to existing ciphertext. So, need to adjust the left over 4717fb8ff4bSktung * length value accordingly 4727fb8ff4bSktung */ 4737fb8ff4bSktung 4747fb8ff4bSktung /* order of following 2 lines MUST not be reversed */ 4757fb8ff4bSktung ciphertext->cd_offset = ciphertext->cd_length; 4767fb8ff4bSktung ciphertext->cd_length = saved_length - ciphertext->cd_length; 47723c57df7Smcpowers ret = ccm_encrypt_final((ccm_ctx_t *)aes_ctx, ciphertext, 47823c57df7Smcpowers AES_BLOCK_LEN, aes_encrypt_block, aes_xor_block); 4797fb8ff4bSktung if (ret != CRYPTO_SUCCESS) { 4807fb8ff4bSktung return (ret); 4817fb8ff4bSktung } 4827fb8ff4bSktung 4837fb8ff4bSktung if (plaintext != ciphertext) { 4847fb8ff4bSktung ciphertext->cd_length = 4857fb8ff4bSktung ciphertext->cd_offset - saved_offset; 4867fb8ff4bSktung } 4877fb8ff4bSktung ciphertext->cd_offset = saved_offset; 488983a1033SMark Powers } else if (aes_ctx->ac_flags & (GCM_MODE|GMAC_MODE)) { 4894d703b5cSMark Powers /* 4904d703b5cSMark Powers * gcm_encrypt_final() will compute the MAC and append 4914d703b5cSMark Powers * it to existing ciphertext. So, need to adjust the left over 4924d703b5cSMark Powers * length value accordingly 4934d703b5cSMark Powers */ 4944d703b5cSMark Powers 4954d703b5cSMark Powers /* order of following 2 lines MUST not be reversed */ 4964d703b5cSMark Powers ciphertext->cd_offset = ciphertext->cd_length; 4974d703b5cSMark Powers ciphertext->cd_length = saved_length - ciphertext->cd_length; 4984d703b5cSMark Powers ret = gcm_encrypt_final((gcm_ctx_t *)aes_ctx, ciphertext, 4994d703b5cSMark Powers AES_BLOCK_LEN, aes_encrypt_block, aes_copy_block, 5004d703b5cSMark Powers aes_xor_block); 5014d703b5cSMark Powers if (ret != CRYPTO_SUCCESS) { 5024d703b5cSMark Powers return (ret); 5034d703b5cSMark Powers } 5044d703b5cSMark Powers 5054d703b5cSMark Powers if (plaintext != ciphertext) { 5064d703b5cSMark Powers ciphertext->cd_length = 5074d703b5cSMark Powers ciphertext->cd_offset - saved_offset; 5084d703b5cSMark Powers } 5094d703b5cSMark Powers ciphertext->cd_offset = saved_offset; 5107fb8ff4bSktung } 5117fb8ff4bSktung 5127c478bd9Sstevel@tonic-gate ASSERT(aes_ctx->ac_remainder_len == 0); 5137c478bd9Sstevel@tonic-gate (void) aes_free_context(ctx); 5147c478bd9Sstevel@tonic-gate 5157c478bd9Sstevel@tonic-gate return (ret); 5167c478bd9Sstevel@tonic-gate } 5177c478bd9Sstevel@tonic-gate 51854034eb2SDan OpenSolaris Anderson 5197c478bd9Sstevel@tonic-gate static int 5207c478bd9Sstevel@tonic-gate aes_decrypt(crypto_ctx_t *ctx, crypto_data_t *ciphertext, 5217c478bd9Sstevel@tonic-gate crypto_data_t *plaintext, crypto_req_handle_t req) 5227c478bd9Sstevel@tonic-gate { 5237c478bd9Sstevel@tonic-gate int ret = CRYPTO_FAILED; 5247c478bd9Sstevel@tonic-gate 5257c478bd9Sstevel@tonic-gate aes_ctx_t *aes_ctx; 5267fb8ff4bSktung off_t saved_offset; 527983a1033SMark Powers size_t saved_length, length_needed; 5287c478bd9Sstevel@tonic-gate 5297c478bd9Sstevel@tonic-gate ASSERT(ctx->cc_provider_private != NULL); 5307c478bd9Sstevel@tonic-gate aes_ctx = ctx->cc_provider_private; 5317c478bd9Sstevel@tonic-gate 532894b2776Smcpowers /* 5337fb8ff4bSktung * For block ciphers, plaintext must be a multiple of AES block size. 534894b2776Smcpowers * This test is only valid for ciphers whose blocksize is a power of 2. 535894b2776Smcpowers */ 536983a1033SMark Powers if (((aes_ctx->ac_flags & (CTR_MODE|CCM_MODE|GCM_MODE|GMAC_MODE)) 537983a1033SMark Powers == 0) && (ciphertext->cd_length & (AES_BLOCK_LEN - 1)) != 0) { 538efcbd7a0Sktung return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE); 539efcbd7a0Sktung } 540894b2776Smcpowers 5417c478bd9Sstevel@tonic-gate AES_ARG_INPLACE(ciphertext, plaintext); 5427c478bd9Sstevel@tonic-gate 5437c478bd9Sstevel@tonic-gate /* 544983a1033SMark Powers * Return length needed to store the output. 545983a1033SMark Powers * Do not destroy context when plaintext buffer is too small. 5467fb8ff4bSktung * 547983a1033SMark Powers * CCM: plaintext is MAC len smaller than cipher text 548983a1033SMark Powers * GCM: plaintext is TAG len smaller than cipher text 549983a1033SMark Powers * GMAC: plaintext length must be zero 5507c478bd9Sstevel@tonic-gate */ 551983a1033SMark Powers switch (aes_ctx->ac_flags & (CCM_MODE|GCM_MODE|GMAC_MODE)) { 552983a1033SMark Powers case CCM_MODE: 553983a1033SMark Powers length_needed = aes_ctx->ac_processed_data_len; 554983a1033SMark Powers break; 555983a1033SMark Powers case GCM_MODE: 556983a1033SMark Powers length_needed = ciphertext->cd_length - aes_ctx->ac_tag_len; 557983a1033SMark Powers break; 558983a1033SMark Powers case GMAC_MODE: 559983a1033SMark Powers if (plaintext->cd_length != 0) 560983a1033SMark Powers return (CRYPTO_ARGUMENTS_BAD); 5614d703b5cSMark Powers 562983a1033SMark Powers length_needed = 0; 563983a1033SMark Powers break; 564983a1033SMark Powers default: 565983a1033SMark Powers length_needed = ciphertext->cd_length; 566983a1033SMark Powers } 567983a1033SMark Powers 568983a1033SMark Powers if (plaintext->cd_length < length_needed) { 569983a1033SMark Powers plaintext->cd_length = length_needed; 5707fb8ff4bSktung return (CRYPTO_BUFFER_TOO_SMALL); 5717fb8ff4bSktung } 572983a1033SMark Powers 5737fb8ff4bSktung saved_offset = plaintext->cd_offset; 5747fb8ff4bSktung saved_length = plaintext->cd_length; 5757c478bd9Sstevel@tonic-gate 5767c478bd9Sstevel@tonic-gate /* 5777c478bd9Sstevel@tonic-gate * Do an update on the specified input data. 5787c478bd9Sstevel@tonic-gate */ 5797c478bd9Sstevel@tonic-gate ret = aes_decrypt_update(ctx, ciphertext, plaintext, req); 5807fb8ff4bSktung if (ret != CRYPTO_SUCCESS) { 5817fb8ff4bSktung goto cleanup; 5827fb8ff4bSktung } 5837fb8ff4bSktung 58423c57df7Smcpowers if (aes_ctx->ac_flags & CCM_MODE) { 58523c57df7Smcpowers ASSERT(aes_ctx->ac_processed_data_len == aes_ctx->ac_data_len); 58623c57df7Smcpowers ASSERT(aes_ctx->ac_processed_mac_len == aes_ctx->ac_mac_len); 5877fb8ff4bSktung 5887fb8ff4bSktung /* order of following 2 lines MUST not be reversed */ 5897fb8ff4bSktung plaintext->cd_offset = plaintext->cd_length; 5907fb8ff4bSktung plaintext->cd_length = saved_length - plaintext->cd_length; 5917fb8ff4bSktung 59223c57df7Smcpowers ret = ccm_decrypt_final((ccm_ctx_t *)aes_ctx, plaintext, 59323c57df7Smcpowers AES_BLOCK_LEN, aes_encrypt_block, aes_copy_block, 59423c57df7Smcpowers aes_xor_block); 5957fb8ff4bSktung if (ret == CRYPTO_SUCCESS) { 5967fb8ff4bSktung if (plaintext != ciphertext) { 5977fb8ff4bSktung plaintext->cd_length = 5987fb8ff4bSktung plaintext->cd_offset - saved_offset; 5997fb8ff4bSktung } 6007fb8ff4bSktung } else { 6017fb8ff4bSktung plaintext->cd_length = saved_length; 6027fb8ff4bSktung } 6037fb8ff4bSktung 6047fb8ff4bSktung plaintext->cd_offset = saved_offset; 605983a1033SMark Powers } else if (aes_ctx->ac_flags & (GCM_MODE|GMAC_MODE)) { 6064d703b5cSMark Powers /* order of following 2 lines MUST not be reversed */ 6074d703b5cSMark Powers plaintext->cd_offset = plaintext->cd_length; 6084d703b5cSMark Powers plaintext->cd_length = saved_length - plaintext->cd_length; 6094d703b5cSMark Powers 6104d703b5cSMark Powers ret = gcm_decrypt_final((gcm_ctx_t *)aes_ctx, plaintext, 6114d703b5cSMark Powers AES_BLOCK_LEN, aes_encrypt_block, aes_xor_block); 6124d703b5cSMark Powers if (ret == CRYPTO_SUCCESS) { 6134d703b5cSMark Powers if (plaintext != ciphertext) { 6144d703b5cSMark Powers plaintext->cd_length = 6154d703b5cSMark Powers plaintext->cd_offset - saved_offset; 6164d703b5cSMark Powers } 6174d703b5cSMark Powers } else { 6184d703b5cSMark Powers plaintext->cd_length = saved_length; 6194d703b5cSMark Powers } 6204d703b5cSMark Powers 6214d703b5cSMark Powers plaintext->cd_offset = saved_offset; 6227fb8ff4bSktung } 6237fb8ff4bSktung 6247c478bd9Sstevel@tonic-gate ASSERT(aes_ctx->ac_remainder_len == 0); 6257fb8ff4bSktung 6267fb8ff4bSktung cleanup: 6277c478bd9Sstevel@tonic-gate (void) aes_free_context(ctx); 6287c478bd9Sstevel@tonic-gate 6297c478bd9Sstevel@tonic-gate return (ret); 6307c478bd9Sstevel@tonic-gate } 6317c478bd9Sstevel@tonic-gate 63254034eb2SDan OpenSolaris Anderson 6337c478bd9Sstevel@tonic-gate /* ARGSUSED */ 6347c478bd9Sstevel@tonic-gate static int 6357c478bd9Sstevel@tonic-gate aes_encrypt_update(crypto_ctx_t *ctx, crypto_data_t *plaintext, 6367c478bd9Sstevel@tonic-gate crypto_data_t *ciphertext, crypto_req_handle_t req) 6377c478bd9Sstevel@tonic-gate { 6387c478bd9Sstevel@tonic-gate off_t saved_offset; 6397c478bd9Sstevel@tonic-gate size_t saved_length, out_len; 6407c478bd9Sstevel@tonic-gate int ret = CRYPTO_SUCCESS; 641894b2776Smcpowers aes_ctx_t *aes_ctx; 6427c478bd9Sstevel@tonic-gate 6437c478bd9Sstevel@tonic-gate ASSERT(ctx->cc_provider_private != NULL); 64423c57df7Smcpowers aes_ctx = ctx->cc_provider_private; 6457c478bd9Sstevel@tonic-gate 6467c478bd9Sstevel@tonic-gate AES_ARG_INPLACE(plaintext, ciphertext); 6477c478bd9Sstevel@tonic-gate 6487c478bd9Sstevel@tonic-gate /* compute number of bytes that will hold the ciphertext */ 64923c57df7Smcpowers out_len = aes_ctx->ac_remainder_len; 6507c478bd9Sstevel@tonic-gate out_len += plaintext->cd_length; 6517c478bd9Sstevel@tonic-gate out_len &= ~(AES_BLOCK_LEN - 1); 6527c478bd9Sstevel@tonic-gate 6537c478bd9Sstevel@tonic-gate /* return length needed to store the output */ 6547c478bd9Sstevel@tonic-gate if (ciphertext->cd_length < out_len) { 6557c478bd9Sstevel@tonic-gate ciphertext->cd_length = out_len; 6567c478bd9Sstevel@tonic-gate return (CRYPTO_BUFFER_TOO_SMALL); 6577c478bd9Sstevel@tonic-gate } 6587c478bd9Sstevel@tonic-gate 6597c478bd9Sstevel@tonic-gate saved_offset = ciphertext->cd_offset; 6607c478bd9Sstevel@tonic-gate saved_length = ciphertext->cd_length; 6617c478bd9Sstevel@tonic-gate 6627c478bd9Sstevel@tonic-gate /* 6637c478bd9Sstevel@tonic-gate * Do the AES update on the specified input data. 6647c478bd9Sstevel@tonic-gate */ 6657c478bd9Sstevel@tonic-gate switch (plaintext->cd_format) { 6667c478bd9Sstevel@tonic-gate case CRYPTO_DATA_RAW: 66723c57df7Smcpowers ret = crypto_update_iov(ctx->cc_provider_private, 66823c57df7Smcpowers plaintext, ciphertext, aes_encrypt_contiguous_blocks, 66923c57df7Smcpowers aes_copy_block64); 6707c478bd9Sstevel@tonic-gate break; 6717c478bd9Sstevel@tonic-gate case CRYPTO_DATA_UIO: 67223c57df7Smcpowers ret = crypto_update_uio(ctx->cc_provider_private, 67323c57df7Smcpowers plaintext, ciphertext, aes_encrypt_contiguous_blocks, 67423c57df7Smcpowers aes_copy_block64); 6757c478bd9Sstevel@tonic-gate break; 6767c478bd9Sstevel@tonic-gate case CRYPTO_DATA_MBLK: 67723c57df7Smcpowers ret = crypto_update_mp(ctx->cc_provider_private, 67823c57df7Smcpowers plaintext, ciphertext, aes_encrypt_contiguous_blocks, 67923c57df7Smcpowers aes_copy_block64); 6807c478bd9Sstevel@tonic-gate break; 6817c478bd9Sstevel@tonic-gate default: 6827c478bd9Sstevel@tonic-gate ret = CRYPTO_ARGUMENTS_BAD; 6837c478bd9Sstevel@tonic-gate } 6847c478bd9Sstevel@tonic-gate 685894b2776Smcpowers /* 686894b2776Smcpowers * Since AES counter mode is a stream cipher, we call 68723c57df7Smcpowers * ctr_mode_final() to pick up any remaining bytes. 688894b2776Smcpowers * It is an internal function that does not destroy 689894b2776Smcpowers * the context like *normal* final routines. 690894b2776Smcpowers */ 69123c57df7Smcpowers if ((aes_ctx->ac_flags & CTR_MODE) && (aes_ctx->ac_remainder_len > 0)) { 69223c57df7Smcpowers ret = ctr_mode_final((ctr_ctx_t *)aes_ctx, 69323c57df7Smcpowers ciphertext, aes_encrypt_block); 694894b2776Smcpowers } 695894b2776Smcpowers 6967c478bd9Sstevel@tonic-gate if (ret == CRYPTO_SUCCESS) { 6977c478bd9Sstevel@tonic-gate if (plaintext != ciphertext) 6987c478bd9Sstevel@tonic-gate ciphertext->cd_length = 6997c478bd9Sstevel@tonic-gate ciphertext->cd_offset - saved_offset; 7007c478bd9Sstevel@tonic-gate } else { 7017c478bd9Sstevel@tonic-gate ciphertext->cd_length = saved_length; 7027c478bd9Sstevel@tonic-gate } 7037c478bd9Sstevel@tonic-gate ciphertext->cd_offset = saved_offset; 7047c478bd9Sstevel@tonic-gate 7057c478bd9Sstevel@tonic-gate return (ret); 7067c478bd9Sstevel@tonic-gate } 7077c478bd9Sstevel@tonic-gate 70854034eb2SDan OpenSolaris Anderson 7097c478bd9Sstevel@tonic-gate static int 7107c478bd9Sstevel@tonic-gate aes_decrypt_update(crypto_ctx_t *ctx, crypto_data_t *ciphertext, 7117c478bd9Sstevel@tonic-gate crypto_data_t *plaintext, crypto_req_handle_t req) 7127c478bd9Sstevel@tonic-gate { 7137c478bd9Sstevel@tonic-gate off_t saved_offset; 7147c478bd9Sstevel@tonic-gate size_t saved_length, out_len; 7157c478bd9Sstevel@tonic-gate int ret = CRYPTO_SUCCESS; 716894b2776Smcpowers aes_ctx_t *aes_ctx; 7177c478bd9Sstevel@tonic-gate 7187c478bd9Sstevel@tonic-gate ASSERT(ctx->cc_provider_private != NULL); 71923c57df7Smcpowers aes_ctx = ctx->cc_provider_private; 7207c478bd9Sstevel@tonic-gate 7217c478bd9Sstevel@tonic-gate AES_ARG_INPLACE(ciphertext, plaintext); 7227c478bd9Sstevel@tonic-gate 7234d703b5cSMark Powers /* 7244d703b5cSMark Powers * Compute number of bytes that will hold the plaintext. 725983a1033SMark Powers * This is not necessary for CCM, GCM, and GMAC since these 726983a1033SMark Powers * mechanisms never return plaintext for update operations. 7274d703b5cSMark Powers */ 728983a1033SMark Powers if ((aes_ctx->ac_flags & (CCM_MODE|GCM_MODE|GMAC_MODE)) == 0) { 72923c57df7Smcpowers out_len = aes_ctx->ac_remainder_len; 7307c478bd9Sstevel@tonic-gate out_len += ciphertext->cd_length; 7317c478bd9Sstevel@tonic-gate out_len &= ~(AES_BLOCK_LEN - 1); 7327c478bd9Sstevel@tonic-gate 7337c478bd9Sstevel@tonic-gate /* return length needed to store the output */ 7347c478bd9Sstevel@tonic-gate if (plaintext->cd_length < out_len) { 7357c478bd9Sstevel@tonic-gate plaintext->cd_length = out_len; 7367c478bd9Sstevel@tonic-gate return (CRYPTO_BUFFER_TOO_SMALL); 7377c478bd9Sstevel@tonic-gate } 7384d703b5cSMark Powers } 7397c478bd9Sstevel@tonic-gate 7407c478bd9Sstevel@tonic-gate saved_offset = plaintext->cd_offset; 7417c478bd9Sstevel@tonic-gate saved_length = plaintext->cd_length; 7427c478bd9Sstevel@tonic-gate 743983a1033SMark Powers if (aes_ctx->ac_flags & (GCM_MODE|GMAC_MODE)) 7444d703b5cSMark Powers gcm_set_kmflag((gcm_ctx_t *)aes_ctx, crypto_kmflag(req)); 7454d703b5cSMark Powers 7467c478bd9Sstevel@tonic-gate /* 7477c478bd9Sstevel@tonic-gate * Do the AES update on the specified input data. 7487c478bd9Sstevel@tonic-gate */ 7497c478bd9Sstevel@tonic-gate switch (ciphertext->cd_format) { 7507c478bd9Sstevel@tonic-gate case CRYPTO_DATA_RAW: 75123c57df7Smcpowers ret = crypto_update_iov(ctx->cc_provider_private, 75223c57df7Smcpowers ciphertext, plaintext, aes_decrypt_contiguous_blocks, 75323c57df7Smcpowers aes_copy_block64); 7547c478bd9Sstevel@tonic-gate break; 7557c478bd9Sstevel@tonic-gate case CRYPTO_DATA_UIO: 75623c57df7Smcpowers ret = crypto_update_uio(ctx->cc_provider_private, 75723c57df7Smcpowers ciphertext, plaintext, aes_decrypt_contiguous_blocks, 75823c57df7Smcpowers aes_copy_block64); 7597c478bd9Sstevel@tonic-gate break; 7607c478bd9Sstevel@tonic-gate case CRYPTO_DATA_MBLK: 76123c57df7Smcpowers ret = crypto_update_mp(ctx->cc_provider_private, 76223c57df7Smcpowers ciphertext, plaintext, aes_decrypt_contiguous_blocks, 76323c57df7Smcpowers aes_copy_block64); 7647c478bd9Sstevel@tonic-gate break; 7657c478bd9Sstevel@tonic-gate default: 7667c478bd9Sstevel@tonic-gate ret = CRYPTO_ARGUMENTS_BAD; 7677c478bd9Sstevel@tonic-gate } 7687c478bd9Sstevel@tonic-gate 769894b2776Smcpowers /* 770894b2776Smcpowers * Since AES counter mode is a stream cipher, we call 77123c57df7Smcpowers * ctr_mode_final() to pick up any remaining bytes. 772894b2776Smcpowers * It is an internal function that does not destroy 773894b2776Smcpowers * the context like *normal* final routines. 774894b2776Smcpowers */ 77523c57df7Smcpowers if ((aes_ctx->ac_flags & CTR_MODE) && (aes_ctx->ac_remainder_len > 0)) { 77623c57df7Smcpowers ret = ctr_mode_final((ctr_ctx_t *)aes_ctx, plaintext, 77723c57df7Smcpowers aes_encrypt_block); 77823c57df7Smcpowers if (ret == CRYPTO_DATA_LEN_RANGE) 77923c57df7Smcpowers ret = CRYPTO_ENCRYPTED_DATA_LEN_RANGE; 780894b2776Smcpowers } 781894b2776Smcpowers 7827c478bd9Sstevel@tonic-gate if (ret == CRYPTO_SUCCESS) { 7837c478bd9Sstevel@tonic-gate if (ciphertext != plaintext) 7847c478bd9Sstevel@tonic-gate plaintext->cd_length = 7857c478bd9Sstevel@tonic-gate plaintext->cd_offset - saved_offset; 7867c478bd9Sstevel@tonic-gate } else { 7877c478bd9Sstevel@tonic-gate plaintext->cd_length = saved_length; 7887c478bd9Sstevel@tonic-gate } 7897c478bd9Sstevel@tonic-gate plaintext->cd_offset = saved_offset; 7907c478bd9Sstevel@tonic-gate 791894b2776Smcpowers 7927c478bd9Sstevel@tonic-gate return (ret); 7937c478bd9Sstevel@tonic-gate } 7947c478bd9Sstevel@tonic-gate 7957c478bd9Sstevel@tonic-gate /* ARGSUSED */ 7967c478bd9Sstevel@tonic-gate static int 7977c478bd9Sstevel@tonic-gate aes_encrypt_final(crypto_ctx_t *ctx, crypto_data_t *data, 7987c478bd9Sstevel@tonic-gate crypto_req_handle_t req) 7997c478bd9Sstevel@tonic-gate { 8007c478bd9Sstevel@tonic-gate aes_ctx_t *aes_ctx; 801894b2776Smcpowers int ret; 8027c478bd9Sstevel@tonic-gate 8037c478bd9Sstevel@tonic-gate ASSERT(ctx->cc_provider_private != NULL); 8047c478bd9Sstevel@tonic-gate aes_ctx = ctx->cc_provider_private; 8057c478bd9Sstevel@tonic-gate 806894b2776Smcpowers if (data->cd_format != CRYPTO_DATA_RAW && 807894b2776Smcpowers data->cd_format != CRYPTO_DATA_UIO && 808894b2776Smcpowers data->cd_format != CRYPTO_DATA_MBLK) { 809894b2776Smcpowers return (CRYPTO_ARGUMENTS_BAD); 810894b2776Smcpowers } 811894b2776Smcpowers 81223c57df7Smcpowers if (aes_ctx->ac_flags & CTR_MODE) { 8137fb8ff4bSktung if (aes_ctx->ac_remainder_len > 0) { 81423c57df7Smcpowers ret = ctr_mode_final((ctr_ctx_t *)aes_ctx, data, 81523c57df7Smcpowers aes_encrypt_block); 8167fb8ff4bSktung if (ret != CRYPTO_SUCCESS) 8177fb8ff4bSktung return (ret); 8187fb8ff4bSktung } 81923c57df7Smcpowers } else if (aes_ctx->ac_flags & CCM_MODE) { 82023c57df7Smcpowers ret = ccm_encrypt_final((ccm_ctx_t *)aes_ctx, data, 82123c57df7Smcpowers AES_BLOCK_LEN, aes_encrypt_block, aes_xor_block); 8227fb8ff4bSktung if (ret != CRYPTO_SUCCESS) { 8237fb8ff4bSktung return (ret); 8247fb8ff4bSktung } 825983a1033SMark Powers } else if (aes_ctx->ac_flags & (GCM_MODE|GMAC_MODE)) { 8264d703b5cSMark Powers size_t saved_offset = data->cd_offset; 8274d703b5cSMark Powers 8284d703b5cSMark Powers ret = gcm_encrypt_final((gcm_ctx_t *)aes_ctx, data, 8294d703b5cSMark Powers AES_BLOCK_LEN, aes_encrypt_block, aes_copy_block, 8304d703b5cSMark Powers aes_xor_block); 8314d703b5cSMark Powers if (ret != CRYPTO_SUCCESS) { 8324d703b5cSMark Powers return (ret); 8334d703b5cSMark Powers } 8344d703b5cSMark Powers data->cd_length = data->cd_offset - saved_offset; 8354d703b5cSMark Powers data->cd_offset = saved_offset; 8367fb8ff4bSktung } else { 8377c478bd9Sstevel@tonic-gate /* 8387c478bd9Sstevel@tonic-gate * There must be no unprocessed plaintext. 8397c478bd9Sstevel@tonic-gate * This happens if the length of the last data is 8407c478bd9Sstevel@tonic-gate * not a multiple of the AES block length. 8417c478bd9Sstevel@tonic-gate */ 842894b2776Smcpowers if (aes_ctx->ac_remainder_len > 0) { 8437c478bd9Sstevel@tonic-gate return (CRYPTO_DATA_LEN_RANGE); 844894b2776Smcpowers } 845efcbd7a0Sktung data->cd_length = 0; 846894b2776Smcpowers } 847894b2776Smcpowers 8487c478bd9Sstevel@tonic-gate (void) aes_free_context(ctx); 8497c478bd9Sstevel@tonic-gate 8507c478bd9Sstevel@tonic-gate return (CRYPTO_SUCCESS); 8517c478bd9Sstevel@tonic-gate } 8527c478bd9Sstevel@tonic-gate 8537c478bd9Sstevel@tonic-gate /* ARGSUSED */ 8547c478bd9Sstevel@tonic-gate static int 8557c478bd9Sstevel@tonic-gate aes_decrypt_final(crypto_ctx_t *ctx, crypto_data_t *data, 8567c478bd9Sstevel@tonic-gate crypto_req_handle_t req) 8577c478bd9Sstevel@tonic-gate { 8587c478bd9Sstevel@tonic-gate aes_ctx_t *aes_ctx; 859894b2776Smcpowers int ret; 8607fb8ff4bSktung off_t saved_offset; 8617fb8ff4bSktung size_t saved_length; 8627c478bd9Sstevel@tonic-gate 8637c478bd9Sstevel@tonic-gate ASSERT(ctx->cc_provider_private != NULL); 8647c478bd9Sstevel@tonic-gate aes_ctx = ctx->cc_provider_private; 8657c478bd9Sstevel@tonic-gate 866894b2776Smcpowers if (data->cd_format != CRYPTO_DATA_RAW && 867894b2776Smcpowers data->cd_format != CRYPTO_DATA_UIO && 868894b2776Smcpowers data->cd_format != CRYPTO_DATA_MBLK) { 869894b2776Smcpowers return (CRYPTO_ARGUMENTS_BAD); 870894b2776Smcpowers } 871894b2776Smcpowers 8727c478bd9Sstevel@tonic-gate /* 8737c478bd9Sstevel@tonic-gate * There must be no unprocessed ciphertext. 8747c478bd9Sstevel@tonic-gate * This happens if the length of the last ciphertext is 8757c478bd9Sstevel@tonic-gate * not a multiple of the AES block length. 8767c478bd9Sstevel@tonic-gate */ 877894b2776Smcpowers if (aes_ctx->ac_remainder_len > 0) { 87823c57df7Smcpowers if ((aes_ctx->ac_flags & CTR_MODE) == 0) 8797c478bd9Sstevel@tonic-gate return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE); 880894b2776Smcpowers else { 88123c57df7Smcpowers ret = ctr_mode_final((ctr_ctx_t *)aes_ctx, data, 88223c57df7Smcpowers aes_encrypt_block); 88323c57df7Smcpowers if (ret == CRYPTO_DATA_LEN_RANGE) 88423c57df7Smcpowers ret = CRYPTO_ENCRYPTED_DATA_LEN_RANGE; 885894b2776Smcpowers if (ret != CRYPTO_SUCCESS) 886894b2776Smcpowers return (ret); 887894b2776Smcpowers } 888894b2776Smcpowers } 889894b2776Smcpowers 89023c57df7Smcpowers if (aes_ctx->ac_flags & CCM_MODE) { 8917fb8ff4bSktung /* 8927fb8ff4bSktung * This is where all the plaintext is returned, make sure 8937fb8ff4bSktung * the plaintext buffer is big enough 8947fb8ff4bSktung */ 89523c57df7Smcpowers size_t pt_len = aes_ctx->ac_data_len; 8967fb8ff4bSktung if (data->cd_length < pt_len) { 8977fb8ff4bSktung data->cd_length = pt_len; 8987fb8ff4bSktung return (CRYPTO_BUFFER_TOO_SMALL); 8997fb8ff4bSktung } 9007fb8ff4bSktung 90123c57df7Smcpowers ASSERT(aes_ctx->ac_processed_data_len == pt_len); 90223c57df7Smcpowers ASSERT(aes_ctx->ac_processed_mac_len == aes_ctx->ac_mac_len); 9037fb8ff4bSktung saved_offset = data->cd_offset; 9047fb8ff4bSktung saved_length = data->cd_length; 90523c57df7Smcpowers ret = ccm_decrypt_final((ccm_ctx_t *)aes_ctx, data, 90623c57df7Smcpowers AES_BLOCK_LEN, aes_encrypt_block, aes_copy_block, 90723c57df7Smcpowers aes_xor_block); 9087fb8ff4bSktung if (ret == CRYPTO_SUCCESS) { 9097fb8ff4bSktung data->cd_length = data->cd_offset - saved_offset; 9107fb8ff4bSktung } else { 9117fb8ff4bSktung data->cd_length = saved_length; 9127fb8ff4bSktung } 9137fb8ff4bSktung 9147fb8ff4bSktung data->cd_offset = saved_offset; 9157fb8ff4bSktung if (ret != CRYPTO_SUCCESS) { 9167fb8ff4bSktung return (ret); 9177fb8ff4bSktung } 918983a1033SMark Powers } else if (aes_ctx->ac_flags & (GCM_MODE|GMAC_MODE)) { 9194d703b5cSMark Powers /* 9204d703b5cSMark Powers * This is where all the plaintext is returned, make sure 9214d703b5cSMark Powers * the plaintext buffer is big enough 9224d703b5cSMark Powers */ 9234d703b5cSMark Powers gcm_ctx_t *ctx = (gcm_ctx_t *)aes_ctx; 9244d703b5cSMark Powers size_t pt_len = ctx->gcm_processed_data_len - ctx->gcm_tag_len; 9254d703b5cSMark Powers 9264d703b5cSMark Powers if (data->cd_length < pt_len) { 9274d703b5cSMark Powers data->cd_length = pt_len; 9284d703b5cSMark Powers return (CRYPTO_BUFFER_TOO_SMALL); 9294d703b5cSMark Powers } 9304d703b5cSMark Powers 9314d703b5cSMark Powers saved_offset = data->cd_offset; 9324d703b5cSMark Powers saved_length = data->cd_length; 9334d703b5cSMark Powers ret = gcm_decrypt_final((gcm_ctx_t *)aes_ctx, data, 9344d703b5cSMark Powers AES_BLOCK_LEN, aes_encrypt_block, aes_xor_block); 9354d703b5cSMark Powers if (ret == CRYPTO_SUCCESS) { 9364d703b5cSMark Powers data->cd_length = data->cd_offset - saved_offset; 9374d703b5cSMark Powers } else { 9384d703b5cSMark Powers data->cd_length = saved_length; 9394d703b5cSMark Powers } 9404d703b5cSMark Powers 9414d703b5cSMark Powers data->cd_offset = saved_offset; 9424d703b5cSMark Powers if (ret != CRYPTO_SUCCESS) { 9434d703b5cSMark Powers return (ret); 9444d703b5cSMark Powers } 9457fb8ff4bSktung } 9467fb8ff4bSktung 9477fb8ff4bSktung 948983a1033SMark Powers if ((aes_ctx->ac_flags & (CTR_MODE|CCM_MODE|GCM_MODE|GMAC_MODE)) == 0) { 949894b2776Smcpowers data->cd_length = 0; 950efcbd7a0Sktung } 9517c478bd9Sstevel@tonic-gate 9527c478bd9Sstevel@tonic-gate (void) aes_free_context(ctx); 9537c478bd9Sstevel@tonic-gate 9547c478bd9Sstevel@tonic-gate return (CRYPTO_SUCCESS); 9557c478bd9Sstevel@tonic-gate } 9567c478bd9Sstevel@tonic-gate 9577c478bd9Sstevel@tonic-gate /* ARGSUSED */ 9587c478bd9Sstevel@tonic-gate static int 9597c478bd9Sstevel@tonic-gate aes_encrypt_atomic(crypto_provider_handle_t provider, 9607c478bd9Sstevel@tonic-gate crypto_session_id_t session_id, crypto_mechanism_t *mechanism, 9617c478bd9Sstevel@tonic-gate crypto_key_t *key, crypto_data_t *plaintext, crypto_data_t *ciphertext, 9627c478bd9Sstevel@tonic-gate crypto_spi_ctx_template_t template, crypto_req_handle_t req) 9637c478bd9Sstevel@tonic-gate { 9647c478bd9Sstevel@tonic-gate aes_ctx_t aes_ctx; /* on the stack */ 9657c478bd9Sstevel@tonic-gate off_t saved_offset; 9667c478bd9Sstevel@tonic-gate size_t saved_length; 9671dcbfafdSMark Powers size_t length_needed; 9687c478bd9Sstevel@tonic-gate int ret; 9697c478bd9Sstevel@tonic-gate 9707c478bd9Sstevel@tonic-gate AES_ARG_INPLACE(plaintext, ciphertext); 9717c478bd9Sstevel@tonic-gate 9727c478bd9Sstevel@tonic-gate /* 973983a1033SMark Powers * CTR, CCM, GCM, and GMAC modes do not require that plaintext 9741dcbfafdSMark Powers * be a multiple of AES block size. 9757c478bd9Sstevel@tonic-gate */ 9761dcbfafdSMark Powers switch (mechanism->cm_type) { 9771dcbfafdSMark Powers case AES_CTR_MECH_INFO_TYPE: 9781dcbfafdSMark Powers case AES_CCM_MECH_INFO_TYPE: 9791dcbfafdSMark Powers case AES_GCM_MECH_INFO_TYPE: 980983a1033SMark Powers case AES_GMAC_MECH_INFO_TYPE: 9811dcbfafdSMark Powers break; 9821dcbfafdSMark Powers default: 9837c478bd9Sstevel@tonic-gate if ((plaintext->cd_length & (AES_BLOCK_LEN - 1)) != 0) 9847c478bd9Sstevel@tonic-gate return (CRYPTO_DATA_LEN_RANGE); 985894b2776Smcpowers } 9867c478bd9Sstevel@tonic-gate 98723c57df7Smcpowers if ((ret = aes_check_mech_param(mechanism, NULL, 0)) != CRYPTO_SUCCESS) 988bbbb143bSmcpowers return (ret); 9897c478bd9Sstevel@tonic-gate 9907c478bd9Sstevel@tonic-gate bzero(&aes_ctx, sizeof (aes_ctx_t)); 9917c478bd9Sstevel@tonic-gate 9927c478bd9Sstevel@tonic-gate ret = aes_common_init_ctx(&aes_ctx, template, mechanism, key, 9937fb8ff4bSktung crypto_kmflag(req), B_TRUE); 9947c478bd9Sstevel@tonic-gate if (ret != CRYPTO_SUCCESS) 9957c478bd9Sstevel@tonic-gate return (ret); 9967c478bd9Sstevel@tonic-gate 9971dcbfafdSMark Powers switch (mechanism->cm_type) { 9981dcbfafdSMark Powers case AES_CCM_MECH_INFO_TYPE: 9991dcbfafdSMark Powers length_needed = plaintext->cd_length + aes_ctx.ac_mac_len; 10001dcbfafdSMark Powers break; 1001983a1033SMark Powers case AES_GMAC_MECH_INFO_TYPE: 1002983a1033SMark Powers if (plaintext->cd_length != 0) 1003983a1033SMark Powers return (CRYPTO_ARGUMENTS_BAD); 1004983a1033SMark Powers /* FALLTHRU */ 10051dcbfafdSMark Powers case AES_GCM_MECH_INFO_TYPE: 10061dcbfafdSMark Powers length_needed = plaintext->cd_length + aes_ctx.ac_tag_len; 10071dcbfafdSMark Powers break; 10081dcbfafdSMark Powers default: 10091dcbfafdSMark Powers length_needed = plaintext->cd_length; 10107fb8ff4bSktung } 10117fb8ff4bSktung 10121dcbfafdSMark Powers /* return size of buffer needed to store output */ 10131dcbfafdSMark Powers if (ciphertext->cd_length < length_needed) { 10141dcbfafdSMark Powers ciphertext->cd_length = length_needed; 10151dcbfafdSMark Powers ret = CRYPTO_BUFFER_TOO_SMALL; 10161dcbfafdSMark Powers goto out; 10171dcbfafdSMark Powers } 10187fb8ff4bSktung 10197c478bd9Sstevel@tonic-gate saved_offset = ciphertext->cd_offset; 10207c478bd9Sstevel@tonic-gate saved_length = ciphertext->cd_length; 10217c478bd9Sstevel@tonic-gate 10227c478bd9Sstevel@tonic-gate /* 10237c478bd9Sstevel@tonic-gate * Do an update on the specified input data. 10247c478bd9Sstevel@tonic-gate */ 10257c478bd9Sstevel@tonic-gate switch (plaintext->cd_format) { 10267c478bd9Sstevel@tonic-gate case CRYPTO_DATA_RAW: 102723c57df7Smcpowers ret = crypto_update_iov(&aes_ctx, plaintext, ciphertext, 102823c57df7Smcpowers aes_encrypt_contiguous_blocks, aes_copy_block64); 10297c478bd9Sstevel@tonic-gate break; 10307c478bd9Sstevel@tonic-gate case CRYPTO_DATA_UIO: 103123c57df7Smcpowers ret = crypto_update_uio(&aes_ctx, plaintext, ciphertext, 103223c57df7Smcpowers aes_encrypt_contiguous_blocks, aes_copy_block64); 10337c478bd9Sstevel@tonic-gate break; 10347c478bd9Sstevel@tonic-gate case CRYPTO_DATA_MBLK: 103523c57df7Smcpowers ret = crypto_update_mp(&aes_ctx, plaintext, ciphertext, 103623c57df7Smcpowers aes_encrypt_contiguous_blocks, aes_copy_block64); 10377c478bd9Sstevel@tonic-gate break; 10387c478bd9Sstevel@tonic-gate default: 10397c478bd9Sstevel@tonic-gate ret = CRYPTO_ARGUMENTS_BAD; 10407c478bd9Sstevel@tonic-gate } 10417c478bd9Sstevel@tonic-gate 10427c478bd9Sstevel@tonic-gate if (ret == CRYPTO_SUCCESS) { 10437fb8ff4bSktung if (mechanism->cm_type == AES_CCM_MECH_INFO_TYPE) { 104423c57df7Smcpowers ret = ccm_encrypt_final((ccm_ctx_t *)&aes_ctx, 104523c57df7Smcpowers ciphertext, AES_BLOCK_LEN, aes_encrypt_block, 104623c57df7Smcpowers aes_xor_block); 10477fb8ff4bSktung if (ret != CRYPTO_SUCCESS) 10487fb8ff4bSktung goto out; 10497c478bd9Sstevel@tonic-gate ASSERT(aes_ctx.ac_remainder_len == 0); 1050983a1033SMark Powers } else if (mechanism->cm_type == AES_GCM_MECH_INFO_TYPE || 1051983a1033SMark Powers mechanism->cm_type == AES_GMAC_MECH_INFO_TYPE) { 10524d703b5cSMark Powers ret = gcm_encrypt_final((gcm_ctx_t *)&aes_ctx, 10534d703b5cSMark Powers ciphertext, AES_BLOCK_LEN, aes_encrypt_block, 10544d703b5cSMark Powers aes_copy_block, aes_xor_block); 10554d703b5cSMark Powers if (ret != CRYPTO_SUCCESS) 10564d703b5cSMark Powers goto out; 10574d703b5cSMark Powers ASSERT(aes_ctx.ac_remainder_len == 0); 10587fb8ff4bSktung } else if (mechanism->cm_type == AES_CTR_MECH_INFO_TYPE) { 1059894b2776Smcpowers if (aes_ctx.ac_remainder_len > 0) { 106023c57df7Smcpowers ret = ctr_mode_final((ctr_ctx_t *)&aes_ctx, 106123c57df7Smcpowers ciphertext, aes_encrypt_block); 1062894b2776Smcpowers if (ret != CRYPTO_SUCCESS) 1063894b2776Smcpowers goto out; 1064894b2776Smcpowers } 10657fb8ff4bSktung } else { 10667fb8ff4bSktung ASSERT(aes_ctx.ac_remainder_len == 0); 10677fb8ff4bSktung } 10687fb8ff4bSktung 10697fb8ff4bSktung if (plaintext != ciphertext) { 1070894b2776Smcpowers ciphertext->cd_length = 1071894b2776Smcpowers ciphertext->cd_offset - saved_offset; 1072894b2776Smcpowers } 1073894b2776Smcpowers } else { 10747c478bd9Sstevel@tonic-gate ciphertext->cd_length = saved_length; 10757c478bd9Sstevel@tonic-gate } 10767c478bd9Sstevel@tonic-gate ciphertext->cd_offset = saved_offset; 10777c478bd9Sstevel@tonic-gate 1078894b2776Smcpowers out: 107923c57df7Smcpowers if (aes_ctx.ac_flags & PROVIDER_OWNS_KEY_SCHEDULE) { 1080894b2776Smcpowers bzero(aes_ctx.ac_keysched, aes_ctx.ac_keysched_len); 1081894b2776Smcpowers kmem_free(aes_ctx.ac_keysched, aes_ctx.ac_keysched_len); 1082894b2776Smcpowers } 1083894b2776Smcpowers 10847c478bd9Sstevel@tonic-gate return (ret); 10857c478bd9Sstevel@tonic-gate } 10867c478bd9Sstevel@tonic-gate 10877c478bd9Sstevel@tonic-gate /* ARGSUSED */ 10887c478bd9Sstevel@tonic-gate static int 10897c478bd9Sstevel@tonic-gate aes_decrypt_atomic(crypto_provider_handle_t provider, 10907c478bd9Sstevel@tonic-gate crypto_session_id_t session_id, crypto_mechanism_t *mechanism, 10917c478bd9Sstevel@tonic-gate crypto_key_t *key, crypto_data_t *ciphertext, crypto_data_t *plaintext, 10927c478bd9Sstevel@tonic-gate crypto_spi_ctx_template_t template, crypto_req_handle_t req) 10937c478bd9Sstevel@tonic-gate { 10947c478bd9Sstevel@tonic-gate aes_ctx_t aes_ctx; /* on the stack */ 10957c478bd9Sstevel@tonic-gate off_t saved_offset; 10967c478bd9Sstevel@tonic-gate size_t saved_length; 10971dcbfafdSMark Powers size_t length_needed; 10987c478bd9Sstevel@tonic-gate int ret; 10997c478bd9Sstevel@tonic-gate 11007c478bd9Sstevel@tonic-gate AES_ARG_INPLACE(ciphertext, plaintext); 11017c478bd9Sstevel@tonic-gate 11027c478bd9Sstevel@tonic-gate /* 1103983a1033SMark Powers * CCM, GCM, CTR, and GMAC modes do not require that ciphertext 11041dcbfafdSMark Powers * be a multiple of AES block size. 11057c478bd9Sstevel@tonic-gate */ 11061dcbfafdSMark Powers switch (mechanism->cm_type) { 11071dcbfafdSMark Powers case AES_CTR_MECH_INFO_TYPE: 11081dcbfafdSMark Powers case AES_CCM_MECH_INFO_TYPE: 11091dcbfafdSMark Powers case AES_GCM_MECH_INFO_TYPE: 1110983a1033SMark Powers case AES_GMAC_MECH_INFO_TYPE: 11111dcbfafdSMark Powers break; 11121dcbfafdSMark Powers default: 11131dcbfafdSMark Powers if ((ciphertext->cd_length & (AES_BLOCK_LEN - 1)) != 0) 11141dcbfafdSMark Powers return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE); 11157c478bd9Sstevel@tonic-gate } 11167c478bd9Sstevel@tonic-gate 111723c57df7Smcpowers if ((ret = aes_check_mech_param(mechanism, NULL, 0)) != CRYPTO_SUCCESS) 1118bbbb143bSmcpowers return (ret); 11197c478bd9Sstevel@tonic-gate 11207c478bd9Sstevel@tonic-gate bzero(&aes_ctx, sizeof (aes_ctx_t)); 11217c478bd9Sstevel@tonic-gate 11227c478bd9Sstevel@tonic-gate ret = aes_common_init_ctx(&aes_ctx, template, mechanism, key, 11237fb8ff4bSktung crypto_kmflag(req), B_FALSE); 11247c478bd9Sstevel@tonic-gate if (ret != CRYPTO_SUCCESS) 11257c478bd9Sstevel@tonic-gate return (ret); 11267c478bd9Sstevel@tonic-gate 11271dcbfafdSMark Powers switch (mechanism->cm_type) { 11281dcbfafdSMark Powers case AES_CCM_MECH_INFO_TYPE: 11291dcbfafdSMark Powers length_needed = aes_ctx.ac_data_len; 11301dcbfafdSMark Powers break; 11311dcbfafdSMark Powers case AES_GCM_MECH_INFO_TYPE: 11321dcbfafdSMark Powers length_needed = ciphertext->cd_length - aes_ctx.ac_tag_len; 11331dcbfafdSMark Powers break; 1134983a1033SMark Powers case AES_GMAC_MECH_INFO_TYPE: 1135983a1033SMark Powers if (plaintext->cd_length != 0) 1136983a1033SMark Powers return (CRYPTO_ARGUMENTS_BAD); 1137983a1033SMark Powers length_needed = 0; 1138983a1033SMark Powers break; 11391dcbfafdSMark Powers default: 11401dcbfafdSMark Powers length_needed = ciphertext->cd_length; 11411dcbfafdSMark Powers } 11421dcbfafdSMark Powers 11431dcbfafdSMark Powers /* return size of buffer needed to store output */ 11441dcbfafdSMark Powers if (plaintext->cd_length < length_needed) { 11451dcbfafdSMark Powers plaintext->cd_length = length_needed; 11467fb8ff4bSktung ret = CRYPTO_BUFFER_TOO_SMALL; 11477fb8ff4bSktung goto out; 11487fb8ff4bSktung } 11497fb8ff4bSktung 11507c478bd9Sstevel@tonic-gate saved_offset = plaintext->cd_offset; 11517c478bd9Sstevel@tonic-gate saved_length = plaintext->cd_length; 11527c478bd9Sstevel@tonic-gate 1153983a1033SMark Powers if (mechanism->cm_type == AES_GCM_MECH_INFO_TYPE || 1154983a1033SMark Powers mechanism->cm_type == AES_GMAC_MECH_INFO_TYPE) 11554d703b5cSMark Powers gcm_set_kmflag((gcm_ctx_t *)&aes_ctx, crypto_kmflag(req)); 11564d703b5cSMark Powers 11577c478bd9Sstevel@tonic-gate /* 11587c478bd9Sstevel@tonic-gate * Do an update on the specified input data. 11597c478bd9Sstevel@tonic-gate */ 11607c478bd9Sstevel@tonic-gate switch (ciphertext->cd_format) { 11617c478bd9Sstevel@tonic-gate case CRYPTO_DATA_RAW: 116223c57df7Smcpowers ret = crypto_update_iov(&aes_ctx, ciphertext, plaintext, 116323c57df7Smcpowers aes_decrypt_contiguous_blocks, aes_copy_block64); 11647c478bd9Sstevel@tonic-gate break; 11657c478bd9Sstevel@tonic-gate case CRYPTO_DATA_UIO: 116623c57df7Smcpowers ret = crypto_update_uio(&aes_ctx, ciphertext, plaintext, 116723c57df7Smcpowers aes_decrypt_contiguous_blocks, aes_copy_block64); 11687c478bd9Sstevel@tonic-gate break; 11697c478bd9Sstevel@tonic-gate case CRYPTO_DATA_MBLK: 117023c57df7Smcpowers ret = crypto_update_mp(&aes_ctx, ciphertext, plaintext, 117123c57df7Smcpowers aes_decrypt_contiguous_blocks, aes_copy_block64); 11727c478bd9Sstevel@tonic-gate break; 11737c478bd9Sstevel@tonic-gate default: 11747c478bd9Sstevel@tonic-gate ret = CRYPTO_ARGUMENTS_BAD; 11757c478bd9Sstevel@tonic-gate } 11767c478bd9Sstevel@tonic-gate 11777c478bd9Sstevel@tonic-gate if (ret == CRYPTO_SUCCESS) { 11787fb8ff4bSktung if (mechanism->cm_type == AES_CCM_MECH_INFO_TYPE) { 117923c57df7Smcpowers ASSERT(aes_ctx.ac_processed_data_len 118023c57df7Smcpowers == aes_ctx.ac_data_len); 118123c57df7Smcpowers ASSERT(aes_ctx.ac_processed_mac_len 118223c57df7Smcpowers == aes_ctx.ac_mac_len); 118323c57df7Smcpowers ret = ccm_decrypt_final((ccm_ctx_t *)&aes_ctx, 118423c57df7Smcpowers plaintext, AES_BLOCK_LEN, aes_encrypt_block, 118523c57df7Smcpowers aes_copy_block, aes_xor_block); 11867fb8ff4bSktung ASSERT(aes_ctx.ac_remainder_len == 0); 11877fb8ff4bSktung if ((ret == CRYPTO_SUCCESS) && 11887fb8ff4bSktung (ciphertext != plaintext)) { 11897fb8ff4bSktung plaintext->cd_length = 11907fb8ff4bSktung plaintext->cd_offset - saved_offset; 11917fb8ff4bSktung } else { 11927fb8ff4bSktung plaintext->cd_length = saved_length; 11937fb8ff4bSktung } 1194983a1033SMark Powers } else if (mechanism->cm_type == AES_GCM_MECH_INFO_TYPE || 1195983a1033SMark Powers mechanism->cm_type == AES_GMAC_MECH_INFO_TYPE) { 11964d703b5cSMark Powers ret = gcm_decrypt_final((gcm_ctx_t *)&aes_ctx, 11974d703b5cSMark Powers plaintext, AES_BLOCK_LEN, aes_encrypt_block, 11984d703b5cSMark Powers aes_xor_block); 11994d703b5cSMark Powers ASSERT(aes_ctx.ac_remainder_len == 0); 12004d703b5cSMark Powers if ((ret == CRYPTO_SUCCESS) && 12014d703b5cSMark Powers (ciphertext != plaintext)) { 12024d703b5cSMark Powers plaintext->cd_length = 12034d703b5cSMark Powers plaintext->cd_offset - saved_offset; 12044d703b5cSMark Powers } else { 12054d703b5cSMark Powers plaintext->cd_length = saved_length; 12064d703b5cSMark Powers } 12077fb8ff4bSktung } else if (mechanism->cm_type != AES_CTR_MECH_INFO_TYPE) { 12087c478bd9Sstevel@tonic-gate ASSERT(aes_ctx.ac_remainder_len == 0); 12097c478bd9Sstevel@tonic-gate if (ciphertext != plaintext) 12107c478bd9Sstevel@tonic-gate plaintext->cd_length = 12117c478bd9Sstevel@tonic-gate plaintext->cd_offset - saved_offset; 12127c478bd9Sstevel@tonic-gate } else { 1213894b2776Smcpowers if (aes_ctx.ac_remainder_len > 0) { 121423c57df7Smcpowers ret = ctr_mode_final((ctr_ctx_t *)&aes_ctx, 121523c57df7Smcpowers plaintext, aes_encrypt_block); 121623c57df7Smcpowers if (ret == CRYPTO_DATA_LEN_RANGE) 121723c57df7Smcpowers ret = CRYPTO_ENCRYPTED_DATA_LEN_RANGE; 1218894b2776Smcpowers if (ret != CRYPTO_SUCCESS) 1219894b2776Smcpowers goto out; 1220894b2776Smcpowers } 1221894b2776Smcpowers if (ciphertext != plaintext) 1222894b2776Smcpowers plaintext->cd_length = 1223894b2776Smcpowers plaintext->cd_offset - saved_offset; 1224894b2776Smcpowers } 1225894b2776Smcpowers } else { 12267c478bd9Sstevel@tonic-gate plaintext->cd_length = saved_length; 12277c478bd9Sstevel@tonic-gate } 12287c478bd9Sstevel@tonic-gate plaintext->cd_offset = saved_offset; 12297c478bd9Sstevel@tonic-gate 1230894b2776Smcpowers out: 123123c57df7Smcpowers if (aes_ctx.ac_flags & PROVIDER_OWNS_KEY_SCHEDULE) { 1232894b2776Smcpowers bzero(aes_ctx.ac_keysched, aes_ctx.ac_keysched_len); 1233894b2776Smcpowers kmem_free(aes_ctx.ac_keysched, aes_ctx.ac_keysched_len); 1234894b2776Smcpowers } 1235894b2776Smcpowers 123623c57df7Smcpowers if (aes_ctx.ac_flags & CCM_MODE) { 123723c57df7Smcpowers if (aes_ctx.ac_pt_buf != NULL) { 123823c57df7Smcpowers kmem_free(aes_ctx.ac_pt_buf, aes_ctx.ac_data_len); 123923c57df7Smcpowers } 1240983a1033SMark Powers } else if (aes_ctx.ac_flags & (GCM_MODE|GMAC_MODE)) { 12414d703b5cSMark Powers if (((gcm_ctx_t *)&aes_ctx)->gcm_pt_buf != NULL) { 12424d703b5cSMark Powers kmem_free(((gcm_ctx_t *)&aes_ctx)->gcm_pt_buf, 12434d703b5cSMark Powers ((gcm_ctx_t *)&aes_ctx)->gcm_pt_buf_len); 12444d703b5cSMark Powers } 12457fb8ff4bSktung } 12467fb8ff4bSktung 12477c478bd9Sstevel@tonic-gate return (ret); 12487c478bd9Sstevel@tonic-gate } 12497c478bd9Sstevel@tonic-gate 12507c478bd9Sstevel@tonic-gate /* 12517c478bd9Sstevel@tonic-gate * KCF software provider context template entry points. 12527c478bd9Sstevel@tonic-gate */ 12537c478bd9Sstevel@tonic-gate /* ARGSUSED */ 12547c478bd9Sstevel@tonic-gate static int 12557c478bd9Sstevel@tonic-gate aes_create_ctx_template(crypto_provider_handle_t provider, 12567c478bd9Sstevel@tonic-gate crypto_mechanism_t *mechanism, crypto_key_t *key, 12577c478bd9Sstevel@tonic-gate crypto_spi_ctx_template_t *tmpl, size_t *tmpl_size, crypto_req_handle_t req) 12587c478bd9Sstevel@tonic-gate { 12597c478bd9Sstevel@tonic-gate void *keysched; 12607c478bd9Sstevel@tonic-gate size_t size; 12617c478bd9Sstevel@tonic-gate int rv; 12627c478bd9Sstevel@tonic-gate 1263bbbb143bSmcpowers if (mechanism->cm_type != AES_ECB_MECH_INFO_TYPE && 1264bbbb143bSmcpowers mechanism->cm_type != AES_CBC_MECH_INFO_TYPE && 12657fb8ff4bSktung mechanism->cm_type != AES_CTR_MECH_INFO_TYPE && 1266983a1033SMark Powers mechanism->cm_type != AES_CCM_MECH_INFO_TYPE && 1267983a1033SMark Powers mechanism->cm_type != AES_GCM_MECH_INFO_TYPE && 1268983a1033SMark Powers mechanism->cm_type != AES_GMAC_MECH_INFO_TYPE) 12697c478bd9Sstevel@tonic-gate return (CRYPTO_MECHANISM_INVALID); 12707c478bd9Sstevel@tonic-gate 12717c478bd9Sstevel@tonic-gate if ((keysched = aes_alloc_keysched(&size, 12727c478bd9Sstevel@tonic-gate crypto_kmflag(req))) == NULL) { 12737c478bd9Sstevel@tonic-gate return (CRYPTO_HOST_MEMORY); 12747c478bd9Sstevel@tonic-gate } 12757c478bd9Sstevel@tonic-gate 12767c478bd9Sstevel@tonic-gate /* 12777c478bd9Sstevel@tonic-gate * Initialize key schedule. Key length information is stored 12787c478bd9Sstevel@tonic-gate * in the key. 12797c478bd9Sstevel@tonic-gate */ 12807c478bd9Sstevel@tonic-gate if ((rv = init_keysched(key, keysched)) != CRYPTO_SUCCESS) { 12817c478bd9Sstevel@tonic-gate bzero(keysched, size); 12827c478bd9Sstevel@tonic-gate kmem_free(keysched, size); 12837c478bd9Sstevel@tonic-gate return (rv); 12847c478bd9Sstevel@tonic-gate } 12857c478bd9Sstevel@tonic-gate 12867c478bd9Sstevel@tonic-gate *tmpl = keysched; 12877c478bd9Sstevel@tonic-gate *tmpl_size = size; 12887c478bd9Sstevel@tonic-gate 12897c478bd9Sstevel@tonic-gate return (CRYPTO_SUCCESS); 12907c478bd9Sstevel@tonic-gate } 12917c478bd9Sstevel@tonic-gate 129254034eb2SDan OpenSolaris Anderson 12937c478bd9Sstevel@tonic-gate static int 12947c478bd9Sstevel@tonic-gate aes_free_context(crypto_ctx_t *ctx) 12957c478bd9Sstevel@tonic-gate { 12967c478bd9Sstevel@tonic-gate aes_ctx_t *aes_ctx = ctx->cc_provider_private; 12977c478bd9Sstevel@tonic-gate 12987c478bd9Sstevel@tonic-gate if (aes_ctx != NULL) { 129923c57df7Smcpowers if (aes_ctx->ac_flags & PROVIDER_OWNS_KEY_SCHEDULE) { 13007c478bd9Sstevel@tonic-gate ASSERT(aes_ctx->ac_keysched_len != 0); 13017c478bd9Sstevel@tonic-gate bzero(aes_ctx->ac_keysched, aes_ctx->ac_keysched_len); 13027c478bd9Sstevel@tonic-gate kmem_free(aes_ctx->ac_keysched, 13037c478bd9Sstevel@tonic-gate aes_ctx->ac_keysched_len); 13047c478bd9Sstevel@tonic-gate } 130523c57df7Smcpowers crypto_free_mode_ctx(aes_ctx); 13067c478bd9Sstevel@tonic-gate ctx->cc_provider_private = NULL; 13077c478bd9Sstevel@tonic-gate } 13087c478bd9Sstevel@tonic-gate 13097c478bd9Sstevel@tonic-gate return (CRYPTO_SUCCESS); 13107c478bd9Sstevel@tonic-gate } 13117c478bd9Sstevel@tonic-gate 131254034eb2SDan OpenSolaris Anderson 13137c478bd9Sstevel@tonic-gate static int 13147c478bd9Sstevel@tonic-gate aes_common_init_ctx(aes_ctx_t *aes_ctx, crypto_spi_ctx_template_t *template, 13157fb8ff4bSktung crypto_mechanism_t *mechanism, crypto_key_t *key, int kmflag, 13167fb8ff4bSktung boolean_t is_encrypt_init) 13177c478bd9Sstevel@tonic-gate { 13187c478bd9Sstevel@tonic-gate int rv = CRYPTO_SUCCESS; 13197c478bd9Sstevel@tonic-gate void *keysched; 13207c478bd9Sstevel@tonic-gate size_t size; 1321894b2776Smcpowers 1322894b2776Smcpowers if (template == NULL) { 1323894b2776Smcpowers if ((keysched = aes_alloc_keysched(&size, kmflag)) == NULL) 1324894b2776Smcpowers return (CRYPTO_HOST_MEMORY); 1325894b2776Smcpowers /* 1326894b2776Smcpowers * Initialize key schedule. 1327894b2776Smcpowers * Key length is stored in the key. 1328894b2776Smcpowers */ 13297fb8ff4bSktung if ((rv = init_keysched(key, keysched)) != CRYPTO_SUCCESS) { 1330894b2776Smcpowers kmem_free(keysched, size); 13317fb8ff4bSktung return (rv); 13327fb8ff4bSktung } 1333894b2776Smcpowers 133423c57df7Smcpowers aes_ctx->ac_flags |= PROVIDER_OWNS_KEY_SCHEDULE; 1335894b2776Smcpowers aes_ctx->ac_keysched_len = size; 1336894b2776Smcpowers } else { 1337894b2776Smcpowers keysched = template; 13387c478bd9Sstevel@tonic-gate } 13397c478bd9Sstevel@tonic-gate aes_ctx->ac_keysched = keysched; 13407c478bd9Sstevel@tonic-gate 134123c57df7Smcpowers switch (mechanism->cm_type) { 134223c57df7Smcpowers case AES_CBC_MECH_INFO_TYPE: 134323c57df7Smcpowers rv = cbc_init_ctx((cbc_ctx_t *)aes_ctx, mechanism->cm_param, 134423c57df7Smcpowers mechanism->cm_param_len, AES_BLOCK_LEN, aes_copy_block64); 134523c57df7Smcpowers break; 134623c57df7Smcpowers case AES_CTR_MECH_INFO_TYPE: { 134723c57df7Smcpowers CK_AES_CTR_PARAMS *pp; 134823c57df7Smcpowers 134923c57df7Smcpowers if (mechanism->cm_param == NULL || 135023c57df7Smcpowers mechanism->cm_param_len != sizeof (CK_AES_CTR_PARAMS)) { 13517fb8ff4bSktung return (CRYPTO_MECHANISM_PARAM_INVALID); 13527fb8ff4bSktung } 135354034eb2SDan OpenSolaris Anderson pp = (CK_AES_CTR_PARAMS *)(void *)mechanism->cm_param; 135423c57df7Smcpowers rv = ctr_init_ctx((ctr_ctx_t *)aes_ctx, pp->ulCounterBits, 135523c57df7Smcpowers pp->cb, aes_copy_block); 135623c57df7Smcpowers break; 135723c57df7Smcpowers } 135823c57df7Smcpowers case AES_CCM_MECH_INFO_TYPE: 135923c57df7Smcpowers if (mechanism->cm_param == NULL || 136023c57df7Smcpowers mechanism->cm_param_len != sizeof (CK_AES_CCM_PARAMS)) { 136123c57df7Smcpowers return (CRYPTO_MECHANISM_PARAM_INVALID); 136223c57df7Smcpowers } 136323c57df7Smcpowers rv = ccm_init_ctx((ccm_ctx_t *)aes_ctx, mechanism->cm_param, 136423c57df7Smcpowers kmflag, is_encrypt_init, AES_BLOCK_LEN, aes_encrypt_block, 136523c57df7Smcpowers aes_xor_block); 136623c57df7Smcpowers break; 13674d703b5cSMark Powers case AES_GCM_MECH_INFO_TYPE: 13684d703b5cSMark Powers if (mechanism->cm_param == NULL || 13694d703b5cSMark Powers mechanism->cm_param_len != sizeof (CK_AES_GCM_PARAMS)) { 13704d703b5cSMark Powers return (CRYPTO_MECHANISM_PARAM_INVALID); 13714d703b5cSMark Powers } 13724d703b5cSMark Powers rv = gcm_init_ctx((gcm_ctx_t *)aes_ctx, mechanism->cm_param, 13734d703b5cSMark Powers AES_BLOCK_LEN, aes_encrypt_block, aes_copy_block, 13744d703b5cSMark Powers aes_xor_block); 13754d703b5cSMark Powers break; 1376983a1033SMark Powers case AES_GMAC_MECH_INFO_TYPE: 1377983a1033SMark Powers if (mechanism->cm_param == NULL || 1378983a1033SMark Powers mechanism->cm_param_len != sizeof (CK_AES_GMAC_PARAMS)) { 1379983a1033SMark Powers return (CRYPTO_MECHANISM_PARAM_INVALID); 1380983a1033SMark Powers } 1381983a1033SMark Powers rv = gmac_init_ctx((gcm_ctx_t *)aes_ctx, mechanism->cm_param, 1382983a1033SMark Powers AES_BLOCK_LEN, aes_encrypt_block, aes_copy_block, 1383983a1033SMark Powers aes_xor_block); 1384983a1033SMark Powers break; 138523c57df7Smcpowers case AES_ECB_MECH_INFO_TYPE: 138623c57df7Smcpowers aes_ctx->ac_flags |= ECB_MODE; 138723c57df7Smcpowers } 138823c57df7Smcpowers 138923c57df7Smcpowers if (rv != CRYPTO_SUCCESS) { 139023c57df7Smcpowers if (aes_ctx->ac_flags & PROVIDER_OWNS_KEY_SCHEDULE) { 13917fb8ff4bSktung bzero(keysched, size); 13927fb8ff4bSktung kmem_free(keysched, size); 13937fb8ff4bSktung } 13947fb8ff4bSktung } 13957fb8ff4bSktung 13967c478bd9Sstevel@tonic-gate return (rv); 13977c478bd9Sstevel@tonic-gate } 1398983a1033SMark Powers 1399983a1033SMark Powers static int 1400983a1033SMark Powers process_gmac_mech(crypto_mechanism_t *mech, crypto_data_t *data, 1401983a1033SMark Powers CK_AES_GCM_PARAMS *gcm_params) 1402983a1033SMark Powers { 1403983a1033SMark Powers /* LINTED: pointer alignment */ 1404983a1033SMark Powers CK_AES_GMAC_PARAMS *params = (CK_AES_GMAC_PARAMS *)mech->cm_param; 1405983a1033SMark Powers 1406983a1033SMark Powers if (mech->cm_type != AES_GMAC_MECH_INFO_TYPE) 1407983a1033SMark Powers return (CRYPTO_MECHANISM_INVALID); 1408983a1033SMark Powers 1409983a1033SMark Powers if (mech->cm_param_len != sizeof (CK_AES_GMAC_PARAMS)) 1410983a1033SMark Powers return (CRYPTO_MECHANISM_PARAM_INVALID); 1411983a1033SMark Powers 1412983a1033SMark Powers if (params->pIv == NULL) 1413983a1033SMark Powers return (CRYPTO_MECHANISM_PARAM_INVALID); 1414983a1033SMark Powers 1415983a1033SMark Powers gcm_params->pIv = params->pIv; 1416983a1033SMark Powers gcm_params->ulIvLen = AES_GMAC_IV_LEN; 1417983a1033SMark Powers gcm_params->ulTagBits = AES_GMAC_TAG_BITS; 1418983a1033SMark Powers 1419983a1033SMark Powers if (data == NULL) 1420983a1033SMark Powers return (CRYPTO_SUCCESS); 1421983a1033SMark Powers 1422983a1033SMark Powers if (data->cd_format != CRYPTO_DATA_RAW) 1423983a1033SMark Powers return (CRYPTO_ARGUMENTS_BAD); 1424983a1033SMark Powers 1425983a1033SMark Powers gcm_params->pAAD = (uchar_t *)data->cd_raw.iov_base; 1426983a1033SMark Powers gcm_params->ulAADLen = data->cd_length; 1427983a1033SMark Powers return (CRYPTO_SUCCESS); 1428983a1033SMark Powers } 1429983a1033SMark Powers 1430983a1033SMark Powers static int 1431983a1033SMark Powers aes_mac_atomic(crypto_provider_handle_t provider, 1432983a1033SMark Powers crypto_session_id_t session_id, crypto_mechanism_t *mechanism, 1433983a1033SMark Powers crypto_key_t *key, crypto_data_t *data, crypto_data_t *mac, 1434983a1033SMark Powers crypto_spi_ctx_template_t template, crypto_req_handle_t req) 1435983a1033SMark Powers { 1436983a1033SMark Powers CK_AES_GCM_PARAMS gcm_params; 1437983a1033SMark Powers crypto_mechanism_t gcm_mech; 1438983a1033SMark Powers int rv; 1439983a1033SMark Powers 1440983a1033SMark Powers if ((rv = process_gmac_mech(mechanism, data, &gcm_params)) 1441983a1033SMark Powers != CRYPTO_SUCCESS) 1442983a1033SMark Powers return (rv); 1443983a1033SMark Powers 1444983a1033SMark Powers gcm_mech.cm_type = AES_GCM_MECH_INFO_TYPE; 1445983a1033SMark Powers gcm_mech.cm_param_len = sizeof (CK_AES_GCM_PARAMS); 1446983a1033SMark Powers gcm_mech.cm_param = (char *)&gcm_params; 1447983a1033SMark Powers 1448983a1033SMark Powers return (aes_encrypt_atomic(provider, session_id, &gcm_mech, 1449983a1033SMark Powers key, &null_crypto_data, mac, template, req)); 1450983a1033SMark Powers } 1451983a1033SMark Powers 1452983a1033SMark Powers static int 1453983a1033SMark Powers aes_mac_verify_atomic(crypto_provider_handle_t provider, 1454983a1033SMark Powers crypto_session_id_t session_id, crypto_mechanism_t *mechanism, 1455983a1033SMark Powers crypto_key_t *key, crypto_data_t *data, crypto_data_t *mac, 1456983a1033SMark Powers crypto_spi_ctx_template_t template, crypto_req_handle_t req) 1457983a1033SMark Powers { 1458983a1033SMark Powers CK_AES_GCM_PARAMS gcm_params; 1459983a1033SMark Powers crypto_mechanism_t gcm_mech; 1460983a1033SMark Powers int rv; 1461983a1033SMark Powers 1462983a1033SMark Powers if ((rv = process_gmac_mech(mechanism, data, &gcm_params)) 1463983a1033SMark Powers != CRYPTO_SUCCESS) 1464983a1033SMark Powers return (rv); 1465983a1033SMark Powers 1466983a1033SMark Powers gcm_mech.cm_type = AES_GCM_MECH_INFO_TYPE; 1467983a1033SMark Powers gcm_mech.cm_param_len = sizeof (CK_AES_GCM_PARAMS); 1468983a1033SMark Powers gcm_mech.cm_param = (char *)&gcm_params; 1469983a1033SMark Powers 1470983a1033SMark Powers return (aes_decrypt_atomic(provider, session_id, &gcm_mech, 1471983a1033SMark Powers key, mac, &null_crypto_data, template, req)); 1472983a1033SMark Powers } 1473