Permalink
Browse files

accept default hashfunc in Key constructor, so wrappers are easier to…

… build
  • Loading branch information...
1 parent 51b219e commit 70e3ee7d6bc7c137749c300727d4d5b552773bb7 @warner committed Oct 4, 2011
Showing with 40 additions and 17 deletions.
  1. +20 −15 ecdsa/keys.py
  2. +20 −2 ecdsa/test_pyecdsa.py
View
@@ -19,15 +19,16 @@ def __init__(self, _error__please_use_generate=None):
raise TypeError("Please use SigningKey.generate() to construct me")
@classmethod
- def from_public_point(klass, point, curve=NIST192p):
+ def from_public_point(klass, point, curve=NIST192p, hashfunc=sha1):
self = klass(_error__please_use_generate=True)
self.curve = curve
+ self.default_hashfunc = hashfunc
self.pubkey = ecdsa.Public_key(curve.generator, point)
self.pubkey.order = curve.order
return self
@classmethod
- def from_string(klass, string, curve=NIST192p):
+ def from_string(klass, string, curve=NIST192p, hashfunc=sha1):
order = curve.order
assert len(string) == curve.verifying_key_length, \
(len(string), curve.verifying_key_length)
@@ -40,7 +41,7 @@ def from_string(klass, string, curve=NIST192p):
assert ecdsa.point_is_valid(curve.generator, x, y)
import ellipticcurve
point = ellipticcurve.Point(curve.curve, x, y, order)
- return klass.from_public_point(point, curve)
+ return klass.from_public_point(point, curve, hashfunc)
@classmethod
def from_pem(klass, string):
@@ -90,7 +91,8 @@ def to_der(self):
self.curve.encoded_oid),
der.encode_bitstring(point_str))
- def verify(self, signature, data, hashfunc=sha1, sigdecode=sigdecode_string):
+ def verify(self, signature, data, hashfunc=None, sigdecode=sigdecode_string):
+ hashfunc = hashfunc or self.default_hashfunc
digest = hashfunc(data).digest()
return self.verify_digest(signature, digest, sigdecode)
@@ -112,44 +114,46 @@ def __init__(self, _error__please_use_generate=None):
raise TypeError("Please use SigningKey.generate() to construct me")
@classmethod
- def generate(klass, curve=NIST192p, entropy=None):
+ def generate(klass, curve=NIST192p, entropy=None, hashfunc=sha1):
secexp = randrange(curve.order, entropy)
- return klass.from_secret_exponent(secexp, curve)
+ return klass.from_secret_exponent(secexp, curve, hashfunc)
# to create a signing key from a short (arbitrary-length) seed, convert
# that seed into an integer with something like
# secexp=util.randrange_from_seed__X(seed, curve.order), and then pass
# that integer into SigningKey.from_secret_exponent(secexp, curve)
@classmethod
- def from_secret_exponent(klass, secexp, curve=NIST192p):
+ def from_secret_exponent(klass, secexp, curve=NIST192p, hashfunc=sha1):
self = klass(_error__please_use_generate=True)
self.curve = curve
+ self.default_hashfunc = hashfunc
self.baselen = curve.baselen
n = curve.order
assert 1 <= secexp < n
pubkey_point = curve.generator*secexp
pubkey = ecdsa.Public_key(curve.generator, pubkey_point)
pubkey.order = n
- self.verifying_key = VerifyingKey.from_public_point(pubkey_point, curve)
+ self.verifying_key = VerifyingKey.from_public_point(pubkey_point, curve,
+ hashfunc)
self.privkey = ecdsa.Private_key(pubkey, secexp)
self.privkey.order = n
return self
@classmethod
- def from_string(klass, string, curve=NIST192p):
+ def from_string(klass, string, curve=NIST192p, hashfunc=sha1):
assert len(string) == curve.baselen, (len(string), curve.baselen)
secexp = string_to_number(string)
- return klass.from_secret_exponent(secexp, curve)
+ return klass.from_secret_exponent(secexp, curve, hashfunc)
@classmethod
- def from_pem(klass, string):
+ def from_pem(klass, string, hashfunc=sha1):
# the privkey pem file has two sections: "EC PARAMETERS" and "EC
# PRIVATE KEY". The first is redundant.
privkey_pem = string[string.index("-----BEGIN EC PRIVATE KEY-----"):]
- return klass.from_der(der.unpem(privkey_pem))
+ return klass.from_der(der.unpem(privkey_pem), hashfunc)
@classmethod
- def from_der(klass, string):
+ def from_der(klass, string, hashfunc=sha1):
# SEQ([int(1), octetstring(privkey),cont[0], oid(secp224r1),
# cont[1],bitstring])
s, empty = der.remove_sequence(string)
@@ -185,7 +189,7 @@ def from_der(klass, string):
# our from_string method likes fixed-length privkey strings
if len(privkey_str) < curve.baselen:
privkey_str = "\x00"*(curve.baselen-len(privkey_str)) + privkey_str
- return klass.from_string(privkey_str, curve)
+ return klass.from_string(privkey_str, curve, hashfunc)
def to_string(self):
secexp = self.privkey.secret_multiplier
@@ -209,7 +213,7 @@ def to_der(self):
def get_verifying_key(self):
return self.verifying_key
- def sign(self, data, entropy=None, hashfunc=sha1, sigencode=sigencode_string):
+ def sign(self, data, entropy=None, hashfunc=None, sigencode=sigencode_string):
"""
hashfunc= should behave like hashlib.sha1 . The output length of the
hash (in bytes) must not be longer than the length of the curve order
@@ -222,6 +226,7 @@ def sign(self, data, entropy=None, hashfunc=sha1, sigencode=sigencode_string):
or hashfunc=hashlib.sha256 for openssl-1.0.0's -ecdsa-with-SHA256.
"""
+ hashfunc = hashfunc or self.default_hashfunc
h = hashfunc(data).digest()
return self.sign_digest(h, entropy, sigencode)
View
@@ -4,7 +4,7 @@
import shutil
import subprocess
from binascii import hexlify, unhexlify
-from hashlib import sha1
+from hashlib import sha1, sha256
from keys import SigningKey, VerifyingKey
from keys import BadSignatureError
@@ -253,7 +253,25 @@ def test_signature_strings(self):
sig_der = priv1.sign(data, sigencode=sigencode_der)
self.failUnlessEqual(type(sig_der), str)
self.failUnless(pub1.verify(sig_der, data, sigdecode=sigdecode_der))
-
+
+ def test_hashfunc(self):
+ sk = SigningKey.generate(curve=NIST256p, hashfunc=sha256)
+ data = "security level is 128 bits"
+ sig = sk.sign(data)
+ vk = VerifyingKey.from_string(sk.get_verifying_key().to_string(),
+ curve=NIST256p, hashfunc=sha256)
+ self.failUnless(vk.verify(sig, data))
+
+ sk2 = SigningKey.generate(curve=NIST256p)
+ sig2 = sk2.sign(data, hashfunc=sha256)
+ vk2 = VerifyingKey.from_string(sk2.get_verifying_key().to_string(),
+ curve=NIST256p, hashfunc=sha256)
+ self.failUnless(vk2.verify(sig2, data))
+
+ vk3 = VerifyingKey.from_string(sk.get_verifying_key().to_string(),
+ curve=NIST256p)
+ self.failUnless(vk3.verify(sig, data, hashfunc=sha256))
+
class OpenSSL(unittest.TestCase):
# test interoperability with OpenSSL tools. Note that openssl's ECDSA

0 comments on commit 70e3ee7

Please sign in to comment.