def _sign(self, pdata, sks, dump_json_data): if not isinstance(sks, list): sks = [sks] jheader = '{"alg": "ES256"}' jheader_b64 = base64url_encode(jheader) jpayload = json.dumps(pdata) if dump_json_data else pdata jpayload_b64 = base64url_encode(jpayload) pdata_sig = {'payload': jpayload_b64, 'signatures': []} for sk in sks: sig_string_b64 = jws.sign(jheader, jpayload, sk, is_json=True) order = sk.curve.order sig_string = base64url_decode(sig_string_b64) r, s = sigdecode_string(sig_string, order) sig_der = sigencode_der(r, s, order) sig_der_b64 = base64url_encode(sig_der) pdata_sig['signatures'].append({'protected': jheader_b64, 'signature': sig_der_b64}) return pdata_sig
def from_signature(klass, sig, recid, h, curve): # TODO use libsecp?? """ See http://www.secg.org/download/aid-780/sec1-v2.pdf, chapter 4.1.6 """ from ecdsa import util, numbertheory from . import msqr curveFp = curve.curve G = curve.generator order = G.order() # extract r,s from signature r, s = util.sigdecode_string(sig, order) # 1.1 x = r + (recid//2) * order # 1.3 alpha = ( x * x * x + curveFp.a() * x + curveFp.b() ) % curveFp.p() beta = msqr.modular_sqrt(alpha, curveFp.p()) y = beta if (beta - recid) % 2 == 0 else curveFp.p() - beta # 1.4 the constructor checks that nR is at infinity try: R = Point(curveFp, x, y, order) except: raise InvalidECPointException() # 1.5 compute e from message: e = string_to_number(h) minus_e = -e % order # 1.6 compute Q = r^-1 (sR - eG) inv_r = numbertheory.inverse_mod(r,order) try: Q = inv_r * ( s * R + minus_e * G ) except: raise InvalidECPointException() return klass.from_public_point( Q, curve )
def verify(self, msg, sig): order = (2 ** self.prepared_key.curve.key_size) - 1 signature = sigencode_der(*sigdecode_string(sig, order), order=order) try: self.prepared_key.verify(signature, msg, ec.ECDSA(self.hash_alg())) return True except: return False
def _create_auth_token(self, sk, profile): jheader = '{"alg": "ES256"}' jheader_b64 = base64url_encode(jheader) body = {'id': profile.profile_id, 'timestamp': int(time.time())} jbody = json.dumps(body) jbody_b64 = base64url_encode(jbody) sig_string_b64 = jws.sign(jheader, jbody, sk, is_json=True) order = sk.curve.order sig_string = base64url_decode(sig_string_b64) r, s = sigdecode_string(sig_string, order) sig_der = sigencode_der(r, s, order) sig_der_b64 = base64url_encode(sig_der) return '{0}.{1}.{2}'.format(jheader_b64, jbody_b64, sig_der_b64)
def verify_message(self, address, signature, message): """ See http://www.secg.org/download/aid-780/sec1-v2.pdf for the math """ from ecdsa import numbertheory, ellipticcurve, util import msqr curve = curve_secp256k1 G = generator_secp256k1 order = G.order() # extract r,s from signature sig = base64.b64decode(signature) if len(sig) != 65: raise BaseException("Wrong encoding") r, s = util.sigdecode_string(sig[1:], order) nV = ord(sig[0]) if nV < 27 or nV >= 35: raise BaseException("Bad encoding") if nV >= 31: compressed = True nV -= 4 else: compressed = False recid = nV - 27 # 1.1 x = r + (recid / 2) * order # 1.3 alpha = (x * x * x + curve.a() * x + curve.b()) % curve.p() beta = msqr.modular_sqrt(alpha, curve.p()) y = beta if (beta - recid) % 2 == 0 else curve.p() - beta # 1.4 the constructor checks that nR is at infinity R = ellipticcurve.Point(curve, x, y, order) # 1.5 compute e from message: h = Hash(self.msg_magic(message)) e = string_to_number(h) minus_e = -e % order # 1.6 compute Q = r^-1 (sR - eG) inv_r = numbertheory.inverse_mod(r, order) Q = inv_r * (s * R + minus_e * G) public_key = ecdsa.VerifyingKey.from_public_point(Q, curve=SECP256k1) # check that Q is the public key public_key.verify_digest(sig[1:], h, sigdecode=ecdsa.util.sigdecode_string) # check that we get the original signing address addr = public_key_to_bc_address(encode_point(public_key, compressed)) if address != addr: raise BaseException("Bad signature")
def verify_message(address, signature, message): """ See http://www.secg.org/download/aid-780/sec1-v2.pdf for the math """ curve = ecdsa.curves.SECP256k1.curve # curve_secp256k1 G = ecdsa.curves.SECP256k1.generator order = G.order() # extract r,s from signature if len(signature) != 65: raise BaseException("Wrong signature") r, s = util.sigdecode_string(signature[1:], order) nV = ord(signature[0]) if nV < 27 or nV >= 35: raise BaseException("Bad encoding") if nV >= 31: compressed = True nV -= 4 else: compressed = False recid = nV - 27 # 1.1 x = r + (recid / 2) * order # 1.3 alpha = (x * x * x + curve.a() * x + curve.b()) % curve.p() beta = ecdsa.numbertheory.square_root_mod_prime(alpha, curve.p()) y = beta if (beta - recid) % 2 == 0 else curve.p() - beta # 1.4 the constructor checks that nR is at infinity R = ellipticcurve.Point(curve, x, y, order) # 1.5 compute e from message: h = sha256(sha256(message_magic(message)).digest()).digest() e = util.string_to_number(h) minus_e = -e % order # 1.6 compute Q = r^-1 (sR - eG) inv_r = numbertheory.inverse_mod(r, order) Q = inv_r * (s * R + minus_e * G) public_key = ecdsa.VerifyingKey.from_public_point(Q, curve=ecdsa.curves.SECP256k1) # check that Q is the public key public_key.verify_digest(signature[1:], h, sigdecode=ecdsa.util.sigdecode_string) if address: address_type = int(binascii.hexlify(tools.b58decode(address, None)[0]), 16) addr = tools.public_key_to_bc_address('\x04' + public_key.to_string(), address_type, compress=compressed) if address != addr: raise Exception("Invalid signature")
def from_signature(cls, sig, recid, h, curve): """ See http://www.secg.org/download/aid-780/sec1-v2.pdf, chapter 4.1.6 """ curveFp = curve.curve G = curve.generator order = G.order() # extract r,s from signature r, s = util.sigdecode_string(sig, order) # 1.1 x = r + (recid / 2) * order # 1.3 alpha = (x * x * x + curveFp.a() * x + curveFp.b()) % curveFp.p() beta = msqr.modular_sqrt(alpha, curveFp.p()) y = beta if (beta - recid) % 2 == 0 else curveFp.p() - beta # 1.4 the constructor checks that nR is at infinity R = Point(curveFp, x, y, order) # 1.5 compute e from message: e = string_to_number(h) minus_e = -e % order # 1.6 compute Q = r^-1 (sR - eG) inv_r = numbertheory.inverse_mod(r, order) Q = inv_r * (s * R + minus_e * G) return cls.from_public_point(Q, curve)
def from_signature(klass, sig, recid, h, curve): """ See http://www.secg.org/download/aid-780/sec1-v2.pdf, chapter 4.1.6 """ from ecdsa import util, numbertheory from . import msqr curveFp = curve.curve G = curve.generator order = G.order() # extract r,s from signature r, s = util.sigdecode_string(sig, order) # 1.1 x = r + (recid // 2) * order # 1.3 alpha = (x * x * x + curveFp.a() * x + curveFp.b()) % curveFp.p() beta = msqr.modular_sqrt(alpha, curveFp.p()) y = beta if (beta - recid) % 2 == 0 else curveFp.p() - beta # 1.4 the constructor checks that nR is at infinity R = Point(curveFp, x, y, order) # 1.5 compute e from message: e = string_to_number(h) minus_e = -e % order # 1.6 compute Q = r^-1 (sR - eG) inv_r = numbertheory.inverse_mod(r, order) Q = inv_r * (s * R + minus_e * G) return klass.from_public_point(Q, curve)
message_2 = str("message_2") #Generates the private key using the NIST224p curve, and SHA-1 hash function sk = SigningKey.generate(curve=NIST224p) #This is the secret number used to sign messages actualPrivateKey = sk.privkey.secret_multiplier #gets the public key (vk) vk = sk.get_verifying_key() #Signing a message signature = sk.sign(message_1.encode('utf-8'), k=22) #Pulling out the Signature Pair r1, s1 = sigdecode_string(signature, vk.pubkey.order) #Singing a second message using the same K value, using the same K value is what opens ECDSA to attack signature2 = sk.sign(message_2.encode("utf-8"), k=22) #Pulling out the second Signature Pair (Note: r1 == r2 due to the K value being the same) r2, s2 = sigdecode_string(signature2, vk.pubkey.order) #Get message Hash messageHash1 = sha1(message_1.encode('utf-8')).hexdigest() messageHash2 = sha1(message_2.encode('utf-8')).hexdigest() #Start the attack privateKeyCalculation = attack(vk.pubkey.order, (r1, s1), (r2, s2), messageHash1, messageHash2)
def verify_message(self, address, signature, message): """Creates a public key from a message signature and verifies message Bitcoin uses a compact format for message signatures (for tx sigs it uses normal DER format). The format has the normal r and s parameters that ECDSA signatures have but also includes a prefix which encodes extra information. Using the prefix the public key can be reconstructed from the signature. | Prefix values: | 27 - 0x1B = first key with even y | 28 - 0x1C = first key with odd y | 29 - 0x1D = second key with even y | 30 - 0x1E = second key with odd y If key is compressed add 4 (31 - 0x1F, 32 - 0x20, 33 - 0x21, 34 - 0x22 respectively) Raises ------ ValueError If signature is invalid """ sig = b64decode(signature.encode('utf-8')) if len(sig) != 65: raise ValueError('Invalid signature size') # get signature prefix, compressed and recid (which key is odd/even) prefix = sig[0] if prefix < 27 or prefix > 35: return False if prefix >= 31: compressed = True recid = prefix - 31 else: compressed = False recid = prefix - 27 # create message digest -- note double hashing message_magic = add_magic_prefix(message) message_digest = hashlib.sha256( hashlib.sha256(message_magic).digest()).digest() # # use recid, r and s to get the point in the curve # # get signature's r and s r, s = sigdecode_string(sig[1:], _order) # ger R's x coordinate x = r + (recid // 2) * _order # get R's y coordinate (y**2 = x**3 + 7) y_values = sqrt_mod((x**3 + 7) % _p, _p, True) if (y_values[0] - recid) % 2 == 0: y = y_values[0] else: y = y_values[1] # get R (recovered ephemeral key) from x,y R = ellipticcurve.Point(_curve, x, y, _order) # get e (hash of message encoded as big integer) e = int(hexlify(message_digest), 16) # compute public key Q = r^-1 (sR - eG) # because Point substraction is not defined we will instead use: # Q = r^-1 (sR + (-eG) ) minus_e = -e % _order inv_r = numbertheory.inverse_mod(r, _order) Q = inv_r * (s * R + minus_e * _G) # instantiate the public key and verify message public_key = VerifyingKey.from_public_point(Q, curve=SECP256k1) key_hex = hexlify(public_key.to_string()).decode('utf-8') pubkey = PublicKey.from_hex('04' + key_hex) if not pubkey.verify(signature, message): return False # confirm that the address provided corresponds to that public key if pubkey.get_address(compressed=compressed).to_string() != address: return False return True
print( "=======================================================================================================" ) print( "=======================================================================================================" ) msg1 = "We are not uncertain with the vote.".encode('utf-8') msg2 = "We are uncertain with the vote.".encode('utf-8') print("Hash 1:\t\t\t\t", int.from_bytes(sha256(msg1).digest(), byteorder='big')) print("Hash 2:\t\t\t\t", int.from_bytes(sha256(msg2).digest(), byteorder='big')) k = 7800010500099000107000320001190009700011500032000104000101000114000101 signature1 = priv_key.sign(msg1, k=k, hashfunc=sha256) signature2 = priv_key.sign(msg2, k=k + 1, hashfunc=sha256) human_sign_1 = sigdecode_string(signature1, pub_key.pubkey.order) human_sign_2 = sigdecode_string(signature2, pub_key.pubkey.order) r1 = human_sign_1[0] r2 = human_sign_2[0] print( "=======================================================================================================" ) print( "=======================================================================================================" ) print("Signature 1") print("\tR:\t\t\t", human_sign_1[0]) print("\tS:\t\t\t", human_sign_1[1]) print("Signature 2") print("\tR:\t\t\t", human_sign_2[0]) print("\tS:\t\t\t", human_sign_2[1])
def ecdsa_sign(sk, msg, k=None): """Sign ecdsa""" sig = sk.sign(msg, hashfunc=sha3.sha3_256, k=k) signature = util.sigdecode_string(sig, order) return signature # matches haskell output
def decode_sig(sig): r, s = sigdecode_string(sig, SECP256k1.generator.order()) return r, s