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.

key.py 8.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. # Copyright (c) 2011 Sam Rushing
  2. """ECC secp256k1 OpenSSL wrapper.
  3. WARNING: This module does not mlock() secrets; your private keys may end up on
  4. disk in swap! Use with caution!
  5. This file is modified from python-bitcoinlib.
  6. """
  7. import ctypes
  8. import ctypes.util
  9. import hashlib
  10. import sys
  11. ssl = ctypes.cdll.LoadLibrary(ctypes.util.find_library ('ssl') or 'libeay32')
  12. ssl.BN_new.restype = ctypes.c_void_p
  13. ssl.BN_new.argtypes = []
  14. ssl.BN_bin2bn.restype = ctypes.c_void_p
  15. ssl.BN_bin2bn.argtypes = [ctypes.c_char_p, ctypes.c_int, ctypes.c_void_p]
  16. ssl.BN_CTX_free.restype = None
  17. ssl.BN_CTX_free.argtypes = [ctypes.c_void_p]
  18. ssl.BN_CTX_new.restype = ctypes.c_void_p
  19. ssl.BN_CTX_new.argtypes = []
  20. ssl.ECDH_compute_key.restype = ctypes.c_int
  21. ssl.ECDH_compute_key.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p, ctypes.c_void_p]
  22. ssl.ECDSA_sign.restype = ctypes.c_int
  23. ssl.ECDSA_sign.argtypes = [ctypes.c_int, ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p]
  24. ssl.ECDSA_verify.restype = ctypes.c_int
  25. ssl.ECDSA_verify.argtypes = [ctypes.c_int, ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p]
  26. ssl.EC_KEY_free.restype = None
  27. ssl.EC_KEY_free.argtypes = [ctypes.c_void_p]
  28. ssl.EC_KEY_new_by_curve_name.restype = ctypes.c_void_p
  29. ssl.EC_KEY_new_by_curve_name.argtypes = [ctypes.c_int]
  30. ssl.EC_KEY_get0_group.restype = ctypes.c_void_p
  31. ssl.EC_KEY_get0_group.argtypes = [ctypes.c_void_p]
  32. ssl.EC_KEY_get0_public_key.restype = ctypes.c_void_p
  33. ssl.EC_KEY_get0_public_key.argtypes = [ctypes.c_void_p]
  34. ssl.EC_KEY_set_private_key.restype = ctypes.c_int
  35. ssl.EC_KEY_set_private_key.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
  36. ssl.EC_KEY_set_conv_form.restype = None
  37. ssl.EC_KEY_set_conv_form.argtypes = [ctypes.c_void_p, ctypes.c_int]
  38. ssl.EC_KEY_set_public_key.restype = ctypes.c_int
  39. ssl.EC_KEY_set_public_key.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
  40. ssl.i2o_ECPublicKey.restype = ctypes.c_void_p
  41. ssl.i2o_ECPublicKey.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
  42. ssl.EC_POINT_new.restype = ctypes.c_void_p
  43. ssl.EC_POINT_new.argtypes = [ctypes.c_void_p]
  44. ssl.EC_POINT_free.restype = None
  45. ssl.EC_POINT_free.argtypes = [ctypes.c_void_p]
  46. ssl.EC_POINT_mul.restype = ctypes.c_int
  47. ssl.EC_POINT_mul.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p]
  48. # this specifies the curve used with ECDSA.
  49. NID_secp256k1 = 714 # from openssl/obj_mac.h
  50. SECP256K1_ORDER = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141
  51. SECP256K1_ORDER_HALF = SECP256K1_ORDER // 2
  52. # Thx to Sam Devlin for the ctypes magic 64-bit fix.
  53. def _check_result(val, func, args):
  54. if val == 0:
  55. raise ValueError
  56. else:
  57. return ctypes.c_void_p (val)
  58. ssl.EC_KEY_new_by_curve_name.restype = ctypes.c_void_p
  59. ssl.EC_KEY_new_by_curve_name.errcheck = _check_result
  60. class CECKey(object):
  61. """Wrapper around OpenSSL's EC_KEY"""
  62. POINT_CONVERSION_COMPRESSED = 2
  63. POINT_CONVERSION_UNCOMPRESSED = 4
  64. def __init__(self):
  65. self.k = ssl.EC_KEY_new_by_curve_name(NID_secp256k1)
  66. def __del__(self):
  67. if ssl:
  68. ssl.EC_KEY_free(self.k)
  69. self.k = None
  70. def set_secretbytes(self, secret):
  71. priv_key = ssl.BN_bin2bn(secret, 32, ssl.BN_new())
  72. group = ssl.EC_KEY_get0_group(self.k)
  73. pub_key = ssl.EC_POINT_new(group)
  74. ctx = ssl.BN_CTX_new()
  75. if not ssl.EC_POINT_mul(group, pub_key, priv_key, None, None, ctx):
  76. raise ValueError("Could not derive public key from the supplied secret.")
  77. ssl.EC_POINT_mul(group, pub_key, priv_key, None, None, ctx)
  78. ssl.EC_KEY_set_private_key(self.k, priv_key)
  79. ssl.EC_KEY_set_public_key(self.k, pub_key)
  80. ssl.EC_POINT_free(pub_key)
  81. ssl.BN_CTX_free(ctx)
  82. return self.k
  83. def set_privkey(self, key):
  84. self.mb = ctypes.create_string_buffer(key)
  85. return ssl.d2i_ECPrivateKey(ctypes.byref(self.k), ctypes.byref(ctypes.pointer(self.mb)), len(key))
  86. def set_pubkey(self, key):
  87. self.mb = ctypes.create_string_buffer(key)
  88. return ssl.o2i_ECPublicKey(ctypes.byref(self.k), ctypes.byref(ctypes.pointer(self.mb)), len(key))
  89. def get_privkey(self):
  90. size = ssl.i2d_ECPrivateKey(self.k, 0)
  91. mb_pri = ctypes.create_string_buffer(size)
  92. ssl.i2d_ECPrivateKey(self.k, ctypes.byref(ctypes.pointer(mb_pri)))
  93. return mb_pri.raw
  94. def get_pubkey(self):
  95. size = ssl.i2o_ECPublicKey(self.k, 0)
  96. mb = ctypes.create_string_buffer(size)
  97. ssl.i2o_ECPublicKey(self.k, ctypes.byref(ctypes.pointer(mb)))
  98. return mb.raw
  99. def get_raw_ecdh_key(self, other_pubkey):
  100. ecdh_keybuffer = ctypes.create_string_buffer(32)
  101. r = ssl.ECDH_compute_key(ctypes.pointer(ecdh_keybuffer), 32,
  102. ssl.EC_KEY_get0_public_key(other_pubkey.k),
  103. self.k, 0)
  104. if r != 32:
  105. raise Exception('CKey.get_ecdh_key(): ECDH_compute_key() failed')
  106. return ecdh_keybuffer.raw
  107. def get_ecdh_key(self, other_pubkey, kdf=lambda k: hashlib.sha256(k).digest()):
  108. # FIXME: be warned it's not clear what the kdf should be as a default
  109. r = self.get_raw_ecdh_key(other_pubkey)
  110. return kdf(r)
  111. def sign(self, hash, low_s = True):
  112. # FIXME: need unit tests for below cases
  113. if not isinstance(hash, bytes):
  114. raise TypeError('Hash must be bytes instance; got %r' % hash.__class__)
  115. if len(hash) != 32:
  116. raise ValueError('Hash must be exactly 32 bytes long')
  117. sig_size0 = ctypes.c_uint32()
  118. sig_size0.value = ssl.ECDSA_size(self.k)
  119. mb_sig = ctypes.create_string_buffer(sig_size0.value)
  120. result = ssl.ECDSA_sign(0, hash, len(hash), mb_sig, ctypes.byref(sig_size0), self.k)
  121. assert 1 == result
  122. assert mb_sig.raw[0] == 0x30
  123. assert mb_sig.raw[1] == sig_size0.value - 2
  124. total_size = mb_sig.raw[1]
  125. assert mb_sig.raw[2] == 2
  126. r_size = mb_sig.raw[3]
  127. assert mb_sig.raw[4 + r_size] == 2
  128. s_size = mb_sig.raw[5 + r_size]
  129. s_value = int.from_bytes(mb_sig.raw[6+r_size:6+r_size+s_size], byteorder='big')
  130. if (not low_s) or s_value <= SECP256K1_ORDER_HALF:
  131. return mb_sig.raw[:sig_size0.value]
  132. else:
  133. low_s_value = SECP256K1_ORDER - s_value
  134. low_s_bytes = (low_s_value).to_bytes(33, byteorder='big')
  135. while len(low_s_bytes) > 1 and low_s_bytes[0] == 0 and low_s_bytes[1] < 0x80:
  136. low_s_bytes = low_s_bytes[1:]
  137. new_s_size = len(low_s_bytes)
  138. new_total_size_byte = (total_size + new_s_size - s_size).to_bytes(1,byteorder='big')
  139. new_s_size_byte = (new_s_size).to_bytes(1,byteorder='big')
  140. return b'\x30' + new_total_size_byte + mb_sig.raw[2:5+r_size] + new_s_size_byte + low_s_bytes
  141. def verify(self, hash, sig):
  142. """Verify a DER signature"""
  143. return ssl.ECDSA_verify(0, hash, len(hash), sig, len(sig), self.k) == 1
  144. def set_compressed(self, compressed):
  145. if compressed:
  146. form = self.POINT_CONVERSION_COMPRESSED
  147. else:
  148. form = self.POINT_CONVERSION_UNCOMPRESSED
  149. ssl.EC_KEY_set_conv_form(self.k, form)
  150. class CPubKey(bytes):
  151. """An encapsulated public key
  152. Attributes:
  153. is_valid - Corresponds to CPubKey.IsValid()
  154. is_fullyvalid - Corresponds to CPubKey.IsFullyValid()
  155. is_compressed - Corresponds to CPubKey.IsCompressed()
  156. """
  157. def __new__(cls, buf, _cec_key=None):
  158. self = super(CPubKey, cls).__new__(cls, buf)
  159. if _cec_key is None:
  160. _cec_key = CECKey()
  161. self._cec_key = _cec_key
  162. self.is_fullyvalid = _cec_key.set_pubkey(self) != 0
  163. return self
  164. @property
  165. def is_valid(self):
  166. return len(self) > 0
  167. @property
  168. def is_compressed(self):
  169. return len(self) == 33
  170. def verify(self, hash, sig):
  171. return self._cec_key.verify(hash, sig)
  172. def __str__(self):
  173. return repr(self)
  174. def __repr__(self):
  175. # Always have represent as b'<secret>' so test cases don't have to
  176. # change for py2/3
  177. if sys.version > '3':
  178. return '%s(%s)' % (self.__class__.__name__, super(CPubKey, self).__repr__())
  179. else:
  180. return '%s(b%s)' % (self.__class__.__name__, super(CPubKey, self).__repr__())