diff --git a/core/drivers/crypto/hisilicon/hpre_montgomery.c b/core/drivers/crypto/hisilicon/hpre_montgomery.c new file mode 100644 index 00000000000..c926e24fe15 --- /dev/null +++ b/core/drivers/crypto/hisilicon/hpre_montgomery.c @@ -0,0 +1,503 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (c) 2022-2024, HiSilicon Technologies Co., Ltd. + * Kunpeng hardware accelerator hpre montgomery algorithm implementation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hpre_main.h" +#include "hpre_montgomery.h" + +#define X25519_CURVE_INDEX 0 +#define X448_CURVE_INDEX 1 + +struct hpre_mgm_curve { + uint32_t key_bits; + const uint8_t *p; + const uint8_t *a; + const uint8_t *x; +}; + +/* NID_X25519 */ +/* p = (2 ^ 255 - 19) big endian */ +static const uint8_t g_x25519_p[] = { + 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xED +}; + +/* a = (486662 - 2) / 4 = 121665 big endian */ +static const uint8_t g_x25519_a[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xDB, 0x41 +}; + +/* big endian */ +static const uint8_t g_x25519_gx[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09 +}; + +/* NID_X448 */ +/* p = (2 ^ 448 - 2 ^ 224 - 1) big endian */ +static const uint8_t g_x448_p[] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; + +/* a = (156326 - 2) / 4 = 39081 big endian */ +static const uint8_t g_x448_a[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0xA9 +}; + +/* big endian */ +static const uint8_t g_x448_gx[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05 +}; + +static const struct hpre_mgm_curve g_curve_list[] = { + { + .key_bits = 256, + .p = g_x25519_p, + .a = g_x25519_a, + .x = g_x25519_gx, + }, { + .key_bits = 448, + .p = g_x448_p, + .a = g_x448_a, + .x = g_x448_gx, + } +}; + +static TEE_Result +hpre_montgomery_alloc_keypair(struct montgomery_keypair *key, + size_t size_bits) +{ + size_t key_size = BITS_TO_BYTES(size_bits); + + if (!key || (size_bits != X25519_KEY_BITS && + size_bits != X448_KEY_BITS)) { + EMSG("Invalid input parameter"); + return TEE_ERROR_BAD_PARAMETERS; + } + + key->priv = calloc(1, key_size); + if (!key->priv) + goto priv_err; + + key->pub = calloc(1, key_size); + if (!key->pub) + goto pub_err; + + return TEE_SUCCESS; +pub_err: + free(key->priv); + key->priv = NULL; +priv_err: + EMSG("HPRE montgomery alloc key pair fail"); + + return TEE_ERROR_OUT_OF_MEMORY; +} + +static TEE_Result gen_random_privkey(uint8_t *priv, size_t key_bits) +{ + size_t key_size = BITS_TO_BYTES(key_bits); + TEE_Result ret = TEE_SUCCESS; + + if (!priv) { + EMSG("Privkey param is NULL"); + return TEE_ERROR_BAD_PARAMETERS; + } + + ret = hw_get_random_bytes(priv, key_size); + if (ret) { + EMSG("Fail to fill privkey"); + return TEE_ERROR_NO_DATA; + } + + return ret; +} + +static enum hisi_drv_status +hpre_montgomery_params_alloc(struct hpre_montgomery_msg *msg) +{ + uint32_t size = HPRE_MONTGOMERY_TOTAL_BUF_SIZE(msg->key_bytes); + + msg->key = calloc(1, size); + if (!msg->key) { + EMSG("Fail to alloc montgomery key buf"); + return HISI_QM_DRVCRYPT_ENOMEM; + } + + msg->key_dma = virt_to_phys(msg->key); + msg->in = msg->key + HPRE_X_KEY_SIZE(msg->key_bytes); + msg->in_dma = msg->key_dma + HPRE_X_KEY_SIZE(msg->key_bytes); + msg->out = msg->in + msg->key_bytes; + msg->out_dma = msg->in_dma + msg->key_bytes; + + return HISI_QM_DRVCRYPT_NO_ERR; +} + +static void hpre_montgomery_params_free(struct hpre_montgomery_msg *msg) +{ + if (msg->key) { + memzero_explicit(msg->key, HPRE_X_KEY_SIZE(msg->key_bytes)); + free(msg->key); + msg->key = NULL; + } +} + +static enum hisi_drv_status +hpre_montgomery_params_pretreatment(struct hpre_montgomery_msg *msg) +{ + uint8_t *p = msg->key; + uint8_t *a = p + msg->key_bytes; + uint8_t *k = a + msg->key_bytes; + uint8_t *u = msg->in; + uint8_t *dst = k; + uint32_t bsize = msg->key_bytes; + uint32_t dsize = msg->curve_bytes; + uint32_t psize = msg->curve_bytes; + uint32_t shift = 0; + int ret = 0; + + /* + * This is a pretreatment of X25519/X448, as described in RFC 7748: + * For X25519, in order to decode 32 random bytes as an integer + * scaler, set the three LSB of the first byte and MSB of the last + * to zero, set the second MSB of the last byte to 1. + * For X448, set the two LSB of the first byte to 0, and MSB of the + * last byte to 1. Decode in little-endian mode. + * HPRE hardware module uses big-endian mode, so the bytes to be + * set are reversed compared to RFC 7748: + * For example, dat[0] of X25519 in RFC 7748 is reversed to dat[31] + * in HPRE specification, so does X448. + * For X25519, when receiving u-array, set MSB of last byte to zero. + * HPRE hardware module uses big-endian mode, so we set MSB of first + * byte to zero instead. + */ + if (msg->key_bytes == BITS_TO_BYTES(X25519_KEY_BITS)) { + dst[31] &= 248; + dst[0] &= 127; + dst[0] |= 64; + u[0] &= 0x7F; + } else { + dst[55 + bsize - dsize] &= 252; + dst[0 + bsize - dsize] |= 128; + } + + shift = bsize - psize; + ret = memcmp(u + shift, p + shift, psize); + if (ret >= 0) { + EMSG("u >= p"); + return HISI_QM_DRVCRYPT_EINVAL; + } + + return HISI_QM_DRVCRYPT_NO_ERR; +} + +static enum hisi_drv_status +hpre_montgomery_params_fill(const struct hpre_mgm_curve *curve, + struct hpre_montgomery_msg *msg, + uint8_t *privkey, uint8_t *pubkey) +{ + uint8_t *p = msg->key; + uint8_t *a = p + msg->key_bytes; + uint8_t *k = a + msg->key_bytes; + uint8_t *x = msg->in; + enum hisi_drv_status ret = HISI_QM_DRVCRYPT_NO_ERR; + + memcpy(p, curve->p, msg->curve_bytes); + memcpy(a, curve->a, msg->curve_bytes); + memcpy(k, privkey, msg->curve_bytes); + msg->x_bytes = msg->curve_bytes; + if (!pubkey) + memcpy(x, curve->x, msg->x_bytes); + else + memcpy(x, pubkey, msg->x_bytes); + + ret = hpre_bin_from_crypto_bin(p, p, msg->key_bytes, msg->curve_bytes); + if (ret) { + EMSG("Fail to transfer montgomery p from crypto_bin to hpre_bin"); + return ret; + } + + ret = hpre_bin_from_crypto_bin(a, a, msg->key_bytes, msg->curve_bytes); + if (ret) { + EMSG("Fail to transfer montgomery a from crypto_bin to hpre_bin"); + return ret; + } + + ret = hpre_bin_from_crypto_bin(k, k, msg->key_bytes, msg->curve_bytes); + if (ret) { + EMSG("Fail to transfer montgomery k from crypto_bin to hpre_bin"); + return ret; + } + + ret = hpre_bin_from_crypto_bin(x, x, msg->key_bytes, msg->x_bytes); + if (ret) { + EMSG("Fail to transfer montgomery x from crypto_bin to hpre_bin"); + return ret; + } + + return hpre_montgomery_params_pretreatment(msg); +} + +static TEE_Result +hpre_montgomery_request_init(const struct hpre_mgm_curve *curve, + struct hpre_montgomery_msg *msg, + uint8_t *privkey, + uint8_t *pubkey) +{ + TEE_Result ret = TEE_SUCCESS; + + msg->alg_type = HPRE_ALG_X_DH_MULTIPLY; + msg->curve_bytes = BITS_TO_BYTES(curve->key_bits); + + if (curve->key_bits == X25519_KEY_BITS) { + msg->key_bytes = BITS_TO_BYTES(HPRE_HW_X25519_KBITS); + } else if (curve->key_bits == X448_KEY_BITS) { + msg->key_bytes = BITS_TO_BYTES(HPRE_HW_X448_KBITS); + } else { + EMSG("Curve key bits param error"); + return TEE_ERROR_BAD_PARAMETERS; + } + + ret = hpre_montgomery_params_alloc(msg); + if (ret) + return TEE_ERROR_OUT_OF_MEMORY; + + ret = hpre_montgomery_params_fill(curve, msg, privkey, pubkey); + if (ret) { + hpre_montgomery_params_free(msg); + return TEE_ERROR_BAD_STATE; + } + + return TEE_SUCCESS; +} + +static void hpre_montgomery_request_deinit(struct hpre_montgomery_msg *msg) +{ + hpre_montgomery_params_free(msg); +} + +static enum hisi_drv_status hpre_montgomery_fill_sqe(void *bd, void *info) +{ + struct hpre_montgomery_msg *msg = info; + struct hpre_sqe *sqe = bd; + + sqe->w0 = msg->alg_type | (0x1 << HPRE_DONE_SHIFT); + sqe->task_len1 = TASK_LENGTH(msg->key_bytes); + sqe->key = msg->key_dma; + sqe->in = msg->in_dma; + sqe->out = msg->out_dma; + + return HISI_QM_DRVCRYPT_NO_ERR; +} + +static enum hisi_drv_status hpre_montgomery_parse_sqe(void *bd, void *info) +{ + struct hpre_montgomery_msg *msg = info; + struct hpre_sqe *sqe = bd; + uint8_t *rx = msg->out; + uint16_t err = 0; + uint16_t err1 = 0; + uint16_t done = 0; + + err = HPRE_TASK_ETYPE(sqe->w0); + err1 = HPRE_TASK_ETYPE1(sqe->w0); + done = HPRE_TASK_DONE(sqe->w0); + if (done != HPRE_HW_TASK_DONE || err || err1) { + EMSG("HPRE do x_dh fail! done=0x%"PRIX16", etype=0x%"PRIX16",etype1=0x%"PRIX16, done, err, err1); + if (done == HPRE_HW_TASK_INIT) { + msg->result = HISI_QM_DRVCRYPT_ENOPROC; + return HISI_QM_DRVCRYPT_ENOPROC; + } + + msg->result = HISI_QM_DRVCRYPT_IN_EPARA; + return HISI_QM_DRVCRYPT_IN_EPARA; + } + + if (hpre_bin_to_crypto_bin(rx, rx, msg->key_bytes, msg->curve_bytes)) { + EMSG("Fail to transfer x_dh out from hpre_bin to crypto_bin"); + msg->result = HISI_QM_DRVCRYPT_EINVAL; + return HISI_QM_DRVCRYPT_EINVAL; + } + + return HISI_QM_DRVCRYPT_NO_ERR; +} + +static TEE_Result hpre_montgomery_do_task(struct hpre_montgomery_msg *msg) +{ + struct hisi_qp *montgomery_qp = NULL; + TEE_Result res = TEE_SUCCESS; + enum hisi_drv_status ret = HISI_QM_DRVCRYPT_NO_ERR; + + montgomery_qp = hpre_create_qp(HISI_QM_CHANNEL_TYPE1); + if (!montgomery_qp) { + EMSG("Fail to create montgomery qp"); + return TEE_ERROR_BUSY; + } + + montgomery_qp->fill_sqe = hpre_montgomery_fill_sqe; + montgomery_qp->parse_sqe = hpre_montgomery_parse_sqe; + ret = hisi_qp_send(montgomery_qp, msg); + if (ret) { + EMSG("Fail to send task, ret=%d", ret); + res = TEE_ERROR_BAD_STATE; + goto done; + } + + ret = hisi_qp_recv_sync(montgomery_qp, msg); + if (ret) { + EMSG("Recv task error, ret=%d", ret); + res = TEE_ERROR_BAD_STATE; + } + +done: + hisi_qm_release_qp(montgomery_qp); + + return res; +} + +static TEE_Result hpre_montgomery_gen_keypair(struct montgomery_keypair *key, + size_t size_bits) +{ + struct hpre_montgomery_msg msg = { }; + const struct hpre_mgm_curve *curve = NULL; + TEE_Result ret = TEE_SUCCESS; + + if (!key || !key->priv || !key->pub) { + EMSG("Invalid montgomery_gen_keypair input parameters"); + return TEE_ERROR_BAD_PARAMETERS; + } + + if (size_bits == X25519_KEY_BITS) + curve = &g_curve_list[X25519_CURVE_INDEX]; + else if (size_bits == X448_KEY_BITS) + curve = &g_curve_list[X448_CURVE_INDEX]; + else + return TEE_ERROR_BAD_PARAMETERS; + + ret = gen_random_privkey(key->priv, size_bits); + if (ret) { + EMSG("Fail to gen privkey"); + return ret; + } + + ret = hpre_montgomery_request_init(curve, &msg, key->priv, NULL); + if (ret) { + EMSG("Fail to init montgomery key pair"); + return ret; + } + + ret = hpre_montgomery_do_task(&msg); + if (ret) { + EMSG("Fail to do montgomery key pair task ret = 0x%"PRIX32, ret); + goto done; + } + memcpy(key->pub, msg.out, msg.curve_bytes); + +done: + hpre_montgomery_request_deinit(&msg); + + return ret; +} + +static TEE_Result +hpre_montgomery_do_shared_secret(struct drvcrypt_secret_data *sdata) +{ + struct hpre_montgomery_msg msg = { }; + const struct hpre_mgm_curve *curve = NULL; + struct montgomery_keypair *key = NULL; + uint8_t *pubkey = NULL; + TEE_Result ret = TEE_SUCCESS; + + if (!sdata || !sdata->key_priv || !sdata->key_pub) { + EMSG("Invalid montgomery_do_shared_secret input parameters"); + return TEE_ERROR_BAD_PARAMETERS; + } + + key = sdata->key_priv; + pubkey = sdata->key_pub; + if (sdata->size_sec == BITS_TO_BYTES(X25519_KEY_BITS)) + curve = &g_curve_list[X25519_CURVE_INDEX]; + else if (sdata->size_sec == BITS_TO_BYTES(X448_KEY_BITS)) + curve = &g_curve_list[X448_CURVE_INDEX]; + else + return TEE_ERROR_BAD_PARAMETERS; + + ret = hpre_montgomery_request_init(curve, &msg, key->priv, pubkey); + if (ret) { + EMSG("Fail to init montgomery shared secret"); + return ret; + } + + ret = hpre_montgomery_do_task(&msg); + if (ret) { + EMSG("Fail to do montgomery shared secret task! ret = 0x%"PRIX32, ret); + goto done; + } + memcpy(sdata->secret.data, msg.out, msg.curve_bytes); + sdata->secret.length = msg.curve_bytes; + memzero_explicit(msg.out, msg.curve_bytes); + +done: + hpre_montgomery_request_deinit(&msg); + + return ret; +} + +static struct drvcrypt_montgomery driver_x25519 = { + .alloc_keypair = hpre_montgomery_alloc_keypair, + .gen_keypair = hpre_montgomery_gen_keypair, + .shared_secret = hpre_montgomery_do_shared_secret, +}; + +static struct drvcrypt_montgomery driver_x448 = { + .alloc_keypair = hpre_montgomery_alloc_keypair, + .gen_keypair = hpre_montgomery_gen_keypair, + .shared_secret = hpre_montgomery_do_shared_secret, +}; + +TEE_Result hpre_montgomery_init(void) +{ + TEE_Result ret = TEE_SUCCESS; + + ret = drvcrypt_register_x25519(&driver_x25519); + if (ret != TEE_SUCCESS) { + EMSG("Hpre x25519 register to crypto fail"); + return ret; + } + + ret = drvcrypt_register_x448(&driver_x448); + if (ret != TEE_SUCCESS) { + EMSG("Hpre x448 register to crypto fail"); + return ret; + } + + return ret; +} + +driver_init(hpre_montgomery_init); diff --git a/core/drivers/crypto/hisilicon/hpre_montgomery.h b/core/drivers/crypto/hisilicon/hpre_montgomery.h new file mode 100644 index 00000000000..1c9a7fc14bf --- /dev/null +++ b/core/drivers/crypto/hisilicon/hpre_montgomery.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2024 HiSilicon Limited. + */ +#ifndef __HPRE_MONTGOMERYH__ +#define __HPRE_MONTGOMERYH__ + +#include +#include +#include +#include + +#define HPRE_X_KEY_PARAM_NUM 3 +#define X25519_KEY_BITS 256 +#define X448_KEY_BITS 448 +#define HPRE_HW_X25519_KBITS 256 +#define HPRE_HW_X448_KBITS 576 +#define HPRE_MONTGOMERY_TOTAL_BUF_SIZE(key_bytes) ((key_bytes) * 5) +#define HPRE_X_KEY_SIZE(hsz) ((hsz) * HPRE_X_KEY_PARAM_NUM) + +struct hpre_montgomery_msg { + uint8_t *key; + paddr_t key_dma; + uint8_t *in; + paddr_t in_dma; + uint8_t *out; + paddr_t out_dma; + uint32_t alg_type; + uint32_t key_bytes; + uint32_t curve_bytes; + uint32_t x_bytes; + uint32_t result; +}; + +TEE_Result hpre_montgomery_init(void); + +#endif diff --git a/core/drivers/crypto/hisilicon/sub.mk b/core/drivers/crypto/hisilicon/sub.mk index d2764ee3571..74dfd905a8c 100644 --- a/core/drivers/crypto/hisilicon/sub.mk +++ b/core/drivers/crypto/hisilicon/sub.mk @@ -6,3 +6,4 @@ srcs-y += sec_cipher.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 +srcs-$(CFG_HISILICON_ACC_V3) += hpre_montgomery.c \ No newline at end of file