Path: blob/main/sys/contrib/openzfs/module/icp/io/aes.c
48529 views
// SPDX-License-Identifier: CDDL-1.01/*2* CDDL HEADER START3*4* The contents of this file are subject to the terms of the5* Common Development and Distribution License (the "License").6* You may not use this file except in compliance with the License.7*8* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE9* or https://opensource.org/licenses/CDDL-1.0.10* See the License for the specific language governing permissions11* and limitations under the License.12*13* When distributing Covered Code, include this CDDL HEADER in each14* file and include the License file at usr/src/OPENSOLARIS.LICENSE.15* If applicable, add the following below this CDDL HEADER, with the16* fields enclosed by brackets "[]" replaced with your own identifying17* information: Portions Copyright [yyyy] [name of copyright owner]18*19* CDDL HEADER END20*/21/*22* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.23*/2425/*26* AES provider for the Kernel Cryptographic Framework (KCF)27*/2829#include <sys/zfs_context.h>30#include <sys/crypto/common.h>31#include <sys/crypto/impl.h>32#include <sys/crypto/spi.h>33#include <sys/crypto/icp.h>34#include <modes/modes.h>35#define _AES_IMPL36#include <aes/aes_impl.h>37#include <modes/gcm_impl.h>3839/*40* Mechanism info structure passed to KCF during registration.41*/42static const crypto_mech_info_t aes_mech_info_tab[] = {43/* AES_CCM */44{SUN_CKM_AES_CCM, AES_CCM_MECH_INFO_TYPE,45CRYPTO_FG_ENCRYPT_ATOMIC | CRYPTO_FG_DECRYPT_ATOMIC},46/* AES_GCM */47{SUN_CKM_AES_GCM, AES_GCM_MECH_INFO_TYPE,48CRYPTO_FG_ENCRYPT_ATOMIC | CRYPTO_FG_DECRYPT_ATOMIC},49};5051static int aes_common_init_ctx(aes_ctx_t *, crypto_spi_ctx_template_t *,52crypto_mechanism_t *, crypto_key_t *, int, boolean_t);5354static int aes_encrypt_atomic(crypto_mechanism_t *, crypto_key_t *,55crypto_data_t *, crypto_data_t *, crypto_spi_ctx_template_t);5657static int aes_decrypt_atomic(crypto_mechanism_t *, crypto_key_t *,58crypto_data_t *, crypto_data_t *, crypto_spi_ctx_template_t);5960static const crypto_cipher_ops_t aes_cipher_ops = {61.encrypt_atomic = aes_encrypt_atomic,62.decrypt_atomic = aes_decrypt_atomic63};6465static int aes_create_ctx_template(crypto_mechanism_t *, crypto_key_t *,66crypto_spi_ctx_template_t *, size_t *);67static int aes_free_context(crypto_ctx_t *);6869static const crypto_ctx_ops_t aes_ctx_ops = {70.create_ctx_template = aes_create_ctx_template,71.free_context = aes_free_context72};7374static const crypto_ops_t aes_crypto_ops = {75&aes_cipher_ops,76NULL,77&aes_ctx_ops,78};7980static const crypto_provider_info_t aes_prov_info = {81"AES Software Provider",82&aes_crypto_ops,83sizeof (aes_mech_info_tab) / sizeof (crypto_mech_info_t),84aes_mech_info_tab85};8687static crypto_kcf_provider_handle_t aes_prov_handle = 0;8889int90aes_mod_init(void)91{92/* Determine the fastest available implementation. */93aes_impl_init();94gcm_impl_init();9596/* Register with KCF. If the registration fails, remove the module. */97if (crypto_register_provider(&aes_prov_info, &aes_prov_handle))98return (EACCES);99100return (0);101}102103int104aes_mod_fini(void)105{106/* Unregister from KCF if module is registered */107if (aes_prov_handle != 0) {108if (crypto_unregister_provider(aes_prov_handle))109return (EBUSY);110111aes_prov_handle = 0;112}113114return (0);115}116117static int118aes_check_mech_param(crypto_mechanism_t *mechanism, aes_ctx_t **ctx)119{120void *p = NULL;121boolean_t param_required = B_TRUE;122size_t param_len;123void *(*alloc_fun)(int);124int rv = CRYPTO_SUCCESS;125126switch (mechanism->cm_type) {127case AES_CCM_MECH_INFO_TYPE:128param_len = sizeof (CK_AES_CCM_PARAMS);129alloc_fun = ccm_alloc_ctx;130break;131case AES_GCM_MECH_INFO_TYPE:132param_len = sizeof (CK_AES_GCM_PARAMS);133alloc_fun = gcm_alloc_ctx;134break;135default:136__builtin_unreachable();137}138if (param_required && mechanism->cm_param != NULL &&139mechanism->cm_param_len != param_len) {140rv = CRYPTO_MECHANISM_PARAM_INVALID;141}142if (ctx != NULL) {143p = (alloc_fun)(KM_SLEEP);144*ctx = p;145}146return (rv);147}148149/*150* Initialize key schedules for AES151*/152static int153init_keysched(crypto_key_t *key, void *newbie)154{155if (key->ck_length < AES_MINBITS ||156key->ck_length > AES_MAXBITS) {157return (CRYPTO_KEY_SIZE_RANGE);158}159160/* key length must be either 128, 192, or 256 */161if ((key->ck_length & 63) != 0)162return (CRYPTO_KEY_SIZE_RANGE);163164aes_init_keysched(key->ck_data, key->ck_length, newbie);165return (CRYPTO_SUCCESS);166}167168/*169* KCF software provider encrypt entry points.170*/171static int172aes_encrypt_atomic(crypto_mechanism_t *mechanism,173crypto_key_t *key, crypto_data_t *plaintext, crypto_data_t *ciphertext,174crypto_spi_ctx_template_t template)175{176aes_ctx_t aes_ctx;177off_t saved_offset;178size_t saved_length;179size_t length_needed;180int ret;181182memset(&aes_ctx, 0, sizeof (aes_ctx_t));183184ASSERT(ciphertext != NULL);185186if ((ret = aes_check_mech_param(mechanism, NULL)) != CRYPTO_SUCCESS)187return (ret);188189ret = aes_common_init_ctx(&aes_ctx, template, mechanism, key,190KM_SLEEP, B_TRUE);191if (ret != CRYPTO_SUCCESS)192return (ret);193194switch (mechanism->cm_type) {195case AES_CCM_MECH_INFO_TYPE:196length_needed = plaintext->cd_length + aes_ctx.ac_mac_len;197break;198case AES_GCM_MECH_INFO_TYPE:199length_needed = plaintext->cd_length + aes_ctx.ac_tag_len;200break;201default:202__builtin_unreachable();203}204205/* return size of buffer needed to store output */206if (ciphertext->cd_length < length_needed) {207ciphertext->cd_length = length_needed;208ret = CRYPTO_BUFFER_TOO_SMALL;209goto out;210}211212saved_offset = ciphertext->cd_offset;213saved_length = ciphertext->cd_length;214215/*216* Do an update on the specified input data.217*/218switch (plaintext->cd_format) {219case CRYPTO_DATA_RAW:220ret = crypto_update_iov(&aes_ctx, plaintext, ciphertext,221aes_encrypt_contiguous_blocks);222break;223case CRYPTO_DATA_UIO:224ret = crypto_update_uio(&aes_ctx, plaintext, ciphertext,225aes_encrypt_contiguous_blocks);226break;227default:228ret = CRYPTO_ARGUMENTS_BAD;229}230231if (ret == CRYPTO_SUCCESS) {232if (mechanism->cm_type == AES_CCM_MECH_INFO_TYPE) {233ret = ccm_encrypt_final((ccm_ctx_t *)&aes_ctx,234ciphertext, AES_BLOCK_LEN, aes_encrypt_block,235aes_xor_block);236if (ret != CRYPTO_SUCCESS)237goto out;238ASSERT0(aes_ctx.ac_remainder_len);239} else if (mechanism->cm_type == AES_GCM_MECH_INFO_TYPE) {240ret = gcm_encrypt_final((gcm_ctx_t *)&aes_ctx,241ciphertext, AES_BLOCK_LEN, aes_encrypt_block,242aes_copy_block, aes_xor_block);243if (ret != CRYPTO_SUCCESS)244goto out;245ASSERT0(aes_ctx.ac_remainder_len);246} else {247ASSERT0(aes_ctx.ac_remainder_len);248}249250if (plaintext != ciphertext) {251ciphertext->cd_length =252ciphertext->cd_offset - saved_offset;253}254} else {255ciphertext->cd_length = saved_length;256}257ciphertext->cd_offset = saved_offset;258259out:260if (aes_ctx.ac_flags & PROVIDER_OWNS_KEY_SCHEDULE) {261memset(aes_ctx.ac_keysched, 0, aes_ctx.ac_keysched_len);262kmem_free(aes_ctx.ac_keysched, aes_ctx.ac_keysched_len);263}264if (aes_ctx.ac_flags & GCM_MODE) {265gcm_clear_ctx((gcm_ctx_t *)&aes_ctx);266}267return (ret);268}269270static int271aes_decrypt_atomic(crypto_mechanism_t *mechanism,272crypto_key_t *key, crypto_data_t *ciphertext, crypto_data_t *plaintext,273crypto_spi_ctx_template_t template)274{275aes_ctx_t aes_ctx;276off_t saved_offset;277size_t saved_length;278size_t length_needed;279int ret;280281memset(&aes_ctx, 0, sizeof (aes_ctx_t));282283ASSERT(plaintext != NULL);284285if ((ret = aes_check_mech_param(mechanism, NULL)) != CRYPTO_SUCCESS)286return (ret);287288ret = aes_common_init_ctx(&aes_ctx, template, mechanism, key,289KM_SLEEP, B_FALSE);290if (ret != CRYPTO_SUCCESS)291return (ret);292293switch (mechanism->cm_type) {294case AES_CCM_MECH_INFO_TYPE:295length_needed = aes_ctx.ac_data_len;296break;297case AES_GCM_MECH_INFO_TYPE:298length_needed = ciphertext->cd_length - aes_ctx.ac_tag_len;299break;300default:301__builtin_unreachable();302}303304/* return size of buffer needed to store output */305if (plaintext->cd_length < length_needed) {306plaintext->cd_length = length_needed;307ret = CRYPTO_BUFFER_TOO_SMALL;308goto out;309}310311saved_offset = plaintext->cd_offset;312saved_length = plaintext->cd_length;313314/*315* Do an update on the specified input data.316*/317switch (ciphertext->cd_format) {318case CRYPTO_DATA_RAW:319ret = crypto_update_iov(&aes_ctx, ciphertext, plaintext,320aes_decrypt_contiguous_blocks);321break;322case CRYPTO_DATA_UIO:323ret = crypto_update_uio(&aes_ctx, ciphertext, plaintext,324aes_decrypt_contiguous_blocks);325break;326default:327ret = CRYPTO_ARGUMENTS_BAD;328}329330if (ret == CRYPTO_SUCCESS) {331if (mechanism->cm_type == AES_CCM_MECH_INFO_TYPE) {332ASSERT(aes_ctx.ac_processed_data_len333== aes_ctx.ac_data_len);334ASSERT(aes_ctx.ac_processed_mac_len335== aes_ctx.ac_mac_len);336ret = ccm_decrypt_final((ccm_ctx_t *)&aes_ctx,337plaintext, AES_BLOCK_LEN, aes_encrypt_block,338aes_copy_block, aes_xor_block);339ASSERT0(aes_ctx.ac_remainder_len);340if ((ret == CRYPTO_SUCCESS) &&341(ciphertext != plaintext)) {342plaintext->cd_length =343plaintext->cd_offset - saved_offset;344} else {345plaintext->cd_length = saved_length;346}347} else if (mechanism->cm_type == AES_GCM_MECH_INFO_TYPE) {348ret = gcm_decrypt_final((gcm_ctx_t *)&aes_ctx,349plaintext, AES_BLOCK_LEN, aes_encrypt_block,350aes_xor_block);351ASSERT0(aes_ctx.ac_remainder_len);352if ((ret == CRYPTO_SUCCESS) &&353(ciphertext != plaintext)) {354plaintext->cd_length =355plaintext->cd_offset - saved_offset;356} else {357plaintext->cd_length = saved_length;358}359} else360__builtin_unreachable();361} else {362plaintext->cd_length = saved_length;363}364plaintext->cd_offset = saved_offset;365366out:367if (aes_ctx.ac_flags & PROVIDER_OWNS_KEY_SCHEDULE) {368memset(aes_ctx.ac_keysched, 0, aes_ctx.ac_keysched_len);369kmem_free(aes_ctx.ac_keysched, aes_ctx.ac_keysched_len);370}371372if (aes_ctx.ac_flags & CCM_MODE) {373if (aes_ctx.ac_pt_buf != NULL) {374vmem_free(aes_ctx.ac_pt_buf, aes_ctx.ac_data_len);375}376} else if (aes_ctx.ac_flags & GCM_MODE) {377gcm_clear_ctx((gcm_ctx_t *)&aes_ctx);378}379380return (ret);381}382383/*384* KCF software provider context template entry points.385*/386static int387aes_create_ctx_template(crypto_mechanism_t *mechanism, crypto_key_t *key,388crypto_spi_ctx_template_t *tmpl, size_t *tmpl_size)389{390void *keysched;391size_t size;392int rv;393394if (mechanism->cm_type != AES_CCM_MECH_INFO_TYPE &&395mechanism->cm_type != AES_GCM_MECH_INFO_TYPE)396return (CRYPTO_MECHANISM_INVALID);397398if ((keysched = aes_alloc_keysched(&size, KM_SLEEP)) == NULL) {399return (CRYPTO_HOST_MEMORY);400}401402/*403* Initialize key schedule. Key length information is stored404* in the key.405*/406if ((rv = init_keysched(key, keysched)) != CRYPTO_SUCCESS) {407memset(keysched, 0, size);408kmem_free(keysched, size);409return (rv);410}411412*tmpl = keysched;413*tmpl_size = size;414415return (CRYPTO_SUCCESS);416}417418419static int420aes_free_context(crypto_ctx_t *ctx)421{422aes_ctx_t *aes_ctx = ctx->cc_provider_private;423424if (aes_ctx != NULL) {425if (aes_ctx->ac_flags & PROVIDER_OWNS_KEY_SCHEDULE) {426ASSERT(aes_ctx->ac_keysched_len != 0);427memset(aes_ctx->ac_keysched, 0,428aes_ctx->ac_keysched_len);429kmem_free(aes_ctx->ac_keysched,430aes_ctx->ac_keysched_len);431}432crypto_free_mode_ctx(aes_ctx);433ctx->cc_provider_private = NULL;434}435436return (CRYPTO_SUCCESS);437}438439440static int441aes_common_init_ctx(aes_ctx_t *aes_ctx, crypto_spi_ctx_template_t *template,442crypto_mechanism_t *mechanism, crypto_key_t *key, int kmflag,443boolean_t is_encrypt_init)444{445int rv = CRYPTO_SUCCESS;446void *keysched;447size_t size = 0;448449if (template == NULL) {450if ((keysched = aes_alloc_keysched(&size, kmflag)) == NULL)451return (CRYPTO_HOST_MEMORY);452/*453* Initialize key schedule.454* Key length is stored in the key.455*/456if ((rv = init_keysched(key, keysched)) != CRYPTO_SUCCESS) {457kmem_free(keysched, size);458return (rv);459}460461aes_ctx->ac_flags |= PROVIDER_OWNS_KEY_SCHEDULE;462aes_ctx->ac_keysched_len = size;463} else {464keysched = template;465}466aes_ctx->ac_keysched = keysched;467468switch (mechanism->cm_type) {469case AES_CCM_MECH_INFO_TYPE:470if (mechanism->cm_param == NULL ||471mechanism->cm_param_len != sizeof (CK_AES_CCM_PARAMS)) {472return (CRYPTO_MECHANISM_PARAM_INVALID);473}474rv = ccm_init_ctx((ccm_ctx_t *)aes_ctx, mechanism->cm_param,475kmflag, is_encrypt_init, AES_BLOCK_LEN, aes_encrypt_block,476aes_xor_block);477break;478case AES_GCM_MECH_INFO_TYPE:479if (mechanism->cm_param == NULL ||480mechanism->cm_param_len != sizeof (CK_AES_GCM_PARAMS)) {481return (CRYPTO_MECHANISM_PARAM_INVALID);482}483rv = gcm_init_ctx((gcm_ctx_t *)aes_ctx, mechanism->cm_param,484AES_BLOCK_LEN, aes_encrypt_block, aes_copy_block,485aes_xor_block);486break;487}488489if (rv != CRYPTO_SUCCESS) {490if (aes_ctx->ac_flags & PROVIDER_OWNS_KEY_SCHEDULE) {491memset(keysched, 0, size);492kmem_free(keysched, size);493}494}495496return (rv);497}498499500