From 29c8d1be6bc9f29d6b607cf156629d756f2f93c0 Mon Sep 17 00:00:00 2001 From: Jong-Shian Wu Date: Sat, 8 Aug 2015 05:04:34 +0800 Subject: [PATCH 1/3] make uECC_sign_deterministic conform to RFC 6979 --- uECC.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++----- uECC.h | 8 ++++++++ 2 files changed, 56 insertions(+), 5 deletions(-) diff --git a/uECC.c b/uECC.c index 8dcd7af..af194a6 100644 --- a/uECC.c +++ b/uECC.c @@ -2594,17 +2594,38 @@ int uECC_sign_deterministic(const uint8_t private_key[uECC_BYTES], uint8_t *V = K + hash_context->result_size; uECC_word_t tries; unsigned i; + uECC_word_t tmp[uECC_N_WORDS]; // an integer converted from message_hash + uint8_t reduced_msg_hash[uECC_N_BYTES] = { 0 }; + for (i = 0; i < hash_context->result_size; ++i) { V[i] = 0x01; K[i] = 0; } + // Convert the octet string of length `uECC_BYTES` into an integer tmp. + // Since this must be done when generating an ECDSA signature, we may + // choose to refactor the codebase so that this operation is done only + // once. + vli_bytesToNative(tmp, message_hash); + + // Modular reduction: tmp <- tmp mod n (ONLY FOR RFC6979) + while (vli_cmp_n(tmp, curve_n) >= 0) { + vli_sub(tmp, tmp, curve_n); + } + + // Convert the integer tmp back to an octet string (ONLY FOR RFC6979) +#if (uECC_CURVE == uECC_secp160r1) + vli_nativeToBytes(reduced_msg_hash + 1, tmp); +#else + vli_nativeToBytes(reduced_msg_hash, tmp); +#endif + // K = HMAC_K(V || 0x00 || int2octets(x) || h(m)) HMAC_init(hash_context, K); V[hash_context->result_size] = 0x00; HMAC_update(hash_context, V, hash_context->result_size + 1); HMAC_update(hash_context, private_key, uECC_BYTES); - HMAC_update(hash_context, message_hash, uECC_BYTES); + HMAC_update(hash_context, reduced_msg_hash, uECC_N_BYTES); HMAC_finish(hash_context, K, K); update_V(hash_context, K, V); @@ -2614,13 +2635,14 @@ int uECC_sign_deterministic(const uint8_t private_key[uECC_BYTES], V[hash_context->result_size] = 0x01; HMAC_update(hash_context, V, hash_context->result_size + 1); HMAC_update(hash_context, private_key, uECC_BYTES); - HMAC_update(hash_context, message_hash, uECC_BYTES); + HMAC_update(hash_context, reduced_msg_hash, uECC_N_BYTES); HMAC_finish(hash_context, K, K); update_V(hash_context, K, V); for (tries = 0; tries < MAX_TRIES; ++tries) { - uECC_word_t T[uECC_N_WORDS]; + uECC_word_t k[uECC_N_WORDS] = { 0 }; // the RFC6979 ephemeral key in each round + uint8_t T[uECC_N_BYTES]; uint8_t *T_ptr = (uint8_t *)T; unsigned T_bytes = 0; while (T_bytes < sizeof(T)) { @@ -2629,11 +2651,32 @@ int uECC_sign_deterministic(const uint8_t private_key[uECC_BYTES], T_ptr[T_bytes] = V[i]; } } + #if (uECC_CURVE == uECC_secp160r1) - T[uECC_WORDS] &= 0x01; + + // Now T is an array containing uECC_N_BYTES=21 random bytes. + + // TODO: In order to comform to RFC6979 for secp160r1, we should right-shift all bits in T by 7 here. + + // Convert the 20 rightmost bytes into an integer k. + vli_bytesToNative(k, T + 1); + + // If the lowest bit in the leftmost byte is 1, add 2^160 to k. + if (T[0] & 1) { + #if (uECC_WORD_SIZE == 1) + k[uECC_N_WORDS - 1] = 0x01; + #elif (uECC_WORD_SIZE == 4) + k[uECC_N_WORDS - 1] = 0x00000001; + #elif (uECC_WORD_SIZE == 8) + k[uECC_N_WORDS - 1] ^= 0x0000000100000000; + #endif + } + + #else + vli_bytesToNative(k, T); #endif - if (uECC_sign_with_k(private_key, message_hash, T, signature)) { + if (uECC_sign_with_k(private_key, message_hash, k, signature)) { return 1; } diff --git a/uECC.h b/uECC.h index cf3efb8..ad24205 100644 --- a/uECC.h +++ b/uECC.h @@ -60,6 +60,14 @@ faster by about 8% but increases the code size. */ #define uECC_BYTES uECC_CONCAT(uECC_size_, uECC_CURVE) +#define uECC_n_size_1 21 /* secp160r1 */ +#define uECC_n_size_2 24 /* secp192r1 */ +#define uECC_n_size_3 32 /* secp256r1 */ +#define uECC_n_size_4 32 /* secp256k1 */ +#define uECC_n_size_5 28 /* secp224r1 */ + +#define uECC_N_BYTES uECC_CONCAT(uECC_n_size_, uECC_CURVE) + #ifdef __cplusplus extern "C" { From be418198d1c6668496b8a3e03e3683535ee630b3 Mon Sep 17 00:00:00 2001 From: Jong-Shian Wu Date: Sun, 9 Aug 2015 13:43:44 +0800 Subject: [PATCH 2/3] fix an issue on uninitialized buffer --- uECC.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uECC.c b/uECC.c index af194a6..09d7e5d 100644 --- a/uECC.c +++ b/uECC.c @@ -2594,7 +2594,7 @@ int uECC_sign_deterministic(const uint8_t private_key[uECC_BYTES], uint8_t *V = K + hash_context->result_size; uECC_word_t tries; unsigned i; - uECC_word_t tmp[uECC_N_WORDS]; // an integer converted from message_hash + uECC_word_t tmp[uECC_N_WORDS] = { 0 }; // an integer converted from message_hash uint8_t reduced_msg_hash[uECC_N_BYTES] = { 0 }; for (i = 0; i < hash_context->result_size; ++i) { From 1853d8c66eb49a290815709434b35dee111b71d9 Mon Sep 17 00:00:00 2001 From: Jong-Shian Wu Date: Sun, 9 Aug 2015 13:44:09 +0800 Subject: [PATCH 3/3] remove redundant code for modular reduction (mod curve_n) --- uECC.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/uECC.c b/uECC.c index 09d7e5d..2ad93b5 100644 --- a/uECC.c +++ b/uECC.c @@ -2608,15 +2608,14 @@ int uECC_sign_deterministic(const uint8_t private_key[uECC_BYTES], // once. vli_bytesToNative(tmp, message_hash); - // Modular reduction: tmp <- tmp mod n (ONLY FOR RFC6979) - while (vli_cmp_n(tmp, curve_n) >= 0) { - vli_sub(tmp, tmp, curve_n); - } - - // Convert the integer tmp back to an octet string (ONLY FOR RFC6979) + // Perform modular reduction tmp <- tmp mod n, and then + // convert tmp back to an octet string (ONLY FOR RFC6979) #if (uECC_CURVE == uECC_secp160r1) vli_nativeToBytes(reduced_msg_hash + 1, tmp); #else + if (vli_cmp_n(tmp, curve_n) >= 0) { + vli_sub(tmp, tmp, curve_n); + } vli_nativeToBytes(reduced_msg_hash, tmp); #endif