7cd9919a46
Signed-off-by: makejian <makejian@xiaomi.com>
403 lines
10 KiB
C
403 lines
10 KiB
C
/****************************************************************************
|
|
* 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 <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/param.h>
|
|
#include <sys/endian.h>
|
|
#include <crypto/cryptodev.h>
|
|
|
|
/****************************************************************************
|
|
* 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;
|
|
}
|