Files
2025-11-07 09:57:14 +08:00

846 lines
20 KiB
C

/*****************************************************************************
*
*
*Copyright (c) 2021-2029 Semidrive Incorporated. All rights reserved.
*Software License Agreement
*
******************************************************************************
*/
#include <pke.h>
#include <pke_prime.h>
#include <rsa.h>
#include <trng.h>
/* function: out = a^e mod n
* parameters:
* a -------------------------- input, uint32_t big integer a, base number,
* make sure a < n e -------------------------- input, uint32_t big integer e,
* exeponent, make sure e < n n -------------------------- input, uint32_t big
* integer n, modulus, make sure n is odd out ------------------------ output,
* out = a^e mod n eBitLen ------------------- input, real bit length of
* uint32_t big integer e nBitLen ------------------- input, real bit length of
* uint32_t big integer n return: RSA_SUCCESS(success), other(error) caution:
* 1. a, n, and out have the same word length:((nBitLen+31)>>5); and e word
* length is (eBitLen+31)>>5
*/
uint32_t RSA_ModExp(uint32_t *a, uint32_t *e, uint32_t *n, uint32_t *out,
uint32_t eBitLen, uint32_t nBitLen)
{
uint32_t eWordLen = GET_WORD_LEN(eBitLen);
uint32_t nWordLen = GET_WORD_LEN(nBitLen);
int32_t ret;
if (NULL == a || NULL == e || NULL == n || NULL == out) {
return RSA_BUFFER_NULL;
} else if (nBitLen > MAX_RSA_BIT_LEN || eBitLen > nBitLen) {
return RSA_INPUT_TOO_LONG;
} else if (!(n[0] & 1)) {
return RSA_INPUT_INVALID;
} else {
;
}
/*a should be in [0,n]*/
ret = uint32_bignumcmp(a, nWordLen, n, nWordLen);
if (ret > 0) {
return RSA_INPUT_INVALID;
} else {
;
}
/*if a is 0 or n*/
if ((0 == ret) || (1 == uint32_bignum_check_zero(a, nWordLen))) {
if (uint32_bignum_check_zero(e, eWordLen)) {
/*0^0 mod n*/
return RSA_INPUT_INVALID;
} else {
/*if a is 0, e is not 0, the output is 0*/
uint32_clear(out, nWordLen);
return RSA_SUCCESS;
}
} else if (uint32_bignum_check_zero(e, eWordLen)) {
/*a is in [1,n-1], e is 0, the output is 1*/
uint32_clear(out, nWordLen);
*out = 1;
return RSA_SUCCESS;
} else {
;
}
ret = pke_pre_calc_mont(n, nBitLen, NULL);
if (PKE_SUCCESS != ret) {
return ret;
} else {
;
}
return pke_modexp(n, e, a, out, nWordLen, eWordLen);
}
/* function: out = a^d mod n, here d represents RSA CRT private key
* (p,q,dp,dq,u) parameters: a -------------------------- input, uint32_t big
* integer a, base number, make sure a < n=pq p --------------------------
* input, uint32_t big integer p, prime number, one part of private key
* (p,q,dp,dq,u) q -------------------------- input, uint32_t big integer q,
* prime number, one part of private key (p,q,dp,dq,u) dp
* ------------------------- input, uint32_t big integer dp = e^(-1) mod (p-1),
* one part of private key (p,q,dp,dq,u) dq ------------------------- input,
* uint32_t big integer dq = e^(-1) mod (q-1), one part of private key
* (p,q,dp,dq,u) u -------------------------- input, uint32_t big integer u =
* q^(-1) mod p, one part of private key (p,q,dp,dq,u) out
* ------------------------ output, out = a^d mod n nBitLen -------------------
* input, real bit length of uint32_t big integer n=pq return:
* RSA_SUCCESS(success), other(error) caution:
* 1. a and out have the same word length:((nBitLen+31)>>5); and
* p,p_h,q,q_h,dp,dq,u have the same word length:((nBitLen/2+31)>>5)
*/
uint32_t RSA_CRTModExp(uint32_t *a, uint32_t *p, uint32_t *q, uint32_t *dp,
uint32_t *dq, uint32_t *u, uint32_t *out,
uint32_t nBitLen)
{
uint32_t buf[MAX_RSA_WORD_LEN];
uint32_t *m1 = buf;
uint32_t *m2 = buf + (MAX_RSA_WORD_LEN / 2);
uint32_t tmp_step;
uint32_t nWordLen = GET_WORD_LEN(nBitLen);
uint32_t pBitLen = nBitLen / 2;
uint32_t pWordLen = GET_WORD_LEN(pBitLen);
int32_t ret;
if (NULL == a || NULL == p || NULL == q || NULL == dp || NULL == dq ||
NULL == u || NULL == out) {
return RSA_BUFFER_NULL;
} else if (nBitLen > MAX_RSA_BIT_LEN || (nBitLen & 1)) {
return RSA_INPUT_INVALID;
} else {
;
}
/*get n = p*q*/
ret = pke_mul(p, q, buf, pWordLen);
if (PKE_SUCCESS != ret) {
return ret;
} else {
;
}
/*a should be in [0,n]*/
ret = uint32_bignumcmp(a, nWordLen, buf, nWordLen);
if (ret > 0) {
return RSA_INPUT_INVALID;
} else if ((0 == ret) || (1 == uint32_bignum_check_zero(a, nWordLen))) {
/*if a is 0 or n, the output is 0*/
uint32_clear(out, nWordLen);
return RSA_SUCCESS;
} else {
;
}
/*store the nBitLen step*/
pke_set_operand_width(pBitLen);
tmp_step = pke_get_operand_bytes();
/*do pke_pre_calc_mont() first, because a may be less than p or q, then
* pke_mod() will not*/
/*call pke_pre_calc_mont() inside, but pke_modexp() needs the output of
* pke_pre_calc_mont().*/
/*m2 = (a) mod q*/
ret = pke_pre_calc_mont(q, pBitLen, NULL);
if (PKE_SUCCESS != ret) {
return ret;
} else {
;
}
ret =
pke_mod(a, nWordLen, q, (uint32_t *)(PKE_B(0, tmp_step)), pWordLen, m2);
if (PKE_SUCCESS != ret) {
return ret;
} else {
;
}
/*m2 = (a)^dq mod q*/
ret = pke_modexp(q, dq, m2, m2, pWordLen, pWordLen);
if (PKE_SUCCESS != ret) {
return ret;
} else {
;
}
/*m1 = (a) mod p*/
ret = pke_pre_calc_mont(p, pBitLen, NULL);
if (PKE_SUCCESS != ret) {
return ret;
} else {
;
}
ret =
pke_mod(a, nWordLen, p, (uint32_t *)(PKE_B(0, tmp_step)), pWordLen, m1);
if (PKE_SUCCESS != ret) {
return ret;
} else {
;
}
/*m1 = (a)^dp mod p*/
ret = pke_modexp(p, dp, m1, m1, pWordLen, pWordLen);
if (PKE_SUCCESS != ret) {
return ret;
} else {
;
}
/*m2 = m2 mod p*/
if (uint32_bignumcmp(m2, pWordLen, p, pWordLen) > 0) {
ret = pke_sub(m2, p, m2, pWordLen);
if (PKE_SUCCESS != ret) {
return ret;
} else {
;
}
} else {
;
}
/*m1 = (m1-m2) mod p*/
ret = pke_modsub(p, m1, m2, m1, pWordLen);
if (PKE_SUCCESS != ret) {
return ret;
} else {
;
}
/*m1 = h = u*(m1-m2) mod p*/
ret = pke_modmul_internal(p, m1, u, m1, pWordLen);
if (PKE_SUCCESS != ret) {
return ret;
} else {
;
}
/*store the nBitLen step*/
pke_set_operand_width(nBitLen);
tmp_step = pke_get_operand_bytes();
/*A1 = hq*/
ret = pke_mul(m1, q, (uint32_t *)(PKE_A(1, tmp_step)), pWordLen);
if (PKE_SUCCESS != ret) {
return ret;
} else {
;
}
/*out = m2+hq*/
uint32_copy((uint32_t *)(PKE_B(1, tmp_step)), m2, pWordLen);
uint32_clear((uint32_t *)(PKE_B(1, tmp_step)) + pWordLen,
nWordLen - pWordLen);
return pke_add((uint32_t *)(PKE_A(1, tmp_step)),
(uint32_t *)(PKE_B(1, tmp_step)), out, nWordLen);
}
/* function: get big odd integer e of eBitLen
* parameters:
* e -------------------------- input, uint32_t big odd integer e
* eBitLen ------------------- input, bit length of uint32_t big odd
* integer e return: 0(success), 1(error: eBitLen<2) caution:
* 1. eBitLen must be big than 1
*/
uint32_t RSA_Get_E1(uint32_t e[], uint32_t eBitLen)
{
uint32_t eWordLen = (eBitLen + 0x1F) >> 5;
uint32_t ret;
if (eBitLen < 2) {
return RSA_INPUT_INVALID;
} else {
;
}
ret = get_rand((uint8_t *)e, eWordLen << 2);
if (TRNG_SUCCESS != ret) {
return ret;
} else {
;
}
eBitLen &= 31;
if (eBitLen) {
e[eWordLen - 1] &= (1 << (eBitLen)) - 1;
e[eWordLen - 1] |= 1 << (eBitLen - 1);
} else {
e[eWordLen - 1] |= 0x80000000;
}
/*make e odd*/
e[0] |= 0x01;
return 0;
}
/* function: get big odd integer e of eBitLen, satisfies e < fai_n of bitLen
* parameters:
* e -------------------------- input, uint32_t big odd integer e
* fai_n ---------------------- input, uint32_t big even integer fai_n
* bitLen ------------------- input, bit length of uint32_t big odd
* integer e and n return: 0(success), 1(error: bitLen<66), 2(error, n is
* 1000000000...000000) caution:
* 1. eBitLen must be big than 65
* 2. n can not be 1000000000...000000
*/
uint32_t RSA_Get_E2(uint32_t e[], uint32_t fai_n[], uint32_t bitLen)
{
uint32_t wordLen;
int32_t i;
uint8_t j;
if (bitLen < 66) {
return 1;
}
RSA_Get_E1(e, bitLen);
wordLen = (bitLen + 0x1F) >> 5;
/* namely j = eBitLen%32;*/
j = bitLen & 31;
if (j == 0) {
j = 32;
}
j--;
i = wordLen - 1;
if (j == 0) {
i--;
j = 32;
}
while (i >= 0) {
e[i] &= (~(1 << (j - 1)));
if (uint32_bignumcmp(e, i + 1, fai_n, i + 1) < 0) {
/*if e < n*/
return 0;
}
j--;
if (0 == j) {
i--;
j = 32;
}
}
return 2; /*fail, because n is 1000000000...000000*/
}
/* function: judge whether big integer a is equal to 0x5a5a5a5a5a...5a or not
* parameters:
* a -------------------------- input, uint32_t big integer a
* aBitLen -------------------- input, real bit length of a
* return: 0(a==0x5a5a5a5a5a...5a), 1(a!=0x5a5a5a5a5a...5a)
* caution:
* 1. aBitLen can not be 0
* 2. if aBitLen%32 != 0, then the highest word of a should be 0
*/
uint32_t CheckValue_0x5a5a5a5a(uint32_t a[], uint32_t aBitLen)
{
uint32_t i, wordLen = aBitLen >> 5;
if (aBitLen & 0x1F) {
if (a[wordLen] != 0) {
return 1;
} else {
;
}
} else {
;
}
for (i = 0; i < wordLen; i++) {
if (a[i] != 0x5a5a5a5a) {
return 1;
} else {
;
}
}
return 0;
}
/* function: generate RSA key (e,d,n)
* parameters:
* e -------------------------- output, uint32_t big integer, RSA public key
* e d -------------------------- output, uint32_t big integer, RSA private key
* d n -------------------------- output, uint32_t big integer, RSA public
* module n eBitLen ------------------- input, real bit length of e nBitLen
* ------------------- input, real bit length of n return: RSA_SUCCESS(success),
* other(error) caution:
* 1. nBitLen can not be even
* 2. eBitLen must be larger than 1, and less than or equal to nBitLen
*/
uint32_t RSA_GetKey(uint32_t *e, uint32_t *d, uint32_t *n, uint32_t eBitLen,
uint32_t nBitLen)
{
uint32_t buf[MAX_RSA_WORD_LEN];
uint32_t *p, *q, *in, *out;
uint32_t pBitLen, pWordLen, eWordLen, nWordLen, tmpLen;
uint32_t count, flag;
if (NULL == e || NULL == d || NULL == n) {
return RSA_BUFFER_NULL;
} else if (nBitLen & 1 || nBitLen < MIN_RSA_BIT_LEN ||
nBitLen > MAX_RSA_BIT_LEN) {
/*nBitLen can not be odd*/
return RSA_INPUT_INVALID;
} else if (eBitLen < 2 || eBitLen > nBitLen) {
return RSA_INPUT_INVALID;
} else {
;
}
p = buf;
q = buf + MAX_RSA_WORD_LEN / 2;
pke_set_operand_width(nBitLen);
tmpLen = pke_get_operand_bytes();
in = (uint32_t *)(PKE_B(1, tmpLen));
out = (uint32_t *)(PKE_A(1, tmpLen));
eWordLen = GET_WORD_LEN(eBitLen);
nWordLen = GET_WORD_LEN(nBitLen);
pBitLen = nBitLen >> 1;
pWordLen = GET_WORD_LEN(pBitLen);
GET_PQ:
flag = get_prime(p, pBitLen);
if (flag) {
return flag;
} else {
;
}
flag = get_prime(q, pBitLen);
if (flag) {
return flag;
} else {
;
}
p[0]--;
q[0]--;
/* get fai(n)=(p-1)(q-1)*/
pke_mul(p, q, n, pWordLen);
count = 0;
GET_E:
count++;
if (count == 7) {
goto GET_PQ;
} else {
;
}
switch (eBitLen) {
case 2: {
e[0] = 3;
break;
}
case 5: {
e[0] = 17;
break;
}
case 17: {
e[0] = 65537;
break;
}
default: {
if (eBitLen == nBitLen) {
flag = RSA_Get_E2(e, n, eBitLen);
if (flag) {
return flag;
} else {
;
}
} else {
flag = RSA_Get_E1(e, eBitLen);
if (flag) {
return flag;
} else {
;
}
}
break;
}
}
/*get d = e^(-1) mod n*/
flag = pke_modinv(n, e, d, nWordLen, eWordLen);
if (PKE_NO_MODINV == flag) {
/*if d doesn't exist*/
if (eBitLen == 2 || eBitLen == 5 || eBitLen == 17) {
/*if e is prime, and e divide fai(n)*/
goto GET_PQ;
} else {
/*1. e is prime, and e divide fai(n) 2.e is not prime, and*/
/*e, fai(n) have common divisor.*/
goto GET_E;
}
} else if (PKE_SUCCESS != flag) {
return flag;
} else {
;
}
/*get n = pq*/
p[0]++;
q[0]++;
flag = pke_mul(p, q, n, pWordLen);
if (PKE_SUCCESS != flag) {
return flag;
} else {
;
}
/*Encryption test*/
if (nBitLen & 0x1F) {
in[nWordLen - 1] = 0;
} else {
;
}
tmpLen = nBitLen >> 5;
uint32_set(in, 0x5a5a5a5a, tmpLen);
flag = pke_pre_calc_mont(n, nBitLen, NULL);
if (PKE_SUCCESS != flag) {
return flag;
} else {
;
}
flag = pke_modexp(n, e, in, out, nWordLen, eWordLen);
if (PKE_SUCCESS != flag) {
return flag;
} else {
;
}
flag = pke_modexp(n, d, out, out, nWordLen, nWordLen);
if (PKE_SUCCESS != flag) {
return flag;
} else {
;
}
if (CheckValue_0x5a5a5a5a(out, nBitLen)) {
goto GET_PQ;
} else {
return RSA_SUCCESS;
}
}
/* Function: generate RSA-CRT key (e,p,q,dp,dq,u,n)
* Parameters:
* e -------------------------- output, uint32_t big integer, RSA public key
* e p -------------------------- output, uint32_t big integer, RSA private key
* p q -------------------------- output, uint32_t big integer, RSA private key
* q dp-------------------------- output, uint32_t big integer, RSA private key
* dp dq-------------------------- output, uint32_t big integer, RSA private key
* dq u -------------------------- output, uint32_t big integer, RSA private key
* u = q^(-1) mod p n -------------------------- output, uint32_t big integer,
* RSA public module n eBitLen ------------------- input, real bit length of e
* nBitLen ------------------- input, real bit length of n
* Return: RSA_SUCCESS(success), other(error)
* Caution:
* 1. nBitLen can not be even
* 2. eBitLen must be larger than 1, and less than or equal to nBitLen
*/
uint32_t RSA_GetCRTKey(uint32_t *e, uint32_t *p, uint32_t *q, uint32_t *dp,
uint32_t *dq, uint32_t *u, uint32_t *n, uint32_t eBitLen,
uint32_t nBitLen)
{
uint32_t buf[MAX_RSA_WORD_LEN];
uint32_t pBitLen, pWordLen, eWordLen, nWordLen, i, wordLen;
int32_t count;
uint32_t ret;
if (NULL == e || NULL == p || NULL == q || NULL == dp || NULL == dq ||
NULL == u || NULL == n) {
return RSA_BUFFER_NULL;
} else if ((nBitLen & 1) || nBitLen < MIN_RSA_BIT_LEN ||
nBitLen > MAX_RSA_BIT_LEN) {
/*nBitLen can not be odd*/
return RSA_INPUT_INVALID;
} else if (eBitLen < 2 || eBitLen > nBitLen) {
return RSA_INPUT_INVALID;
} else {
;
}
eWordLen = GET_WORD_LEN(eBitLen);
nWordLen = GET_WORD_LEN(nBitLen);
pBitLen = nBitLen >> 1;
pWordLen = GET_WORD_LEN(pBitLen);
GET_PQ:
ret = get_prime(p, pBitLen);
if (ret) {
return ret;
} else {
;
}
ret = get_prime(q, pBitLen);
if (ret) {
return ret;
} else {
;
}
/* make p > q, for get u = q^(-1) mod p convenient*/
count = uint32_bignumcmp(p, pWordLen, q, pWordLen);
if (count == -1) {
for (i = 0; i < pWordLen; i++) {
wordLen = p[i];
p[i] = q[i];
q[i] = wordLen;
}
} else if (count == 0) {
goto GET_PQ;
} else {
;
}
p[0]--;
q[0]--;
if (eBitLen == nBitLen) {
ret = pke_mul(p, q, n, pWordLen);
if (PKE_SUCCESS != ret) {
return ret;
} else {
;
}
} else {
;
}
count = 0;
GET_E:
count++;
if (count == 7) {
goto GET_PQ;
} else {
;
}
switch (eBitLen) {
case 2: {
e[0] = 3;
break;
}
case 5: {
e[0] = 17;
break;
}
case 17: {
e[0] = 65537;
break;
}
default: {
if (eBitLen == nBitLen) {
ret = RSA_Get_E2(e, n, eBitLen);
if (ret) {
return ret;
} else {
;
}
} else {
ret = RSA_Get_E1(e, eBitLen);
if (ret) {
return ret;
} else {
;
}
}
break;
}
}
/* dp = e^(-1) mod (p-1)*/
if (uint32_bignumcmp(e, eWordLen, p, pWordLen) > 0) {
ret = pke_mod(e, eWordLen, p, NULL, pWordLen, u);
if (PKE_SUCCESS != ret) {
return ret;
} else {
;
}
wordLen = pWordLen;
} else {
uint32_copy(u, e, eWordLen);
wordLen = eWordLen;
}
ret = pke_modinv(p, u, dp, pWordLen, wordLen);
if (PKE_NO_MODINV == ret) {
if (eBitLen == 2 || eBitLen == 5 || eBitLen == 17) {
/*if e is prime, and e divide fai(n)*/
goto GET_PQ;
} else {
goto GET_E;
}
} else if (PKE_SUCCESS != ret) {
return ret;
} else {
;
}
/* dq = e^(-1) mod (q-1)*/
if (uint32_bignumcmp(e, eWordLen, q, pWordLen) > 0) {
ret = pke_mod(e, eWordLen, q, NULL, pWordLen, u);
if (PKE_SUCCESS != ret) {
return ret;
} else {
;
}
wordLen = pWordLen;
} else {
uint32_copy(u, e, eWordLen);
wordLen = eWordLen;
}
ret = pke_modinv(q, u, dq, pWordLen, wordLen);
if (PKE_NO_MODINV == ret) {
if (eBitLen == 2 || eBitLen == 5 || eBitLen == 17) {
goto GET_PQ;
} else {
goto GET_E;
}
} else if (PKE_SUCCESS != ret) {
return ret;
} else {
;
}
p[0]++;
q[0]++;
/* u = q^(-1) mod p*/
ret = pke_modinv(p, q, u, pWordLen, pWordLen);
if (PKE_NO_MODINV == ret) {
goto GET_PQ;
} else if (PKE_SUCCESS != ret) {
return ret;
} else {
;
}
/* get n*/
ret = pke_mul(p, q, n, pWordLen);
if (PKE_SUCCESS != ret) {
return ret;
} else {
;
}
/*Encryption test*/
if (nBitLen & 0x1F) {
buf[nWordLen - 1] = 0;
} else {
;
}
wordLen = nBitLen >> 5;
uint32_set(buf, 0x5a5a5a5a, wordLen);
ret = pke_pre_calc_mont(n, nBitLen, NULL);
if (PKE_SUCCESS != ret) {
return ret;
} else {
;
}
ret = pke_modexp(n, e, buf, buf, nWordLen, eWordLen);
if (PKE_SUCCESS != ret) {
return ret;
} else {
;
}
if (!CheckValue_0x5a5a5a5a(buf, nBitLen)) {
goto GET_PQ;
} else {
;
}
ret = RSA_CRTModExp(buf, p, q, dp, dq, u, buf, nBitLen);
if (PKE_SUCCESS != ret) {
return ret;
} else {
;
}
if (CheckValue_0x5a5a5a5a(buf, nBitLen)) {
goto GET_PQ;
} else {
return RSA_SUCCESS;
}
}