diff --git a/src/ecdsa/ecdh.py b/src/ecdsa/ecdh.py index 824a09b4..7f697d9a 100644 --- a/src/ecdsa/ecdh.py +++ b/src/ecdsa/ecdh.py @@ -116,7 +116,7 @@ def generate_private_key(self): :raises NoCurveError: Curve must be set before key generation. :return: public (verifying) key from this private key. - :rtype: VerifyingKey object + :rtype: VerifyingKey """ if not self.curve: raise NoCurveError("Curve must be set prior to key generation.") @@ -135,7 +135,7 @@ def load_private_key(self, private_key): :raises InvalidCurveError: private_key curve not the same as self.curve :return: public (verifying) key from this private key. - :rtype: VerifyingKey object + :rtype: VerifyingKey """ if not self.curve: self.curve = private_key.curve @@ -158,7 +158,7 @@ def load_private_key_bytes(self, private_key): :raises NoCurveError: Curve must be set before loading. :return: public (verifying) key from this private key. - :rtype: VerifyingKey object + :rtype: VerifyingKey """ if not self.curve: raise NoCurveError("Curve must be set prior to key load.") @@ -183,7 +183,7 @@ def load_private_key_der(self, private_key_der): :raises InvalidCurveError: private_key curve not the same as self.curve :return: public (verifying) key from this private key. - :rtype: VerifyingKey object + :rtype: VerifyingKey """ return self.load_private_key(SigningKey.from_der(private_key_der)) @@ -204,7 +204,7 @@ def load_private_key_pem(self, private_key_pem): :raises InvalidCurveError: private_key curve not the same as self.curve :return: public (verifying) key from this private key. - :rtype: VerifyingKey object + :rtype: VerifyingKey """ return self.load_private_key(SigningKey.from_pem(private_key_pem)) @@ -215,7 +215,7 @@ def get_public_key(self): Needs to be sent to the remote party. :return: public (verifying) key from local private key. - :rtype: VerifyingKey object + :rtype: VerifyingKey """ return self.private_key.get_verifying_key() @@ -310,7 +310,7 @@ def generate_sharedsecret_bytes(self): :raises NoKeyError: public_key or private_key is not set :return: shared secret - :rtype: byte string + :rtype: bytes """ return number_to_string( self.generate_sharedsecret(), self.private_key.curve.curve.p() @@ -323,9 +323,9 @@ def generate_sharedsecret(self): The objects needs to have both private key and received public key before generation is allowed. - It's the same for local and remote party. - shared secret(local private key, remote public key ) == - shared secret (local public key, remote private key) + It's the same for local and remote party, + shared secret(local private key, remote public key) == + shared secret(local public key, remote private key) :raises InvalidCurveError: public_key curve not the same as self.curve :raises NoKeyError: public_key or private_key is not set diff --git a/src/ecdsa/ecdsa.py b/src/ecdsa/ecdsa.py index 1e24c8f8..8dc85031 100644 --- a/src/ecdsa/ecdsa.py +++ b/src/ecdsa/ecdsa.py @@ -1,56 +1,64 @@ #! /usr/bin/env python """ -Implementation of Elliptic-Curve Digital Signatures. +Low level implementation of Elliptic-Curve Digital Signatures. + +.. note :: + You're most likely looking for the :py:class:`~ecdsa.keys` module. + This is a low-level implementation of the ECDSA that operates on + integers, not byte strings. Classes and methods for elliptic-curve signatures: private keys, public keys, signatures, -NIST prime-modulus curves with modulus lengths of -192, 224, 256, 384, and 521 bits. +and definitions of prime-modulus curves. Example: - # (In real-life applications, you would probably want to - # protect against defects in SystemRandom.) - from random import SystemRandom - randrange = SystemRandom().randrange +.. code-block:: python - # Generate a public/private key pair using the NIST Curve P-192: + # (In real-life applications, you would probably want to + # protect against defects in SystemRandom.) + from random import SystemRandom + randrange = SystemRandom().randrange - g = generator_192 - n = g.order() - secret = randrange( 1, n ) - pubkey = Public_key( g, g * secret ) - privkey = Private_key( pubkey, secret ) + # Generate a public/private key pair using the NIST Curve P-192: - # Signing a hash value: + g = generator_192 + n = g.order() + secret = randrange( 1, n ) + pubkey = Public_key( g, g * secret ) + privkey = Private_key( pubkey, secret ) - hash = randrange( 1, n ) - signature = privkey.sign( hash, randrange( 1, n ) ) + # Signing a hash value: - # Verifying a signature for a hash value: + hash = randrange( 1, n ) + signature = privkey.sign( hash, randrange( 1, n ) ) - if pubkey.verifies( hash, signature ): - print_("Demo verification succeeded.") - else: - print_("*** Demo verification failed.") + # Verifying a signature for a hash value: - # Verification fails if the hash value is modified: + if pubkey.verifies( hash, signature ): + print_("Demo verification succeeded.") + else: + print_("*** Demo verification failed.") - if pubkey.verifies( hash-1, signature ): - print_("**** Demo verification failed to reject tampered hash.") - else: - print_("Demo verification correctly rejected tampered hash.") + # Verification fails if the hash value is modified: -Version of 2009.05.16. + if pubkey.verifies( hash-1, signature ): + print_("**** Demo verification failed to reject tampered hash.") + else: + print_("Demo verification correctly rejected tampered hash.") Revision history: 2005.12.31 - Initial version. + 2008.11.25 - Substantial revisions introducing new classes. + 2009.05.16 - Warn against using random.randrange in real applications. + 2009.05.17 - Use random.SystemRandom by default. -Written in 2005 by Peter Pearson and placed in the public domain. +Originally written in 2005 by Peter Pearson and placed in the public domain, +modified as part of the python-ecdsa package. """ from six import int2byte, b @@ -69,16 +77,26 @@ class InvalidPointError(RuntimeError): class Signature(object): - """ECDSA signature.""" + """ + ECDSA signature. + + :ivar int r: the ``r`` element of the ECDSA signature + :ivar int s: the ``s`` element of the ECDSA signature + """ def __init__(self, r, s): self.r = r self.s = s def recover_public_keys(self, hash, generator): - """Returns two public keys for which the signature is valid - hash is signed hash - generator is the used generator of the signature + """ + Returns two public keys for which the signature is valid + + :param int hash: signed hash + :param AbstractPoint generator: is the generator used in creation + of the signature + :rtype: tuple(Public_key, Public_key) + :return: a pair of public keys that can validate the signature """ curve = generator.curve() n = generator.order() diff --git a/src/ecdsa/ellipticcurve.py b/src/ecdsa/ellipticcurve.py index 6d0bc304..b4185789 100644 --- a/src/ecdsa/ellipticcurve.py +++ b/src/ecdsa/ellipticcurve.py @@ -224,7 +224,7 @@ def from_bytes( :param data: single point encoding of the public key :type data: :term:`bytes-like object` :param curve: the curve on which the public key is expected to lay - :type curve: ecdsa.ellipticcurve.CurveFp + :type curve: ~ecdsa.ellipticcurve.CurveFp :param validate_encoding: whether to verify that the encoding of the point is self-consistent, defaults to True, has effect only on ``hybrid`` encoding @@ -235,8 +235,8 @@ def from_bytes( name). All formats by default (specified with ``None``). :type valid_encodings: :term:`set-like object` - :raises MalformedPointError: if the public point does not lay on the - curve or the encoding is invalid + :raises `~ecdsa.errors.MalformedPointError`: if the public point does + not lay on the curve or the encoding is invalid :return: x and y coordinates of the encoded point :rtype: tuple(int, int) @@ -391,7 +391,7 @@ def from_bytes( :param data: single point encoding of the public key :type data: :term:`bytes-like object` :param curve: the curve on which the public key is expected to lay - :type curve: ecdsa.ellipticcurve.CurveFp + :type curve: ~ecdsa.ellipticcurve.CurveFp :param validate_encoding: whether to verify that the encoding of the point is self-consistent, defaults to True, has effect only on ``hybrid`` encoding @@ -407,8 +407,8 @@ def from_bytes( such, it will be commonly used with scalar multiplication. This will cause to precompute multiplication table generation for it - :raises MalformedPointError: if the public point does not lay on the - curve or the encoding is invalid + :raises `~ecdsa.errors.MalformedPointError`: if the public point does + not lay on the curve or the encoding is invalid :return: Point on curve :rtype: PointJacobi @@ -970,7 +970,7 @@ def from_bytes( :param data: single point encoding of the public key :type data: :term:`bytes-like object` :param curve: the curve on which the public key is expected to lay - :type curve: ecdsa.ellipticcurve.CurveFp + :type curve: ~ecdsa.ellipticcurve.CurveFp :param validate_encoding: whether to verify that the encoding of the point is self-consistent, defaults to True, has effect only on ``hybrid`` encoding @@ -983,8 +983,8 @@ def from_bytes( :param int order: the point order, must be non zero when using generator=True - :raises MalformedPointError: if the public point does not lay on the - curve or the encoding is invalid + :raises `~ecdsa.errors.MalformedPointError`: if the public point does + not lay on the curve or the encoding is invalid :return: Point on curve :rtype: Point diff --git a/src/ecdsa/keys.py b/src/ecdsa/keys.py index 29c77d13..ab08a1b1 100644 --- a/src/ecdsa/keys.py +++ b/src/ecdsa/keys.py @@ -58,9 +58,9 @@ bytes-like object All the types that implement the buffer protocol. That includes - ``str`` (only on python2), ``bytes``, ``bytesarray``, ``array.array` + ``str`` (only on python2), ``bytes``, ``bytesarray``, ``array.array`` and ``memoryview`` of those objects. - Please note that ``array.array` serialisation (converting it to byte + Please note that ``array.array`` serialisation (converting it to byte string) is endianess dependant! Signature computed over ``array.array`` of integers on a big-endian system will not be verified on a little-endian system and vice-versa. @@ -159,13 +159,13 @@ class VerifyingKey(object): """ Class for handling keys that can verify signatures (public keys). - :ivar ecdsa.curves.Curve curve: The Curve over which all the cryptographic - operations will take place + :ivar `~ecdsa.curves.Curve` ~.curve: The Curve over which all the + cryptographic operations will take place :ivar default_hashfunc: the function that will be used for hashing the data. Should implement the same API as hashlib.sha1 :vartype default_hashfunc: callable :ivar pubkey: the actual public key - :vartype pubkey: ecdsa.ecdsa.Public_key + :vartype pubkey: ~ecdsa.ecdsa.Public_key """ def __init__(self, _error__please_use_generate=None): @@ -204,13 +204,13 @@ def from_public_point( This is a low-level method, generally you will not want to use it. :param point: The point to wrap around, the actual public key - :type point: ecdsa.ellipticcurve.Point + :type point: ~ecdsa.ellipticcurve.AbstractPoint :param curve: The curve on which the point needs to reside, defaults to NIST192p - :type curve: ecdsa.curves.Curve + :type curve: ~ecdsa.curves.Curve :param hashfunc: The default hash function that will be used for verification, needs to implement the same interface - as hashlib.sha1 + as :py:class:`hashlib.sha1` :type hashfunc: callable :type bool validate_point: whether to check if the point lays on curve should always be used if the public point is not a result @@ -287,7 +287,7 @@ def from_string( :param string: single point encoding of the public key :type string: :term:`bytes-like object` :param curve: the curve on which the public key is expected to lay - :type curve: ecdsa.curves.Curve + :type curve: ~ecdsa.curves.Curve :param hashfunc: The default hash function that will be used for verification, needs to implement the same interface as hashlib.sha1 :type hashfunc: callable @@ -339,7 +339,7 @@ def from_pem( By default :term:`uncompressed`, :term:`compressed`, and :term:`hybrid`. To read malformed files, include :term:`raw encoding` with ``raw`` in the list. - :type valid_encodings: :term:`set-like object + :type valid_encodings: :term:`set-like object` :param valid_curve_encodings: list of allowed encoding formats for curve parameters. By default (``None``) all are supported: ``named_curve`` and ``explicit``. @@ -392,7 +392,7 @@ def from_der( By default :term:`uncompressed`, :term:`compressed`, and :term:`hybrid`. To read malformed files, include :term:`raw encoding` with ``raw`` in the list. - :type valid_encodings: :term:`set-like object + :type valid_encodings: :term:`set-like object` :param valid_curve_encodings: list of allowed encoding formats for curve parameters. By default (``None``) all are supported: ``named_curve`` and ``explicit``. @@ -456,7 +456,7 @@ def from_public_key_recovery( :param data: the data to be hashed for signature verification :type data: bytes-like object :param curve: the curve over which the signature was performed - :type curve: ecdsa.curves.Curve + :type curve: ~ecdsa.curves.Curve :param hashfunc: The default hash function that will be used for verification, needs to implement the same interface as hashlib.sha1 :type hashfunc: callable @@ -506,7 +506,7 @@ def from_public_key_recovery_with_digest( :param digest: the hash value of the message signed by the signature :type digest: bytes-like object :param curve: the curve over which the signature was performed - :type curve: ecdsa.curves.Curve + :type curve: ~ecdsa.curves.Curve :param hashfunc: The default hash function that will be used for verification, needs to implement the same interface as hashlib.sha1 :type hashfunc: callable @@ -740,14 +740,14 @@ class SigningKey(object): """ Class for handling keys that can create signatures (private keys). - :ivar ecdsa.curves.Curve curve: The Curve over which all the cryptographic - operations will take place + :ivar `~ecdsa.curves.Curve` ~.curve: The Curve over which all the + cryptographic operations will take place :ivar default_hashfunc: the function that will be used for hashing the - data. Should implement the same API as hashlib.sha1 + data. Should implement the same API as :py:class:`hashlib.sha1` :ivar int baselen: the length of a :term:`raw encoding` of private key - :ivar ecdsa.keys.VerifyingKey verifying_key: the public key + :ivar `~ecdsa.keys.VerifyingKey` verifying_key: the public key associated with this private key - :ivar ecdsa.ecdsa.Private_key privkey: the actual private key + :ivar `~ecdsa.ecdsa.Private_key` privkey: the actual private key """ def __init__(self, _error__please_use_generate=None): @@ -781,7 +781,7 @@ def generate(cls, curve=NIST192p, entropy=None, hashfunc=sha1): :param curve: The curve on which the point needs to reside, defaults to NIST192p - :type curve: ecdsa.curves.Curve + :type curve: ~ecdsa.curves.Curve :param entropy: Source of randomness for generating the private keys, should provide cryptographically secure random numbers if the keys need to be secure. Uses os.urandom() by default. @@ -808,7 +808,7 @@ def from_secret_exponent(cls, secexp, curve=NIST192p, hashfunc=sha1): :param int secexp: secret multiplier (the actual private key in ECDSA). Needs to be an integer between 1 and the curve order. :param curve: The curve on which the point needs to reside - :type curve: ecdsa.curves.Curve + :type curve: ~ecdsa.curves.Curve :param hashfunc: The default hash function that will be used for signing, needs to implement the same interface as hashlib.sha1 @@ -855,7 +855,7 @@ def from_string(cls, string, curve=NIST192p, hashfunc=sha1): :param string: the raw encoding of the private key :type string: bytes like object :param curve: The curve on which the point needs to reside - :type curve: ecdsa.curves.Curve + :type curve: ~ecdsa.curves.Curve :param hashfunc: The default hash function that will be used for signing, needs to implement the same interface as hashlib.sha1 @@ -959,7 +959,7 @@ def from_der(cls, string, hashfunc=sha1, valid_curve_encodings=None): is part of the PrivateKeyAlgorithmIdentifier. The PKCS #8 format includes an ECPrivateKey object as the `privateKey` - field within a larger structure: + field within a larger structure:: OneAsymmetricKey ::= SEQUENCE { version Version, diff --git a/src/ecdsa/rfc6979.py b/src/ecdsa/rfc6979.py index 1e577c0a..0728b5a4 100644 --- a/src/ecdsa/rfc6979.py +++ b/src/ecdsa/rfc6979.py @@ -42,14 +42,17 @@ def bits2octets(data, order): # https://tools.ietf.org/html/rfc6979#section-3.2 def generate_k(order, secexp, hash_func, data, retry_gen=0, extra_entropy=b""): """ - order - order of the DSA generator used in the signature - secexp - secure exponent (private key) in numeric form - hash_func - reference to the same hash function used for generating - hash - data - hash in binary form of the signing data - retry_gen - int - how many good 'k' values to skip before returning - extra_entropy - extra added data in binary form as per section-3.6 of - rfc6979 + Generate the ``k`` value - the nonce for DSA. + + :param int order: order of the DSA generator used in the signature + :param int secexp: secure exponent (private key) in numeric form + :param hash_func: reference to the same hash function used for generating + hash, like :py:class:`hashlib.sha1` + :param bytes data: hash in binary form of the signing data + :param int retry_gen: how many good 'k' values to skip before returning + :param bytes extra_entropy: additional added data in binary form as per + section-3.6 of rfc6979 + :rtype: int """ qlen = bit_length(order)