mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 03:15:31 +09:00
crypto: rockchip: add ECC/SM2 support
Add support for the following algorithms:
1. ecdsa-nist-p192
2. ecdsa-nist-p224
3. ecdsa-nist-p256
4. sm2
Signed-off-by: Lin Jinhan <troy.lin@rock-chips.com>
Change-Id: Id58c7755a78293ccb6bfba2a781587922876d5bc
This commit is contained in:
@@ -11,12 +11,19 @@ rk_crypto-$(CONFIG_CRYPTO_DEV_ROCKCHIP_V1) += \
|
||||
rk_crypto_v1_ahash.o \
|
||||
rk_crypto_v1_skcipher.o
|
||||
|
||||
$(obj)/rk_sm2signature.asn1.o: $(obj)/rk_sm2signature.asn1.c $(obj)/rk_sm2signature.asn1.h
|
||||
$(obj)/rk_ecdsasignature.asn1.o: $(obj)/rk_ecdsasignature.asn1.c $(obj)/rk_ecdsasignature.asn1.h
|
||||
$(obj)/rk_crypto_ecc.o: $(obj)/rk_sm2signature.asn1.h $(obj)/rk_ecdsasignature.asn1.h
|
||||
|
||||
rk_crypto-$(CONFIG_CRYPTO_DEV_ROCKCHIP_V2) += \
|
||||
rk_crypto_v2.o \
|
||||
rk_crypto_v2_ahash.o \
|
||||
rk_crypto_v2_skcipher.o \
|
||||
rk_crypto_v2_akcipher.o \
|
||||
rk_crypto_v2_pka.o \
|
||||
rk_crypto_ecc.o \
|
||||
rk_sm2signature.asn1.o \
|
||||
rk_ecdsasignature.asn1.o \
|
||||
rk_crypto_bignum.o
|
||||
|
||||
rk_crypto-$(CONFIG_CRYPTO_DEV_ROCKCHIP_V3) += \
|
||||
@@ -25,6 +32,9 @@ rk_crypto-$(CONFIG_CRYPTO_DEV_ROCKCHIP_V3) += \
|
||||
rk_crypto_v3_skcipher.o \
|
||||
rk_crypto_v2_akcipher.o \
|
||||
rk_crypto_v2_pka.o \
|
||||
rk_crypto_ecc.o \
|
||||
rk_sm2signature.asn1.o \
|
||||
rk_ecdsasignature.asn1.o \
|
||||
rk_crypto_bignum.o
|
||||
|
||||
obj-$(CONFIG_CRYPTO_DEV_ROCKCHIP_DEV) += cryptodev_linux/
|
||||
|
||||
@@ -128,3 +128,91 @@ int rk_bn_highest_bit(const struct rk_bignum *bn)
|
||||
|
||||
return (int)(bn->n_words - 1) * RK_WORD_SIZE + b;
|
||||
}
|
||||
|
||||
void rk_ecc_free_point(struct rk_ecp_point *point)
|
||||
{
|
||||
if (!point)
|
||||
return;
|
||||
|
||||
rk_bn_free(point->x);
|
||||
rk_bn_free(point->y);
|
||||
|
||||
kfree(point);
|
||||
}
|
||||
|
||||
struct rk_ecp_point *rk_ecc_alloc_point_zero(u32 max_size)
|
||||
{
|
||||
struct rk_ecp_point *point = NULL;
|
||||
|
||||
point = kzalloc(sizeof(*point), GFP_KERNEL);
|
||||
if (!point)
|
||||
return NULL;
|
||||
|
||||
point->x = rk_bn_alloc(max_size);
|
||||
if (!point->x)
|
||||
goto error;
|
||||
|
||||
point->y = rk_bn_alloc(max_size);
|
||||
if (!point->y)
|
||||
goto error;
|
||||
|
||||
return point;
|
||||
|
||||
error:
|
||||
rk_ecc_free_point(point);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct rk_ecp_point *rk_ecc_alloc_point(const uint8_t *x, uint32_t x_len,
|
||||
const uint8_t *y, uint32_t y_len,
|
||||
enum bignum_endian endian, u32 max_size)
|
||||
{
|
||||
struct rk_ecp_point *point = NULL;
|
||||
|
||||
point = kzalloc(sizeof(*point), GFP_KERNEL);
|
||||
if (!point)
|
||||
return NULL;
|
||||
|
||||
point->x = rk_bn_alloc(max_size);
|
||||
if (!point->x)
|
||||
goto error;
|
||||
|
||||
if (rk_bn_set_data(point->x, x, x_len, endian) != 0)
|
||||
goto error;
|
||||
|
||||
point->y = rk_bn_alloc(max_size);
|
||||
if (!point->y)
|
||||
goto error;
|
||||
|
||||
if (rk_bn_set_data(point->y, y, y_len, endian) != 0)
|
||||
goto error;
|
||||
|
||||
return point;
|
||||
|
||||
error:
|
||||
rk_ecc_free_point(point);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool rk_ecp_point_is_zero(struct rk_ecp_point *point)
|
||||
{
|
||||
uint32_t i;
|
||||
bool ret = true;
|
||||
|
||||
if (!point || !point->x || !point->y)
|
||||
return false;
|
||||
|
||||
for (i = 0; i < point->x->n_words; i++) {
|
||||
if (point->x->data[i] != 0)
|
||||
ret = false;
|
||||
}
|
||||
|
||||
for (i = 0; i < point->y->n_words; i++) {
|
||||
if (point->y->data[i] != 0)
|
||||
ret = false;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,11 @@ struct rk_bignum {
|
||||
u32 *data;
|
||||
};
|
||||
|
||||
struct rk_ecp_point {
|
||||
struct rk_bignum *x; /*!< the point's X coordinate */
|
||||
struct rk_bignum *y; /*!< the point's Y coordinate */
|
||||
};
|
||||
|
||||
struct rk_bignum *rk_bn_alloc(u32 max_size);
|
||||
void rk_bn_free(struct rk_bignum *bn);
|
||||
int rk_bn_set_data(struct rk_bignum *bn, const u8 *data, u32 size, enum bignum_endian endian);
|
||||
@@ -24,4 +29,11 @@ int rk_bn_get_data(const struct rk_bignum *bn, u8 *data, u32 size, enum bignum_e
|
||||
u32 rk_bn_get_size(const struct rk_bignum *bn);
|
||||
int rk_bn_highest_bit(const struct rk_bignum *src);
|
||||
|
||||
struct rk_ecp_point *rk_ecc_alloc_point_zero(u32 max_size);
|
||||
struct rk_ecp_point *rk_ecc_alloc_point(const uint8_t *x, uint32_t x_len,
|
||||
const uint8_t *y, uint32_t y_len,
|
||||
enum bignum_endian endian, u32 max_size);
|
||||
void rk_ecc_free_point(struct rk_ecp_point *point);
|
||||
bool rk_ecp_point_is_zero(struct rk_ecp_point *point);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -672,7 +672,7 @@ static char *crypto_full_algs_name[] = {
|
||||
"ecb(des3_ede)", "cbc(des3_ede)", "cfb(des3_ede)", "ofb(des3_ede)",
|
||||
"sha1", "sha224", "sha256", "sha384", "sha512", "md5", "sm3",
|
||||
"hmac(sha1)", "hmac(sha256)", "hmac(sha512)", "hmac(md5)", "hmac(sm3)",
|
||||
"rsa"
|
||||
"rsa", "ecc-192", "ecc-224", "ecc-256", "sm2",
|
||||
};
|
||||
|
||||
static const struct rk_crypto_soc_data px30_soc_data =
|
||||
|
||||
@@ -213,9 +213,19 @@ struct rk_cipher_ctx {
|
||||
|
||||
struct rk_rsa_ctx {
|
||||
struct rk_alg_ctx algs_ctx;
|
||||
struct rk_bignum *n;
|
||||
struct rk_bignum *e;
|
||||
struct rk_bignum *d;
|
||||
struct rk_bignum *n;
|
||||
struct rk_bignum *e;
|
||||
struct rk_bignum *d;
|
||||
|
||||
struct rk_crypto_dev *rk_dev;
|
||||
};
|
||||
|
||||
struct rk_ecc_ctx {
|
||||
struct rk_alg_ctx algs_ctx;
|
||||
uint32_t group_id;
|
||||
uint32_t nbits;
|
||||
bool pub_key_set;
|
||||
struct rk_ecp_point *point_Q;
|
||||
|
||||
struct rk_crypto_dev *rk_dev;
|
||||
};
|
||||
@@ -245,6 +255,15 @@ struct rk_crypto_algt {
|
||||
bool valid_flag;
|
||||
};
|
||||
|
||||
enum rk_asym_algo {
|
||||
ASYM_ALGO_RSA,
|
||||
ASYM_ALGO_ECC_P192,
|
||||
ASYM_ALGO_ECC_P224,
|
||||
ASYM_ALGO_ECC_P256,
|
||||
ASYM_ALGO_SM2,
|
||||
ASYM_ALGO_MAX,
|
||||
};
|
||||
|
||||
enum rk_hash_algo {
|
||||
HASH_ALGO_MD5,
|
||||
HASH_ALGO_SHA1,
|
||||
@@ -439,6 +458,27 @@ enum rk_cipher_mode {
|
||||
} \
|
||||
}
|
||||
|
||||
#define RK_ASYM_ECC_INIT(key_bits) {\
|
||||
.name = "ecc-" #key_bits, \
|
||||
.type = ALG_TYPE_ASYM, \
|
||||
.algo = ASYM_ALGO_ECC_P##key_bits, \
|
||||
.alg.asym = { \
|
||||
.verify = rk_ecc_verify, \
|
||||
.set_pub_key = rk_ecc_set_pub_key, \
|
||||
.max_size = rk_ecc_max_size, \
|
||||
.init = rk_ecc_init_tfm, \
|
||||
.exit = rk_ecc_exit_tfm, \
|
||||
.reqsize = 64, \
|
||||
.base = { \
|
||||
.cra_name = "ecdsa-nist-p" #key_bits, \
|
||||
.cra_driver_name = "ecdsa-nist-p" #key_bits "-rk", \
|
||||
.cra_priority = RK_CRYPTO_PRIORITY, \
|
||||
.cra_module = THIS_MODULE, \
|
||||
.cra_ctxsize = sizeof(struct rk_ecc_ctx), \
|
||||
},\
|
||||
} \
|
||||
}
|
||||
|
||||
#define CRYPTO_MAJOR_VER(ver) ((ver) & 0x0f000000)
|
||||
|
||||
#define CRYPTO_MAJOR_VER_3 0x03000000
|
||||
|
||||
469
drivers/crypto/rockchip/rk_crypto_ecc.c
Normal file
469
drivers/crypto/rockchip/rk_crypto_ecc.c
Normal file
@@ -0,0 +1,469 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2024 Rockchip Electronics Co., Ltd.
|
||||
*
|
||||
* Author: Lin Jinhan <troy.lin@rock-chips.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/iopoll.h>
|
||||
|
||||
#include "rk_crypto_core.h"
|
||||
#include "rk_crypto_v2.h"
|
||||
#include "rk_crypto_v2_reg.h"
|
||||
#include "rk_crypto_ecc.h"
|
||||
|
||||
static void __iomem *ecc_base;
|
||||
|
||||
#define WORDS2BYTES(words) ((words) * 4)
|
||||
|
||||
#define RK_ECP_POLL_PERIOD_US 10000
|
||||
#define RK_ECP_POLL_TIMEOUT_US 500000
|
||||
|
||||
#define RK_LOAD_GROUP_A(G) do { \
|
||||
grp->curve_name = #G; \
|
||||
grp->wide = G ## _wide;\
|
||||
grp->p = G ## _p; \
|
||||
grp->p_len = sizeof(G ## _p); \
|
||||
grp->a = G ## _a; \
|
||||
grp->a_len = sizeof(G ## _a); \
|
||||
grp->n = G ## _n; \
|
||||
grp->n_len = sizeof(G ## _n); \
|
||||
grp->gx = G ## _gx; \
|
||||
grp->gx_len = sizeof(G ## _gx); \
|
||||
grp->gy = G ## _gy; \
|
||||
grp->gy_len = sizeof(G ## _gy); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Domain parameters for secp192r1
|
||||
*/
|
||||
static const uint32_t secp192r1_wide = RK_ECC_CURVE_WIDE_192;
|
||||
|
||||
static const uint8_t secp192r1_p[] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
};
|
||||
|
||||
static const uint8_t secp192r1_a[] = {
|
||||
0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
};
|
||||
|
||||
static const uint8_t secp192r1_gx[] = {
|
||||
0x12, 0x10, 0xFF, 0x82, 0xFD, 0x0A, 0xFF, 0xF4,
|
||||
0x00, 0x88, 0xA1, 0x43, 0xEB, 0x20, 0xBF, 0x7C,
|
||||
0xF6, 0x90, 0x30, 0xB0, 0x0E, 0xA8, 0x8D, 0x18,
|
||||
};
|
||||
|
||||
static const uint8_t secp192r1_gy[] = {
|
||||
0x11, 0x48, 0x79, 0x1E, 0xA1, 0x77, 0xF9, 0x73,
|
||||
0xD5, 0xCD, 0x24, 0x6B, 0xED, 0x11, 0x10, 0x63,
|
||||
0x78, 0xDA, 0xC8, 0xFF, 0x95, 0x2B, 0x19, 0x07,
|
||||
};
|
||||
|
||||
static const uint8_t secp192r1_n[] = {
|
||||
0x31, 0x28, 0xD2, 0xB4, 0xB1, 0xC9, 0x6B, 0x14,
|
||||
0x36, 0xF8, 0xDE, 0x99, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
};
|
||||
|
||||
/*
|
||||
* Domain parameters for secp224r1
|
||||
*/
|
||||
static const uint32_t secp224r1_wide = RK_ECC_CURVE_WIDE_224;
|
||||
|
||||
static const uint8_t secp224r1_p[] = {
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
static const uint8_t secp224r1_a[] = {
|
||||
0xFE, 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, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
static const uint8_t secp224r1_gx[] = {
|
||||
0x21, 0x1D, 0x5C, 0x11, 0xD6, 0x80, 0x32, 0x34,
|
||||
0x22, 0x11, 0xC2, 0x56, 0xD3, 0xC1, 0x03, 0x4A,
|
||||
0xB9, 0x90, 0x13, 0x32, 0x7F, 0xBF, 0xB4, 0x6B,
|
||||
0xBD, 0x0C, 0x0E, 0xB7,
|
||||
};
|
||||
|
||||
static const uint8_t secp224r1_gy[] = {
|
||||
0x34, 0x7E, 0x00, 0x85, 0x99, 0x81, 0xD5, 0x44,
|
||||
0x64, 0x47, 0x07, 0x5A, 0xA0, 0x75, 0x43, 0xCD,
|
||||
0xE6, 0xDF, 0x22, 0x4C, 0xFB, 0x23, 0xF7, 0xB5,
|
||||
0x88, 0x63, 0x37, 0xBD,
|
||||
};
|
||||
|
||||
static const uint8_t secp224r1_n[] = {
|
||||
0x3D, 0x2A, 0x5C, 0x5C, 0x45, 0x29, 0xDD, 0x13,
|
||||
0x3E, 0xF0, 0xB8, 0xE0, 0xA2, 0x16, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF,
|
||||
};
|
||||
|
||||
/*
|
||||
* Domain parameters for secp256r1
|
||||
*/
|
||||
static const uint32_t secp256r1_wide = RK_ECC_CURVE_WIDE_256;
|
||||
|
||||
static const uint8_t secp256r1_p[] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
};
|
||||
|
||||
static const uint8_t secp256r1_a[] = {
|
||||
0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
};
|
||||
|
||||
static const uint8_t secp256r1_gx[] = {
|
||||
0x96, 0xC2, 0x98, 0xD8, 0x45, 0x39, 0xA1, 0xF4,
|
||||
0xA0, 0x33, 0xEB, 0x2D, 0x81, 0x7D, 0x03, 0x77,
|
||||
0xF2, 0x40, 0xA4, 0x63, 0xE5, 0xE6, 0xBC, 0xF8,
|
||||
0x47, 0x42, 0x2C, 0xE1, 0xF2, 0xD1, 0x17, 0x6B,
|
||||
};
|
||||
|
||||
static const uint8_t secp256r1_gy[] = {
|
||||
0xF5, 0x51, 0xBF, 0x37, 0x68, 0x40, 0xB6, 0xCB,
|
||||
0xCE, 0x5E, 0x31, 0x6B, 0x57, 0x33, 0xCE, 0x2B,
|
||||
0x16, 0x9E, 0x0F, 0x7C, 0x4A, 0xEB, 0xE7, 0x8E,
|
||||
0x9B, 0x7F, 0x1A, 0xFE, 0xE2, 0x42, 0xE3, 0x4F,
|
||||
};
|
||||
|
||||
static const uint8_t secp256r1_n[] = {
|
||||
0x51, 0x25, 0x63, 0xFC, 0xC2, 0xCA, 0xB9, 0xF3,
|
||||
0x84, 0x9E, 0x17, 0xA7, 0xAD, 0xFA, 0xE6, 0xBC,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
};
|
||||
|
||||
/*
|
||||
* Domain parameters for sm2p256v1_p
|
||||
*/
|
||||
static const uint32_t sm2p256v1_wide = RK_ECC_CURVE_WIDE_256;
|
||||
|
||||
static const uint8_t sm2p256v1_p[] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF,
|
||||
};
|
||||
|
||||
static const uint8_t sm2p256v1_a[] = {
|
||||
0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF,
|
||||
};
|
||||
|
||||
static const uint8_t sm2p256v1_gx[] = {
|
||||
0xC7, 0x74, 0x4C, 0x33, 0x89, 0x45, 0x5A, 0x71,
|
||||
0xE1, 0x0B, 0x66, 0xF2, 0xBF, 0x0B, 0xE3, 0x8F,
|
||||
0x94, 0xC9, 0x39, 0x6A, 0x46, 0x04, 0x99, 0x5F,
|
||||
0x19, 0x81, 0x19, 0x1F, 0x2C, 0xAE, 0xC4, 0x32,
|
||||
};
|
||||
|
||||
static const uint8_t sm2p256v1_gy[] = {
|
||||
0xA0, 0xF0, 0x39, 0x21, 0xE5, 0x32, 0xDF, 0x02,
|
||||
0x40, 0x47, 0x2A, 0xC6, 0x7C, 0x87, 0xA9, 0xD0,
|
||||
0x53, 0x21, 0x69, 0x6B, 0xE3, 0xCE, 0xBD, 0x59,
|
||||
0x9C, 0x77, 0xF6, 0xF4, 0xA2, 0x36, 0x37, 0xBC,
|
||||
};
|
||||
|
||||
static const uint8_t sm2p256v1_n[] = {
|
||||
0x23, 0x41, 0xD5, 0x39, 0x09, 0xF4, 0xBB, 0x53,
|
||||
0x2B, 0x05, 0xC6, 0x21, 0x6B, 0xDF, 0x03, 0x72,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF,
|
||||
};
|
||||
|
||||
static void dump_ecc_sram(void)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
int i;
|
||||
uint32_t len = 0x300;
|
||||
uint32_t *buffer;
|
||||
|
||||
buffer = kzalloc(len, GFP_KERNEL);
|
||||
|
||||
for (i = 0; i < len / 4; i++)
|
||||
buffer[i] = ((uint32_t *)SM2_RAM_BASE)[i];
|
||||
|
||||
CRYPTO_DUMPHEX("ECC SRAM ", buffer, len);
|
||||
|
||||
kfree(buffer);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void ecc_word_memcpy(uint32_t *dst, uint32_t *src, uint32_t size)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < size; i++, dst++)
|
||||
writel_relaxed(src[i], (void *)dst);
|
||||
}
|
||||
|
||||
static void ecc_word_memset(uint32_t *buff, uint32_t val, uint32_t size)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < size; i++, buff++)
|
||||
writel_relaxed(val, (void *)buff);
|
||||
}
|
||||
|
||||
static void rk_reverse_buf(uint8_t *buff, uint32_t size)
|
||||
{
|
||||
uint8_t *buf_h_swap, *buf_l_swap;
|
||||
uint32_t i;
|
||||
uint32_t temp;
|
||||
|
||||
buf_h_swap = buff + size - 1;
|
||||
buf_l_swap = buff;
|
||||
|
||||
for (i = 0 ; i < (size / 2) ; i++) {
|
||||
temp = *buf_h_swap;
|
||||
*(buf_h_swap--) = *buf_l_swap;
|
||||
*(buf_l_swap++) = temp;
|
||||
}
|
||||
}
|
||||
|
||||
static int rk_word_cmp_zero(uint32_t *buf1, uint32_t n_words)
|
||||
{
|
||||
int ret = 0;
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0 ; i < n_words; i++) {
|
||||
if (buf1[i] != 0)
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rk_load_hash_bn(struct rk_ecp_group *grp, struct rk_bignum *bn,
|
||||
uint8_t *hash, uint32_t hash_len)
|
||||
{
|
||||
if (grp == NULL || RK_ECP_IS_BIGNUM_INVALID(bn))
|
||||
return -EINVAL;
|
||||
|
||||
hash_len = hash_len > grp->p_len ? grp->p_len : hash_len;
|
||||
|
||||
memset(bn->data, 0x00, WORDS2BYTES(bn->n_words));
|
||||
memcpy(bn->data, hash, hash_len);
|
||||
|
||||
rk_reverse_buf((void *)bn->data, hash_len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set a group using well-known domain parameters
|
||||
*/
|
||||
static int rk_ecp_group_load(struct rk_ecp_group *grp, enum rk_ecp_group_id id)
|
||||
{
|
||||
memset(grp, 0x00, sizeof(*grp));
|
||||
|
||||
grp->id = id;
|
||||
grp->endian = RK_BG_LITTILE_ENDIAN;
|
||||
|
||||
switch (id) {
|
||||
case RK_ECP_DP_SECP192R1:
|
||||
RK_LOAD_GROUP_A(secp192r1);
|
||||
return 0;
|
||||
|
||||
case RK_ECP_DP_SECP224R1:
|
||||
RK_LOAD_GROUP_A(secp224r1);
|
||||
return 0;
|
||||
|
||||
case RK_ECP_DP_SECP256R1:
|
||||
RK_LOAD_GROUP_A(secp256r1);
|
||||
return 0;
|
||||
|
||||
case RK_ECP_DP_SM2P256V1:
|
||||
RK_LOAD_GROUP_A(sm2p256v1);
|
||||
return 0;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int rockchip_ecc_request_set(uint32_t ecc_ctl, uint32_t wide)
|
||||
{
|
||||
RK_ECP_WRITE_REG(RK_ECC_CURVE_WIDE, wide);
|
||||
|
||||
RK_ECP_WRITE_REG(RK_ECC_INT_EN, 0);
|
||||
RK_ECP_WRITE_REG(RK_ECC_INT_ST, RK_ECP_READ_REG(RK_ECC_INT_ST));
|
||||
RK_ECP_WRITE_REG(RK_ECC_CTL, ecc_ctl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rockchip_ecc_request_wait_done(void)
|
||||
{
|
||||
int ret;
|
||||
u32 reg_val = 0;
|
||||
|
||||
ret = readx_poll_timeout(RK_ECP_READ_REG, RK_ECC_INT_ST, reg_val,
|
||||
reg_val != 0, RK_ECP_POLL_PERIOD_US, RK_ECP_POLL_TIMEOUT_US);
|
||||
if (ret) {
|
||||
CRYPTO_TRACE("rk ecp poll RK_ECC_INT_ST timeout.\ns");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (RK_ECP_READ_REG(RK_ECC_ABN_ST)) {
|
||||
ret = -EFAULT;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
exit:
|
||||
if (ret) {
|
||||
CRYPTO_TRACE("RK_ECC_CTL = %08x\n", RK_ECP_READ_REG(RK_ECC_CTL));
|
||||
CRYPTO_TRACE("RK_ECC_INT_EN = %08x\n", RK_ECP_READ_REG(RK_ECC_INT_EN));
|
||||
CRYPTO_TRACE("RK_ECC_CURVE_WIDE = %08x\n", RK_ECP_READ_REG(RK_ECC_CURVE_WIDE));
|
||||
CRYPTO_TRACE("RK_ECC_RAM_CTL = %08x\n", RK_ECP_READ_REG(RK_ECC_RAM_CTL));
|
||||
CRYPTO_TRACE("RK_ECC_INT_ST = %08x\n", RK_ECP_READ_REG(RK_ECC_INT_ST));
|
||||
CRYPTO_TRACE("RK_ECC_ABN_ST = %08x\n", RK_ECP_READ_REG(RK_ECC_ABN_ST));
|
||||
}
|
||||
|
||||
RK_ECP_WRITE_REG(RK_ECC_CTL, 0);
|
||||
RK_ECP_RAM_FOR_CPU();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rockchip_ecc_request_trigger(void)
|
||||
{
|
||||
uint32_t ecc_ctl = RK_ECP_READ_REG(RK_ECC_CTL);
|
||||
|
||||
RK_ECP_RAM_FOR_ECC();
|
||||
|
||||
RK_ECP_WRITE_REG(RK_ECC_CTL, ecc_ctl | RK_ECC_CTL_REQ_ECC);
|
||||
|
||||
return rockchip_ecc_request_wait_done();
|
||||
}
|
||||
|
||||
int rockchip_ecc_verify(int group_id, uint8_t *hash, uint32_t hash_len,
|
||||
struct rk_ecp_point *point_P, struct rk_ecp_point *point_sign)
|
||||
{
|
||||
int ret;
|
||||
uint32_t curve_sel = 0;
|
||||
struct rk_bignum *bn_hash = NULL;
|
||||
struct rk_ecp_group grp;
|
||||
struct rk_ecc_verify *ecc_st = (struct rk_ecc_verify *)SM2_RAM_BASE;
|
||||
|
||||
CRYPTO_TRACE("ecc_st = %p, ecc_base = %p\n", ecc_st, ecc_base);
|
||||
|
||||
if (!hash ||
|
||||
RK_ECP_IS_POINT_INVALID(point_P) ||
|
||||
RK_ECP_IS_POINT_INVALID(point_sign)) {
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = rk_ecp_group_load(&grp, group_id);
|
||||
if (ret)
|
||||
goto exit;
|
||||
|
||||
bn_hash = rk_bn_alloc(RK_ECP_MAX_BYTES);
|
||||
if (!bn_hash) {
|
||||
ret = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
curve_sel = group_id == RK_ECP_DP_SM2P256V1 ?
|
||||
RK_ECC_CTL_FUNC_SM2_CURVER : RK_ECC_CTL_FUNC_ECC_CURVER;
|
||||
|
||||
rk_load_hash_bn(&grp, bn_hash, hash, hash_len);
|
||||
|
||||
RK_ECP_LOAD_DATA(ecc_st->e, bn_hash);
|
||||
RK_ECP_LOAD_DATA(ecc_st->r_, point_sign->x);
|
||||
RK_ECP_LOAD_DATA(ecc_st->s_, point_sign->y);
|
||||
RK_ECP_LOAD_DATA(ecc_st->p_x, point_P->x);
|
||||
RK_ECP_LOAD_DATA(ecc_st->p_y, point_P->y);
|
||||
|
||||
RK_ECP_LOAD_DATA_EXT(ecc_st->A, grp.a, grp.a_len);
|
||||
RK_ECP_LOAD_DATA_EXT(ecc_st->P, grp.p, grp.p_len);
|
||||
RK_ECP_LOAD_DATA_EXT(ecc_st->N, grp.n, grp.n_len);
|
||||
|
||||
RK_ECP_LOAD_DATA_EXT(ecc_st->G_x, grp.gx, grp.gx_len);
|
||||
RK_ECP_LOAD_DATA_EXT(ecc_st->G_y, grp.gy, grp.gy_len);
|
||||
|
||||
rockchip_ecc_request_set(curve_sel | RK_ECC_CTL_FUNC_SEL_VERIFY, grp.wide);
|
||||
|
||||
ret = rockchip_ecc_request_trigger();
|
||||
exit:
|
||||
if (ret || rk_word_cmp_zero(ecc_st->v, RK_ECP_MAX_WORDS)) {
|
||||
ret = -EKEYREJECTED;
|
||||
dump_ecc_sram();
|
||||
}
|
||||
|
||||
rk_bn_free(bn_hash);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void rockchip_ecc_init(void __iomem *base)
|
||||
{
|
||||
ecc_base = base - RK_ECC_BASE_OFFSET;
|
||||
|
||||
RK_ECP_WRITE_REG(RK_ECC_DATA_ENDIAN, RK_ECC_DATA_ENDIAN_LITTLE);
|
||||
}
|
||||
|
||||
void rockchip_ecc_deinit(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
uint32_t rockchip_ecc_get_max_size(void)
|
||||
{
|
||||
return RK_ECP_MAX_BYTES;
|
||||
}
|
||||
|
||||
uint32_t rockchip_ecc_get_curve_nbits(uint32_t group_id)
|
||||
{
|
||||
switch (group_id) {
|
||||
case RK_ECP_DP_SECP192R1:
|
||||
return 192;
|
||||
|
||||
case RK_ECP_DP_SECP224R1:
|
||||
return 224;
|
||||
|
||||
case RK_ECP_DP_SECP256R1:
|
||||
case RK_ECP_DP_SM2P256V1:
|
||||
return 256;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t rockchip_ecc_get_group_id(uint32_t asym_algo)
|
||||
{
|
||||
|
||||
switch (asym_algo) {
|
||||
case ASYM_ALGO_ECC_P192:
|
||||
return RK_ECP_DP_SECP192R1;
|
||||
case ASYM_ALGO_ECC_P224:
|
||||
return RK_ECP_DP_SECP224R1;
|
||||
case ASYM_ALGO_ECC_P256:
|
||||
return RK_ECP_DP_SECP256R1;
|
||||
case ASYM_ALGO_SM2:
|
||||
return RK_ECP_DP_SM2P256V1;
|
||||
default:
|
||||
return RK_ECP_DP_NONE;
|
||||
}
|
||||
}
|
||||
152
drivers/crypto/rockchip/rk_crypto_ecc.h
Normal file
152
drivers/crypto/rockchip/rk_crypto_ecc.h
Normal file
@@ -0,0 +1,152 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
|
||||
/* Copyright (c) 2024 Rockchip Electronics Co. Ltd. */
|
||||
|
||||
#ifndef __RK_CRYPTO_ECC_H__
|
||||
#define __RK_CRYPTO_ECC_H__
|
||||
|
||||
#include "rk_crypto_bignum.h"
|
||||
|
||||
#define RK_ECP_MAX_BITS 256
|
||||
#define RK_ECP_MAX_BYTES ((RK_ECP_MAX_BITS) / 8)
|
||||
#define RK_ECP_MAX_WORDS ((RK_ECP_MAX_BITS) / 32)
|
||||
#define RK_ECP_MAX_WORDS_ALL (512 / 32)
|
||||
|
||||
/*************************************************************/
|
||||
/* Macros for waiting PKA machine ready states */
|
||||
/*************************************************************/
|
||||
#define RK_ECP_WRITE_REG(offset, val) writel_relaxed((val), (ecc_base) + (offset))
|
||||
#define RK_ECP_READ_REG(offset) readl_relaxed((ecc_base) + (offset))
|
||||
|
||||
#define RK_ECP_RAM_FOR_ECC() \
|
||||
RK_ECP_WRITE_REG(RK_ECC_RAM_CTL, RK_ECC_RAM_CTL_SEL_MASK | RK_ECC_RAM_CTL_ECC)
|
||||
|
||||
#define RK_ECP_RAM_FOR_CPU() \
|
||||
RK_ECP_WRITE_REG(RK_ECC_RAM_CTL, RK_ECC_RAM_CTL_SEL_MASK | RK_ECC_RAM_CTL_CPU)
|
||||
|
||||
#define RK_ECP_LOAD_DATA(dst, big_src) \
|
||||
do { \
|
||||
ecc_word_memset((dst), 0, RK_ECP_MAX_WORDS);\
|
||||
ecc_word_memcpy((dst), (big_src->data), (big_src->n_words)); \
|
||||
} while (0)
|
||||
|
||||
#define RK_ECP_LOAD_DATA_EXT(dst, src, n_bytes) \
|
||||
do { \
|
||||
ecc_word_memset((void *)(dst), 0, RK_ECP_MAX_WORDS);\
|
||||
ecc_word_memcpy((void *)(dst), (void *)(src), (n_bytes) / 4); \
|
||||
} while (0)
|
||||
|
||||
#define RK_ECC_BASE_OFFSET 0x0480
|
||||
|
||||
#define RK_ECC_CTL 0x03F0
|
||||
#define RK_ECC_CTL_RAND_K_SRC_SOFT _SBF(12, 0)
|
||||
#define RK_ECC_CTL_RAND_K_SRC_HARD _SBF(12, 1)
|
||||
#define RK_ECC_CTL_FUNC_SM2_CURVER _SBF(8, 0x0)
|
||||
#define RK_ECC_CTL_FUNC_ECC_CURVER _SBF(8, 0x1)
|
||||
|
||||
#define RK_ECC_CTL_FUNC_SEL_MUL _SBF(4, 0x0)
|
||||
#define RK_ECC_CTL_FUNC_SEL_KG _SBF(4, 0x1)
|
||||
#define RK_ECC_CTL_FUNC_SEL_SIGN _SBF(4, 0x2)
|
||||
#define RK_ECC_CTL_FUNC_SEL_VERIFY _SBF(4, 0x3)
|
||||
#define RK_ECC_CTL_FUNC_SEL_MUL_MOD _SBF(4, 0x4)
|
||||
#define RK_ECC_CTL_FUNC_SEL_ADD_MOD _SBF(4, 0x5)
|
||||
#define RK_ECC_CTL_FUNC_SEL_DOUBLE_POINT _SBF(4, 0x6)
|
||||
#define RK_ECC_CTL_FUNC_SEL_ADD_POINT _SBF(4, 0x7)
|
||||
#define RK_ECC_CTL_FUNC_SEL_KP _SBF(4, 0x8)
|
||||
#define RK_ECC_CTL_FUNC_SEL_KP_KG _SBF(4, 0xa)
|
||||
#define RK_ECC_CTL_REQ_ECC _SBF(0, 1)
|
||||
|
||||
#define RK_ECC_INT_EN 0x03F4
|
||||
#define RK_ECC_INT_EN_DONE _BIT(0)
|
||||
|
||||
#define RK_ECC_INT_ST 0x03F8
|
||||
#define RK_ECC_INT_ST_DONE _BIT(0)
|
||||
|
||||
#define RK_ECC_ABN_ST 0x03FC
|
||||
#define RK_ECC_ABN_ST_BAD_INV_OUT _BIT(8)
|
||||
#define RK_ECC_ABN_ST_BAD_K_IN _BIT(7)
|
||||
#define RK_ECC_ABN_ST_BAD_R_IN _BIT(6)
|
||||
#define RK_ECC_ABN_ST_BAD_S_IN _BIT(5)
|
||||
#define RK_ECC_ABN_ST_BAD_R_K_MID _BIT(4)
|
||||
#define RK_ECC_ABN_ST_BAD_R_OUT _BIT(3)
|
||||
#define RK_ECC_ABN_ST_BAD_S_OUT _BIT(2)
|
||||
#define RK_ECC_ABN_ST_BAD_T_OUT _BIT(1)
|
||||
#define RK_ECC_ABN_ST_BAD_POINT_OUT _BIT(0)
|
||||
|
||||
#define RK_ECC_CURVE_WIDE 0x0400
|
||||
#define RK_ECC_CURVE_WIDE_192 192
|
||||
#define RK_ECC_CURVE_WIDE_224 224
|
||||
#define RK_ECC_CURVE_WIDE_256 256
|
||||
|
||||
#define RK_ECC_MAX_CURVE_WIDE 0x0404
|
||||
|
||||
#define RK_ECC_DATA_ENDIAN 0x0408
|
||||
#define RK_ECC_DATA_ENDIAN_LITTLE 0x0
|
||||
#define RK_ECC_DATA_ENDIAN_BIG 0x1
|
||||
|
||||
#define RK_ECC_RAM_CTL 0x0480
|
||||
#define RK_ECC_RAM_CTL_SEL_MASK _SBF(16, 3)
|
||||
#define RK_ECC_RAM_CTL_CPU _SBF(0, 0)
|
||||
#define RK_ECC_RAM_CTL_PKA _SBF(0, 1)
|
||||
#define RK_ECC_RAM_CTL_ECC _SBF(0, 2)
|
||||
|
||||
#define SM2_RAM_BASE ((ecc_base) + 0x1000)
|
||||
|
||||
enum rk_ecp_group_id {
|
||||
RK_ECP_DP_NONE = 0,
|
||||
RK_ECP_DP_SECP192R1, /*!< 192-bits NIST curve */
|
||||
RK_ECP_DP_SECP224R1, /*!< 224-bits NIST curve */
|
||||
RK_ECP_DP_SECP256R1, /*!< 256-bits NIST curve */
|
||||
RK_ECP_DP_SM2P256V1, /*!< */
|
||||
};
|
||||
|
||||
#define RK_ECP_IS_BIGNUM_INVALID(b) (!b || !b->data || b->n_words < RK_ECP_MAX_WORDS)
|
||||
#define RK_ECP_IS_POINT_INVALID(p) (RK_ECP_IS_BIGNUM_INVALID(p->x) && \
|
||||
RK_ECP_IS_BIGNUM_INVALID(p->y))
|
||||
|
||||
struct rk_ecp_group {
|
||||
enum rk_ecp_group_id id; /*!< internal group identifier */
|
||||
const char *curve_name;
|
||||
uint32_t wide;
|
||||
const uint8_t *p; /*!< prime modulus of the base field */
|
||||
const uint8_t *a; /*!< 1. A in the equation, or 2. (A + 2) / 4 */
|
||||
const uint8_t *n;
|
||||
const uint8_t *gx;
|
||||
const uint8_t *gy;
|
||||
size_t p_len;
|
||||
size_t a_len;
|
||||
size_t n_len;
|
||||
size_t gx_len;
|
||||
size_t gy_len;
|
||||
enum bignum_endian endian;
|
||||
};
|
||||
|
||||
struct rk_ecc_verify {
|
||||
uint32_t e[RK_ECP_MAX_WORDS_ALL]; // 0x00
|
||||
uint32_t r_[RK_ECP_MAX_WORDS_ALL]; // 0x40
|
||||
uint32_t s_[RK_ECP_MAX_WORDS_ALL]; // 0x80
|
||||
uint32_t p_x[RK_ECP_MAX_WORDS_ALL]; // 0xC0
|
||||
uint32_t p_y[RK_ECP_MAX_WORDS_ALL]; // 0x100
|
||||
uint32_t A[RK_ECP_MAX_WORDS_ALL]; // 0x140
|
||||
uint32_t P[RK_ECP_MAX_WORDS_ALL]; // 0x180
|
||||
uint32_t N[RK_ECP_MAX_WORDS_ALL]; // 0x1C0
|
||||
uint32_t G_x[RK_ECP_MAX_WORDS_ALL]; // 0x200
|
||||
uint32_t G_y[RK_ECP_MAX_WORDS_ALL]; // 0x240
|
||||
uint32_t r[RK_ECP_MAX_WORDS_ALL]; // 0x280
|
||||
uint32_t v[RK_ECP_MAX_WORDS_ALL]; // 0x2C0
|
||||
};
|
||||
|
||||
int rockchip_ecc_verify(int group_id, uint8_t *hash, uint32_t hash_len,
|
||||
struct rk_ecp_point *point_P, struct rk_ecp_point *point_sign);
|
||||
|
||||
void rockchip_ecc_init(void __iomem *base);
|
||||
|
||||
void rockchip_ecc_deinit(void);
|
||||
|
||||
uint32_t rockchip_ecc_get_max_size(void);
|
||||
|
||||
uint32_t rockchip_ecc_get_curve_nbits(uint32_t group_id);
|
||||
|
||||
uint32_t rockchip_ecc_get_group_id(uint32_t asym_algo);
|
||||
|
||||
#endif
|
||||
@@ -8,13 +8,18 @@
|
||||
*
|
||||
* Some ideas are from marvell/cesa.c and s5p-sss.c driver.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/asn1_decoder.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/scatterlist.h>
|
||||
|
||||
#include "rk_crypto_core.h"
|
||||
#include "rk_crypto_v2.h"
|
||||
#include "rk_crypto_v2_reg.h"
|
||||
#include "rk_crypto_v2_pka.h"
|
||||
#include "rk_crypto_ecc.h"
|
||||
#include "rk_sm2signature.asn1.h"
|
||||
#include "rk_ecdsasignature.asn1.h"
|
||||
|
||||
#define BG_WORDS2BYTES(words) ((words) * sizeof(u32))
|
||||
#define BG_BYTES2WORDS(bytes) (((bytes) + sizeof(u32) - 1) / sizeof(u32))
|
||||
@@ -294,12 +299,16 @@ static void rk_rsa_exit_tfm(struct crypto_akcipher *tfm)
|
||||
|
||||
rk_rsa_clear_ctx(ctx);
|
||||
|
||||
ctx->rk_dev->release_crypto(ctx->rk_dev, "rsa");
|
||||
if (ctx->rk_dev && ctx->rk_dev->release_crypto)
|
||||
ctx->rk_dev->release_crypto(ctx->rk_dev, "rsa");
|
||||
|
||||
memset(ctx, 0x00, sizeof(*ctx));
|
||||
}
|
||||
|
||||
struct rk_crypto_algt rk_v2_asym_rsa = {
|
||||
.name = "rsa",
|
||||
.type = ALG_TYPE_ASYM,
|
||||
.algo = ASYM_ALGO_RSA,
|
||||
.alg.asym = {
|
||||
.encrypt = rk_rsa_enc,
|
||||
.decrypt = rk_rsa_dec,
|
||||
@@ -319,3 +328,241 @@ struct rk_crypto_algt rk_v2_asym_rsa = {
|
||||
},
|
||||
};
|
||||
|
||||
int rk_ecc_get_signature_r(void *context, size_t hdrlen, unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct rk_ecp_point *sig = context;
|
||||
const uint8_t *tmp_value = value;
|
||||
|
||||
if (!value || !vlen)
|
||||
return -EINVAL;
|
||||
|
||||
/* skip first zero */
|
||||
if (tmp_value[0] == 0x00) {
|
||||
tmp_value += 1;
|
||||
vlen -= 1;
|
||||
}
|
||||
|
||||
return rk_bn_set_data(sig->x, tmp_value, vlen, RK_BG_BIG_ENDIAN);
|
||||
}
|
||||
|
||||
int rk_ecc_get_signature_s(void *context, size_t hdrlen, unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct rk_ecp_point *sig = context;
|
||||
const uint8_t *tmp_value = value;
|
||||
|
||||
if (!value || !vlen)
|
||||
return -EINVAL;
|
||||
|
||||
/* skip first zero */
|
||||
if (tmp_value[0] == 0x00) {
|
||||
tmp_value += 1;
|
||||
vlen -= 1;
|
||||
}
|
||||
|
||||
return rk_bn_set_data(sig->y, tmp_value, vlen, RK_BG_BIG_ENDIAN);
|
||||
}
|
||||
|
||||
static int rk_ecc_verify(struct akcipher_request *req)
|
||||
{
|
||||
struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
|
||||
struct rk_ecc_ctx *ctx = akcipher_tfm_ctx(tfm);
|
||||
size_t keylen = ctx->nbits / 8;
|
||||
struct rk_ecp_point *sig_point = NULL;
|
||||
u8 rawhash[RK_ECP_MAX_BYTES];
|
||||
unsigned char *buffer;
|
||||
ssize_t diff;
|
||||
int ret;
|
||||
|
||||
if (unlikely(!ctx->pub_key_set))
|
||||
return -EINVAL;
|
||||
|
||||
buffer = kmalloc(req->src_len + req->dst_len, GFP_KERNEL);
|
||||
if (!buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
sig_point = rk_ecc_alloc_point_zero(RK_ECP_MAX_BYTES);
|
||||
if (!sig_point) {
|
||||
ret = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
sg_pcopy_to_buffer(req->src, sg_nents_for_len(req->src, req->src_len + req->dst_len),
|
||||
buffer, req->src_len + req->dst_len, 0);
|
||||
|
||||
CRYPTO_DUMPHEX("total signture:", buffer, req->src_len);
|
||||
|
||||
if (ctx->group_id == RK_ECP_DP_SM2P256V1)
|
||||
ret = asn1_ber_decoder(&rk_sm2signature_decoder, sig_point, buffer, req->src_len);
|
||||
else
|
||||
ret = asn1_ber_decoder(&rk_ecdsasignature_decoder, sig_point, buffer, req->src_len);
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
|
||||
CRYPTO_DUMPHEX("bn r value = ", sig_point->x->data, BG_WORDS2BYTES(sig_point->x->n_words));
|
||||
CRYPTO_DUMPHEX("bn s value = ", sig_point->y->data, BG_WORDS2BYTES(sig_point->y->n_words));
|
||||
|
||||
/* if the hash is shorter then we will add leading zeros to fit to ndigits */
|
||||
memset(rawhash, 0x00, sizeof(rawhash));
|
||||
diff = keylen - req->dst_len;
|
||||
if (diff >= 0) {
|
||||
if (diff)
|
||||
memset(rawhash, 0, diff);
|
||||
memcpy(&rawhash[diff], buffer + req->src_len, req->dst_len);
|
||||
} else if (diff < 0) {
|
||||
/* given hash is longer, we take the left-most bytes */
|
||||
memcpy(&rawhash, buffer + req->src_len, keylen);
|
||||
}
|
||||
|
||||
CRYPTO_DUMPHEX("rawhash:", rawhash, sizeof(rawhash));
|
||||
|
||||
mutex_lock(&akcipher_mutex);
|
||||
|
||||
ret = rockchip_ecc_verify(ctx->group_id, rawhash, keylen, ctx->point_Q, sig_point);
|
||||
|
||||
mutex_unlock(&akcipher_mutex);
|
||||
exit:
|
||||
kfree(buffer);
|
||||
rk_ecc_free_point(sig_point);
|
||||
|
||||
CRYPTO_TRACE("ret = %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the public key given the raw uncompressed key data from an X509
|
||||
* certificate. The key data contain the concatenated X and Y coordinates of
|
||||
* the public key.
|
||||
*/
|
||||
static int rk_ecc_set_pub_key(struct crypto_akcipher *tfm, const void *key, unsigned int keylen)
|
||||
{
|
||||
struct rk_ecc_ctx *ctx = akcipher_tfm_ctx(tfm);
|
||||
struct rk_ecp_point *pub_Q = ctx->point_Q;
|
||||
const unsigned char *d = key;
|
||||
uint32_t nbytes;
|
||||
|
||||
CRYPTO_TRACE();
|
||||
|
||||
CRYPTO_DUMPHEX("key = ", key, keylen);
|
||||
|
||||
if (keylen < 1 || (((keylen - 1) >> 1) % sizeof(u32)) != 0)
|
||||
return -EINVAL;
|
||||
|
||||
/* we only accept uncompressed format indicated by '4' */
|
||||
if (d[0] != 4)
|
||||
return -EINVAL;
|
||||
|
||||
keylen--;
|
||||
d++;
|
||||
|
||||
nbytes = keylen / 2;
|
||||
|
||||
CRYPTO_TRACE("keylen = %u, nbytes = %u, group_id = %u, curve_byte = %u\n",
|
||||
keylen, nbytes, ctx->group_id,
|
||||
rockchip_ecc_get_curve_nbits(ctx->group_id) / 8);
|
||||
|
||||
if (nbytes != rockchip_ecc_get_curve_nbits(ctx->group_id) / 8)
|
||||
return -EINVAL;
|
||||
|
||||
rk_bn_set_data(pub_Q->x, d, nbytes, RK_BG_BIG_ENDIAN);
|
||||
rk_bn_set_data(pub_Q->y, d + nbytes, nbytes, RK_BG_BIG_ENDIAN);
|
||||
|
||||
CRYPTO_DUMPHEX("Qx = ", pub_Q->x->data, BG_WORDS2BYTES(pub_Q->x->n_words));
|
||||
CRYPTO_DUMPHEX("Qy = ", pub_Q->y->data, BG_WORDS2BYTES(pub_Q->y->n_words));
|
||||
|
||||
if (rk_ecp_point_is_zero(pub_Q))
|
||||
return -EINVAL;
|
||||
|
||||
ctx->pub_key_set = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int rk_ecc_max_size(struct crypto_akcipher *tfm)
|
||||
{
|
||||
CRYPTO_TRACE();
|
||||
|
||||
return rockchip_ecc_get_max_size();
|
||||
}
|
||||
|
||||
static int rk_ecc_init_tfm(struct crypto_akcipher *tfm)
|
||||
{
|
||||
struct rk_ecc_ctx *ctx = akcipher_tfm_ctx(tfm);
|
||||
struct akcipher_alg *alg = __crypto_akcipher_alg(tfm->base.__crt_alg);
|
||||
struct rk_crypto_algt *algt;
|
||||
struct rk_crypto_dev *rk_dev;
|
||||
|
||||
CRYPTO_TRACE();
|
||||
|
||||
if (!ctx)
|
||||
return -EINVAL;
|
||||
|
||||
memset(ctx, 0x00, sizeof(*ctx));
|
||||
|
||||
algt = container_of(alg, struct rk_crypto_algt, alg.asym);
|
||||
rk_dev = algt->rk_dev;
|
||||
|
||||
if (!rk_dev->request_crypto)
|
||||
return -EFAULT;
|
||||
|
||||
rk_dev->request_crypto(rk_dev, algt->name);
|
||||
|
||||
ctx->rk_dev = rk_dev;
|
||||
ctx->group_id = rockchip_ecc_get_group_id(algt->algo);
|
||||
ctx->nbits = rockchip_ecc_get_curve_nbits(ctx->group_id);
|
||||
ctx->point_Q = rk_ecc_alloc_point_zero(RK_ECP_MAX_BYTES);
|
||||
|
||||
rockchip_ecc_init(ctx->rk_dev->pka_reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rk_ecc_exit_tfm(struct crypto_akcipher *tfm)
|
||||
{
|
||||
struct rk_ecc_ctx *ctx = akcipher_tfm_ctx(tfm);
|
||||
struct akcipher_alg *alg = __crypto_akcipher_alg(tfm->base.__crt_alg);
|
||||
struct rk_crypto_algt *algt;
|
||||
|
||||
CRYPTO_TRACE();
|
||||
|
||||
if (!ctx)
|
||||
return;
|
||||
|
||||
rk_ecc_free_point(ctx->point_Q);
|
||||
|
||||
rockchip_ecc_deinit();
|
||||
|
||||
algt = container_of(alg, struct rk_crypto_algt, alg.asym);
|
||||
|
||||
if (ctx->rk_dev && ctx->rk_dev->release_crypto)
|
||||
ctx->rk_dev->release_crypto(ctx->rk_dev, algt->name);
|
||||
|
||||
memset(ctx, 0x00, sizeof(*ctx));
|
||||
}
|
||||
|
||||
struct rk_crypto_algt rk_asym_ecc_p192 = RK_ASYM_ECC_INIT(192);
|
||||
struct rk_crypto_algt rk_asym_ecc_p224 = RK_ASYM_ECC_INIT(224);
|
||||
struct rk_crypto_algt rk_asym_ecc_p256 = RK_ASYM_ECC_INIT(256);
|
||||
|
||||
struct rk_crypto_algt rk_asym_sm2 = {
|
||||
.name = "sm2",
|
||||
.type = ALG_TYPE_ASYM,
|
||||
.algo = ASYM_ALGO_SM2,
|
||||
.alg.asym = {
|
||||
.verify = rk_ecc_verify,
|
||||
.set_pub_key = rk_ecc_set_pub_key,
|
||||
.max_size = rk_ecc_max_size,
|
||||
.init = rk_ecc_init_tfm,
|
||||
.exit = rk_ecc_exit_tfm,
|
||||
.reqsize = 64,
|
||||
.base = {
|
||||
.cra_name = "sm2",
|
||||
.cra_driver_name = "sm2-rk",
|
||||
.cra_priority = RK_CRYPTO_PRIORITY,
|
||||
.cra_module = THIS_MODULE,
|
||||
.cra_ctxsize = sizeof(struct rk_ecc_ctx),
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
@@ -434,6 +434,7 @@ exit:
|
||||
static void pka_finish(void)
|
||||
{
|
||||
RK_PKA_TERMINATE();
|
||||
PKA_RAM_FOR_CPU();
|
||||
PKA_CLK_DISABLE();
|
||||
}
|
||||
|
||||
|
||||
@@ -94,6 +94,10 @@ static struct rk_crypto_algt *crypto_v3_algs[] = {
|
||||
|
||||
/* Shared v2 version implementation */
|
||||
&rk_v2_asym_rsa, /* rsa */
|
||||
&rk_asym_ecc_p192, /* ecc nist p192 */
|
||||
&rk_asym_ecc_p224, /* ecc nist p224 */
|
||||
&rk_asym_ecc_p256, /* ecc nist p256 */
|
||||
&rk_asym_sm2, /* sm2 */
|
||||
};
|
||||
|
||||
static bool rk_is_cipher_support(struct rk_crypto_dev *rk_dev, u32 algo, u32 mode, u32 key_len)
|
||||
@@ -161,6 +165,21 @@ static bool rk_is_hash_support(struct rk_crypto_dev *rk_dev, u32 algo, u32 type)
|
||||
return version & mask;
|
||||
}
|
||||
|
||||
static bool rk_is_asym_support(struct rk_crypto_dev *rk_dev, u32 algo)
|
||||
{
|
||||
switch (algo) {
|
||||
case ASYM_ALGO_RSA:
|
||||
return !!CRYPTO_READ(rk_dev, CRYPTO_PKA_VERSION);
|
||||
case ASYM_ALGO_ECC_P192:
|
||||
case ASYM_ALGO_ECC_P224:
|
||||
case ASYM_ALGO_ECC_P256:
|
||||
case ASYM_ALGO_SM2:
|
||||
return !!CRYPTO_READ(rk_dev, CRYPTO_ECC_MAX_CURVE_WIDE);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int rk_hw_crypto_v3_init(struct device *dev, void *hw_info)
|
||||
{
|
||||
struct rk_hw_crypto_v3_info *info =
|
||||
@@ -208,8 +227,8 @@ bool rk_hw_crypto_v3_algo_valid(struct rk_crypto_dev *rk_dev, struct rk_crypto_a
|
||||
CRYPTO_TRACE("HASH/HMAC");
|
||||
return rk_is_hash_support(rk_dev, aglt->algo, aglt->type);
|
||||
} else if (aglt->type == ALG_TYPE_ASYM) {
|
||||
CRYPTO_TRACE("RSA");
|
||||
return true;
|
||||
CRYPTO_TRACE("ASYM");
|
||||
return rk_is_asym_support(rk_dev, aglt->algo);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -72,6 +72,10 @@ extern struct rk_crypto_algt rk_v3_hmac_sm3;
|
||||
|
||||
/* Shared v2 version implementation */
|
||||
extern struct rk_crypto_algt rk_v2_asym_rsa;
|
||||
extern struct rk_crypto_algt rk_asym_ecc_p192;
|
||||
extern struct rk_crypto_algt rk_asym_ecc_p224;
|
||||
extern struct rk_crypto_algt rk_asym_ecc_p256;
|
||||
extern struct rk_crypto_algt rk_asym_sm2;
|
||||
|
||||
int rk_hw_crypto_v3_init(struct device *dev, void *hw_info);
|
||||
void rk_hw_crypto_v3_deinit(struct device *dev, void *hw_info);
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
#define CRYPTO_BC_MID_IS_VALID BIT(0)
|
||||
#define CRYPTO_HASH_MID_IS_VALID BIT(1)
|
||||
|
||||
#define CRYPTO_ECC_MAX_CURVE_WIDE 0x0404
|
||||
|
||||
#define CRYPTO_KEY_SEL 0x0610
|
||||
|
||||
#define CRYPTO_MID_VALID_SWITCH 0x0630
|
||||
|
||||
8
drivers/crypto/rockchip/rk_ecdsasignature.asn1
Normal file
8
drivers/crypto/rockchip/rk_ecdsasignature.asn1
Normal file
@@ -0,0 +1,8 @@
|
||||
-- SPDX-License-Identifier: BSD-3-Clause
|
||||
--
|
||||
-- Copyright (c) 2024 Rockchip Electronics Co., Ltd.
|
||||
|
||||
ECDSASignature ::= SEQUENCE {
|
||||
x INTEGER ({ rk_ecc_get_signature_r }),
|
||||
y INTEGER ({ rk_ecc_get_signature_s })
|
||||
}
|
||||
8
drivers/crypto/rockchip/rk_sm2signature.asn1
Normal file
8
drivers/crypto/rockchip/rk_sm2signature.asn1
Normal file
@@ -0,0 +1,8 @@
|
||||
-- SPDX-License-Identifier: BSD-3-Clause
|
||||
--
|
||||
-- Copyright (c) 2024 Rockchip Electronics Co., Ltd.
|
||||
|
||||
Sm2Signature ::= SEQUENCE {
|
||||
x INTEGER ({ rk_ecc_get_signature_r }),
|
||||
y INTEGER ({ rk_ecc_get_signature_s })
|
||||
}
|
||||
Reference in New Issue
Block a user