From 160faa851cd0b1a12819244dd1ccb8ba1d0028ee Mon Sep 17 00:00:00 2001 From: Jacob Barthelmeh Date: Tue, 16 Mar 2021 13:00:35 +0700 Subject: [PATCH] add deterministic k generation for ECC sign --- wolfcrypt/src/ecc.c | 331 +++++++++++++++++++++++++++++++++++++++- wolfcrypt/test/test.c | 97 ++++++++++++ wolfssl/wolfcrypt/ecc.h | 14 +- 3 files changed, 437 insertions(+), 5 deletions(-) diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index dbeee2e32..888232c67 100644 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -127,7 +127,9 @@ ECC Curve Sizes: #include #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 #include #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) { diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 2d4e74046..2ddebb7dc 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -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) { diff --git a/wolfssl/wolfcrypt/ecc.h b/wolfssl/wolfcrypt/ecc.h index 3901e4295..a0de8df6b 100644 --- a/wolfssl/wolfcrypt/ecc.h +++ b/wolfssl/wolfcrypt/ecc.h @@ -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);