• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tlsfuzzer / python-ecdsa / 13832902924

13 Mar 2025 10:54AM UTC coverage: 99.579% (+0.001%) from 99.578%
13832902924

Pull #359

github

web-flow
Merge 658ddc81b into 3c5df06ae
Pull Request #359: add release notes for 0.19.1 release

2560 of 2571 branches covered (99.57%)

Branch coverage included in aggregate %.

6663 of 6691 relevant lines covered (99.58%)

19.18 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

87.74
/src/ecdsa/util.py
1
"""
2
This module includes some utility functions.
3

4
The methods most typically used are the sigencode and sigdecode functions
5
to be used with :func:`~ecdsa.keys.SigningKey.sign` and
6
:func:`~ecdsa.keys.VerifyingKey.verify`
7
respectively. See the :func:`sigencode_strings`, :func:`sigdecode_string`,
8
:func:`sigencode_der`, :func:`sigencode_strings_canonize`,
9
:func:`sigencode_string_canonize`, :func:`sigencode_der_canonize`,
10
:func:`sigdecode_strings`, :func:`sigdecode_string`, and
11
:func:`sigdecode_der` functions.
12
"""
13

14
from __future__ import division
20✔
15

16
import os
20✔
17
import math
20✔
18
import binascii
20✔
19
import sys
20✔
20
from hashlib import sha256
20✔
21
from six import PY2, int2byte, next
20✔
22
from . import der
20✔
23
from ._compat import normalise_bytes
20✔
24

25

26
# RFC5480:
27
#   The "unrestricted" algorithm identifier is:
28
#     id-ecPublicKey OBJECT IDENTIFIER ::= {
29
#       iso(1) member-body(2) us(840) ansi-X9-62(10045) keyType(2) 1 }
30

31
oid_ecPublicKey = (1, 2, 840, 10045, 2, 1)
20✔
32
encoded_oid_ecPublicKey = der.encode_oid(*oid_ecPublicKey)
20✔
33

34
# RFC5480:
35
# The ECDH algorithm uses the following object identifier:
36
#      id-ecDH OBJECT IDENTIFIER ::= {
37
#        iso(1) identified-organization(3) certicom(132) schemes(1)
38
#        ecdh(12) }
39

40
oid_ecDH = (1, 3, 132, 1, 12)
20✔
41

42
# RFC5480:
43
# The ECMQV algorithm uses the following object identifier:
44
#      id-ecMQV OBJECT IDENTIFIER ::= {
45
#        iso(1) identified-organization(3) certicom(132) schemes(1)
46
#        ecmqv(13) }
47

48
oid_ecMQV = (1, 3, 132, 1, 13)
20✔
49

50
if sys.version_info >= (3,):  # pragma: no branch
20✔
51

52
    def entropy_to_bits(ent_256):
12✔
53
        """Convert a bytestring to string of 0's and 1's"""
54
        return bin(int.from_bytes(ent_256, "big"))[2:].zfill(len(ent_256) * 8)
12✔
55

56
else:
57

58
    def entropy_to_bits(ent_256):
8✔
59
        """Convert a bytestring to string of 0's and 1's"""
60
        return "".join(bin(ord(x))[2:].zfill(8) for x in ent_256)
8✔
61

62

63
if sys.version_info < (2, 7):  # pragma: no branch
20✔
64
    # Can't add a method to a built-in type so we are stuck with this
65
    def bit_length(x):
1✔
66
        return len(bin(x)) - 2
1✔
67

68
else:
69

70
    def bit_length(x):
19✔
71
        return x.bit_length() or 1
19✔
72

73

74
def orderlen(order):
20✔
75
    return (1 + len("%x" % order)) // 2  # bytes
20✔
76

77

78
def randrange(order, entropy=None):
20✔
79
    """Return a random integer k such that 1 <= k < order, uniformly
80
    distributed across that range. Worst case should be a mean of 2 loops at
81
    (2**k)+2.
82

83
    Note that this function is not declared to be forwards-compatible: we may
84
    change the behavior in future releases. The entropy= argument (which
85
    should get a callable that behaves like os.urandom) can be used to
86
    achieve stability within a given release (for repeatable unit tests), but
87
    should not be used as a long-term-compatible key generation algorithm.
88
    """
89
    assert order > 1
20✔
90
    if entropy is None:
20✔
91
        entropy = os.urandom
20✔
92
    upper_2 = bit_length(order - 2)
20✔
93
    upper_256 = upper_2 // 8 + 1
