summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHubert Kario <hkario@redhat.com>2023-03-02 16:20:45 +0100
committerGitHub <noreply@github.com>2023-03-02 16:20:45 +0100
commit2457dc7c9b7337edcb868a323c5b648a32da2b8c (patch)
tree70df67fabd47999a946451ee2d68a5645d8653d8
parent31039b4950e1b6be2b41744ce452653ab62c0d10 (diff)
parent98312f650ed8f5186230a66355f733b043e11b93 (diff)
downloadecdsa-master.tar.gz
Merge pull request #317 from tlsfuzzer/more-docsHEADmaster
More tests and docs
-rw-r--r--src/ecdsa/test_malformed_sigs.py2
-rw-r--r--src/ecdsa/test_pyecdsa.py82
-rw-r--r--src/ecdsa/util.py122
3 files changed, 185 insertions, 21 deletions
diff --git a/src/ecdsa/test_malformed_sigs.py b/src/ecdsa/test_malformed_sigs.py
index 6db0176..2091237 100644
--- a/src/ecdsa/test_malformed_sigs.py
+++ b/src/ecdsa/test_malformed_sigs.py
@@ -282,7 +282,7 @@ def st_der():
of a valid DER structure, sequence of valid DER objects or a constructed
encoding of any of the above.
"""
- return st.recursive(
+ return st.recursive( # pragma: no branch
st.just(b"")
| st_der_integer(max_value=2**4096)
| st_der_bit_string(max_size=1024**2)
diff --git a/src/ecdsa/test_pyecdsa.py b/src/ecdsa/test_pyecdsa.py
index b250677..fc7e64f 100644
--- a/src/ecdsa/test_pyecdsa.py
+++ b/src/ecdsa/test_pyecdsa.py
@@ -20,8 +20,14 @@ from six import b, print_, binary_type
from .keys import SigningKey, VerifyingKey
from .keys import BadSignatureError, MalformedPointError, BadDigestError
from . import util
-from .util import sigencode_der, sigencode_strings
-from .util import sigdecode_der, sigdecode_strings
+from .util import (
+ sigencode_der,
+ sigencode_strings,
+ sigencode_strings_canonize,
+ sigencode_string_canonize,
+ sigencode_der_canonize,
+)
+from .util import sigdecode_der, sigdecode_strings, sigdecode_string
from .util import number_to_string, encoded_oid_ecPublicKey, MalformedSignature
from .curves import Curve, UnknownCurveError
from .curves import (
@@ -451,6 +457,78 @@ class ECDSA(unittest.TestCase):
self.assertEqual(type(sig_der), binary_type)
self.assertTrue(pub1.verify(sig_der, data, sigdecode=sigdecode_der))
+ def test_sigencode_string_canonize_no_change(self):
+ r = 12
+ s = 400
+ order = SECP112r1.order
+
+ new_r, new_s = sigdecode_string(
+ sigencode_string_canonize(r, s, order), order
+ )
+
+ self.assertEqual(r, new_r)
+ self.assertEqual(s, new_s)
+
+ def test_sigencode_string_canonize(self):
+ r = 12
+ order = SECP112r1.order
+ s = order - 10
+
+ new_r, new_s = sigdecode_string(
+ sigencode_string_canonize(r, s, order), order
+ )
+
+ self.assertEqual(r, new_r)
+ self.assertEqual(order - s, new_s)
+
+ def test_sigencode_strings_canonize_no_change(self):
+ r = 12
+ s = 400
+ order = SECP112r1.order
+
+ new_r, new_s = sigdecode_strings(
+ sigencode_strings_canonize(r, s, order), order
+ )
+
+ self.assertEqual(r, new_r)
+ self.assertEqual(s, new_s)
+
+ def test_sigencode_strings_canonize(self):
+ r = 12
+ order = SECP112r1.order
+ s = order - 10
+
+ new_r, new_s = sigdecode_strings(
+ sigencode_strings_canonize(r, s, order), order
+ )
+
+ self.assertEqual(r, new_r)
+ self.assertEqual(order - s, new_s)
+
+ def test_sigencode_der_canonize_no_change(self):
+ r = 13
+ s = 200
+ order = SECP112r1.order
+
+ new_r, new_s = sigdecode_der(
+ sigencode_der_canonize(r, s, order), order
+ )
+
+ self.assertEqual(r, new_r)
+ self.assertEqual(s, new_s)
+
+ def test_sigencode_der_canonize(self):
+ r = 13
+ order = SECP112r1.order
+ s = order - 14
+
+ new_r, new_s = sigdecode_der(
+ sigencode_der_canonize(r, s, order), order
+ )
+
+ self.assertEqual(r, new_r)
+ self.assertEqual(order - s, new_s)
+
def test_sig_decode_strings_with_invalid_count(self):
with self.assertRaises(MalformedSignature):
sigdecode_strings([b("one"), b("two"), b("three")], 0xFF)
diff --git a/src/ecdsa/util.py b/src/ecdsa/util.py
index 9a56110..2477f7e 100644
--- a/src/ecdsa/util.py
+++ b/src/ecdsa/util.py
@@ -1,3 +1,16 @@
+"""
+This module includes some utility functions.
+
+The methods most typically used are the sigencode and sigdecode functions
+to be used with :func:`~ecdsa.keys.SigningKey.sign` and
+:func:`~ecdsa.keys.VerifyingKey.verify`
+respectively. See the :func:`sigencode_strings`, :func:`sigdecode_string`,
+:func:`sigencode_der`, :func:`sigencode_strings_canonize`,
+:func:`sigencode_string_canonize`, :func:`sigencode_der_canonize`,
+:func:`sigdecode_strings`, :func:`sigdecode_string`, and
+:func:`sigdecode_der` functions.
+"""
+
from __future__ import division
import os
@@ -9,6 +22,7 @@ from six import PY2, int2byte, b, next
from . import der
from ._compat import normalise_bytes
+
# RFC5480:
# The "unrestricted" algorithm identifier is:
# id-ecPublicKey OBJECT IDENTIFIER ::= {
@@ -221,12 +235,24 @@ def string_to_number_fixedlen(string, order):
return int(binascii.hexlify(string), 16)
-# these methods are useful for the sigencode= argument to SK.sign() and the
-# sigdecode= argument to VK.verify(), and control how the signature is packed
-# or unpacked.
+def sigencode_strings(r, s, order):
+ """
+ Encode the signature to a pair of strings in a tuple
+
+ Encodes signature into raw encoding (:term:`raw encoding`) with the
+ ``r`` and ``s`` parts of the signature encoded separately.
+ It's expected that this function will be used as a ``sigencode=`` parameter
+ in :func:`ecdsa.keys.SigningKey.sign` method.
-def sigencode_strings(r, s, order):
+ :param int r: first parameter of the signature
+ :param int s: second parameter of the signature
+ :param int order: the order of the curve over which the signature was
+ computed
+
+ :return: raw encoding of ECDSA signature
+ :rtype: tuple(bytes, bytes)
+ """
r_str = number_to_string(r, order)
s_str = number_to_string(s, order)
return (r_str, s_str)
@@ -236,7 +262,7 @@ def sigencode_string(r, s, order):
"""
Encode the signature to raw format (:term:`raw encoding`)
- It's expected that this function will be used as a `sigencode=` parameter
+ It's expected that this function will be used as a ``sigencode=`` parameter
in :func:`ecdsa.keys.SigningKey.sign` method.
:param int r: first parameter of the signature
@@ -264,7 +290,7 @@ def sigencode_der(r, s, order):
s INTEGER
}
- It's expected that this function will be used as a `sigencode=` parameter
+ It's expected that this function will be used as a ``sigencode=`` parameter
in :func:`ecdsa.keys.SigningKey.sign` method.
:param int r: first parameter of the signature
@@ -278,23 +304,83 @@ def sigencode_der(r, s, order):
return der.encode_sequence(der.encode_integer(r), der.encode_integer(s))
-# canonical versions of sigencode methods
-# these enforce low S values, by negating the value (modulo the order) if
-# above order/2 see CECKey::Sign()
-# https://github.com/bitcoin/bitcoin/blob/master/src/key.cpp#L214
def sigencode_strings_canonize(r, s, order):
+ """
+ Encode the signature to a pair of strings in a tuple
+
+ Encodes signature into raw encoding (:term:`raw encoding`) with the
+ ``r`` and ``s`` parts of the signature encoded separately.
+
+ Makes sure that the signature is encoded in the canonical format, where
+ the ``s`` parameter is always smaller than ``order / 2``.
+ Most commonly used in bitcoin.
+
+ It's expected that this function will be used as a ``sigencode=`` parameter
+ in :func:`ecdsa.keys.SigningKey.sign` method.
+
+ :param int r: first parameter of the signature
+ :param int s: second parameter of the signature
+ :param int order: the order of the curve over which the signature was
+ computed
+
+ :return: raw encoding of ECDSA signature
+ :rtype: tuple(bytes, bytes)
+ """
if s > order / 2:
s = order - s
return sigencode_strings(r, s, order)
def sigencode_string_canonize(r, s, order):
+ """
+ Encode the signature to raw format (:term:`raw encoding`)
+
+ Makes sure that the signature is encoded in the canonical format, where
+ the ``s`` parameter is always smaller than ``order / 2``.
+ Most commonly used in bitcoin.
+
+ It's expected that this function will be used as a ``sigencode=`` parameter
+ in :func:`ecdsa.keys.SigningKey.sign` method.
+
+ :param int r: first parameter of the signature
+ :param int s: second parameter of the signature
+ :param int order: the order of the curve over which the signature was
+ computed
+
+ :return: raw encoding of ECDSA signature
+ :rtype: bytes
+ """
if s > order / 2:
s = order - s
return sigencode_string(r, s, order)
def sigencode_der_canonize(r, s, order):
+ """
+ Encode the signature into the ECDSA-Sig-Value structure using :term:`DER`.
+
+ Makes sure that the signature is encoded in the canonical format, where
+ the ``s`` parameter is always smaller than ``order / 2``.
+ Most commonly used in bitcoin.
+
+ Encodes the signature to the following :term:`ASN.1` structure::
+
+ Ecdsa-Sig-Value ::= SEQUENCE {
+ r INTEGER,
+ s INTEGER
+ }
+
+ It's expected that this function will be used as a ``sigencode=`` parameter
+ in :func:`ecdsa.keys.SigningKey.sign` method.
+
+ :param int r: first parameter of the signature
+ :param int s: second parameter of the signature
+ :param int order: the order of the curve over which the signature was
+ computed
+
+ :return: DER encoding of ECDSA signature
+ :rtype: bytes
+ """
if s > order / 2:
s = order - s
return sigencode_der(r, s, order)
@@ -321,7 +407,7 @@ def sigdecode_string(signature, order):
the signature, with each encoded using the same amount of bytes depending
on curve size/order.
- It's expected that this function will be used as the `sigdecode=`
+ It's expected that this function will be used as the ``sigdecode=``
parameter to the :func:`ecdsa.keys.VerifyingKey.verify` method.
:param signature: encoded signature
@@ -331,7 +417,7 @@ def sigdecode_string(signature, order):
:raises MalformedSignature: when the encoding of the signature is invalid
- :return: tuple with decoded 'r' and 's' values of signature
+ :return: tuple with decoded ``r`` and ``s`` values of signature
:rtype: tuple of ints
"""
signature = normalise_bytes(signature)
@@ -350,10 +436,10 @@ def sigdecode_strings(rs_strings, order):
"""
Decode the signature from two strings.
- First string needs to be a big endian encoding of 'r', second needs to
- be a big endian encoding of the 's' parameter of an ECDSA signature.
+ First string needs to be a big endian encoding of ``r``, second needs to
+ be a big endian encoding of the ``s`` parameter of an ECDSA signature.
- It's expected that this function will be used as the `sigdecode=`
+ It's expected that this function will be used as the ``sigdecode=``
parameter to the :func:`ecdsa.keys.VerifyingKey.verify` method.
:param list rs_strings: list of two bytes-like objects, each encoding one
@@ -362,7 +448,7 @@ def sigdecode_strings(rs_strings, order):
:raises MalformedSignature: when the encoding of the signature is invalid
- :return: tuple with decoded 'r' and 's' values of signature
+ :return: tuple with decoded ``r`` and ``s`` values of signature
:rtype: tuple of ints
"""
if not len(rs_strings) == 2:
@@ -404,7 +490,7 @@ def sigdecode_der(sig_der, order):
s INTEGER
}
- It's expected that this function will be used as as the `sigdecode=`
+ It's expected that this function will be used as as the ``sigdecode=``
parameter to the :func:`ecdsa.keys.VerifyingKey.verify` method.
:param sig_der: encoded signature
@@ -414,7 +500,7 @@ def sigdecode_der(sig_der, order):
:raises UnexpectedDER: when the encoding of signature is invalid
- :return: tuple with decoded 'r' and 's' values of signature
+ :return: tuple with decoded ``r`` and ``s`` values of signature
:rtype: tuple of ints
"""
sig_der = normalise_bytes(sig_der)