465 lines
13 KiB
C
465 lines
13 KiB
C
/*****************************************************************************
|
|
*
|
|
*
|
|
*Copyright (c) 2021-2029 Semidrive Incorporated. All rights reserved.
|
|
*Software License Agreement
|
|
*
|
|
******************************************************************************
|
|
*/
|
|
#include <ecdsa.h>
|
|
#include <pke.h>
|
|
#include <sdrv_crypto_utility.h>
|
|
#include <trng.h>
|
|
|
|
/* function: Generate ECDSA Signature in U32 little-endian big integer style
|
|
* parameters:
|
|
* curve ---------------------- input, ecc curve struct pointer, please make
|
|
* sure it is valid e -------------------------- input, derived from hash value
|
|
* k -------------------------- input, internal random integer k
|
|
* dA ------------------------- input, private key
|
|
* r -------------------------- output, signature r
|
|
* s -------------------------- output, signature s
|
|
* return:
|
|
* ECDSA_SUCCESS(success); other(error)
|
|
* caution:
|
|
* 1. please make sure e is in [0,n-1], dA is in [1,n-1]
|
|
*/
|
|
uint32_t ecdsa_sign_uint32(eccp_curve_t *curve, uint32_t *e, uint32_t *k,
|
|
uint32_t *dA, uint32_t *r, uint32_t *s)
|
|
{
|
|
uint32_t nWordLen;
|
|
uint32_t pWordLen;
|
|
uint32_t tmp1[ECCP_MAX_WORD_LEN];
|
|
uint32_t ret;
|
|
|
|
if (NULL == curve || NULL == e || NULL == k || NULL == dA || NULL == r ||
|
|
NULL == s) {
|
|
return ECDSA_POINTOR_NULL;
|
|
} else if (curve->eccp_p_bitLen > ECCP_MAX_BIT_LEN) {
|
|
return ECDSA_INVALID_INPUT;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
nWordLen = GET_WORD_LEN(curve->eccp_n_bitLen);
|
|
pWordLen = GET_WORD_LEN(curve->eccp_p_bitLen);
|
|
|
|
/*make sure k in [1, n-1]*/
|
|
if (uint32_bignum_check_zero(k, nWordLen)) {
|
|
return ECDSA_ZERO_ALL;
|
|
} else if (uint32_bignumcmp(k, nWordLen, curve->eccp_n, nWordLen) >= 0) {
|
|
return ECDSA_INTEGER_TOO_BIG;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
/*get x1*/
|
|
if (curve->eccp_half_Gx && curve->eccp_half_Gy) {
|
|
ret = eccp_pointMul_base(curve, k, tmp1, NULL);
|
|
} else {
|
|
/*y coordinate is not needed*/
|
|
ret =
|
|
eccp_pointMul(curve, k, curve->eccp_Gx, curve->eccp_Gy, tmp1, NULL);
|
|
}
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
/*r = x1 mod n*/
|
|
ret = pke_mod(tmp1, pWordLen, curve->eccp_n, curve->eccp_n_h, nWordLen, r);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else if (uint32_bignum_check_zero(r, nWordLen)) {
|
|
/*make sure r is not zero*/
|
|
return ECDSA_ZERO_ALL;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
/*tmp1 = r*dA mod n*/
|
|
if (NULL == curve->eccp_n_h) {
|
|
ret = pke_modmul(curve->eccp_n, r, dA, tmp1, nWordLen);
|
|
} else {
|
|
pke_load_pre_calc_mont(curve->eccp_n_h, nWordLen);
|
|
ret = pke_modmul_internal(curve->eccp_n, r, dA, tmp1, nWordLen);
|
|
}
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
/*tmp1 = e + r*dA mod n*/
|
|
ret = pke_modadd(curve->eccp_n, e, tmp1, tmp1, nWordLen);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
/*s = k^(-1) mod n*/
|
|
ret = pke_modinv(curve->eccp_n, k, s, nWordLen, nWordLen);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
/*s = (k^(-1))*(e + r*dA) mod n*/
|
|
ret = pke_modmul_internal(curve->eccp_n, s, tmp1, s, nWordLen);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
/*make sure s is not zero*/
|
|
if (uint32_bignum_check_zero(s, nWordLen)) {
|
|
return ECDSA_ZERO_ALL;
|
|
} else {
|
|
return ECDSA_SUCCESS;
|
|
}
|
|
}
|
|
|
|
/* function: Generate ECDSA Signature in byte string style
|
|
* parameters:
|
|
* curve ---------------------- input, ecc curve struct pointer, please make
|
|
* sure it is valid E -------------------------- input, hash value, big-endian
|
|
* EByteLen ------------------- input, byte length of E
|
|
* rand_k --------------------- input, random big integer k in signing,
|
|
* big-endian priKey --------------------- input, private key, big-endian
|
|
* signature ------------------ output, signature r and s, big-endian
|
|
* return:
|
|
* ECDSA_SUCCESS(success); other(error)
|
|
* caution:
|
|
* 1. the method of getting big integer e from hash value E is based on SEC1
|
|
* V2.
|
|
*/
|
|
uint32_t ecdsa_sign(eccp_curve_t *curve, uint8_t *E, uint32_t EByteLen,
|
|
uint8_t *rand_k, uint8_t *priKey, uint8_t *signature)
|
|
{
|
|
uint32_t tmpLen;
|
|
uint32_t nByteLen;
|
|
uint32_t nWordLen;
|
|
uint32_t e[ECCP_MAX_WORD_LEN], k[ECCP_MAX_WORD_LEN], dA[ECCP_MAX_WORD_LEN];
|
|
uint32_t r[ECCP_MAX_WORD_LEN], s[ECCP_MAX_WORD_LEN];
|
|
uint32_t ret;
|
|
|
|
if (NULL == curve || NULL == priKey || NULL == signature) {
|
|
return ECDSA_POINTOR_NULL;
|
|
} else if (curve->eccp_p_bitLen > ECCP_MAX_BIT_LEN) {
|
|
return ECDSA_INVALID_INPUT;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
/*E could be zero*/
|
|
if (NULL == E) {
|
|
EByteLen = 0;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
nByteLen = GET_BYTE_LEN(curve->eccp_n_bitLen);
|
|
nWordLen = GET_WORD_LEN(curve->eccp_n_bitLen);
|
|
|
|
/*get integer e from hash value E(according to SEC1-V2 2009)*/
|
|
uint32_clear(e, nWordLen);
|
|
if (NULL != E) {
|
|
if (curve->eccp_n_bitLen >= (EByteLen << 3)) {
|
|
/*in this case, make E as e directly*/
|
|
reverse_byte_array((uint8_t *)E, (uint8_t *)e, EByteLen);
|
|
} else {
|
|
/*in this case, make left eccp_n_bitLen bits of E as e*/
|
|
reverse_byte_array((uint8_t *)E, (uint8_t *)e, nByteLen);
|
|
tmpLen = (curve->eccp_n_bitLen) & 7;
|
|
|
|
if (tmpLen) {
|
|
big_div2n(e, nWordLen, 8 - tmpLen);
|
|
} else {
|
|
;
|
|
}
|
|
}
|
|
}
|
|
/*get e = e mod n, i.e., make sure e in [0, n-1]*/
|
|
if (uint32_bignumcmp(e, nWordLen, curve->eccp_n, nWordLen) >= 0) {
|
|
ret = pke_sub(e, curve->eccp_n, e, nWordLen);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
} else {
|
|
;
|
|
}
|
|
|
|
/*make sure priKey in [1, n-1]*/
|
|
memset_(((uint8_t *)dA) + nByteLen, 0, (nWordLen << 2) - nByteLen);
|
|
reverse_byte_array((uint8_t *)priKey, (uint8_t *)dA, nByteLen);
|
|
|
|
if (uint32_bignum_check_zero(dA, nWordLen)) {
|
|
return ECDSA_ZERO_ALL;
|
|
} else if (uint32_bignumcmp(dA, nWordLen, curve->eccp_n, nWordLen) >= 0) {
|
|
return ECDSA_INTEGER_TOO_BIG;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
/*get k*/
|
|
memset_(((uint8_t *)k) + nByteLen, 0, (nWordLen << 2) - nByteLen);
|
|
|
|
if (rand_k) {
|
|
reverse_byte_array(rand_k, (uint8_t *)k, nByteLen);
|
|
} else {
|
|
ECDSA_SIGN_LOOP:
|
|
|
|
ret = get_rand((uint8_t *)k, nByteLen);
|
|
|
|
if (TRNG_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
/*make sure k has the same bit length as n*/
|
|
tmpLen = (curve->eccp_n_bitLen) & 0x1F;
|
|
|
|
if (tmpLen) {
|
|
k[nWordLen - 1] &= (1 << (tmpLen)) - 1;
|
|
} else {
|
|
;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*sign*/
|
|
ret = ecdsa_sign_uint32(curve, e, k, dA, r, s);
|
|
|
|
if ((ECDSA_ZERO_ALL == ret || ECDSA_INTEGER_TOO_BIG == ret) &&
|
|
(NULL == rand_k)) {
|
|
goto ECDSA_SIGN_LOOP;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
if (ECDSA_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
reverse_byte_array((uint8_t *)r, signature, nByteLen);
|
|
reverse_byte_array((uint8_t *)s, signature + nByteLen, nByteLen);
|
|
|
|
return ECDSA_SUCCESS;
|
|
}
|
|
}
|
|
|
|
/* function: Verify ECDSA Signature in byte string style
|
|
* parameters:
|
|
* curve ---------------------- input, ecc curve struct pointer, please make
|
|
* sure it is valid E -------------------------- input, hash value, big-endian
|
|
* EByteLen ------------------- input, byte length of E
|
|
* pubKey --------------------- input, public key, big-endian
|
|
* signature ------------------ input, signature r and s, big-endian
|
|
* return:
|
|
* ECDSA_SUCCESS(success); other(error)
|
|
* caution:
|
|
* 1. the method of getting big integer e from hash value E is based on SEC1
|
|
* V2.
|
|
*/
|
|
uint32_t ecdsa_verify(eccp_curve_t *curve, uint8_t *E, uint32_t EByteLen,
|
|
uint8_t *pubKey, uint8_t *signature)
|
|
{
|
|
uint32_t tmpLen;
|
|
uint32_t nByteLen;
|
|
uint32_t nWordLen;
|
|
uint32_t pByteLen;
|
|
uint32_t pWordLen;
|
|
uint32_t maxWordLen;
|
|
uint32_t e[ECCP_MAX_WORD_LEN], r[ECCP_MAX_WORD_LEN], s[ECCP_MAX_WORD_LEN];
|
|
uint32_t tmp[ECCP_MAX_WORD_LEN], x[ECCP_MAX_WORD_LEN];
|
|
uint32_t ret;
|
|
|
|
if (NULL == curve || NULL == pubKey || NULL == signature) {
|
|
return ECDSA_POINTOR_NULL;
|
|
} else if (curve->eccp_p_bitLen > ECCP_MAX_BIT_LEN) {
|
|
return ECDSA_INVALID_INPUT;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
/*E could be zero*/
|
|
if (NULL == E) {
|
|
EByteLen = 0;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
nByteLen = GET_BYTE_LEN(curve->eccp_n_bitLen);
|
|
nWordLen = GET_WORD_LEN(curve->eccp_n_bitLen);
|
|
pByteLen = GET_BYTE_LEN(curve->eccp_p_bitLen);
|
|
pWordLen = GET_WORD_LEN(curve->eccp_p_bitLen);
|
|
maxWordLen = GET_MAX_LEN(nWordLen, pWordLen);
|
|
|
|
/*make sure r in [1, n-1]*/
|
|
memset_(((uint8_t *)r) + nByteLen, 0, (nWordLen << 2) - nByteLen);
|
|
reverse_byte_array(signature, (uint8_t *)r, nByteLen);
|
|
|
|
if (uint32_bignum_check_zero(r, nWordLen)) {
|
|
return ECDSA_ZERO_ALL;
|
|
} else if (uint32_bignumcmp(r, nWordLen, curve->eccp_n, nWordLen) >= 0) {
|
|
return ECDSA_INTEGER_TOO_BIG;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
/*make sure s in [1, n-1]*/
|
|
memset_(((uint8_t *)s) + nByteLen, 0, (nWordLen << 2) - nByteLen);
|
|
reverse_byte_array(signature + nByteLen, (uint8_t *)s, nByteLen);
|
|
|
|
if (uint32_bignum_check_zero(s, nWordLen)) {
|
|
return ECDSA_ZERO_ALL;
|
|
} else if (uint32_bignumcmp(s, nWordLen, curve->eccp_n, nWordLen) >= 0) {
|
|
return ECDSA_INTEGER_TOO_BIG;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
/*tmp = s^(-1) mod n*/
|
|
ret = pke_modinv(curve->eccp_n, s, tmp, nWordLen, nWordLen);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
/*get integer e from hash value E(according to SEC1-V2 2009)*/
|
|
uint32_clear(e, nWordLen);
|
|
|
|
if (NULL != E) {
|
|
if (curve->eccp_n_bitLen >= (EByteLen << 3)) {
|
|
/*in this case, make E as e directly*/
|
|
reverse_byte_array((uint8_t *)E, (uint8_t *)e, EByteLen);
|
|
} else {
|
|
/*in this case, make left eccp_n_bitLen bits of E as e*/
|
|
memcpy_(e, E, nByteLen);
|
|
reverse_byte_array((uint8_t *)E, (uint8_t *)e, nByteLen);
|
|
tmpLen = (curve->eccp_n_bitLen) & 7;
|
|
|
|
if (tmpLen) {
|
|
big_div2n(e, nWordLen, 8 - tmpLen);
|
|
} else {
|
|
;
|
|
}
|
|
}
|
|
}
|
|
/*get e = e mod n, i.e., make sure e in [0, n-1]*/
|
|
if (uint32_bignumcmp(e, nWordLen, curve->eccp_n, nWordLen) >= 0) {
|
|
ret = pke_sub(e, curve->eccp_n, e, nWordLen);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
} else {
|
|
;
|
|
}
|
|
|
|
/*x = e*(s^(-1)) mod n*/
|
|
if (NULL == curve->eccp_n_h) {
|
|
ret = pke_modmul(curve->eccp_n, e, tmp, x, nWordLen);
|
|
} else {
|
|
pke_load_pre_calc_mont(curve->eccp_n_h, nWordLen);
|
|
ret = pke_modmul_internal(curve->eccp_n, e, tmp, x, nWordLen);
|
|
}
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
/*tmp = r*(s^(-1)) mod n*/
|
|
ret = pke_modmul_internal(curve->eccp_n, r, tmp, tmp, nWordLen);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
/*check public key*/
|
|
memset_(e, 0, (maxWordLen << 2) - pByteLen);
|
|
memset_(s, 0, (maxWordLen << 2) - pByteLen);
|
|
reverse_byte_array(pubKey, (uint8_t *)e, pByteLen);
|
|
reverse_byte_array(pubKey + pByteLen, (uint8_t *)s, pByteLen);
|
|
ret = eccp_pointVerify(curve, e, s);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
if (curve->eccp_half_Gx && curve->eccp_half_Gy) {
|
|
ret = eccp_pointMul_Shamir(curve, tmp, e, s, x, curve->eccp_Gx,
|
|
curve->eccp_Gy, e, s);
|
|
} else {
|
|
ret = ~(PKE_SUCCESS);
|
|
}
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
ret = eccp_pointMul(curve, tmp, e, s, e, s);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
if (!uint32_bignum_check_zero(x, nWordLen)) {
|
|
ret =
|
|
eccp_pointMul(curve, x, curve->eccp_Gx, curve->eccp_Gy, x, tmp);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
ret = eccp_pointAdd(curve, e, s, x, tmp, e, s);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
} else {
|
|
;
|
|
}
|
|
} else {
|
|
;
|
|
}
|
|
|
|
/*x = x1 mod n*/
|
|
ret = pke_mod(e, pWordLen, curve->eccp_n, curve->eccp_n_h, nWordLen, tmp);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
if (uint32_bignumcmp(tmp, nWordLen, r, nWordLen)) {
|
|
return ECDSA_VERIFY_FAILED;
|
|
} else {
|
|
return ECDSA_SUCCESS;
|
|
}
|
|
}
|