add deterministic k generation for ECC sign

This commit is contained in:
Jacob Barthelmeh
2021-03-16 13:00:35 +07:00
parent 7345b2418b
commit 160faa851c
3 changed files with 437 additions and 5 deletions

View File

@ -127,7 +127,9 @@ ECC Curve Sizes:
#include <wolfssl/wolfcrypt/sp.h>
#endif
#ifdef HAVE_ECC_ENCRYPT
#if defined(HAVE_ECC_ENCRYPT) || defined(WOLFSSL_ECDSA_SET_K) || \
defined(WOLFSSL_ECDSA_SET_K_ONE_LOOP) || \
defined(WOLFSSL_ECDSA_DETERMINISTIC_K)
#include <wolfssl/wolfcrypt/hmac.h>
#include <wolfssl/wolfcrypt/aes.h>
#endif
@ -5299,6 +5301,48 @@ int wc_ecc_sign_hash(const byte* in, word32 inlen, byte* out, word32 *outlen,
}
#endif /* !NO_ASN */
#if defined(WOLFSSL_ECDSA_DETERMINISTIC_K)
/* returns MP_OKAY on success */
static int deterministic_sign_helper(const byte* in, word32 inlen, ecc_key* key)
{
int err;
DECLARE_CURVE_SPECS(curve, 1);
ALLOC_CURVE_SPECS(1);
/* get curve order */
err = wc_ecc_curve_load(key->dp, &curve, ECC_CURVE_FIELD_ORDER);
if (err == MP_OKAY) {
if (key->sign_k == NULL) {
key->sign_k = (mp_int*)XMALLOC(sizeof(mp_int), key->heap,
DYNAMIC_TYPE_ECC);
if (key->sign_k) {
/* currently limiting to SHA256 for auto create */
if (mp_init(key->sign_k) != MP_OKAY ||
wc_ecc_gen_deterministic_k(in, inlen,
WC_HASH_TYPE_SHA256, &key->k, key->sign_k,
curve->order, key->heap) != 0) {
mp_free(key->sign_k);
XFREE(key->sign_k, key->heap, DYNAMIC_TYPE_ECC);
key->sign_k = NULL;
wc_ecc_curve_free(curve);
FREE_CURVE_SPECS();
return ECC_PRIV_KEY_E;
}
}
else {
wc_ecc_curve_free(curve);
FREE_CURVE_SPECS();
return MEMORY_E;
}
}
}
wc_ecc_curve_free(curve);
FREE_CURVE_SPECS();
return err;
}
#endif /* WOLFSSL_ECDSA_DETERMINISTIC_K */
#if defined(WOLFSSL_STM32_PKA)
int wc_ecc_sign_hash_ex(const byte* in, word32 inlen, WC_RNG* rng,
ecc_key* key, mp_int *r, mp_int *s)
@ -5356,7 +5400,8 @@ static int ecc_sign_hash_sw(ecc_key* key, ecc_key* pubkey, WC_RNG* rng,
err = RNG_FAILURE_E;
break;
}
#if defined(WOLFSSL_ECDSA_SET_K) || defined(WOLFSSL_ECDSA_SET_K_ONE_LOOP)
#if defined(WOLFSSL_ECDSA_SET_K) || defined(WOLFSSL_ECDSA_SET_K_ONE_LOOP) || \
defined(WOLFSSL_ECDSA_DETERMINISTIC_K)
if (key->sign_k != NULL) {
if (loop_check > 1) {
err = RNG_FAILURE_E;
@ -5375,6 +5420,13 @@ static int ecc_sign_hash_sw(ecc_key* key, ecc_key* pubkey, WC_RNG* rng,
#ifdef WOLFSSL_ECDSA_SET_K_ONE_LOOP
loop_check = 64;
#endif
#ifdef WOLFSSL_ECDSA_DETERMINISTIC_K
if (key->deterministic == 1) {
/* sign_k generated earlier in function for SP calls.
* Only go through the loop once and fail if error */
loop_check = 64;
}
#endif
/* compute public key based on provided "k" */
err = ecc_make_pub_ex(pubkey, curve, NULL, rng);
@ -5474,6 +5526,7 @@ int wc_ecc_sign_hash_ex(const byte* in, word32 inlen, WC_RNG* rng,
#endif
#if defined(WOLFSSL_ECDSA_SET_K) || defined(WOLFSSL_ECDSA_SET_K_ONE_LOOP) || \
defined(WOLFSSL_ECDSA_DETERMINISTIC_K) || \
(defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_ECC) && \
(defined(HAVE_CAVIUM_V) || defined(HAVE_INTEL_QA)))
DECLARE_CURVE_SPECS(curve, ECC_CURVE_FIELD_COUNT);
@ -5504,13 +5557,24 @@ int wc_ecc_sign_hash_ex(const byte* in, word32 inlen, WC_RNG* rng,
}
#endif
#if defined(WOLFSSL_ECDSA_DETERMINISTIC_K)
/* generate deterministic 'k' value to be used either with SP or normal */
if (key->deterministic == 1) {
if (deterministic_sign_helper(in, inlen, key)) {
WOLFSSL_MSG("Error generating deterministic k to sign");
return ECC_PRIV_KEY_E;
}
}
#endif
#if defined(WOLFSSL_HAVE_SP_ECC)
if (key->idx != ECC_CUSTOM_IDX
#if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_ECC)
&& key->asyncDev.marker != WOLFSSL_ASYNC_MARKER_ECC
#endif
) {
#if defined(WOLFSSL_ECDSA_SET_K) || defined(WOLFSSL_ECDSA_SET_K_ONE_LOOP)
#if defined(WOLFSSL_ECDSA_SET_K) || defined(WOLFSSL_ECDSA_SET_K_ONE_LOOP) \
|| defined(WOLFSSL_ECDSA_DETERMINISTIC_K)
mp_int* sign_k = key->sign_k;
#else
mp_int* sign_k = NULL;
@ -5611,7 +5675,8 @@ int wc_ecc_sign_hash_ex(const byte* in, word32 inlen, WC_RNG* rng,
}
/* load curve info */
#if defined(WOLFSSL_ECDSA_SET_K) || defined(WOLFSSL_ECDSA_SET_K_ONE_LOOP)
#if defined(WOLFSSL_ECDSA_SET_K) || defined(WOLFSSL_ECDSA_SET_K_ONE_LOOP) || \
defined(WOLFSSL_ECDSA_DETERMINISTIC_K)
ALLOC_CURVE_SPECS(ECC_CURVE_FIELD_COUNT);
err = wc_ecc_curve_load(key->dp, &curve, ECC_CURVE_FIELD_ALL);
#else
@ -5756,6 +5821,264 @@ int wc_ecc_sign_hash_ex(const byte* in, word32 inlen, WC_RNG* rng,
return err;
}
#if defined(WOLFSSL_ECDSA_DETERMINISTIC_K)
/* helper function to do HMAC operations
* returns 0 on success and updates "out" buffer
*/
static int _HMAC_K(byte* K, word32 KSz, byte* V, word32 VSz,
const byte* h1, word32 h1Sz, byte* x, word32 xSz, byte* oct,
byte* out, enum wc_HashType hashType, void* heap) {
Hmac hmac;
int ret;
ret = wc_HmacInit(&hmac, heap, 0);
if (ret == 0)
ret = wc_HmacSetKey(&hmac, hashType, K, KSz);
if (ret == 0)
ret = wc_HmacUpdate(&hmac, V, VSz);
if (ret == 0 && oct != NULL)
ret = wc_HmacUpdate(&hmac, oct, 1);
if (ret == 0)
wc_HmacUpdate(&hmac, x, xSz);
if (ret == 0)
wc_HmacUpdate(&hmac, h1, h1Sz);
if (ret == 0)
wc_HmacFinal(&hmac, out);
wc_HmacFree(&hmac);
return ret;
}
/* Generates a deterministic key based of the message using RFC6967
* @param [in] hash Hash value to sign
* @param [in] hashSz Size of 'hash' buffer passed in
* @param [in] hashType Type of hash to use with deterministic k gen, i.e.
* WC_HASH_TYPE_SHA256
* @param [in] priv Current ECC private key set
* @param [out] k An initialized mp_int to set the k value generated in
* @param [in] order ECC order parameter to use with generation
* @return 0 on success.
*/
int wc_ecc_gen_deterministic_k(const byte* hash, word32 hashSz,
enum wc_HashType hashType, mp_int* priv, mp_int* k, mp_int* order,
void* heap)
{
int ret = 0, qbits = 0;
#ifndef WOLFSSL_SMALL_STACK
byte h1[WC_MAX_DIGEST_SIZE];
byte V[WC_MAX_DIGEST_SIZE];
byte K[WC_MAX_DIGEST_SIZE];
byte x[MAX_ECC_BYTES];
#else
byte *h1 = NULL;
byte *V = NULL;
byte *K = NULL;
byte *x = NULL;
#endif
word32 xSz, VSz, KSz, h1len;
byte intOct;
mp_int z1;
if (hash == NULL || k == NULL || order == NULL) {
return BAD_FUNC_ARG;
}
if (hashSz > WC_MAX_DIGEST_SIZE) {
WOLFSSL_MSG("hash size was too large!");
return BAD_FUNC_ARG;
}
if ((xSz = mp_unsigned_bin_size(priv)) > MAX_ECC_BYTES) {
WOLFSSL_MSG("private key larger than max expected!");
return BAD_FUNC_ARG;
}
#ifdef WOLFSSL_SMALL_STACK
h1 = (byte*)XMALLOC(WC_MAX_DIGEST_SIZE, heap, DYNAMIC_TYPE_DIGEST);
if (h1 == NULL) {
ret = MEMORY_E;
}
if (ret == 0) {
V = (byte*)XMALLOC(WC_MAX_DIGEST_SIZE, heap, DYNAMIC_TYPE_ECC_BUFFER);
if (V == NULL)
ret = MEMORY_E;
}
if (ret == 0) {
K = (byte*)XMALLOC(WC_MAX_DIGEST_SIZE, heap, DYNAMIC_TYPE_ECC_BUFFER);
if (K == NULL)
ret = MEMORY_E;
}
if (ret == 0) {
x = (byte*)XMALLOC(MAX_ECC_BYTES, heap, DYNAMIC_TYPE_PRIVATE_KEY);
if (x == NULL)
ret = MEMORY_E;
}
/* bail out if any error has been hit at this point */
if (ret != 0) {
if (x != NULL)
XFREE(x, heap, DYNAMIC_TYPE_PRIVATE_KEY);
if (K != NULL)
XFREE(K, heap, DYNAMIC_TYPE_ECC_BUFFER);
if (V != NULL)
XFREE(V, heap, DYNAMIC_TYPE_ECC_BUFFER);
if (h1 != NULL)
XFREE(h1, heap, DYNAMIC_TYPE_DIGEST);
return ret;
}
#endif
VSz = KSz = h1len = hashSz;
XMEMSET(V, 0x01, VSz);
XMEMSET(K, 0x00, KSz);
ret = mp_to_unsigned_bin(priv, x);
mp_init(&z1); /* always init z1 and free z1 */
if (ret == 0) {
qbits = mp_count_bits(order);
}
if (ret == 0) {
ret = mp_read_unsigned_bin(&z1, hash, hashSz);
}
if (ret == 0) {
/* right shift by bits in hash minus bits in order */
mp_rshb(&z1, (hashSz * WOLFSSL_BIT_SIZE) - qbits);
XMEMSET(h1, 0, sizeof(h1));
}
if (ret == 0) {
/* mod reduce by order using conditional subtract */
if (mp_cmp(&z1, order) == MP_GT) {
mp_sub(&z1, order, &z1);
h1len = mp_unsigned_bin_size(&z1);
if (h1len < 0 || h1len > WC_MAX_DIGEST_SIZE) {
ret = BUFFER_E;
}
else {
ret = mp_to_unsigned_bin(&z1, h1);
}
}
else {
/* use original hash and keep leading 0's */
h1len = hashSz;
XMEMCPY(h1, hash, hashSz);
}
}
mp_free(&z1);
/* step d. */
if (ret == 0) {
intOct = 0x00;
ret = _HMAC_K(K, KSz, V, VSz, h1, h1len, x, xSz, &intOct, K,
hashType, heap);
}
/* step e. */
if (ret == 0) {
ret = _HMAC_K(K, KSz, V, VSz, NULL, 0, NULL, 0, NULL, V, hashType,
heap);
}
/* step f. */
if (ret == 0) {
intOct = 0x01;
ret = _HMAC_K(K, KSz, V, VSz, h1, h1len, x, xSz, &intOct, K, hashType,
heap);
}
/* step g. */
if (ret == 0) {
ret = _HMAC_K(K, KSz, V, VSz, NULL, 0, NULL, 0, NULL, V, hashType,
heap);
}
/* step h. */
if (ret == 0 ) {
int err;
intOct = 0x00;
do {
err = 0; /* start as good until generated k is tested */
ret = _HMAC_K(K, KSz, V, VSz, NULL, 0, NULL, 0, NULL, V, hashType,
heap);
if (ret == 0) {
mp_clear(k);
ret = mp_read_unsigned_bin(k, V, VSz);
}
if ((ret == 0) && ((int)(VSz * WOLFSSL_BIT_SIZE) != qbits)) {
/* handle odd case where shift of 'k' is needed */
mp_rshb(k, (VSz * WOLFSSL_BIT_SIZE) - qbits);
}
/* the key should be smaller than the order of base point */
if (ret == 0) {
if (mp_cmp(k, order) != MP_LT) {
err = MP_VAL;
}
}
/* no 0 key's */
if (ret == 0) {
if (mp_iszero(k) == MP_YES)
err = MP_ZERO_E;
}
/* if there was a problem with 'k' generated then try again */
if (ret == 0 && err != 0) {
ret = _HMAC_K(K, KSz, V, VSz, NULL, 0, NULL, 0, &intOct, K,
hashType, heap);
if (ret == 0) {
ret = _HMAC_K(K, KSz, V, VSz, NULL, 0, NULL, 0, NULL, V,
hashType, heap);
}
}
} while (ret == 0 && err != 0);
}
#ifdef WOLFSSL_SMALL_STACK
if (x != NULL)
XFREE(x, heap, DYNAMIC_TYPE_PRIVATE_KEY);
if (K != NULL)
XFREE(K, heap, DYNAMIC_TYPE_ECC_BUFFER);
if (V != NULL)
XFREE(V, heap, DYNAMIC_TYPE_ECC_BUFFER);
if (h1 != NULL)
XFREE(h1, heap, DYNAMIC_TYPE_DIGEST);
#endif
return ret;
}
/* Sets the deterministic flag for 'k' generation with sign.
* returns 0 on success
*/
int wc_ecc_set_deterministic(ecc_key* key, byte flag)
{
if (key == NULL) {
return BAD_FUNC_ARG;
}
key->deterministic = flag;
return 0;
}
#endif
#if defined(WOLFSSL_ECDSA_SET_K) || defined(WOLFSSL_ECDSA_SET_K_ONE_LOOP)
int wc_ecc_sign_set_k(const byte* k, word32 klen, ecc_key* key)
{

View File

@ -20663,6 +20663,95 @@ static int ecc_test_vector(int keySize)
return 0;
}
#if defined(HAVE_ECC_SIGN) && defined(WOLFSSL_ECDSA_DETERMINISTIC_K)
static int ecc_test_deterministic_k(WC_RNG* rng)
{
int ret;
ecc_key key;
byte sig[72];
word32 sigSz;
unsigned char msg[] = "sample";
unsigned char hash[32];
const char* dIUT =
"C9AFA9D845BA75166B5C215767B1D6934E50C3DB36E89B127B8A622B120F6721";
const char* QIUTx =
"60FED4BA255A9D31C961EB74C6356D68C049B8923B61FA6CE669622E60F29FB6";
const char* QIUTy =
"7903FE1008B8BC99A41AE9E95628BC64F2F1B20C2D7E9F5177A3C294D4462299";
const byte expSig[] = {
0x30, 0x46, 0x02, 0x21, 0x00, 0xEF, 0xD4, 0x8B,
0x2A, 0xAC, 0xB6, 0xA8, 0xFD, 0x11, 0x40, 0xDD,
0x9C, 0xD4, 0x5E, 0x81, 0xD6, 0x9D, 0x2C, 0x87,
0x7B, 0x56, 0xAA, 0xF9, 0x91, 0xC3, 0x4D, 0x0E,
0xA8, 0x4E, 0xAF, 0x37, 0x16, 0x02, 0x21, 0x00,
0xF7, 0xCB, 0x1C, 0x94, 0x2D, 0x65, 0x7C, 0x41,
0xD4, 0x36, 0xC7, 0xA1, 0xB6, 0xE2, 0x9F, 0x65,
0xF3, 0xE9, 0x00, 0xDB, 0xB9, 0xAF, 0xF4, 0x06,
0x4D, 0xC4, 0xAB, 0x2F, 0x84, 0x3A, 0xCD, 0xA8
};
ret = wc_ecc_init_ex(&key, HEAP_HINT, devId);
if (ret != 0) {
return ret;
}
ret = wc_ecc_import_raw(&key, QIUTx, QIUTy, dIUT, "SECP256R1");
if (ret != 0) {
goto done;
}
ret = wc_Hash(WC_HASH_TYPE_SHA256, msg,
(word32)XSTRLEN((const char*)msg), hash, sizeof(hash));
if (ret != 0) {
goto done;
}
ret = wc_ecc_set_deterministic(&key, 1);
if (ret != 0) {
goto done;
}
sigSz = sizeof(sig);
do {
#if defined(WOLFSSL_ASYNC_CRYPT)
ret = wc_AsyncWait(ret, &key.asyncDev, WC_ASYNC_FLAG_CALL_AGAIN);
#endif
if (ret == 0)
ret = wc_ecc_sign_hash(hash, sizeof(hash), sig, &sigSz, rng, &key);
} while (ret == WC_PENDING_E);
if (ret != 0) {
goto done;
}
TEST_SLEEP();
if (sigSz != sizeof(expSig)) {
ret = -9830;
goto done;
}
if (XMEMCMP(sig, expSig, sigSz) != 0) {
ret = -9831;
goto done;
}
sigSz = sizeof(sig);
do {
#if defined(WOLFSSL_ASYNC_CRYPT)
ret = wc_AsyncWait(ret, &key.asyncDev, WC_ASYNC_FLAG_CALL_AGAIN);
#endif
if (ret == 0)
ret = wc_ecc_sign_hash(hash, sizeof(hash), sig, &sigSz, rng, &key);
} while (ret == WC_PENDING_E);
if (ret != 0) {
goto done;
}
TEST_SLEEP();
done:
wc_ecc_free(&key);
return ret;
}
#endif
#if defined(HAVE_ECC_SIGN) && defined(WOLFSSL_ECDSA_SET_K)
static int ecc_test_sign_vectors(WC_RNG* rng)
{
@ -23547,6 +23636,14 @@ WOLFSSL_TEST_SUBROUTINE int ecc_test(void)
}
#endif
#if defined(HAVE_ECC_SIGN) && defined(WOLFSSL_ECDSA_DETERMINISTIC_K)
ret = ecc_test_deterministic_k(&rng);
if (ret != 0) {
printf("ecc_test_deterministic_k failed! %d\n", ret);
goto done;
}
#endif
#if defined(HAVE_ECC_SIGN) && defined(WOLFSSL_ECDSA_SET_K)
ret = ecc_test_sign_vectors(&rng);
if (ret != 0) {

View File

@ -456,9 +456,13 @@ struct ecc_key {
ecc_context_t ctx;
#endif
#if defined(WOLFSSL_ECDSA_SET_K) || defined(WOLFSSL_ECDSA_SET_K_ONE_LOOP)
#if defined(WOLFSSL_ECDSA_SET_K) || defined(WOLFSSL_ECDSA_SET_K_ONE_LOOP) || \
defined(WOLFSSL_ECDSA_DETERMINISTIC_K)
mp_int *sign_k;
#endif
#if defined(WOLFSSL_ECDSA_DETERMINISTIC_K)
byte deterministic:1;
#endif
#ifdef WOLFSSL_SMALL_STACK_CACHE
mp_int* t1;
@ -566,6 +570,14 @@ int wc_ecc_sign_hash(const byte* in, word32 inlen, byte* out, word32 *outlen,
WOLFSSL_API
int wc_ecc_sign_hash_ex(const byte* in, word32 inlen, WC_RNG* rng,
ecc_key* key, mp_int *r, mp_int *s);
#ifdef WOLFSSL_ECDSA_DETERMINISTIC_K
WOLFSSL_API
int wc_ecc_set_deterministic(ecc_key* key, byte flag);
WOLFSSL_API
int wc_ecc_gen_deterministic_k(const byte* hash, word32 hashSz,
enum wc_HashType hashType, mp_int* priv, mp_int* k, mp_int* order,
void* heap);
#endif
#if defined(WOLFSSL_ECDSA_SET_K) || defined(WOLFSSL_ECDSA_SET_K_ONE_LOOP)
WOLFSSL_API
int wc_ecc_sign_set_k(const byte* k, word32 klen, ecc_key* key);