20✔
94
    while True:  # I don't think this needs a counter with bit-wise randrange
18✔
95
        ent_256 = entropy(upper_256)
20✔
96
        ent_2 = entropy_to_bits(ent_256)
20✔
97
        rand_num = int(ent_2[:upper_2], base=2) + 1
20✔
98
        if 0 < rand_num < order:
20✔
99
            return rand_num
20✔
100

101

102
class PRNG:
20✔
103
    # this returns a callable which, when invoked with an integer N, will
104
    # return N pseudorandom bytes. Note: this is a short-term PRNG, meant
105
    # primarily for the needs of randrange_from_seed__trytryagain(), which
106
    # only needs to run it a few times per seed. It does not provide
107
    # protection against state compromise (forward security).
108
    def __init__(self, seed):
20✔
109
        self.generator = self.block_generator(seed)
20✔
110

111
    def __call__(self, numbytes):
20✔
112
        a = [next(self.generator) for i in range(numbytes)]
20✔
113

114
        if PY2:  # pragma: no branch
20✔
115
            return "".join(a)
8✔
116
        else:
117
            return bytes(a)
12✔
118

119
    def block_generator(self, seed):
20✔
120
        counter = 0
20✔
121
        while True:
18✔
122
            for byte in sha256(
20✔
123
                ("prng-%d-%s" % (counter, seed)).encode()
124
            ).digest():
125
                yield byte
20✔
126
            counter += 1
20✔
127

128

129
def randrange_from_seed__overshoot_modulo(seed, order):
20✔
130
    # hash the data, then turn the digest into a number in [1,order).
131
    #
132
    # We use David-Sarah Hopwood's suggestion: turn it into a number that's
133
    # sufficiently larger than the group order, then modulo it down to fit.
134
    # This should give adequate (but not perfect) uniformity, and simple
135
    # code. There are other choices: try-try-again is the main one.
136
    base = PRNG(seed)(2 * orderlen(order))
×
137
    number = (int(binascii.hexlify(base), 16) % (order - 1)) + 1
×
138
    assert 1 <= number < order, (1, number, order)
×
139
    return number
×
140

141

142
def lsb_of_ones(numbits):
20✔
143
    return (1 << numbits) - 1
20✔
144

145

146
def bits_and_bytes(order):
20✔
147
    bits = int(math.log(order - 1, 2) + 1)
20✔
148
    bytes = bits // 8
20✔
149
    extrabits = bits % 8
20✔
150
    return bits, bytes, extrabits
20✔
151

152

153
# the following randrange_from_seed__METHOD() functions take an
154
# arbitrarily-sized secret seed and turn it into a number that obeys the same
155
# range limits as randrange() above. They are meant for deriving consistent
156
# signing keys from a secret rather than generating them randomly, for
157
# example a protocol in which three signing keys are derived from a master
158
# secret. You should use a uniformly-distributed unguessable seed with about
159
# curve.baselen bytes of entropy. To use one, do this:
160
#   seed = os.urandom(curve.baselen) # or other starting point
161
#   secexp = ecdsa.util.randrange_from_seed__trytryagain(sed, curve.order)
162
#   sk = SigningKey.from_secret_exponent(secexp, curve)
163

164

165
def randrange_from_seed__truncate_bytes(seed, order, hashmod=sha256):
20✔
166
    # hash the seed, then turn the digest into a number in [1,order), but
167
    # don't worry about trying to uniformly fill the range. This will lose,
168
    # on average, four bits of entropy.
169
    bits, _bytes, extrabits = bits_and_bytes(order)
×
170
    if extrabits:
×
171
        _bytes += 1
×
172
    base = hashmod(seed).digest()[:_bytes]
×
173
    base = "\x00" * (_bytes - len(base)) + base
×
174
    number = 1 + int(binascii.hexlify(base), 16)
×
175
    assert 1 <= number < order
×
176
    return number
×
177

178

179
def randrange_from_seed__truncate_bits(seed, order, hashmod=sha256):
20✔
180
    # like string_to_randrange_truncate_bytes, but only lose an average of
181
    # half a bit
182
    bits = int(math.log(order - 1, 2) + 1)
×
183
    maxbytes = (bits + 7) // 8
×
184
    base = hashmod(seed).digest()[:maxbytes]
×
185
    base = "\x00" * (maxbytes - len(base)) + base
×
186
    topbits = 8 * maxbytes - bits
×
187
    if topbits:
×
188
        base = int2byte(ord(base[0]) & lsb_of_ones(topbits)) + base[1:]
