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