def compute_issuer_public_keys(cert): sig = Sequence.load(cert["signature_value"].native) r = sig[0].native s = sig[1].native tbs_hash = sha512(cert["tbs_certificate"].dump()).digest() z = int.from_bytes(tbs_hash, byteorder="big") u1 = (z * pow(s, P521.q - 2, P521.q)) % P521.q u2 = (pow(r, P521.q - 2, P521.q) * s) % P521.q ky = (r**3 + P521.a * r + P521.b) % P521.p y0 = pow(ky, (P521.p + 1) // 4, P521.p) y1 = P521.p - y0 Q0 = u2 * (Point(r, y0, curve=P521) - u1 * P521.G) Q1 = u2 * (Point(r, y1, curve=P521) - u1 * P521.G) if key_id(Q0) == cert.authority_key_identifier: issuer_pub = Q0 elif key_id(Q1) == cert.authority_key_identifier: issuer_pub = Q1 if issuer_pub: return (issuer_pub, ) else: return (Q0, Q1)
def recoverECDSAKey(token, hashalg, curve, compressed): header, body, sig = token.split(".") rs = base64.b64decode(sig + "==") n = len(rs) // 2 r = int(rs[:n].hex(), 16) s = int(rs[n:].hex(), 16) # compute the 2 points having r has X coordinate y1, y2 = mod_sqrt(r**3 + curve.a * r + curve.b, curve.p) R1 = Point(r, y1, curve) R2 = Point(r, y2, curve) # compute r^1 r_inv = int(gmpy2.invert(r, curve.q)) # compute message hash message = header + "." + body h = int(hashalg.new(message.encode()).hexdigest(), 16) G = Point(curve.gx, curve.gy, curve) # recover the two possible public keys k1 = r_inv * (s * R1 - h * G) k2 = r_inv * (s * R2 - h * G) k1_ = ECC.construct(curve=curve.name.lower(), point_x=k1.x, point_y=k1.y) k2_ = ECC.construct(curve=curve.name.lower(), point_x=k2.x, point_y=k2.y) print("Found 2 public ECDSA keys !") print(f"x={k1.x}\ny={k1.y}") print(k1_.export_key(format="PEM", compress=compressed)) print("") print(f"x={k2.x}\ny={k2.y}") print(k2_.export_key(format="PEM", compress=compressed))
def handle_ecdh(self, body): self.ecdh_blob = body key, signature = body[:0x90], body[0x90:] x = key[0x8:0x8+0x20] y = key[0x4c:0x4c+0x20] x, y = [int(hexlify(i[::-1]), 0x10) for i in [x, y]] if not P256.is_point_on_curve( (x, y) ): raise Exception('Point is not on the curve') self.ecdh_q = Point(x, y, P256) self.trace('ECDH params:') self.trace('x=0x%x' % x) self.trace('y=0x%x' % y) l, signature = signature[:4], signature[4:] l, = unpack('<L', l) signature, zeroes = signature[:l], signature[l:] if zeroes != b'\0'*len(zeroes): raise Exception('Zeroes expected') # The following pub key is hardcoded for each fw revision in the synaWudfBioUsb.dll. # Corresponding private key should only be known to a genuine Synaptic device. fwpub=Point( 0xf727653b4e16ce0665a6894d7f3a30d7d0a0be310d1292a743671fdf69f6a8d3, 0xa85538f8b6bec50d6eef8bd5f4d07a886243c58b2393948df761a84721a6ca94, P256) signature=DEREncoder().decode_signature(signature) if not verify(signature, key, fwpub): raise Exception('Untrusted device')
def decode_point(point, curve=BASE_CURVE): # See http://www.secg.org/download/aid-780/sec1-v2.pdf section 2.3.4 elliptic_curve = curve order = elliptic_curve.q base_length = orderlen(order) if point[0] == 4: # 3 x_str = point[1:base_length + 1] y_str = point[base_length + 1:] return Point(string_to_number(x_str), string_to_number(y_str), curve=elliptic_curve) else: # 2.3 if point[0] == 2: yp = 0 elif point[0] == 3: yp = 1 else: return None # 2.2 x_str = point[1:base_length + 1] x = string_to_number(x_str) # 2.4.1 alpha = ((x * x * x) + (elliptic_curve.a * x) + elliptic_curve.b) % elliptic_curve.p beta = numbertheory.square_root_mod_prime(alpha, elliptic_curve.p) if (beta - yp) % 2 == 0: y = beta else: y = elliptic_curve.p - beta return Point(x, y, curve=elliptic_curve)
def blind_signature_verify(rho, omega, sigma, delta, Z, message, public_key): public_key = Point(public_key[0], public_key[1], curve) Z = Point(Z[0], Z[1], curve) A = rho * base + omega * public_key B = sigma * base + delta * Z hash = hash_for_blind_signature(A, B, Z, message) return (omega + delta) % q == hash
def deserialize(dic: dict) -> 'TXO': P = Point.deserialize(dic['P']) amount = int(dic['amount']) public_key = PublicKey.deserialize(dic['public_key']) T = int(dic['T']) R = dic.get('R') if R is not None: R = Point.deserialize(R) return TXO(P, amount, public_key, T, R)
def test_P192_arith(self): S = Point(0xd458e7d127ae671b0c330266d246769353a012073e97acf8, 0x325930500d851f336bddc050cf7fb11b5673a1645086df3b, curve=P192) d = 0xa78a236d60baec0c5dd41b33a542463a8255391af64c74ee expected = Point(0x1faee4205a4f669d2d0a8f25e3bcec9a62a6952965bf6d31, 0x5ff2cdfa508a2581892367087c696f179e7a4d7e8260fb06, curve=P192) R = d * S self.assertEqual(R, expected)
def test_P224_arith(self): S = Point(0x6eca814ba59a930843dc814edd6c97da95518df3c6fdf16e9a10bb5b, 0xef4b497f0963bc8b6aec0ca0f259b89cd80994147e05dc6b64d7bf22, curve=P224) d = 0xa78ccc30eaca0fcc8e36b2dd6fbb03df06d37f52711e6363aaf1d73b expected = Point( 0x96a7625e92a8d72bff1113abdb95777e736a14c6fdaacc392702bca4, 0x0f8e5702942a3c5e13cd2fd5801915258b43dfadc70d15dbada3ed10, curve=P224) R = d * S self.assertEqual(R, expected)
def test_decode_public_key(self): expected_public = Point( x=0xE5E2C01985AAFB6E2C3AD49F3DB5CCC54B2E63343AF405B521303D0F35835062, y=0x3DAD76DF888ABDE5ED0CC5AF1B83968EDFFCAE5D70BEDB24FDC18BB5F79499D0, curve=secp256k1, ) public_from_compressed = SEC1Encoder.decode_public_key( unhexlify(b"02e5e2c01985aafb6e2c3ad49f3db5ccc54b2e63343af405b521303d0f35835062"), secp256k1 ) public_from_uncompressed = SEC1Encoder.decode_public_key( unhexlify( b"04e5e2c01985aafb6e2c3ad49f3db5ccc54b2e63343af405b521303d0f3583506" b"23dad76df888abde5ed0cc5af1b83968edffcae5d70bedb24fdc18bb5f79499d0" ), secp256k1, ) # Same values as in `test_encode_public_key`, verified using openssl self.assertEqual(public_from_compressed, expected_public) self.assertEqual(public_from_uncompressed, expected_public) with self.assertRaises(InvalidSEC1PublicKey) as e: SEC1Encoder.decode_public_key(b"\x02", secp256k1) # invalid compressed length self.assertEqual(e.exception.args[0], "A compressed public key must be 33 bytes long") with self.assertRaises(InvalidSEC1PublicKey) as e: SEC1Encoder.decode_public_key(b"\x04", secp256k1) # invalid uncompressed length self.assertEqual(e.exception.args[0], "An uncompressed public key must be 65 bytes long") with self.assertRaises(InvalidSEC1PublicKey) as e: # invalid prefix value SEC1Encoder.decode_public_key( unhexlify(b"05e5e2c01985aafb6e2c3ad49f3db5ccc54b2e63343af405b521303d0f35835062"), secp256k1 ) self.assertEqual(e.exception.args[0], "Wrong key format") # With P256, same values as in `test_encode_public_key`, verified using openssl expected_P256 = Point( x=0x12C9DDF64B0D1F1D91D9BD729ABFB880079FA889D66604CC0B78C9CBC271824C, y=0x9A7D581BCF2ABA680B53CEDBADE03BE62FE95869DA04A168A458F369AC6A823E, curve=P256, ) public_from_compressed = SEC1Encoder.decode_public_key( unhexlify(b"0212c9ddf64b0d1f1d91d9bd729abfb880079fa889d66604cc0b78c9cbc271824c"), P256 ) self.assertEqual(public_from_compressed, expected_P256) # With secp192k1, same values as in `test_encode_public_key`, verified using openssl expected_secp192k1 = Point( x=0xA3BEC5FBA6D13E51FB55BD88DD097CB9B04F827BC151D22D, y=0xF07A73819149E8D903AA983E52AB1CFF38F0D381F940D361, curve=secp192k1, ) public_from_compressed = SEC1Encoder.decode_public_key( unhexlify(b"03a3bec5fba6d13e51fb55bd88dd097cb9b04f827bc151d22d"), secp192k1 ) self.assertEqual(public_from_compressed, expected_secp192k1)
def test_encode_point(): xs = 0xde2444bebc8d36e682edd27e0f271508617519b3221a8fa0b77cab3989da97c9 ys = 0xc093ae7ff36e5380fc01a5aad1e66659702de80f53cec576b6350b243042a256 s = Point(xs, ys, curve=curve.P256) assert encode_point( s, True ) == b'\x02\xde$D\xbe\xbc\x8d6\xe6\x82\xed\xd2~\x0f\'\x15\x08au\x19\xb3"\x1a\x8f\xa0\xb7|\xab9\x89\xda\x97\xc9' s = Point(xs, ys, curve=curve.P256) assert encode_point( s, False ) == b'\x04\xde$D\xbe\xbc\x8d6\xe6\x82\xed\xd2~\x0f\'\x15\x08au\x19\xb3"\x1a\x8f\xa0\xb7|\xab9\x89\xda\x97\xc9\xc0\x93\xae\x7f\xf3nS\x80\xfc\x01\xa5\xaa\xd1\xe6fYp-\xe8\x0fS\xce\xc5v\xb65\x0b$0B\xa2V'
def test_P256_arith(self): S = Point( 0xde2444bebc8d36e682edd27e0f271508617519b3221a8fa0b77cab3989da97c9, 0xc093ae7ff36e5380fc01a5aad1e66659702de80f53cec576b6350b243042a256, curve=P256) d = 0xc51e4753afdec1e6b6c6a5b992f43f8dd0c7a8933072708b6522468b2ffb06fd expected = Point( 0x51d08d5f2d4278882946d88d83c97d11e62becc3cfc18bedacc89ba34eeca03f, 0x75ee68eb8bf626aa5b673ab51f6e744e06f8fcf8a6c0cf3035beca956a7b41d5, curve=P256) R = d * S self.assertEqual(R, expected)
def bytes_to_point(b: bytes) -> Point: """Takes a compressed bytes representation and returns the corresponding point""" if b == 0: return Point.IDENTITY_ELEMENT p = CURVE.p yp, x_enc = b[0], b[1:] yp = 0 if yp == 2 else 1 x = int.from_bytes(x_enc, "big") y = mod_sqrt((x ** 3 + CURVE.a * x + CURVE.b) % p, p)[0] if y % 2 == yp: return Point(x, y, CURVE) else: return Point(x, p - y, CURVE)
def pub_key_to_point(pub_key: str) -> Point: ''' Given a public key, return a Point object (Used to verify signatures) ''' xs, ys = pub_key.split('x') return Point(int(xs, 16), int(ys, 16), curve=curve.P256)
def verify(pub_key, data, signature, hashfunc=sha256, curve=curve.P256, sign_fmt='DER', sign_size=32, pub_key_fmt='RAW'): if pub_key_fmt == 'RAW': pub_key_encoded = pub_key.encode() elif pub_key_fmt == '04': pub_key_encoded = pub_key[2:].encode() else: raise UnknownPublicKeyFormatError("fmt: '%s'" % sign_fmt) x, y = split_str_to_halves(pub_key_encoded) x, y = int(x, 16), int(y, 16) pub_key_point = Point(x, y, curve=curve) if sign_fmt in ['RAW', 'DER']: r, s = decode_sig(bytes.fromhex(signature), fmt=sign_fmt) else: raise UnknownSignatureFormatError("fmt: '%s'" % sign_fmt) priv_key = keys.gen_private_key(curve) valid = ecdsa.verify((r, s), data, pub_key_point, curve=curve, hashfunc=hashfunc) return valid
def handle_priv(self, body): self.priv_blob = body prefix, body = body[0], body[1:] if prefix != 2: raise Exception('Unknown private key prefix %02x' % prefix) c, hs = body[:-0x20], body[-0x20:] sig=hmac.new(psk_validation_key, c, sha256).digest() if hs != sig: raise Exception('Signature verification failed. This device was probably paired with another computer.') iv, c = c[:AES.block_size], c[AES.block_size:] aes=AES.new(psk_encryption_key, AES.MODE_CBC, iv) m=aes.decrypt(c) m=m[:-m[-1]] # unpad (standard this time) x, m = m[:0x20], m[0x20:] y, m = m[:0x20], m[0x20:] d, m = m[:0x20], m[0x20:] x, y, d = [int(hexlify(i[::-1]), 0x10) for i in [x, y, d]] if not P256.is_point_on_curve( (x, y) ): raise Exception('Point is not on the curve') # TODO check if the priv key belogs to this public key self.trace('Private key:') self.trace('x=0x%x' % x) self.trace('y=0x%x' % y) self.trace('d=0x%x' % d) self.pub_key = Point(x, y, P256) self.priv_key = d
def gen_prediction(observed, Q, d): checkbits = observed & 0xffff for high_bits in range(2**16): guess = (high_bits << (8 * 30)) | (observed >> (8 * 2)) on_curve, y = find_point_on_p256(guess) if on_curve: # use the backdoor to guess the next 30 bytes # point = Point(p256.curve, guess, y) point = Point(guess, y, curve=P256) s = (d * point).x r = (s * Q).x & (2**(8 * 30) - 1) if VERBOSE: stdout.write('Checking: %x (%x vs %x) \r' % (high_bits, checkbits, (r >> (8 * 28)))) stdout.flush() # check the first 2 bytes against the observed bytes if checkbits == (r >> (8 * 28)): if VERBOSE: stdout.write('\r\n') stdout.flush() # if we have a match then we know the next 28 bits return r & (2**(8 * 28) - 1) return 0
def main(): # P, Q, d = gen_point() P = Point( 0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296, 0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5, curve=P256) Q = Point( 0x43595b13c9dc2e7e6fdc09175a5527c4973778d96a9e602fc5bf35d7f8f43424, 0xda93baf3284401b5426dea5354e63738817ff4938f9532157ccff8535f6d1076, curve=P256) d = 0xe7366b3509adb3de385d04712f8556c1cca77ee91d7e7df1fcfbd902c127d744 e = gen_ECC(20639247711360085, P, Q) focus = 0x56929a811a2ac18732371d1615c937d92c61204481c746c9f836febf862b6096 predicted = gen_prediction(focus, Q, d) print "[+]predicted:", hex(predicted), predicted
def elliptic_hash(msg: bytes, CURVE: Curve): p = CURVE.p i = 0 while True: i += 1 prefixed_msg = str(i).encode() + msg h = sha256(prefixed_msg).hexdigest() x = int(h, 16) if x >= p: continue y_sq = (x ** 3 + CURVE.a * x + CURVE.b) % p y = mod_sqrt(y_sq, p)[0] if CURVE.is_point_on_curve((x, y)): b = int(md5(prefixed_msg).hexdigest(), 16) % 2 return Point(x, y, CURVE) if b else Point(x, p - y, CURVE)
def verify(self): x, y = DEREncoder.decode_signature(base64.b64decode(self.sender)) public_key = Point(x, y, Transaction._curve) r, s = DEREncoder.decode_signature(base64.b64decode(self.signature)) return ecdsa.verify((r, s), self.data, public_key, curve=Transaction._curve)
def Pub2Point(public_key): x = int(public_key[2:66], 16) if len(public_key) < 70: y = bit.format.x_to_y(x, int(public_key[:2], 16) % 2) else: y = int(public_key[66:], 16) return Point(x, y, curve=curve.secp256k1)
def receive_public(self, data): """ Remember to include the nonce for ultra-secure key exchange! """ Px = int(data["Px"]) Py = int(data["Py"]) self.recieved = Point(Px, Py, curve=secp256k1) self.nonce = int(data['nonce'])
def deserialize(dic: dict) -> 'Transaction': R = Point.deserialize(dic['R']) T = int(dic['T']) inputs = [ Signature.deserialize(signature) for signature in dic['inputs'] ] outputs = [TXO.deserialize(txo) for txo in dic['outputs']] return Transaction(R, T, inputs, outputs)
def hash_to_point(info): # @todo remove hardcode if info == 'seed-for-test': return Point( 0x8e7e4fd43549adbc1d1114eba80fd4a41a1bc823b0e1b0dc3f75580979a7b188, 0xcecb5cf337d7908efcfea414d9b6f9ced465a94b086cbfc056180ba978a778d0, curve) return create_point(info, curve)
def check_signature(r, s, pk_string, data): n_r = int(r) n_s = int(s) pk = pk_string.split('\n') x = pk[0].split()[1] y = pk[1].split()[1] S = Point(int(x, 0), int(y, 0), curve=P256) valid = ecdsa.verify((n_r, n_s), data, S) return valid
def check_shadow(shadow, j, exponents): sum = point_at_infinity x = 1 for exponent in exponents: sum = sum + x * Point(exponent[0], exponent[1], secp256k1) x = x * j return shadow * base == sum
def G(self): """ The base point of the curve. For the purposes of ECDSA this point is multiplied by a private key to obtain the corresponding public key. Make a property to avoid cyclic dependency of Point on Curve (a point lies on a curve) and Curve on Point (curves have a base point). """ from fastecdsa.point import Point return Point(self.gx, self.gy, self)
def create_encrypted_json(data, sx, sy, st, pswd, iv): data_str = str(data) encrypted_data = encrypt(data_str, pswd, iv) S = Point(int(sx, 0), int(sy, 0), curve=P256) r, s, pk = sign_message(data_str, S, st) encrypted_r = encrypt(str(r), pswd, iv) encrypted_s = encrypt(str(s), pswd, iv) encrypted_pk = encrypt(str(pk), pswd, iv) encrypted_st = encrypt(str(st), pswd, iv) output = {"data": encrypted_data, "r": encrypted_r, "s": encrypted_s, "pn": encrypted_st,"pk": encrypted_pk} return output
def test_secp256k1_arith(self): # http://crypto.stackexchange.com/a/787/17884 m = 0xAA5E28D6A97A2479A65527F7290311A3624D4CC0FA1578598EE3C2613BF99522 expected = Point( 0x34F9460F0E4F08393D192B3C5133A6BA099AA0AD9FD54EBCCFACDFA239FF49C6, 0x0B71EA9BD730FD8923F6D25A7A91E7DD7728A960686CB5A901BB419E0F2CA232, curve=secp256k1) R = m * secp256k1.G self.assertEqual(R, expected) m = 0x7E2B897B8CEBC6361663AD410835639826D590F393D90A9538881735256DFAE3 expected = Point( 0xD74BF844B0862475103D96A611CF2D898447E288D34B360BC885CB8CE7C00575, 0x131C670D414C4546B88AC3FF664611B1C38CEB1C21D76369D7A7A0969D61D97D, curve=secp256k1) R = m * secp256k1.G self.assertEqual(R, expected) m = 0x6461E6DF0FE7DFD05329F41BF771B86578143D4DD1F7866FB4CA7E97C5FA945D expected = Point( 0xE8AECC370AEDD953483719A116711963CE201AC3EB21D3F3257BB48668C6A72F, 0xC25CAF2F0EBA1DDB2F0F3F47866299EF907867B7D27E95B3873BF98397B24EE1, curve=secp256k1) R = m * secp256k1.G self.assertEqual(R, expected) m = 0x376A3A2CDCD12581EFFF13EE4AD44C4044B8A0524C42422A7E1E181E4DEECCEC expected = Point( 0x14890E61FCD4B0BD92E5B36C81372CA6FED471EF3AA60A3E415EE4FE987DABA1, 0x297B858D9F752AB42D3BCA67EE0EB6DCD1C2B7B0DBE23397E66ADC272263F982, curve=secp256k1) R = m * secp256k1.G self.assertEqual(R, expected) m = 0x1B22644A7BE026548810C378D0B2994EEFA6D2B9881803CB02CEFF865287D1B9 expected = Point( 0xF73C65EAD01C5126F28F442D087689BFA08E12763E0CEC1D35B01751FD735ED3, 0xF449A8376906482A84ED01479BD18882B919C140D638307F0C0934BA12590BDE, curve=secp256k1) R = m * secp256k1.G self.assertEqual(R, expected)
def test_P521_arith(self): S = Point( int( '000001d5c693f66c08ed03ad0f031f937443458f601fd098d3d0227b4bf62873af50740b0bb84aa15' '7fc847bcf8dc16a8b2b8bfd8e2d0a7d39af04b089930ef6dad5c1b4', 16), int( '00000144b7770963c63a39248865ff36b074151eac33549b224af5c8664c54012b818ed037b2b7c1a' '63ac89ebaa11e07db89fcee5b556e49764ee3fa66ea7ae61ac01823', 16), curve=P521) d = int( '000001eb7f81785c9629f136a7e8f8c674957109735554111a2a866fa5a166699419bfa9936c78b62' '653964df0d6da940a695c7294d41b2d6600de6dfcf0edcfc89fdcb1', 16) expected = Point( int( '00000091b15d09d0ca0353f8f96b93cdb13497b0a4bb582ae9ebefa35eee61bf7b7d041b8ec34c6c0' '0c0c0671c4ae063318fb75be87af4fe859608c95f0ab4774f8c95bb', 16), int( '00000130f8f8b5e1abb4dd94f6baaf654a2d5810411e77b7423965e0c7fd79ec1ae563c207bd255ee' '9828eb7a03fed565240d2cc80ddd2cecbb2eb50f0951f75ad87977f', 16), curve=P521) R = d * S self.assertEqual(R, expected)
def load_pub(str_key): """ Convert str key to public key from json file. :param public_key: str key to convert :type public_key: str :return: Public key :rtype: Point """ x, y = tuple(map(lambda sig: int(sig, 0), str_key.split(','))) public_key = Point(x, y, secp256k1) return public_key