Skip to content

Commit 6f0cbf8

Browse files
committed
bytes input for VerifyingKey.verify()
1 parent 12567ae commit 6f0cbf8

File tree

4 files changed

+88
-6
lines changed

4 files changed

+88
-6
lines changed

src/ecdsa/der.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ def remove_integer(string):
180180
if not string:
181181
raise UnexpectedDER("Empty string is an invalid encoding of an "
182182
"integer")
183-
if not string.startswith(b("\x02")):
183+
if string[:1] != b"\x02":
184184
n = string[0] if isinstance(string[0], integer_types) \
185185
else ord(string[0])
186186
raise UnexpectedDER("wanted type 'integer' (0x02), got 0x%02x" % n)

src/ecdsa/keys.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -543,7 +543,7 @@ def verify(self, signature, data, hashfunc=None,
543543
as the `sigdecode` parameter.
544544
545545
:param signature: encoding of the signature
546-
:type signature: bytes like object
546+
:type signature: sigdecode method dependant
547547
:param data: data signed by the `signature`, will be hashed using
548548
`hashfunc`, if specified, or default hash function
549549
:type data: bytes like object
@@ -565,6 +565,10 @@ def verify(self, signature, data, hashfunc=None,
565565
:return: True if the verification was successful
566566
:rtype: bool
567567
"""
568+
# signature doesn't have to be a bytes-like-object so don't normalise
569+
# it, the decoders will do that
570+
data = normalise_bytes(data)
571+
568572
hashfunc = hashfunc or self.default_hashfunc
569573
digest = hashfunc(data).digest()
570574
return self.verify_digest(signature, digest, sigdecode)
@@ -579,7 +583,7 @@ def verify_digest(self, signature, digest, sigdecode=sigdecode_string):
579583
as the `sigdecode` parameter.
580584
581585
:param signature: encoding of the signature
582-
:type signature: bytes like object
586+
:type signature: sigdecode method dependant
583587
:param digest: raw hash value that the signature authenticates.
584588
:type digest: bytes like object
585589
:param sigdecode: Callable to define the way the signature needs to
@@ -597,6 +601,9 @@ def verify_digest(self, signature, digest, sigdecode=sigdecode_string):
597601
:return: True if the verification was successful
598602
:rtype: bool
599603
"""
604+
# signature doesn't have to be a bytes-like-object so don't normalise
605+
# it, the decoders will do that
606+
digest = normalise_bytes(digest)
600607
if len(digest) > self.curve.baselen:
601608
raise BadDigestError("this curve (%s) is too short "
602609
"for your digest (%d)" % (self.curve.name,

src/ecdsa/test_keys.py

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,12 @@
1212
import six
1313
import sys
1414
import pytest
15+
import hashlib
1516

16-
from .keys import VerifyingKey
17+
from .keys import VerifyingKey, SigningKey
1718
from .der import unpem
19+
from .util import sigencode_string, sigencode_der, sigencode_strings, \
20+
sigdecode_string, sigdecode_der, sigdecode_strings
1821

1922

2023
class TestVerifyingKeyFromString(unittest.TestCase):
@@ -153,3 +156,70 @@ def test_array_array_of_bytes_memoryview(self):
153156
vk = VerifyingKey.from_der(buffer(arr))
154157

155158
self.assertEqual(self.vk.to_string(), vk.to_string())
159+
160+
161+
# test VerifyingKey.verify()
162+
prv_key_str = (
163+
"-----BEGIN EC PRIVATE KEY-----\n"
164+
"MF8CAQEEGF7IQgvW75JSqULpiQQ8op9WH6Uldw6xxaAKBggqhkjOPQMBAaE0AzIA\n"
165+
"BLiBd9CE7xf15FY5QIAoNg+fWbSk1yZOYtoGUdzkejWkxbRc9RWTQjqLVXucIJnz\n"
166+
"bA==\n"
167+
"-----END EC PRIVATE KEY-----\n")
168+
key_bytes = unpem(prv_key_str)
169+
assert isinstance(key_bytes, bytes)
170+
sk = SigningKey.from_der(key_bytes)
171+
vk = sk.verifying_key
172+
173+
data = (b"some string for signing"
174+
b"contents don't really matter"
175+
b"but do include also some crazy values: "
176+
b"\x00\x01\t\r\n\x00\x00\x00\xff\xf0")
177+
assert len(data) % 4 == 0
178+
sha1 = hashlib.sha1()
179+
sha1.update(data)
180+
data_hash = sha1.digest()
181+
182+
sig_raw = sk.sign(data, sigencode=sigencode_string)
183+
assert isinstance(sig_raw, bytes)
184+
sig_der = sk.sign(data, sigencode=sigencode_der)
185+
assert isinstance(sig_der, bytes)
186+
sig_strings = sk.sign(data, sigencode=sigencode_strings)
187+
assert isinstance(sig_strings[0], bytes)
188+
189+
verifiers = []
190+
for modifier, fun in [
191+
("bytes", lambda x: x),
192+
("bytes memoryview", lambda x: buffer(x)),
193+
("bytearray", lambda x: bytearray(x)),
194+
("bytearray memoryview", lambda x: buffer(bytearray(x))),
195+
("array.array of bytes", lambda x: array.array('B', x)),
196+
("array.array of bytes memoryview", lambda x: buffer(array.array('B', x))),
197+
("array.array of ints", lambda x: array.array('I', x)),
198+
("array.array of ints memoryview", lambda x: buffer(array.array('I', x)))
199+
]:
200+
if "ints" in modifier:
201+
conv = lambda x: x
202+
else:
203+
conv = fun
204+
for sig_format, signature, decoder, mod_apply in [
205+
("raw", sig_raw, sigdecode_string, lambda x: conv(x)),
206+
("der", sig_der, sigdecode_der, lambda x: conv(x)),
207+
("strings", sig_strings, sigdecode_strings, lambda x:
208+
tuple(conv(i) for i in x))
209+
]:
210+
for method_name, vrf_mthd, vrf_data in [
211+
("verify", vk.verify, data),
212+
("verify_digest", vk.verify_digest, data_hash)
213+
]:
214+
verifiers.append(pytest.param(
215+
signature, decoder, mod_apply, fun, vrf_mthd, vrf_data,
216+
id="{2}-{0}-{1}".format(modifier, sig_format, method_name)))
217+
218+
@pytest.mark.parametrize(
219+
"signature,decoder,mod_apply,fun,vrf_mthd,vrf_data",
220+
verifiers)
221+
def test_VerifyingKey_verify(
222+
signature, decoder, mod_apply, fun, vrf_mthd, vrf_data):
223+
sig = mod_apply(signature)
224+
225+
assert vrf_mthd(sig, fun(vrf_data), sigdecode=decoder)

src/ecdsa/util.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from hashlib import sha256
77
from six import PY3, int2byte, b, next
88
from . import der
9+
from ._compat import normalise_bytes
910

1011
# RFC5480:
1112
# The "unrestricted" algorithm identifier is:
@@ -312,6 +313,7 @@ def sigdecode_string(signature, order):
312313
:return: tuple with decoded 'r' and 's' values of signature
313314
:rtype: tuple of ints
314315
"""
316+
signature = normalise_bytes(signature)
315317
l = orderlen(order)
316318
if not len(signature) == 2 * l:
317319
raise MalformedSignature(
@@ -347,6 +349,8 @@ def sigdecode_strings(rs_strings, order):
347349
"Invalid number of strings provided: {0}, expected 2"
348350
.format(len(rs_strings)))
349351
(r_str, s_str) = rs_strings
352+
r_str = normalise_bytes(r_str)
353+
s_str = normalise_bytes(s_str)
350354
l = orderlen(order)
351355
if not len(r_str) == l:
352356
raise MalformedSignature(
@@ -388,14 +392,15 @@ def sigdecode_der(sig_der, order):
388392
:return: tuple with decoded 'r' and 's' values of signature
389393
:rtype: tuple of ints
390394
"""
395+
sig_der = normalise_bytes(sig_der)
391396
# return der.encode_sequence(der.encode_integer(r), der.encode_integer(s))
392397
rs_strings, empty = der.remove_sequence(sig_der)
393-
if empty != b(""):
398+
if empty != b"":
394399
raise der.UnexpectedDER("trailing junk after DER sig: %s" %
395400
binascii.hexlify(empty))
396401
r, rest = der.remove_integer(rs_strings)
397402
s, empty = der.remove_integer(rest)
398-
if empty != b(""):
403+
if empty != b"":
399404
raise der.UnexpectedDER("trailing junk after DER numbers: %s" %
400405
binascii.hexlify(empty))
401406
return r, s

0 commit comments

Comments
 (0)