From 7cd9919a46c4c550fe400ff44584e988181375aa Mon Sep 17 00:00:00 2001 From: makejian Date: Wed, 7 Aug 2024 21:58:52 +0800 Subject: [PATCH] testing/crypto: add rsa testcase Signed-off-by: makejian --- testing/crypto/CMakeLists.txt | 14 ++ testing/crypto/Kconfig | 4 + testing/crypto/Makefile | 5 + testing/crypto/rsa.c | 402 ++++++++++++++++++++++++++++++++++ 4 files changed, 425 insertions(+) create mode 100644 testing/crypto/rsa.c diff --git a/testing/crypto/CMakeLists.txt b/testing/crypto/CMakeLists.txt index 36f07b63a..84b0f008d 100644 --- a/testing/crypto/CMakeLists.txt +++ b/testing/crypto/CMakeLists.txt @@ -159,4 +159,18 @@ if(CONFIG_TESTING_CRYPTO) dhm.c) endif() + if(CONFIG_TESTING_CRYPTO_RSA) + nuttx_add_application( + NAME + rsa + PRIORITY + ${CONFIG_TESTING_CRYPTO_PRIORITY} + STACKSIZE + ${CONFIG_TESTING_CRYPTO_STACKSIZE} + MODULE + ${CONFIG_TESTING_CRYPTO} + SRCS + rsa.c) + endif() + endif() diff --git a/testing/crypto/Kconfig b/testing/crypto/Kconfig index 9bf14ed1e..c07a557d0 100644 --- a/testing/crypto/Kconfig +++ b/testing/crypto/Kconfig @@ -46,6 +46,10 @@ config TESTING_CRYPTO_ECDH bool "ecdh crypto test" default n +config TESTING_CRYPTO_RSA + bool "rsa crypto test" + default n + config TESTING_CRYPTO_PRIORITY int "crypto test task priority" default 100 diff --git a/testing/crypto/Makefile b/testing/crypto/Makefile index 950428e83..00a1ab03e 100644 --- a/testing/crypto/Makefile +++ b/testing/crypto/Makefile @@ -71,6 +71,11 @@ PROGNAME += dhm MAINSRC += dhm.c endif +ifeq ($(CONFIG_TESTING_CRYPTO_RSA),y) +PROGNAME += rsa +MAINSRC += rsa.c +endif + PRIORITY = $(CONFIG_TESTING_CRYPTO_PRIORITY) STACKSIZE = $(CONFIG_TESTING_CRYPTO_STACKSIZE) MODULE = $(CONFIG_TESTING_CRYPTO) diff --git a/testing/crypto/rsa.c b/testing/crypto/rsa.c new file mode 100644 index 000000000..32a93866b --- /dev/null +++ b/testing/crypto/rsa.c @@ -0,0 +1,402 @@ +/**************************************************************************** + * apps/testing/crypto/rsa.c + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define MOD_LEN 128 +#define PRIVATE_KEYLEN 128 +#define PUBLIC_KEYLEN 5 +#define PLAIN_LEN 24 +#define PADDING_LEN (MOD_LEN - PLAIN_LEN) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +typedef struct rsa_data_s +{ + unsigned char e[PUBLIC_KEYLEN]; + unsigned char d[PRIVATE_KEYLEN]; + unsigned char n[MOD_LEN]; +} +rsa_data_t; + +typedef struct crypto_context_s +{ + int fd; + int cryptodev_fd; +} +crypto_context_t; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* Example RSA-1024 keypair, for test purposes */ + +static const unsigned char g_rsa_n[] = +"9292758453063D803DD603D5E777D788" +"8ED1D5BF35786190FA2F23EBC0848AEA" +"DDA92CA6C3D80B32C4D109BE0F36D6AE" +"7130B9CED7ACDF54CFC7555AC14EEBAB" +"93A89813FBF3C4F8066D2D800F7C38A8" +"1AE31942917403FF4946B0A83D3D3E05" +"EE57C6F5F5606FB5D4BC6CD34EE0801A" +"5E94BB77B07507233A0BC7BAC8F90F79"; + +static const unsigned char g_rsa_e[] = "10001"; + +static const unsigned char g_rsa_d[] = +"24BF6185468786FDD303083D25E64EFC" +"66CA472BC44D253102F8B4A9D3BFA750" +"91386C0077937FE33FA3252D28855837" +"AE1B484A8A9A45F7EE8C0C634F99E8CD" +"DF79C5CE07EE72C7F123142198164234" +"CABB724CF78B8173B9F880FC86322407" +"AF1FEDFDDE2BEB674CA15F3E81A1521E" +"071513A1E85B5DFA031F21ECAE91A34D"; + +static const unsigned char g_message[] = +"\xAA\xBB\xCC\x03\x02\x01\x00\xFF\xFF\xFF\xFF\xFF" +"\x11\x22\x33\x0A\x0B\x0C\xCC\xDD\xDD\xDD\xDD\xDD"; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static void pkcs1_v15_padding(FAR unsigned char *padding, + size_t pad_len) +{ + int i; + + /* this padding is only for rsa sign */ + + *padding++ = 0; + *padding++ = 0x02; + for (i = 0; i < pad_len - 3; i++) + { + *padding++ = rand() % 256; + } + + *padding++ = 0; +} + +static void rsa_be32toh(FAR uint8_t *dst, size_t len, FAR const uint8_t *src) +{ + int i; + size_t rlen = len / 4; + uint32_t *dst32 = (uint32_t *)dst; + uint32_t *src32 = (uint32_t *)src; + + for (i = 0; i < rlen; i++) + { + dst32[i] = be32toh(src32[rlen - i - 1]); + } +} + +static void mpi_get_digit(FAR uint8_t *d, char c) +{ + if (c >= '0' && c <= '9') + { + *d = c - '0'; + } + + if (c >= 'A' && c <= 'F') + { + *d = c - 'A' + 10; + } + + if (c >= 'a' && c <= 'f') + { + *d = c - 'a' + 10; + } +} + +static void mpi_from_string(FAR unsigned char *buf, + FAR const unsigned char *s, + size_t slen) +{ + int i; + int j; + uint8_t d = 0; + + for (i = slen, j = 0; i > 0; i--, j++) + { + mpi_get_digit(&d, s[i - 1]); + buf[j / 2] |= d << ((j % 2) << 2); + } +} + +static int rsa_data_init(FAR rsa_data_t *data, + FAR const unsigned char *e, size_t elen, + FAR const unsigned char *d, size_t dlen, + FAR const unsigned char *n, size_t nlen) +{ + memset(data, 0, sizeof(rsa_data_t)); + mpi_from_string(data->e, e, elen); + mpi_from_string(data->d, d, dlen); + mpi_from_string(data->n, n, nlen); + return 0; +} + +static void cryptodev_free(FAR crypto_context_t *ctx) +{ + if (ctx->cryptodev_fd != 0) + { + close(ctx->cryptodev_fd); + ctx->cryptodev_fd = 0; + } + + if (ctx->fd != 0) + { + close(ctx->fd); + ctx->fd = 0; + } +} + +static int cryptodev_init(FAR crypto_context_t *ctx) +{ + memset(ctx, 0, sizeof(crypto_context_t)); + if ((ctx->fd = open("/dev/crypto", O_RDWR, 0)) < 0) + { + perror("CRIOGET"); + cryptodev_free(ctx); + return 1; + } + + if (ioctl(ctx->fd, CRIOGET, &ctx->cryptodev_fd) == -1) + { + perror("CRIOGET"); + cryptodev_free(ctx); + return 1; + } + + return 0; +} + +static int cryptodev_rsa_calc(FAR crypto_context_t *ctx, + FAR rsa_data_t *data, + FAR const unsigned char *input, size_t ilen, + FAR const unsigned char *output, size_t olen, + bool is_priv) +{ + struct crypt_kop cryptk; + + memset(&cryptk, 0, sizeof(struct crypt_kop)); + cryptk.crk_op = CRK_MOD_EXP; + cryptk.crk_iparams = 3; + cryptk.crk_oparams = 1; + cryptk.crk_param[0].crp_p = (caddr_t)input; + cryptk.crk_param[0].crp_nbits = ilen * 8; + if (is_priv) + { + cryptk.crk_param[1].crp_p = (caddr_t)data->d; + cryptk.crk_param[1].crp_nbits = sizeof(data->d) * 8; + } + else + { + cryptk.crk_param[1].crp_p = (caddr_t)data->e; + cryptk.crk_param[1].crp_nbits = sizeof(data->e) * 8; + } + + cryptk.crk_param[2].crp_p = (caddr_t)data->n; + cryptk.crk_param[2].crp_nbits = sizeof(data->n) * 8; + cryptk.crk_param[3].crp_p = (caddr_t)output; + cryptk.crk_param[3].crp_nbits = olen * 8; + + if (ioctl(ctx->cryptodev_fd, CIOCKEY, &cryptk) == -1) + { + perror("rsa calculate failed"); + return -1; + } + + return cryptk.crk_status; +} + +static int cryptodev_rsa_verify( + FAR crypto_context_t *ctx, FAR rsa_data_t *data, + FAR const unsigned char *sig, size_t sig_len, + FAR const unsigned char *hash, size_t hash_len, + FAR const unsigned char *padding, size_t pad_len) +{ + struct crypt_kop cryptk; + + memset(&cryptk, 0, sizeof(struct crypt_kop)); + cryptk.crk_op = CRK_RSA_PKCS15_VERIFY; + cryptk.crk_iparams = 5; + cryptk.crk_oparams = 0; + + cryptk.crk_param[0].crp_p = (caddr_t)data->e; + cryptk.crk_param[0].crp_nbits = sizeof(data->e) * 8; + cryptk.crk_param[1].crp_p = (caddr_t)data->n; + cryptk.crk_param[1].crp_nbits = sizeof(data->n) * 8; + cryptk.crk_param[2].crp_p = (caddr_t)sig; + cryptk.crk_param[2].crp_nbits = sig_len * 8; + cryptk.crk_param[3].crp_p = (caddr_t)hash; + cryptk.crk_param[3].crp_nbits = hash_len * 8; + cryptk.crk_param[4].crp_p = (caddr_t)padding; + cryptk.crk_param[4].crp_nbits = pad_len * 8; + + if (ioctl(ctx->cryptodev_fd, CIOCKEY, &cryptk) == -1) + { + perror("CIOCKEY"); + return -1; + } + + return cryptk.crk_status; +} + +static int rsa_test(void) +{ + crypto_context_t ctx; + rsa_data_t rsa_data; + unsigned char cipher[MOD_LEN]; + unsigned char plain[PLAIN_LEN]; + unsigned char data[MOD_LEN]; + unsigned char padding[PADDING_LEN]; + unsigned char sig[MOD_LEN]; + unsigned char data_he[MOD_LEN]; + unsigned char pad_he[PADDING_LEN]; + unsigned char hash_he[MOD_LEN]; + int ret = 0; + + ret = cryptodev_init(&ctx); + if (ret != 0) + { + goto free; + } + + ret = rsa_data_init(&rsa_data, g_rsa_e, sizeof(g_rsa_e) - 1, + g_rsa_d, sizeof(g_rsa_d) - 1, + g_rsa_n, sizeof(g_rsa_n) - 1); + if (ret != 0) + { + goto free; + } + + /* test 1: encrypt with private key and decrypt with public key */ + + memset(cipher, 0, MOD_LEN); + memset(plain, 0, PLAIN_LEN); + + /* encrypt with private key: g_message ^ ctx.data.d % n = cipher */ + + ret = cryptodev_rsa_calc(&ctx, &rsa_data, g_message, PLAIN_LEN, + cipher, MOD_LEN, TRUE); + if (ret != 0) + { + printf("rsa encrypt with private key failed\n"); + goto free; + } + + /* dencrypt with public key: cipher ^ ctx.data.e % n = plain */ + + ret = cryptodev_rsa_calc(&ctx, &rsa_data, cipher, MOD_LEN, plain, + PLAIN_LEN, FALSE); + if (ret != 0) + { + printf("rsa decrypt with pulic key failed\n"); + goto free; + } + + ret = memcmp(g_message, plain, PLAIN_LEN); + if (ret != 0) + { + printf("rsa test case 1 failed\n"); + goto free; + } + else + { + printf("rsa test case 1 success\n"); + } + + /* test 2: rsa sign and verify */ + + memset(data, 0, MOD_LEN); + memset(padding, 0, PADDING_LEN); + memset(sig, 0, MOD_LEN); + + /* pkcs15 v1 padding for sign: 0x00 0x02 (... random) 0x00 */ + + pkcs1_v15_padding(padding, PADDING_LEN); + memcpy(data, padding, PADDING_LEN); + memcpy(data + PADDING_LEN, g_message, PLAIN_LEN); + + rsa_be32toh(data_he, MOD_LEN, data); + rsa_be32toh(pad_he, PADDING_LEN, padding); + rsa_be32toh(hash_he, PLAIN_LEN, g_message); + + /* sign with private key: (hash + padding) ^ d % n = sig */ + + ret = cryptodev_rsa_calc(&ctx, &rsa_data, data_he, MOD_LEN, sig, + MOD_LEN, TRUE); + if (ret != 0) + { + printf("rsa sign failed\n"); + goto free; + } + + /* verify with public key: sig ^ e % n = (hash + padding) */ + + ret = cryptodev_rsa_verify(&ctx, &rsa_data, sig, MOD_LEN, hash_he, + PLAIN_LEN, pad_he, PADDING_LEN); + if (ret != 0) + { + printf("rsa verify failed\n"); + } + else + { + printf("rsa test case 2 success\n"); + } + +free: + cryptodev_free(&ctx); + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int main(void) +{ + if (rsa_test() == 0) + { + printf("rsa test success\n"); + } + else + { + printf("rsa test failed\n"); + } + + return 0; +}