From ccff82353d5150375d4b60f163f34ce7c1f14ec0 Mon Sep 17 00:00:00 2001 From: Hubert Kario Date: Wed, 11 Nov 2020 13:00:45 +0100 Subject: [PATCH] fix truncation of hash input with order bit size not multiple of 8 all curves we have defined, with exception of NIST P-521, have bit length of order that's multiple of 8, and there are no hashes that are longer than 512 bits, so NIST P-521 is not affected either, but do fix this issue in case user provides raw input longer than 512 bits or uses custom curves --- src/ecdsa/keys.py | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/ecdsa/keys.py b/src/ecdsa/keys.py index 7e448aad..09dbfc57 100644 --- a/src/ecdsa/keys.py +++ b/src/ecdsa/keys.py @@ -77,7 +77,7 @@ from .numbertheory import square_root_mod_prime, SquareRootError from .ecdsa import RSZeroError from .util import string_to_number, number_to_string, randrange -from .util import sigencode_string, sigdecode_string +from .util import sigencode_string, sigdecode_string, bit_length from .util import ( oid_ecPublicKey, encoded_oid_ecPublicKey, @@ -694,14 +694,28 @@ def verify_digest( # signature doesn't have to be a bytes-like-object so don't normalise # it, the decoders will do that digest = normalise_bytes(digest) - if allow_truncate: - digest = digest[: self.curve.baselen] - if len(digest) > self.curve.baselen: + if not allow_truncate and len(digest) > self.curve.baselen: raise BadDigestError( "this curve (%s) is too short " "for your digest (%d)" % (self.curve.name, 8 * len(digest)) ) number = string_to_number(digest) + if allow_truncate: + max_length = bit_length(self.curve.order) + # we don't use bit_length(number) as that truncates leading zeros + length = len(digest) * 8 + + # See NIST FIPS 186-4: + # + # When the length of the output of the hash function is greater + # than N (i.e., the bit length of q), then the leftmost N bits of + # the hash function output block shall be used in any calculation + # using the hash function output during the generation or + # verification of a digital signature. + # + # as such, we need to shift-out the low-order bits: + number >>= max(0, length - max_length) + try: r, s = sigdecode(signature, self.pubkey.order) except (der.UnexpectedDER, MalformedSignature) as e: