You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

247 lines
9.6 KiB

4 years ago
  1. from __future__ import division
  2. import os
  3. import math
  4. import binascii
  5. from hashlib import sha256
  6. from . import der
  7. from .curves import orderlen
  8. from .six import PY3, int2byte, b, next
  9. # RFC5480:
  10. # The "unrestricted" algorithm identifier is:
  11. # id-ecPublicKey OBJECT IDENTIFIER ::= {
  12. # iso(1) member-body(2) us(840) ansi-X9-62(10045) keyType(2) 1 }
  13. oid_ecPublicKey = (1, 2, 840, 10045, 2, 1)
  14. encoded_oid_ecPublicKey = der.encode_oid(*oid_ecPublicKey)
  15. def randrange(order, entropy=None):
  16. """Return a random integer k such that 1 <= k < order, uniformly
  17. distributed across that range. For simplicity, this only behaves well if
  18. 'order' is fairly close (but below) a power of 256. The try-try-again
  19. algorithm we use takes longer and longer time (on average) to complete as
  20. 'order' falls, rising to a maximum of avg=512 loops for the worst-case
  21. (256**k)+1 . All of the standard curves behave well. There is a cutoff at
  22. 10k loops (which raises RuntimeError) to prevent an infinite loop when
  23. something is really broken like the entropy function not working.
  24. Note that this function is not declared to be forwards-compatible: we may
  25. change the behavior in future releases. The entropy= argument (which
  26. should get a callable that behaves like os.urandom) can be used to
  27. achieve stability within a given release (for repeatable unit tests), but
  28. should not be used as a long-term-compatible key generation algorithm.
  29. """
  30. # we could handle arbitrary orders (even 256**k+1) better if we created
  31. # candidates bit-wise instead of byte-wise, which would reduce the
  32. # worst-case behavior to avg=2 loops, but that would be more complex. The
  33. # change would be to round the order up to a power of 256, subtract one
  34. # (to get 0xffff..), use that to get a byte-long mask for the top byte,
  35. # generate the len-1 entropy bytes, generate one extra byte and mask off
  36. # the top bits, then combine it with the rest. Requires jumping back and
  37. # forth between strings and integers a lot.
  38. if entropy is None:
  39. entropy = os.urandom
  40. assert order > 1
  41. bytes = orderlen(order)
  42. dont_try_forever = 10000 # gives about 2**-60 failures for worst case
  43. while dont_try_forever > 0:
  44. dont_try_forever -= 1
  45. candidate = string_to_number(entropy(bytes)) + 1
  46. if 1 <= candidate < order:
  47. return candidate
  48. continue
  49. raise RuntimeError("randrange() tried hard but gave up, either something"
  50. " is very wrong or you got realllly unlucky. Order was"
  51. " %x" % order)
  52. class PRNG:
  53. # this returns a callable which, when invoked with an integer N, will
  54. # return N pseudorandom bytes. Note: this is a short-term PRNG, meant
  55. # primarily for the needs of randrange_from_seed__trytryagain(), which
  56. # only needs to run it a few times per seed. It does not provide
  57. # protection against state compromise (forward security).
  58. def __init__(self, seed):
  59. self.generator = self.block_generator(seed)
  60. def __call__(self, numbytes):
  61. a = [next(self.generator) for i in range(numbytes)]
  62. if PY3:
  63. return bytes(a)
  64. else:
  65. return "".join(a)
  66. def block_generator(self, seed):
  67. counter = 0
  68. while True:
  69. for byte in sha256(("prng-%d-%s" % (counter, seed)).encode()).digest():
  70. yield byte
  71. counter += 1
  72. def randrange_from_seed__overshoot_modulo(seed, order):
  73. # hash the data, then turn the digest into a number in [1,order).
  74. #
  75. # We use David-Sarah Hopwood's suggestion: turn it into a number that's
  76. # sufficiently larger than the group order, then modulo it down to fit.
  77. # This should give adequate (but not perfect) uniformity, and simple
  78. # code. There are other choices: try-try-again is the main one.
  79. base = PRNG(seed)(2*orderlen(order))
  80. number = (int(binascii.hexlify(base), 16) % (order-1)) + 1
  81. assert 1 <= number < order, (1, number, order)
  82. return number
  83. def lsb_of_ones(numbits):
  84. return (1 << numbits) - 1
  85. def bits_and_bytes(order):
  86. bits = int(math.log(order-1, 2)+1)
  87. bytes = bits // 8
  88. extrabits = bits % 8
  89. return bits, bytes, extrabits
  90. # the following randrange_from_seed__METHOD() functions take an
  91. # arbitrarily-sized secret seed and turn it into a number that obeys the same
  92. # range limits as randrange() above. They are meant for deriving consistent
  93. # signing keys from a secret rather than generating them randomly, for
  94. # example a protocol in which three signing keys are derived from a master
  95. # secret. You should use a uniformly-distributed unguessable seed with about
  96. # curve.baselen bytes of entropy. To use one, do this:
  97. # seed = os.urandom(curve.baselen) # or other starting point
  98. # secexp = ecdsa.util.randrange_from_seed__trytryagain(sed, curve.order)
  99. # sk = SigningKey.from_secret_exponent(secexp, curve)
  100. def randrange_from_seed__truncate_bytes(seed, order, hashmod=sha256):
  101. # hash the seed, then turn the digest into a number in [1,order), but
  102. # don't worry about trying to uniformly fill the range. This will lose,
  103. # on average, four bits of entropy.
  104. bits, bytes, extrabits = bits_and_bytes(order)
  105. if extrabits:
  106. bytes += 1
  107. base = hashmod(seed).digest()[:bytes]
  108. base = "\x00"*(bytes-len(base)) + base
  109. number = 1+int(binascii.hexlify(base), 16)
  110. assert 1 <= number < order
  111. return number
  112. def randrange_from_seed__truncate_bits(seed, order, hashmod=sha256):
  113. # like string_to_randrange_truncate_bytes, but only lose an average of
  114. # half a bit
  115. bits = int(math.log(order-1, 2)+1)
  116. maxbytes = (bits+7) // 8
  117. base = hashmod(seed).digest()[:maxbytes]
  118. base = "\x00"*(maxbytes-len(base)) + base
  119. topbits = 8*maxbytes - bits
  120. if topbits:
  121. base = int2byte(ord(base[0]) & lsb_of_ones(topbits)) + base[1:]
  122. number = 1+int(binascii.hexlify(base), 16)
  123. assert 1 <= number < order
  124. return number
  125. def randrange_from_seed__trytryagain(seed, order):
  126. # figure out exactly how many bits we need (rounded up to the nearest
  127. # bit), so we can reduce the chance of looping to less than 0.5 . This is
  128. # specified to feed from a byte-oriented PRNG, and discards the
  129. # high-order bits of the first byte as necessary to get the right number
  130. # of bits. The average number of loops will range from 1.0 (when
  131. # order=2**k-1) to 2.0 (when order=2**k+1).
  132. assert order > 1
  133. bits, bytes, extrabits = bits_and_bytes(order)
  134. generate = PRNG(seed)
  135. while True:
  136. extrabyte = b("")
  137. if extrabits:
  138. extrabyte = int2byte(ord(generate(1)) & lsb_of_ones(extrabits))
  139. guess = string_to_number(extrabyte + generate(bytes)) + 1
  140. if 1 <= guess < order:
  141. return guess
  142. def number_to_string(num, order):
  143. l = orderlen(order)
  144. fmt_str = "%0" + str(2*l) + "x"
  145. string = binascii.unhexlify((fmt_str % num).encode())
  146. assert len(string) == l, (len(string), l)
  147. return string
  148. def number_to_string_crop(num, order):
  149. l = orderlen(order)
  150. fmt_str = "%0" + str(2*l) + "x"
  151. string = binascii.unhexlify((fmt_str % num).encode())
  152. return string[:l]
  153. def string_to_number(string):
  154. return int(binascii.hexlify(string), 16)
  155. def string_to_number_fixedlen(string, order):
  156. l = orderlen(order)
  157. assert len(string) == l, (len(string), l)
  158. return int(binascii.hexlify(string), 16)
  159. # these methods are useful for the sigencode= argument to SK.sign() and the
  160. # sigdecode= argument to VK.verify(), and control how the signature is packed
  161. # or unpacked.
  162. def sigencode_strings(r, s, order):
  163. r_str = number_to_string(r, order)
  164. s_str = number_to_string(s, order)
  165. return (r_str, s_str)
  166. def sigencode_string(r, s, order):
  167. # for any given curve, the size of the signature numbers is
  168. # fixed, so just use simple concatenation
  169. r_str, s_str = sigencode_strings(r, s, order)
  170. return r_str + s_str
  171. def sigencode_der(r, s, order):
  172. return der.encode_sequence(der.encode_integer(r), der.encode_integer(s))
  173. # canonical versions of sigencode methods
  174. # these enforce low S values, by negating the value (modulo the order) if above order/2
  175. # see CECKey::Sign() https://github.com/bitcoin/bitcoin/blob/master/src/key.cpp#L214
  176. def sigencode_strings_canonize(r, s, order):
  177. if s > order / 2:
  178. s = order - s
  179. return sigencode_strings(r, s, order)
  180. def sigencode_string_canonize(r, s, order):
  181. if s > order / 2:
  182. s = order - s
  183. return sigencode_string(r, s, order)
  184. def sigencode_der_canonize(r, s, order):
  185. if s > order / 2:
  186. s = order - s
  187. return sigencode_der(r, s, order)
  188. def sigdecode_string(signature, order):
  189. l = orderlen(order)
  190. assert len(signature) == 2*l, (len(signature), 2*l)
  191. r = string_to_number_fixedlen(signature[:l], order)
  192. s = string_to_number_fixedlen(signature[l:], order)
  193. return r, s
  194. def sigdecode_strings(rs_strings, order):
  195. (r_str, s_str) = rs_strings
  196. l = orderlen(order)
  197. assert len(r_str) == l, (len(r_str), l)
  198. assert len(s_str) == l, (len(s_str), l)
  199. r = string_to_number_fixedlen(r_str, order)
  200. s = string_to_number_fixedlen(s_str, order)
  201. return r, s
  202. def sigdecode_der(sig_der, order):
  203. #return der.encode_sequence(der.encode_integer(r), der.encode_integer(s))
  204. rs_strings, empty = der.remove_sequence(sig_der)
  205. if empty != b(""):
  206. raise der.UnexpectedDER("trailing junk after DER sig: %s" %
  207. binascii.hexlify(empty))
  208. r, rest = der.remove_integer(rs_strings)
  209. s, empty = der.remove_integer(rest)
  210. if empty != b(""):
  211. raise der.UnexpectedDER("trailing junk after DER numbers: %s" %
  212. binascii.hexlify(empty))
  213. return r, s