Convert hash to int in sign/verify (#53) Previously, callers would need to manually convert the hash value appropriately if it was not the same length as curve_n. Now, callers just pass in the full hash value and the length; uECC will convert the hash as appropriate.
diff --git a/test/test_ecdsa.c b/test/test_ecdsa.c index 1332690..ed1ea77 100644 --- a/test/test_ecdsa.c +++ b/test/test_ecdsa.c
@@ -31,12 +31,12 @@ } memcpy(hash, public, sizeof(hash)); - if (!uECC_sign(private, hash, sig, curves[c])) { + if (!uECC_sign(private, hash, sizeof(hash), sig, curves[c])) { printf("uECC_sign() failed\n"); return 1; } - if (!uECC_verify(public, hash, sig, curves[c])) { + if (!uECC_verify(public, hash, sizeof(hash), sig, curves[c])) { printf("uECC_verify() failed\n"); return 1; }
diff --git a/uECC.c b/uECC.c index 8ee63d0..e8ecaf2 100644 --- a/uECC.c +++ b/uECC.c
@@ -1014,8 +1014,33 @@ /* -------- ECDSA code -------- */ +static void bits2int(uECC_word_t *native, + const uint8_t *bits, + unsigned bits_size, + uECC_Curve curve) { + unsigned num_n_bytes = BITS_TO_BYTES(curve->num_n_bits); + unsigned num_n_words = BITS_TO_WORDS(curve->num_n_bits); + if (bits_size > num_n_bytes) { + bits_size = num_n_bytes; + } + uECC_vli_bytesToNative(native, bits, bits_size, curve); + if (bits_size * 8 <= (unsigned)curve->num_n_bits) { + return; + } + int shift = bits_size * 8 - curve->num_n_bits; + uECC_word_t carry = 0; + uECC_word_t *end = native; + native += num_n_words; + while (native-- > end) { + uECC_word_t temp = *native; + *native = (temp >> shift) | carry; + carry = temp << (uECC_WORD_BITS - shift); + } +} + static int uECC_sign_with_k(const uint8_t *private_key, const uint8_t *message_hash, + unsigned hash_size, uECC_word_t *k, uint8_t *signature, uECC_Curve curve) { @@ -1071,7 +1096,7 @@ uECC_vli_set(s, p, num_words); uECC_vli_modMult(s, tmp, s, curve->n, num_n_words); /* s = r*d */ - uECC_vli_bytesToNative(tmp, message_hash, curve->num_bytes, curve); + bits2int(tmp, message_hash, hash_size, curve); uECC_vli_modAdd(s, tmp, s, curve->n, num_n_words); /* s = e + r*d */ uECC_vli_modMult(s, s, k, curve->n, num_n_words); /* s = (e + r*d) / k */ if (uECC_vli_numBits(s, num_n_words) > (bitcount_t)curve->num_bytes * 8) { @@ -1083,6 +1108,7 @@ int uECC_sign(const uint8_t *private_key, const uint8_t *message_hash, + unsigned hash_size, uint8_t *signature, uECC_Curve curve) { uECC_word_t k[uECC_MAX_WORDS]; @@ -1095,7 +1121,7 @@ return 0; } - if (uECC_sign_with_k(private_key, message_hash, k, signature, curve)) { + if (uECC_sign_with_k(private_key, message_hash, hash_size, k, signature, curve)) { return 1; } } @@ -1146,13 +1172,14 @@ } /* Deterministic signing, similar to RFC 6979. Differences are: - * We just use (truncated) H(m) directly rather than bits2octets(H(m)) + * We just use H(m) directly rather than bits2octets(H(m)) (it is not reduced modulo curve_n). * We generate a value for k (aka T) directly rather than converting endianness. Layout of hash_context->tmp: <K> | <V> | (1 byte overlapped 0x00 or 0x01) / <HMAC pad> */ int uECC_sign_deterministic(const uint8_t *private_key, const uint8_t *message_hash, + unsigned hash_size, uECC_HashContext *hash_context, uint8_t *signature, uECC_Curve curve) { @@ -1173,7 +1200,7 @@ V[hash_context->result_size] = 0x00; HMAC_update(hash_context, V, hash_context->result_size + 1); HMAC_update(hash_context, private_key, num_bytes); - HMAC_update(hash_context, message_hash, num_bytes); + HMAC_update(hash_context, message_hash, hash_size); HMAC_finish(hash_context, K, K); update_V(hash_context, K, V); @@ -1183,7 +1210,7 @@ V[hash_context->result_size] = 0x01; HMAC_update(hash_context, V, hash_context->result_size + 1); HMAC_update(hash_context, private_key, num_bytes); - HMAC_update(hash_context, message_hash, num_bytes); + HMAC_update(hash_context, message_hash, hash_size); HMAC_finish(hash_context, K, K); update_V(hash_context, K, V); @@ -1208,7 +1235,7 @@ mask >> ((bitcount_t)(num_n_words * uECC_WORD_SIZE * 8 - num_n_bits)); } - if (uECC_sign_with_k(private_key, message_hash, T, signature, curve)) { + if (uECC_sign_with_k(private_key, message_hash, hash_size, T, signature, curve)) { return 1; } @@ -1228,7 +1255,8 @@ } int uECC_verify(const uint8_t *public_key, - const uint8_t *hash, + const uint8_t *message_hash, + unsigned hash_size, const uint8_t *signature, uECC_Curve curve) { uECC_word_t u1[uECC_MAX_WORDS], u2[uECC_MAX_WORDS]; @@ -1272,7 +1300,7 @@ /* Calculate u1 and u2. */ uECC_vli_modInv(z, s, curve->n, num_n_words); /* z = 1/s */ u1[num_n_words - 1] = 0; - uECC_vli_bytesToNative(u1, hash, curve->num_bytes, curve); + bits2int(u1, message_hash, hash_size, curve); uECC_vli_modMult(u1, u1, z, curve->n, num_n_words); /* u1 = e/s */ uECC_vli_modMult(u2, r, z, curve->n, num_n_words); /* u2 = r/s */
diff --git a/uECC.h b/uECC.h index 06c6cdd..41c98e4 100644 --- a/uECC.h +++ b/uECC.h
@@ -209,6 +209,7 @@ Inputs: private_key - Your private key. message_hash - The hash of the message to sign. + hash_size - The size of message_hash in bytes. Outputs: signature - Will be filled in with the signature value. Must be at least 2 * curve size long. @@ -218,6 +219,7 @@ */ int uECC_sign(const uint8_t *private_key, const uint8_t *message_hash, + unsigned hash_size, uint8_t *signature, uECC_Curve curve); @@ -277,11 +279,13 @@ attacks. Usage: Compute a hash of the data you wish to sign (SHA-2 is recommended) and pass it in to -this function along with your private key and a hash context. +this function along with your private key and a hash context. Note that the message_hash +does not need to be computed with the same hash function used by hash_context. Inputs: private_key - Your private key. message_hash - The hash of the message to sign. + hash_size - The size of message_hash in bytes. hash_context - A hash context to use. Outputs: @@ -291,6 +295,7 @@ */ int uECC_sign_deterministic(const uint8_t *private_key, const uint8_t *message_hash, + unsigned hash_size, uECC_HashContext *hash_context, uint8_t *signature, uECC_Curve curve); @@ -302,14 +307,16 @@ pass it to this function along with the signer's public key and the signature values (r and s). Inputs: - public_key - The signer's public key - hash - The hash of the signed data. - signature - The signature value. + public_key - The signer's public key. + message_hash - The hash of the signed data. + hash_size - The size of message_hash in bytes. + signature - The signature value. Returns 1 if the signature is valid, 0 if it is invalid. */ int uECC_verify(const uint8_t *private_key, - const uint8_t *hash, + const uint8_t *message_hash, + unsigned hash_size, const uint8_t *signature, uECC_Curve curve);