×
189
    number = 1 + int(binascii.hexlify(base), 16)
×
190
    assert 1 <= number < order
×
191
    return number
×
192

193

194
def randrange_from_seed__trytryagain(seed, order):
20✔
195
    # figure out exactly how many bits we need (rounded up to the nearest
196
    # bit), so we can reduce the chance of looping to less than 0.5 . This is
197
    # specified to feed from a byte-oriented PRNG, and discards the
198
    # high-order bits of the first byte as necessary to get the right number
199
    # of bits. The average number of loops will range from 1.0 (when
200
    # order=2**k-1) to 2.0 (when order=2**k+1).
201
    assert order > 1
20✔
202
    bits, bytes, extrabits = bits_and_bytes(order)
20✔
203
    generate = PRNG(seed)
20✔
204
    while True:
18✔
205
        extrabyte = b""
20✔
206
        if extrabits:
20✔
207
            extrabyte = int2byte(ord(generate(1)) & lsb_of_ones(extrabits))
20✔
208
        guess = string_to_number(extrabyte + generate(bytes)) + 1
20✔
209
        if 1 <= guess < order:
20✔
210
            return guess
20✔
211

212

213
def number_to_string(num, order):
20✔
214
    l = orderlen(order)
20✔
215
    fmt_str = "%0" + str(2 * l) + "x"
20✔
216
    string = binascii.unhexlify((fmt_str % num).encode())
20✔
217
    assert len(string) == l, (len(string), l)
20✔
218
    return string
20✔
219

220

221
def number_to_string_crop(num, order):
20✔
222
    l = orderlen(order)
20✔
223
    fmt_str = "%0" + str(2 * l) + "x"
20✔
224
    string = binascii.unhexlify((fmt_str % num).encode())
20✔
225
    return string[:l]
20✔
226

227

228
def string_to_number(string):
20✔
229
    return int(binascii.hexlify(string), 16)
20✔
230

231

232
def string_to_number_fixedlen(string, order):
20✔
233
    l = orderlen(order)
20✔
234
    assert len(string) == l, (len(string), l)
20✔
235
    return int(binascii.hexlify(string), 16)
20✔
236

237

238
def sigencode_strings(r, s, order):
20✔
239
    """
240
    Encode the signature to a pair of strings in a tuple
241

242
    Encodes signature into raw encoding (:term:`raw encoding`) with the
243
    ``r`` and ``s`` parts of the signature encoded separately.
244

245
    It's expected that this function will be used as a ``sigencode=`` parameter
246
    in :func:`ecdsa.keys.SigningKey.sign` method.
247

248
    :param int r: first parameter of the signature
249
    :param int s: second parameter of the signature
250
    :param int order: the order of the curve over which the signature was
251
        computed
252

253
    :return: raw encoding of ECDSA signature
254
    :rtype: tuple(bytes, bytes)
255
    """
256
    r_str = number_to_string(r, order)
20✔
257
    s_str = number_to_string(s, order)
20✔
258
    return (r_str, s_str)
20✔
259

260

261
def sigencode_string(r, s, order):
20✔
262
    """
263
    Encode the signature to raw format (:term:`raw encoding`)
264

265
    It's expected that this function will be used as a ``sigencode=`` parameter
266
    in :func:`ecdsa.keys.SigningKey.sign` method.
267

268
    :param int r: first parameter of the signature
269
    :param int s: second parameter of the signature
270
    :param int order: the order of the curve over which the signature was
271
        computed
272

273
    :return: raw encoding of ECDSA signature
274
    :rtype: bytes
275
    """
276
    # for any given curve, the size of the signature numbers is
277
    # fixed, so just use simple concatenation
278
    r_str, s_str = sigencode_strings(r, s, order)
20✔
279
    return r_str + s_str
20✔
280

281

282
def sigencode_der(r, s, order):
20✔
283
    """
284
    Encode the signature into the ECDSA-Sig-Value structure using :term:`DER`.
285

286
    Encodes the signature to the following :term:`ASN.1` structure::
287

288
        Ecdsa-Sig-Value ::= SEQUENCE {
289
            r       INTEGER,
290
            s       INTEGER
291
        }
292

293
    It's expected that this function will be used as a ``sigencode=`` parameter
294
    in :func:`ecdsa.keys.SigningKey.sign` method.
295

296
    :param int r: first parameter of the signature
297
    :param int s: second parameter of the signature
298
    :param int order: the order of the curve over which the signature was
299
        computed
300

301
    :return: DER encoding of ECDSA signature
302
    :rtype: bytes
303
    """
