├── Attack-Main.py └── README.md /Attack-Main.py: -------------------------------------------------------------------------------- 1 | from ecdsa import SigningKey, NIST224p 2 | from ecdsa.util import sigencode_string, sigdecode_string 3 | from ecdsa.numbertheory import inverse_mod 4 | from hashlib import sha1 5 | 6 | def attack(publicKeyOrderInteger, signaturePair1, signaturePair2, messageHash1, messageHash2): 7 | r1 = signaturePair1[0] 8 | s1 = signaturePair1[1] 9 | r2 = signaturePair2[0] 10 | s2 = signaturePair2[1] 11 | 12 | #Convert Hex into Int 13 | L1 = int(messageHash1, 16) 14 | L2 = int(messageHash2, 16) 15 | 16 | if (r1 != r2): 17 | print("ERROR: The signature pairs given are not susceptible to this attack") 18 | return None 19 | 20 | #A bit of Math 21 | #L1 = Hash(message_1) 22 | #L2 = Hash(message_2) 23 | #pk = Private Key (unknown to attacker) 24 | #R = r1 == r2 25 | #K = K value that was used (unknown to attacker) 26 | #N = integer order of G (part of public key) 27 | 28 | # From Signing Defintion 29 | #s1 = (L1 + pk * R) / K Mod N and s2 = (L2 + pk * R) / K Mod N 30 | 31 | # Rearrange 32 | #K = (L1 + pk * R) / s1 Mod N and K = (L2 + pk * R) / s2 Mod N 33 | 34 | # Set Equal 35 | #(L1 + pk * R) / s1 = (L2 + pk * R) / s2 Mod N 36 | 37 | # Solve for pk (private key) 38 | #pk Mod N = (s2 * L1 - s1 * L2) / R * (s1 - s2) 39 | #pk Mod N = (s2 * L1 - s1 * L2) * (R * (s1 - s2)) ** -1 40 | 41 | numerator = (((s2 * L1) % publicKeyOrderInteger) - ((s1 * L2) % publicKeyOrderInteger)) 42 | denominator = inverse_mod(r1 * ((s1 - s2) % publicKeyOrderInteger), publicKeyOrderInteger) 43 | 44 | privateKey = numerator * denominator % publicKeyOrderInteger 45 | 46 | return privateKey 47 | 48 | if __name__ == "__main__": 49 | ### PROOF OF CONCEPT #### 50 | 51 | #Messages to be signed 52 | message_1 = str("message_1") 53 | message_2 = str("message_2") 54 | 55 | #Generates the private key using the NIST224p curve, and SHA-1 hash function 56 | sk = SigningKey.generate(curve=NIST224p) 57 | 58 | #This is the secret number used to sign messages 59 | actualPrivateKey = sk.privkey.secret_multiplier 60 | 61 | #gets the public key (vk) 62 | vk = sk.get_verifying_key() 63 | 64 | #Signing a message 65 | signature = sk.sign(message_1.encode('utf-8'),k=22) 66 | 67 | #Pulling out the Signature Pair 68 | r1, s1 = sigdecode_string(signature, vk.pubkey.order) 69 | 70 | #Singing a second message using the same K value, using the same K value is what opens ECDSA to attack 71 | signature2 = sk.sign(message_2.encode("utf-8"),k=22) 72 | 73 | #Pulling out the second Signature Pair (Note: r1 == r2 due to the K value being the same) 74 | r2, s2 = sigdecode_string(signature2, vk.pubkey.order) 75 | 76 | #Get message Hash 77 | messageHash1 = sha1(message_1.encode('utf-8')).hexdigest() 78 | messageHash2 = sha1(message_2.encode('utf-8')).hexdigest() 79 | 80 | #Start the attack 81 | privateKeyCalculation = attack(vk.pubkey.order, (r1,s1), (r2,s2), messageHash1, messageHash2) 82 | 83 | #By compairing the actual secret key with calculation we can prove that we have just solved for the private key 84 | print(actualPrivateKey) 85 | print(privateKeyCalculation) 86 | 87 | 88 | 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## DESCRIPTION 2 | This code shows how you can extract a ECDSA private key from two messages signed with the same Nonce value. 3 | Every signature requires a unique integer plus the private key to avoid this attack. 4 | 5 | ## HISTORICAL RELEVANCE 6 | In 2011, Sony's private key was revealed by this attack. This allowed anyone with the private key to sign messages and make them appear to be from Sony. Attackers used this to sign binaries, allowing arbitary code to be exectued on Playstation 3 consoles. 7 | 8 | ## DEPENDINCES 9 | Tested on python version 3.6.2, 10 | 11 | ecdsa 0.13, 12 | 13 | Install command: "pip install ecdsa" 14 | --------------------------------------------------------------------------------