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 @@ int main() { } 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 @@ int uECC_compute_public_key(const uint8_t *private_key, uint8_t *public_key, uEC /* -------- 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 @@ got_random: 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 @@ got_random: 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 @@ int uECC_sign(const uint8_t *private_key, 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 @@ static void update_V(uECC_HashContext *hash_context, uint8_t *K, uint8_t *V) { } /* 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: | | (1 byte overlapped 0x00 or 0x01) / */ 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 @@ int uECC_sign_deterministic(const uint8_t *private_key, 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 @@ int uECC_sign_deterministic(const uint8_t *private_key, 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 @@ int uECC_sign_deterministic(const uint8_t *private_key, 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 @@ static bitcount_t smax(bitcount_t a, bitcount_t b) { } 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 @@ int uECC_verify(const uint8_t *public_key, /* 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 @@ this function along with your private key. 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 @@ Returns 1 if the signature generated successfully, 0 if an error occurred. */ 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 @@ this function; however, if the RNG is defined it will improve resistance to side 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 @@ Returns 1 if the signature generated successfully, 0 if an error occurred. */ 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 @@ Usage: Compute the hash of the signed data using the same hash as the signer and 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);