blob: b0f300ad3edc6abed993e4b71924747a18a84610 [file] [log] [blame]
/********************************************************************************************************
* @file app_ecdsa.c
*
* @brief This is the source file for TLSR8278
*
* @author Driver Group
* @date May 8, 2018
*
* @par Copyright (c) 2018, Telink Semiconductor (Shanghai) Co., Ltd.
* All rights reserved.
*
* The information contained herein is confidential property of Telink
* Semiconductor (Shanghai) Co., Ltd. and is available under the terms
* of Commercial License Agreement between Telink Semiconductor (Shanghai)
* Co., Ltd. and the licensee or the terms described here-in. This heading
* MUST NOT be removed from this file.
*
* Licensees are granted free, non-transferable use of the information in this
* file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
* @par History:
* 1.initial release(DEC. 26 2018)
*
* @version A001
*
*******************************************************************************************************/
#include "tl_common.h"
#include "drivers.h"
#include "app_ecdsa.h"
#include "./pke_common/app_pke.h"
#if (PKE_TEST_MODE == PKE_ECDSA)
unsigned int secp256r1_p[8] = {0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0x00000000,0x00000000,0x00000000,0x00000001,0xFFFFFFFF};
unsigned int secp256r1_p_h[8] = {0x00000003,0x00000000,0xFFFFFFFF,0xFFFFFFFB,0xFFFFFFFE,0xFFFFFFFF,0xFFFFFFFD,0x00000004};
unsigned int secp256r1_p_n1[1] = {1};
unsigned int secp256r1_a[8] = {0xFFFFFFFC,0xFFFFFFFF,0xFFFFFFFF,0x00000000,0x00000000,0x00000000,0x00000001,0xFFFFFFFF};
unsigned int secp256r1_b[8] = {0x27D2604B,0x3BCE3C3E,0xCC53B0F6,0x651D06B0,0x769886BC,0xB3EBBD55,0xAA3A93E7,0x5AC635D8};
unsigned int secp256r1_Gx[8] = {0xD898C296,0xF4A13945,0x2DEB33A0,0x77037D81,0x63A440F2,0xF8BCE6E5,0xE12C4247,0x6B17D1F2};
unsigned int secp256r1_Gy[8] = {0x37BF51F5,0xCBB64068,0x6B315ECE,0x2BCE3357,0x7C0F9E16,0x8EE7EB4A,0xFE1A7F9B,0x4FE342E2};
unsigned int secp256r1_n[8] = {0xFC632551,0xF3B9CAC2,0xA7179E84,0xBCE6FAAD,0xFFFFFFFF,0xFFFFFFFF,0x00000000,0xFFFFFFFF};
unsigned int secp256r1_n_h[8] = {0xBE79EEA2,0x83244C95,0x49BD6FA6,0x4699799C,0x2B6BEC59,0x2845B239,0xF3D95620,0x66E12D94};
unsigned int secp256r1_n_n1[1] = {0xEE00BC4F};
eccp_curve_t secp256r1[1]={
{ 256,
256,
secp256r1_p,
secp256r1_p_h,
secp256r1_p_n1,
secp256r1_a,
secp256r1_b,
secp256r1_Gx,
secp256r1_Gy,
secp256r1_n,
secp256r1_n_h,
secp256r1_n_n1,}
};
/**
* @brief Generate ECDSA Signature in U32 little-endian big integer style
* @param[in] curve - ecc curve struct pointer, please make sure it is valid
* @param[in] e - derived from hash value
* @param[in] k - internal random integer k
* @param[in] dA - private key
* @param[out] r - signature r
* @param[out] s - signature s
* @return ECDSA_SUCCESS(success); other(error)
*/
unsigned char ecdsa_sign4(eccp_curve_t *curve, unsigned int *e, unsigned int *k, unsigned int *dA, unsigned int *r, unsigned int *s)
{
unsigned char ret;
unsigned int nWordLen = GET_WORD_LEN(curve->eccp_n_bitLen);
unsigned int pWordLen = GET_WORD_LEN(curve->eccp_p_bitLen);
unsigned int tmp1[ECC_MAX_WORD_LEN];
if(0 == curve || 0 == e || 0 == k || 0 == dA || 0 == r || 0 == s)
{
return ECDSA_POINTOR_NULL;
}
if(curve->eccp_p_bitLen > ECC_MAX_BIT_LEN)
{
return ECDSA_INVALID_INPUT;
}
//make sure k in [1, n-1]
if(ismemzero4(k, nWordLen<<2))
{
return ECDSA_ZERO;
}
if(big_integer_compare(k, nWordLen, curve->eccp_n, nWordLen) >= 0)
{
return ECDSA_LARGE_INTEGER;
}
//get x1
ret = pke_eccp_point_mul(curve, k, curve->eccp_Gx, curve->eccp_Gy, tmp1, 0); //y coordinate is not needed
if(PKE_SUCCESS != ret)
{
return ret;
}
//r = x1 mod n
ret = pke_mod(tmp1, pWordLen, curve->eccp_n, curve->eccp_n_h, curve->eccp_n_n1, nWordLen, r);
if(PKE_SUCCESS != ret)
{
return ret;
}
//make sure r is not zero
if(ismemzero4(r, nWordLen<<2))
{
return ECDSA_ZERO;
}
//tmp1 = r*dA mod n
if(curve->eccp_n_h && curve->eccp_n_n1)
{
pke_load_pre_calc_mont(curve->eccp_n_h, curve->eccp_n_n1, nWordLen);
ret = pke_mod_mul(curve->eccp_n, r, dA, tmp1, nWordLen);
}
if(PKE_SUCCESS != ret)
{
return ret;
}
//tmp1 = e + r*dA mod n
ret = pke_mod_add(curve->eccp_n, e, tmp1, tmp1, nWordLen);
if(PKE_SUCCESS != ret)
{
return ret;
}
//s = k^(-1) mod n
ret = pke_mod_inv(curve->eccp_n, k, s, nWordLen, nWordLen);
if(PKE_SUCCESS != ret)
{
return ret;
}
//s = (k^(-1))*(e + r*dA) mod n
ret = pke_mod_mul(curve->eccp_n, s, tmp1, s, nWordLen);
if(PKE_SUCCESS != ret)
{
return ret;
}
//make sure s is not zero
if(ismemzero4(s, nWordLen<<2))
{
return ECDSA_ZERO;
}
return ECDSA_SUCCESS;
}
/**
* @brief Generate ECDSA Signature in octet string style
* @param[in] curve - ecc curve struct pointer, please make sure it is valid
* @param[in] E - hash value, big-endian
* @param[in] EByteLen - byte length of E
* @param[in] priKey - private key, big-endian
* @param[out] signature - signature r and s, big-endian
* @return ECDSA_SUCCESS(success); other(error)
*/
unsigned char ecdsa_sign(eccp_curve_t *curve, unsigned char *E, unsigned int EByteLen, unsigned char *rand_k, unsigned char *priKey,
unsigned char *signature)
{
unsigned int tmpLen;
unsigned int nByteLen = GET_BYTE_LEN(curve->eccp_n_bitLen);
unsigned int nWordLen = GET_WORD_LEN(curve->eccp_n_bitLen);
unsigned int e[ECC_MAX_WORD_LEN], k[ECC_MAX_WORD_LEN], dA[ECC_MAX_WORD_LEN];
unsigned int r[ECC_MAX_WORD_LEN], s[ECC_MAX_WORD_LEN];
unsigned char ret;
if(0 == curve || 0 == E || 0 == priKey || 0 == signature)
{
return ECDSA_POINTOR_NULL;
}
if(0 == EByteLen)
{
return ECDSA_INVALID_INPUT;
}
if(curve->eccp_p_bitLen > ECC_MAX_BIT_LEN)
{
return ECDSA_INVALID_INPUT;
}
//get integer e from hash value E(according to SEC1-V2 2009)
memset(e, 0, nWordLen<<2);
if(curve->eccp_n_bitLen >= (EByteLen<<3)) //in this case, make E as e directly
{
memcpy((unsigned char *)e, (unsigned char *)E, EByteLen);
}
else //in this case, make left eccp_n_bitLen bits of E as e
{
memcpy((unsigned char *)e, (unsigned char *)E, nByteLen);
tmpLen = (curve->eccp_n_bitLen)&7;
if(tmpLen)
{
div2n_u32(e, nWordLen, 8-tmpLen);
}
}
//get e = e mod n, i.e., make sure e in [0, n-1]
if(big_integer_compare(e, nWordLen, curve->eccp_n, nWordLen) >= 0)
{
sub_u32(e, curve->eccp_n, k, nWordLen);
memcpy(e, k, nWordLen<<2);
}
//make sure priKey in [1, n-1]
memset(dA, 0, (nWordLen<<2)-nByteLen);
memcpy((unsigned char *)dA, (unsigned char *)priKey, nByteLen);
if(ismemzero4(dA, nWordLen<<2))
{
return ECDSA_ZERO;
}
if(big_integer_compare(dA, nWordLen, curve->eccp_n, nWordLen) >= 0)
{
return ECDSA_LARGE_INTEGER;
}
//get k
memset(k, 0, (nWordLen<<2)-nByteLen);
if(rand_k)
{
memcpy((unsigned char *)k, rand_k, nByteLen);
}
else
{
ECDSA_SIGN_LOOP:
ret = rand_get((unsigned char *)k, nByteLen);
if(TRNG_SUCCESS != ret)
{
return ret;
}
//make sure k has the same bit length as n
tmpLen = (curve->eccp_n_bitLen)&0x1F;
if(tmpLen)
{
k[nWordLen-1] &= (1<<(tmpLen))-1;
}
}
//sign
ret = ecdsa_sign4(curve, e, k, dA, r, s);
if(ECDSA_ZERO == ret || ECDSA_LARGE_INTEGER == ret)
{
if(rand_k)
{
return ret;
}
else
{
goto ECDSA_SIGN_LOOP;
}
}
else if(ECDSA_SUCCESS != ret)
{
return ret;
}
memcpy(signature, (unsigned char *)r, nByteLen);
memcpy(signature+nByteLen, (unsigned char *)s, nByteLen);
return ECDSA_SUCCESS;
}
/**
* @brief Verify ECDSA Signature in octet string style
* @param[in] curve - ecc curve struct pointer, please make sure it is valid
* @param[in] E - hash value, big-endian
* @param[in] EByteLen - byte length of E
* @param[in] pubKey - public key, big-endian
* @param[in] signature - signature r and s, big-endian
* @return ECDSA_SUCCESS(success); other(error)
*/
u8 B_proc = 0;
unsigned char ecdsa_verify(eccp_curve_t *curve, unsigned char *E, unsigned int EByteLen, unsigned char *pubKey, unsigned char *signature)
{
unsigned int tmpLen;
unsigned int nByteLen = GET_BYTE_LEN(curve->eccp_n_bitLen);
unsigned int nWordLen = GET_WORD_LEN(curve->eccp_n_bitLen);
unsigned int pByteLen = GET_BYTE_LEN(curve->eccp_p_bitLen);
unsigned int pWordLen = GET_WORD_LEN(curve->eccp_p_bitLen);
unsigned int maxWordLen = GET_MAX_LEN(nWordLen,pWordLen);
unsigned int e[ECC_MAX_WORD_LEN], r[ECC_MAX_WORD_LEN], s[ECC_MAX_WORD_LEN];
unsigned int tmp[ECC_MAX_WORD_LEN], x[ECC_MAX_WORD_LEN];
unsigned char ret;
if(0 == curve || 0 == E || 0 == pubKey || 0 == signature)
{
return ECDSA_POINTOR_NULL;
}
if(0 == EByteLen)
{
return ECDSA_INVALID_INPUT;
}
if(curve->eccp_p_bitLen > ECC_MAX_BIT_LEN)
{
return ECDSA_INVALID_INPUT;
}
//make sure r in [1, n-1]
memset(r, 0, (nWordLen<<2)-nByteLen);
swapX(signature, (unsigned char *)r, nByteLen);
//memcpy((unsigned char *)r, signature, nByteLen);
if(ismemzero4(r, nWordLen<<2))
{
return ECDSA_ZERO;
}
if(big_integer_compare(r, nWordLen, curve->eccp_n, nWordLen) >= 0)
{
return ECDSA_LARGE_INTEGER;
}
//make sure s in [1, n-1]
memset(s, 0, (nWordLen<<2)-nByteLen);
swapX(signature+nByteLen, (unsigned char *)s, nByteLen);
//memcpy((unsigned char *)s, signature+nByteLen, nByteLen);
if(ismemzero4(s, nWordLen<<2))
{
return ECDSA_ZERO;
}
if(big_integer_compare(s, nWordLen, curve->eccp_n, nWordLen) >= 0)
{
return ECDSA_LARGE_INTEGER;
}
//tmp = s^(-1) mod n
ret = pke_mod_inv(curve->eccp_n, s, tmp, nWordLen, nWordLen);
if(PKE_SUCCESS != ret)
{
return ret;
}
//get integer e from hash value E(according to SEC1-V2 2009)
memset(e, 0, nWordLen<<2);
if(curve->eccp_n_bitLen >= (EByteLen<<3)) //in this case, make E as e directly
{
swapX((unsigned char *)E, (unsigned char *)e, nByteLen);
//memcpy((unsigned char *)e, (unsigned char *)E, EByteLen);
}
else //in this case, make left eccp_n_bitLen bits of E as e
{
memcpy(e, E, nByteLen);
swapX((unsigned char *)E, (unsigned char *)e, nByteLen);
//memcpy((unsigned char *)e, (unsigned char *)E, nByteLen);
tmpLen = (curve->eccp_n_bitLen)&7;
if(tmpLen)
{
div2n_u32(e, nWordLen, 8-tmpLen);
}
}
//get e = e mod n, i.e., make sure e in [0, n-1]
if(big_integer_compare(e, nWordLen, curve->eccp_n, nWordLen) >= 0)
{
sub_u32(e, curve->eccp_n, x, nWordLen);
memcpy(e, x, nWordLen<<2);
}
//x = e*(s^(-1)) mod n
if(curve->eccp_n_h && curve->eccp_n_n1)
{
pke_load_pre_calc_mont(curve->eccp_n_h, curve->eccp_n_n1, nWordLen);
ret = pke_mod_mul(curve->eccp_n, e, tmp, x, nWordLen);
}
if(PKE_SUCCESS != ret)
{
return ret;
}
//tmp = r*(s^(-1)) mod n
ret = pke_mod_mul(curve->eccp_n, r, tmp, tmp, nWordLen);
if(PKE_SUCCESS != ret)
{
return ret;
}
//check public key
memset(e, 0, (maxWordLen<<2)-pByteLen);
memset(s, 0, (maxWordLen<<2)-pByteLen);
swapX(pubKey, (unsigned char *)e, pByteLen);
swapX(pubKey+pByteLen, (unsigned char *)s, pByteLen);
// memcpy((unsigned char *)e, pubKey, pByteLen);
// memcpy((unsigned char *)s, pubKey+pByteLen, pByteLen);
static int B_len = 0;
B_len = pByteLen;
ret = pke_eccp_point_verify(curve, e, s);
B_proc = 4;
if(PKE_SUCCESS != ret)
{
return ret;
}
ret = pke_eccp_point_mul(curve, tmp, e, s, e, s);
B_proc = 5;
if(PKE_SUCCESS != ret)
{
return ret;
}
B_proc = 6;
if(!ismemzero4(x, nWordLen<<2))
{
ret = pke_eccp_point_mul(curve, x, curve->eccp_Gx, curve->eccp_Gy, x, tmp);
if(PKE_SUCCESS != ret)
{
return ret;
}
B_proc = 7;
ret = pke_eccp_point_add(curve, e, s, x, tmp, e, s);
if(PKE_SUCCESS != ret)
{
return ret;
}
}
//x = x1 mod n
ret = pke_mod(e, pWordLen, curve->eccp_n, curve->eccp_n_h, curve->eccp_n_n1, nWordLen, tmp);
if(PKE_SUCCESS != ret)
{
return ret;
}
B_proc = 8;
if(big_integer_compare(tmp, nWordLen, r, nWordLen))
{
return ECDSA_VERIFY_FAIL;
}
return ECDSA_SUCCESS;
}
#endif