From 553afd6ca4364c59b8d9fde92022e91d2f100f4c Mon Sep 17 00:00:00 2001 From: leisen Date: Sat, 14 Dec 2024 10:27:05 +0800 Subject: [PATCH] drivers: crypto: hisilicon: add pbkdf2 algorithm Add pbkdf2 algorithm for hisilicon SEC driver. Signed-off-by: leisen --- core/arch/arm/plat-d06/conf.mk | 2 + core/drivers/crypto/hisilicon/crypto.mk | 2 + core/drivers/crypto/hisilicon/sec_pbkdf2.c | 349 +++++++++++++++++++++ core/drivers/crypto/hisilicon/sec_pbkdf2.h | 38 +++ core/drivers/crypto/hisilicon/sub.mk | 1 + 5 files changed, 392 insertions(+) create mode 100644 core/drivers/crypto/hisilicon/sec_pbkdf2.c create mode 100644 core/drivers/crypto/hisilicon/sec_pbkdf2.h diff --git a/core/arch/arm/plat-d06/conf.mk b/core/arch/arm/plat-d06/conf.mk index 7c250a7c304..55f1c3970f9 100644 --- a/core/arch/arm/plat-d06/conf.mk +++ b/core/arch/arm/plat-d06/conf.mk @@ -17,6 +17,8 @@ $(call force,CFG_WITH_LPAE,y) $(call force,CFG_ARM_GICV3,y) $(call force,CFG_LPAE_ADDR_SPACE_BITS,48) $(call force,CFG_LPC_UART,y) +$(call force,CFG_CRYPTO_PBKDF2,y) +$(call force,CFG_CRYPTO_HW_PBKDF2,y) CFG_TEE_CORE_LOG_LEVEL ?= 4 diff --git a/core/drivers/crypto/hisilicon/crypto.mk b/core/drivers/crypto/hisilicon/crypto.mk index 6b7cc7ca25e..a79b3078349 100644 --- a/core/drivers/crypto/hisilicon/crypto.mk +++ b/core/drivers/crypto/hisilicon/crypto.mk @@ -7,6 +7,8 @@ $(call force, CFG_CRYPTO_DRV_HASH,y,Mandated by CFG_HISILICON_CRYPTO_DRIVER) $(call force, CFG_CRYPTO_DRV_MAC,y,Mandated by CFG_HISILICON_CRYPTO_DRIVER) $(call force, CFG_CRYPTO_DRV_CIPHER,y,Mandated by CFG_HISILICON_CRYPTO_DRIVER) $(call force,CFG_CRYPTO_DRV_AUTHENC,y,Mandated by CFG_HISILICON_CRYPTO_DRIVER) +$(call force,CFG_CRYPTO_PBKDF2,y,Mandated by CFG_HISILICON_CRYPTO_DRIVER) +$(call force,CFG_CRYPTO_HW_PBKDF2,y,Mandated by CFG_HISILICON_CRYPTO_DRIVER) ifeq ($(CFG_HISILICON_ACC_V3), y) $(call force, CFG_CRYPTO_DRV_DH,y,Mandated by CFG_HISILICON_ACC_V3) diff --git a/core/drivers/crypto/hisilicon/sec_pbkdf2.c b/core/drivers/crypto/hisilicon/sec_pbkdf2.c new file mode 100644 index 00000000000..c3f324c6b0e --- /dev/null +++ b/core/drivers/crypto/hisilicon/sec_pbkdf2.c @@ -0,0 +1,349 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (c) 2024, HiSilicon Technologies Co., Ltd. + * Kunpeng hardware accelerator pbkdf2 implementation. + */ + +#include +#include + +#include "sec_main.h" +#include "sec_pbkdf2.h" + +static enum hisi_drv_status sec_pbkdf2_parse_sqe(void *bd, void *msg __unused) +{ + struct hisi_sec_sqe *sqe = bd; + uint16_t done = 0; + + done = SEC_GET_FIELD(sqe->type2.done_flag, SEC_DONE_MASK, 0); + if (done != SEC_HW_TASK_DONE || sqe->type2.error_type) { + EMSG("SEC do pbkdf2 fail! done=%#"PRIx16", etype=%#"PRIx8, + done, sqe->type2.error_type); + return HISI_QM_DRVCRYPT_IN_EPARA; + } + + return HISI_QM_DRVCRYPT_NO_ERR; +} + +static enum hisi_drv_status sec_pbkdf2_fill_sqe(void *bd, void *msg) +{ + struct sec_pbkdf2_msg *pbkdf2_msg = msg; + struct hisi_sec_sqe *sqe = bd; + + sqe->type_auth_cipher = BD_TYPE2; + sqe->type_auth_cipher |= SHIFT_U32(AUTH_MAC_CALCULATE, SEC_AUTH_OFFSET); + sqe->sds_sa_type = SHIFT_U32(SCENE_PBKDF2, SEC_SCENE_OFFSET); + + sqe->type2.mac_key_alg = SHIFT_U32(pbkdf2_msg->derive_type, + SEC_AEAD_ALG_OFFSET); + /* mac_len = 1 and a_key_len = 1 only for hardware check */ + sqe->type2.mac_key_alg |= 0x1; + sqe->type2.mac_key_alg |= SHIFT_U32(0x1, SEC_AKEY_OFFSET); + + sqe->type2.alen_ivllen = pbkdf2_msg->salt_len; + sqe->type2.clen_ivhlen = pbkdf2_msg->c_num; + sqe->type2.pass_word_len = (uint16_t)pbkdf2_msg->key_len; + sqe->type2.dk_len = (uint16_t)pbkdf2_msg->out_len; + + if (IS_ENABLED(CFG_CRYPTO_HW_PBKDF2_WITH_EFUSE)) + sqe->huk_ci_key = SHIFT_U32(SEC_HUK_ENABLE, SEC_HUK_OFFSET); + else + sqe->type2.a_key_addr = pbkdf2_msg->key_dma; + + sqe->type2.data_src_addr = pbkdf2_msg->salt_dma; + sqe->type2.mac_addr = pbkdf2_msg->out_dma; + + return HISI_QM_DRVCRYPT_NO_ERR; +} + +static enum hisi_drv_status sec_pbkdf2_parse_bd3_sqe(void *bd, + void *msg __unused) +{ + struct hisi_sec_bd3_sqe *sqe = bd; + uint16_t done = 0; + + done = SEC_GET_FIELD(sqe->done_flag, SEC_DONE_MASK, 0); + if (done != SEC_HW_TASK_DONE || sqe->error_type) { + EMSG("SEC do pbkdf2 fail! done=%#"PRIx16", etype=%#"PRIx8, + done, sqe->error_type); + return HISI_QM_DRVCRYPT_IN_EPARA; + } + + return HISI_QM_DRVCRYPT_NO_ERR; +} + +static enum hisi_drv_status sec_pbkdf2_fill_bd3_sqe(void *bd, void *msg) +{ + struct sec_pbkdf2_msg *pbkdf2_msg = msg; + struct hisi_sec_bd3_sqe *sqe = bd; + + sqe->bd_param = BD_TYPE3 | SHIFT_U32(SCENE_PBKDF2, SEC_SCENE_OFFSET_V3); + sqe->auth_mac_key = AUTH_MAC_CALCULATE; + sqe->auth_mac_key |= SHIFT_U32(pbkdf2_msg->derive_type, + SEC_AUTH_ALG_OFFSET_V3); + /* mac_len = 1 and a_key_len = 1 only for hardware check */ + sqe->auth_mac_key |= SHIFT_U32(0x1, SEC_AKEY_OFFSET_V3); + sqe->auth_mac_key |= SHIFT_U32(0x1, SEC_MAC_OFFSET_V3); + sqe->a_len_key = pbkdf2_msg->salt_len; + sqe->pbkdf2_scene.pbkdf2_salt_len = pbkdf2_msg->salt_len; + sqe->pbkdf2_scene.pass_word_dk_len = pbkdf2_msg->key_len; + sqe->pbkdf2_scene.c_num = pbkdf2_msg->c_num; + sqe->pbkdf2_scene.pass_word_dk_len |= SHIFT_U32(pbkdf2_msg->out_len, + SEC_DK_LEN_OFFSET_V3); + + if (IS_ENABLED(CFG_CRYPTO_HW_PBKDF2_WITH_EFUSE)) + sqe->auth_mac_key |= SHIFT_U32(SEC_IMG_ROTKEY_AP, + SEC_KEY_SEL_OFFSET_V3); + else + sqe->a_key_addr = pbkdf2_msg->key_dma; + + sqe->data_src_addr = pbkdf2_msg->salt_dma; + sqe->mac_addr = pbkdf2_msg->out_dma; + + return HISI_QM_DRVCRYPT_NO_ERR; +} + +static TEE_Result sec_pbkdf2_do_task(void *msg) +{ + enum hisi_drv_status ret = HISI_QM_DRVCRYPT_NO_ERR; + TEE_Result res = TEE_SUCCESS; + struct hisi_qp *qp = NULL; + + qp = sec_create_qp(HISI_QM_CHANNEL_TYPE1); + if (!qp) { + EMSG("Fail to create pbkdf2 qp"); + return TEE_ERROR_BUSY; + } + + if (qp->qm->version == HISI_QM_HW_V2) { + qp->fill_sqe = sec_pbkdf2_fill_sqe; + qp->parse_sqe = sec_pbkdf2_parse_sqe; + } else { + qp->fill_sqe = sec_pbkdf2_fill_bd3_sqe; + qp->parse_sqe = sec_pbkdf2_parse_bd3_sqe; + } + + ret = hisi_qp_send(qp, msg); + if (ret) { + EMSG("Fail to send task, ret=%d", ret); + res = TEE_ERROR_BAD_STATE; + goto done_proc; + } + + ret = hisi_qp_recv_sync(qp, msg); + if (ret) { + EMSG("Recv task error, ret=%d", ret); + res = TEE_ERROR_BAD_STATE; + goto done_proc; + } + +done_proc: + hisi_qm_release_qp(qp); + + return res; +} + +static TEE_Result sec_pbkdf2_dk_iteration_check(uint32_t alg, uint32_t c_num, + size_t dk_len) +{ + TEE_Result ret = TEE_SUCCESS; + size_t hash_len = 0; + size_t t_num = 0; + size_t time = 0; + + if (dk_len > SEC_MAX_DK_LEN) { + EMSG("Unsupported derived key len %zu", dk_len); + return TEE_ERROR_NOT_SUPPORTED; + } + + if (c_num > SEC_MAX_ITERATION_NUM) { + EMSG("Unsupported iteration count %u", c_num); + return TEE_ERROR_NOT_SUPPORTED; + } + + if (c_num <= SEC_CRITICAL_ITERATION_NUM) + return TEE_SUCCESS; + + ret = tee_alg_get_digest_size(alg, &hash_len); + if (ret || hash_len == 0) { + EMSG("Fail to get digest size"); + return TEE_ERROR_NOT_SUPPORTED; + } + + t_num = ROUNDUP_DIV(dk_len, hash_len); + + if (alg < TEE_ALG_HMAC_SHA384 || alg > TEE_ALG_HMAC_SHA512) + time = t_num * SEC_PER_BLOCK_TIME1_NS * c_num; + else + time = t_num * SEC_PER_BLOCK_TIME2_NS * c_num; + + if (time > SEC_MAX_TIMEOUT_NS) { + EMSG("Time %zu is more than sec max timeout", time); + return TEE_ERROR_NOT_SUPPORTED; + } + + return TEE_SUCCESS; +} + +static TEE_Result sec_pbkdf2_params_check(uint32_t hash_id, size_t password_len, + size_t salt_len, uint32_t c_num, + size_t derived_key_len) +{ + uint32_t alg = TEE_ALG_HMAC_ALGO(hash_id); + + if (!password_len || !salt_len || !c_num || !derived_key_len) { + EMSG("Invalid input parameters"); + return TEE_ERROR_BAD_PARAMETERS; + } + + if ((alg < TEE_ALG_HMAC_SHA384 || alg > TEE_ALG_HMAC_SHA512) && + (password_len > (SEC_MAX_PASSWORD_LEN / 2))) { + EMSG("Password_len %zu does not match alg %#"PRIx32, + password_len, alg); + return TEE_ERROR_BAD_PARAMETERS; + } + + if (password_len > SEC_MAX_PASSWORD_LEN) { + EMSG("Unsupported password len %zu", password_len); + return TEE_ERROR_NOT_SUPPORTED; + } + + if (salt_len > SEC_MAX_SALT_LEN) { + EMSG("Unsupported salt len %zu", salt_len); + return TEE_ERROR_NOT_SUPPORTED; + } + + return sec_pbkdf2_dk_iteration_check(alg, c_num, derived_key_len); +} + +static TEE_Result sec_pbkdf2_set_derive_type(uint32_t hash_id, + struct sec_pbkdf2_msg *msg) +{ + uint32_t alg = TEE_ALG_HMAC_ALGO(hash_id); + + switch (alg) { + case TEE_ALG_HMAC_SHA1: + msg->derive_type = SEC_HMAC_SHA1; + break; + case TEE_ALG_HMAC_SHA224: + msg->derive_type = SEC_HMAC_SHA224; + break; + case TEE_ALG_HMAC_SHA256: + msg->derive_type = SEC_HMAC_SHA256; + break; + case TEE_ALG_HMAC_SHA384: + msg->derive_type = SEC_HMAC_SHA384; + break; + case TEE_ALG_HMAC_SHA512: + msg->derive_type = SEC_HMAC_SHA512; + break; + case TEE_ALG_HMAC_SM3: + msg->derive_type = SEC_HMAC_SM3; + break; + default: + EMSG("Invalid hamc alg type %#"PRIx32, alg); + return TEE_ERROR_BAD_PARAMETERS; + } + + return TEE_SUCCESS; +} + +static TEE_Result sec_pbkdf2_set_buf(const uint8_t *password, + const uint8_t *salt, + struct sec_pbkdf2_msg *msg) +{ + msg->key_dma = virt_to_phys(msg->base_key); + if (!msg->key_dma) { + EMSG("Fail to get key dma addr"); + return TEE_ERROR_BAD_STATE; + } + + msg->salt_dma = virt_to_phys(msg->salt); + if (!msg->salt_dma) { + EMSG("Fail to get salt dma addr"); + return TEE_ERROR_BAD_STATE; + } + + msg->out_dma = virt_to_phys(msg->out); + if (!msg->out_dma) { + EMSG("Fail to get out dma addr"); + return TEE_ERROR_BAD_STATE; + } + + if (password) + memcpy(msg->base_key, password, msg->key_len); + + memcpy(msg->salt, salt, msg->salt_len); + + return TEE_SUCCESS; +} + +static void sec_pbkdf2_clean_buf(struct sec_pbkdf2_msg *msg) +{ + memzero_explicit(msg->base_key, msg->key_len); + memzero_explicit(msg->salt, msg->salt_len); +} + +static TEE_Result sec_pbkdf2_msg_init(uint32_t hash_id, size_t password_len, + size_t salt_len, size_t derived_key_len, + uint32_t iteration_count, + struct sec_pbkdf2_msg *msg) +{ + msg->key_len = password_len; + msg->salt_len = salt_len; + msg->out_len = derived_key_len; + msg->c_num = iteration_count; + return sec_pbkdf2_set_derive_type(hash_id, msg); +} + +TEE_Result tee_cryp_pbkdf2(uint32_t hash_id, const uint8_t *password, + size_t password_len, const uint8_t *salt, + size_t salt_len, uint32_t iteration_count, + uint8_t *derived_key, size_t derived_key_len) +{ + TEE_Result ret = TEE_ERROR_GENERIC; + struct sec_pbkdf2_msg *msg = NULL; + + if (!IS_ENABLED(CFG_CRYPTO_HW_PBKDF2_WITH_EFUSE) && !password) { + EMSG("Password buf is NULL"); + return TEE_ERROR_BAD_PARAMETERS; + } + + if (!salt || !derived_key) { + EMSG("Invalid pbkdf2 buf"); + return TEE_ERROR_BAD_PARAMETERS; + } + + ret = sec_pbkdf2_params_check(hash_id, password_len, salt_len, + iteration_count, derived_key_len); + if (ret) + return ret; + + msg = calloc(1, sizeof(*msg)); + if (!msg) { + EMSG("Fail to calloc msg"); + return TEE_ERROR_OUT_OF_MEMORY; + } + + ret = sec_pbkdf2_msg_init(hash_id, password_len, salt_len, + derived_key_len, iteration_count, msg); + if (ret) + goto free_msg; + + ret = sec_pbkdf2_set_buf(password, salt, msg); + if (ret) + goto free_msg; + + ret = sec_pbkdf2_do_task(msg); + if (ret) + goto clean_buf; + + memcpy(derived_key, msg->out, msg->out_len); + +clean_buf: + sec_pbkdf2_clean_buf(msg); +free_msg: + free(msg); + + return ret; +} diff --git a/core/drivers/crypto/hisilicon/sec_pbkdf2.h b/core/drivers/crypto/hisilicon/sec_pbkdf2.h new file mode 100644 index 00000000000..644dbe40fcf --- /dev/null +++ b/core/drivers/crypto/hisilicon/sec_pbkdf2.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* Copyright (c) 2022-2024 HiSilicon Limited. */ + +#ifndef __SEC_PBKDF2_H__ +#define __SEC_PBKDF2_H__ + +#define SEC_MAX_SALT_LEN 1024 +#define SEC_MAX_PASSWORD_LEN 128 +#define SEC_MAX_DK_LEN 512 +#define SEC_MAX_ITERATION_NUM 16777215 +#define SEC_HMAC_SHA1 0x10 +#define SEC_HMAC_SHA256 0x11 +#define SEC_HMAC_SHA224 0x13 +#define SEC_HMAC_SHA384 0x14 +#define SEC_HMAC_SHA512 0x15 +#define SEC_HMAC_SM3 0x26 +#define SEC_HUK_ENABLE 0x1 +#define SEC_IMG_ROTKEY_AP 0x6 +#define SEC_CRITICAL_ITERATION_NUM 1000000 +#define SEC_PER_BLOCK_TIME1_NS (3 * 48) +#define SEC_PER_BLOCK_TIME2_NS (3 * 68) +#define SEC_MAX_TIMEOUT_NS 4000000000 + +struct sec_pbkdf2_msg { + uint8_t salt[SEC_MAX_SALT_LEN]; + uint8_t base_key[SEC_MAX_PASSWORD_LEN]; + uint8_t out[SEC_MAX_DK_LEN]; + uintptr_t salt_dma; + uintptr_t key_dma; + uintptr_t out_dma; + uint32_t salt_len; + uint32_t key_len; + uint32_t out_len; + uint32_t c_num; + uint32_t derive_type; +}; + +#endif diff --git a/core/drivers/crypto/hisilicon/sub.mk b/core/drivers/crypto/hisilicon/sub.mk index cf2439645e1..1615cbccf6b 100644 --- a/core/drivers/crypto/hisilicon/sub.mk +++ b/core/drivers/crypto/hisilicon/sub.mk @@ -4,6 +4,7 @@ srcs-y += sec_hash.c srcs-y += sec_hmac.c srcs-y += sec_cipher.c srcs-y += sec_authenc.c +srcs-y += sec_pbkdf2.c srcs-$(CFG_HISILICON_ACC_V3) += hpre_main.c srcs-$(CFG_HISILICON_ACC_V3) += hpre_dh.c srcs-$(CFG_HISILICON_ACC_V3) += hpre_ecc.c