304
    return der.encode_sequence(der.encode_integer(r), der.encode_integer(s))
20✔
305

306

307
def _canonize(s, order):
20✔
308
    """
309
    Internal function for ensuring that the ``s`` value of a signature is in
310
    the "canonical" format.
311

312
    :param int s: the second parameter of ECDSA signature
313
    :param int order: the order of the curve over which the signatures was
314
        computed
315

316
    :return: canonical value of s
317
    :rtype: int
318
    """
319
    if s > order // 2:
20✔
320
        s = order - s
20✔
321
    return s
20✔
322

323

324
def sigencode_strings_canonize(r, s, order):
20✔
325
    """
326
    Encode the signature to a pair of strings in a tuple
327

328
    Encodes signature into raw encoding (:term:`raw encoding`) with the
329
    ``r`` and ``s`` parts of the signature encoded separately.
330

331
    Makes sure that the signature is encoded in the canonical format, where
332
    the ``s`` parameter is always smaller than ``order / 2``.
333
    Most commonly used in bitcoin.
334

335
    It's expected that this function will be used as a ``sigencode=`` parameter
336
    in :func:`ecdsa.keys.SigningKey.sign` method.
337

338
    :param int r: first parameter of the signature
339
    :param int s: second parameter of the signature
340
    :param int order: the order of the curve over which the signature was
341
        computed
342

343
    :return: raw encoding of ECDSA signature
344
    :rtype: tuple(bytes, bytes)
345
    """
346
    s = _canonize(s, order)
20✔
347
    return sigencode_strings(r, s, order)
20✔
348

349

350
def sigencode_string_canonize(r, s, order):
20✔
351
    """
352
    Encode the signature to raw format (:term:`raw encoding`)
353

354
    Makes sure that the signature is encoded in the canonical format, where
355
    the ``s`` parameter is always smaller than ``order / 2``.
356
    Most commonly used in bitcoin.
357

358
    It's expected that this function will be used as a ``sigencode=`` parameter
359
    in :func:`ecdsa.keys.SigningKey.sign` method.
360

361
    :param int r: first parameter of the signature
362
    :param int s: second parameter of the signature
363
    :param int order: the order of the curve over which the signature was
364
        computed
365

366
    :return: raw encoding of ECDSA signature
367
    :rtype: bytes
368
    """
369
    s = _canonize(s, order)
20✔
370
    return sigencode_string(r, s, order)
20✔
371

372

373
def sigencode_der_canonize(r, s, order):
20✔
374
    """
375
    Encode the signature into the ECDSA-Sig-Value structure using :term:`DER`.
376

377
    Makes sure that the signature is encoded in the canonical format, where
378
    the ``s`` parameter is always smaller than ``order / 2``.
379
    Most commonly used in bitcoin.
380

381
    Encodes the signature to the following :term:`ASN.1` structure::
382

383
        Ecdsa-Sig-Value ::= SEQUENCE {
384
            r       INTEGER,
385
            s       INTEGER
386
        }
387

388
    It's expected that this function will be used as a ``sigencode=`` parameter
389
    in :func:`ecdsa.keys.SigningKey.sign` method.
390

391
    :param int r: first parameter of the signature
392
    :param int s: second parameter of the signature
393
    :param int order: the order of the curve over which the signature was
394
        computed
395

396
    :return: DER encoding of ECDSA signature
397
    :rtype: bytes
398
    """
399
    s = _canonize(s, order)
20✔
400
    return sigencode_der(r, s, order)
20✔
401

402

403
class MalformedSignature(Exception):
20✔
404
    """
405
    Raised by decoding functions when the signature is malformed.
406

407
    Malformed in this context means that the relevant strings or integers
408
    do not match what a signature over provided curve would create. Either
409
    because the byte strings have incorrect lengths or because the encoded
410
    values are too large.
411
    """
412

413
    pass
20✔
414

415

416
def sigdecode_string(signature, order):
20✔
417
    """
418
    Decoder for :term:`raw encoding`  of ECDSA signatures.
419

420
    raw encoding is a simple concatenation of the two integers that comprise
421
    the signature, with each encoded using the same amount of bytes depending
422
    on curve size/order.
423

424
    It's expected that this function will be used as the ``sigdecode=``
425
    parameter to the :func:`ecdsa.keys.VerifyingKey.verify` method.
426

427
    :param signature: encoded signature
428
    :type signature: bytes like object
429
    :param order: order of the curve over which the signature was computed
430
    :type order: int
431

432
    :raises MalformedSignature: when the encoding of the signature is invalid
433

434
    :return: tuple with decoded ``r`` and ``s`` values of signature
435
    :rtype: tuple of ints
436
    """
437
    signature = normalise_bytes(signature)
20✔
438
    l = orderlen(order)
20✔
439
    if not len(signature) == 2 * l:
20✔
440
        raise MalformedSignature(
20✔
441
            "Invalid length of signature, expected {0} bytes long, "
442
            "provided string is {1} bytes long".format(2 * l, len(signature))
443
        )
444
    r = string_to_number_fixedlen(signature[:l], order)
20✔
445
    s = string_to_number_fixedlen(signature[l:], order)
20✔
446
    return r, s
20✔
447

448

449
def sigdecode_strings(rs_strings, order):
20✔
450
    """
451
    Decode the signature from two strings.
452

453
    First string needs to be a big endian encoding of ``r``, second needs to
454
    be a big endian encoding of the ``s`` parameter of an ECDSA signature.
455

456
    It's expected that this function will be used as the ``sigdecode=``
457
    parameter to the :func:`ecdsa.keys.VerifyingKey.verify` method.
458

459
    :param list rs_strings: list of two bytes-like objects, each encoding one
460
        parameter of signature
461
    :param int order: order of the curve over which the signature was computed
462

463
    :raises MalformedSignature: when the encoding of the signature is invalid
464

465
    :return: tuple with decoded ``r`` and ``s`` values of signature
466
    :rtype: tuple of ints
467
    """
468
    if not len(rs_strings) == 2:
20✔
469
        raise MalformedSignature(
20✔
470
            "Invalid number of strings provided: {0}, expected 2".format(
471
                len(rs_strings)
472
            )
473
        )
474
    (r_str, s_str) = rs_strings
20✔
475
    r_str = normalise_bytes(r_str)
20✔
476
    s_str = normalise_bytes(s_str)
20✔
477
    l = orderlen(order)
20✔
478
    if not len(r_str) == l:
20✔
479
        raise MalformedSignature(
20✔
480
            "Invalid length of first string ('r' parameter), "
481
            "expected {0} bytes long, provided string is {1} "
482
            "bytes long".format(l, len(r_str))
483
        )
484
    if not len(s_str) == l:
20✔
485
        raise MalformedSignature(
20✔
486
            "Invalid length of second string ('s' parameter), "
487
            "expected {0} bytes long, provided string is {1} "
488
            "bytes long".format(l, len(s_str))
489
        )
490
    r = string_to_number_fixedlen(r_str, order)
20✔
491
    s = string_to_number_fixedlen(s_str, order)
20✔
492
    return r, s
20✔
493

494

495
def sigdecode_der(sig_der, order):
20✔
496
    """
497
    Decoder for DER format of ECDSA signatures.
498

499
    DER format of signature is one that uses the :term:`ASN.1` :term:`DER`
500
    rules to encode it as a sequence of two integers::
501

502
        Ecdsa-Sig-Value ::= SEQUENCE {
503
            r       INTEGER,
504
            s       INTEGER
505
        }
506

507
    It's expected that this function will be used as as the ``sigdecode=``
508
    parameter to the :func:`ecdsa.keys.VerifyingKey.verify` method.
509

510
    :param sig_der: encoded signature
511
    :type sig_der: bytes like object
512
    :param order: order of the curve over which the signature was computed
513
    :type order: int
514

515
    :raises UnexpectedDER: when the encoding of signature is invalid
516

517
    :return: tuple with decoded ``r`` and ``s`` values of signature
518
    :rtype: tuple of ints
519
    """
520
    sig_der = normalise_bytes(sig_der)
20✔
521
    # return der.encode_sequence(der.encode_integer(r), der.encode_integer(s))
522
    rs_strings, empty = der.remove_sequence(sig_der)
20✔
523
    if empty != b"":
20✔
524
        raise der.UnexpectedDER(
20✔
525
            "trailing junk after DER sig: %s" % binascii.hexlify(empty)
526
        )
527
    r, rest = der.remove_integer(rs_strings)
20✔
528
    s, empty = der.remove_integer(rest)
20✔
529
    if empty != b"":
20✔
530
        raise der.UnexpectedDER(
20✔
531
            "trailing junk after DER numbers: %s" % binascii.hexlify(empty)
532
        )
533
    return r, s
20✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc