def __init__(self, x, y, curve_name, secret_multiplier=None): if not curve_name: raise ValueError("curve_name must be specified") self.curve_name = curve_name for c in curves: if c.name == curve_name or c.openssl_name == curve_name: curve = c break else: raise ValueError( "Curve '{0}' not supported by python-ecdsa".format(curve_name)) self.private_key = None self.public_key = None self.key_type = "ecdsa" if secret_multiplier: self.private_key = SigningKey.from_secret_exponent( secret_multiplier, curve) if x and y: point = Point(curve.curve, x, y) self.public_key = VerifyingKey.from_public_point(point, curve) if not self.public_key: self.public_key = self.private_key.get_verifying_key()
def verify(cls, key: 'EC2', data: bytes, signature: bytes) -> bool: p = Point(curve=cls.get_curve().curve, x=int(hexlify(key.x), 16), y=int(hexlify(key.y), 16)) vk = VerifyingKey.from_public_point(p, cls.get_curve(), cls.get_hash_func(), validate_point=True) try: return vk.verify(signature=signature, data=data, hashfunc=cls.get_hash_func()) except BadSignatureError: return False
def signing_key_from_seed(encoded_seed: str) -> SigningKey: """ Derives SigningKey from master seed. Reference: https://ripple.com/wiki/Account_Family#Root_Key_.28GenerateRootDeterministicKey.29 """ # Ripple seeds are base58-encoded and prefixed with letter "s" assert encoded_seed[0] == 's' seed = base58.b58decode_check(encoded_seed, alphabet=base58.RIPPLE_ALPHABET)[1:] seq = 0 while True: private_gen = int.from_bytes(first_half_of_sha512( seed, seq.to_bytes(4, byteorder='big')), byteorder='big') seq += 1 if SECP256k1.order >= private_gen: break public_key = VerifyingKey.from_public_point(SECP256k1.generator * private_gen, curve=SECP256k1) # Now that we have the private and public generators, we apparently # have to calculate a secret from them that can be used as a ECDSA # signing key. secret = i = 0 public_gen_compressed = public_key.to_string(encoding='compressed') while True: secret = int.from_bytes(first_half_of_sha512( public_gen_compressed, bytes(4), i.to_bytes(4, byteorder='big')), byteorder='big') i += 1 if SECP256k1.order >= secret: break secret = (secret + private_gen) % SECP256k1.order return SigningKey.from_secret_exponent(secret, curve=SECP256k1)
def create_verifying_key(x, y): point = Point(SECP256k1.curve, x, y) return VerifyingKey.from_public_point(point, curve=SECP256k1)
def test_ecdh_check(self): ''' https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-23#appendix-C ''' v_stc_material = { "kty": "EC", "crv": "P-256", "x": "gI0GAILBdu7T53akrFmMyGcsF3n5dO7MmwNBHKW5SV0", "y": "SLW_xSffzlPWrHEVI30DHM_4egVwt3NQqeUD7nMFpps", "d": "0_NxaRPUMQoAJt50Gz8YiTr8gRTwyEaCumd-MToTmIo" } u_epk_material = { "kty": "EC", "crv": "P-256", "x": "weNJy2HscCSM6AEDTDg04biOvhFhyyWvOHQfeF_PxMQ", "y": "e8lnCO-AlStT-NJVX-crhB7QRYhiix03illJOVAOyck", "d": "VEmDZpDXXK8p8N0Cndsxs924q6nS1RXFASRl6BfUqdw" } import re def _to_pub(km): return ( int(re.search(r"P-(\d+)$", km['crv']).group(1)), (base64.long_from_b64(km['x']), base64.long_from_b64(km['y'])), ) def _to_pri(km): return ( int(re.search(r"P-(\d+)$", km['crv']).group(1)), base64.long_from_b64(km['d']), ) pub_tuple = _to_pub(v_stc_material) pri_tuple = _to_pri(v_stc_material) import pydoc curve = pydoc.locate('ecdsa.curves.NIST{0}p'.format(pub_tuple[0])) from ecdsa import ( SigningKey, VerifyingKey, ellipticcurve as ec) x, y = pub_tuple[1] v_pub = VerifyingKey.from_public_point( ec.Point(curve.curve, x, y, curve.order), curve, ) v_stc = SigningKey.from_secret_exponent(pri_tuple[1], curve) # Party U provides a ephemeral key pub_tuple = _to_pub(u_epk_material) pri_tuple = _to_pri(u_epk_material) x, y = pub_tuple[1] u_epk = SigningKey.from_secret_exponent(pri_tuple[1], curve) from jose.jwa.ec import ecdsa_dhZ # Party U compute shared_secret_u = ecdsa_dhZ(v_pub, u_epk) print("Aggreement:", base64.long_to_b64(shared_secret_u)) from Crypto.Util.number import long_to_bytes from math import ceil block_size = int(ceil(pub_tuple[0] / 8.0)) # bit number(512 ) / 8 -> octets Zu = long_to_bytes(shared_secret_u, block_size) Z_jwa = [158, 86, 217, 29, 129, 113, 53, 211, 114, 131, 66, 131, 191, 132, 38, 156, 251, 49, 110, 163, 218, 128, 106, 72, 246, 218, 167, 121, 140, 254, 144, 196] self.assertEqual(_ilist(Zu), Z_jwa) # Other Information used in Concat KDF # AlgorithmID || PartyUInfo || PartyVInfo || SuppPubInfo from struct import pack def _otherInfo(alg, pu, pv, klen): return b('').join([ pack("!I", len(alg)), alg, pack("!I", len(pu)), pu, pack("!I", len(pv)), pv, pack("!I", klen), ]) oi_u = _otherInfo( b("A128GCM"), b("Alice"), b("Bob"), 16 * 8, # A128GCM ) oi_jwa = [ 0, 0, 0, 7, 65, 49, 50, 56, 71, 67, 77, 0, 0, 0, 5, 65, 108, 105, 99, 101, 0, 0, 0, 3, 66, 111, 98, 0, 0, 0, 128] print(">>>>>>>", type(oi_u)) print("<<<<<<<", oi_u) self.assertEqual(_ilist(oi_u), oi_jwa) # Coccat KDF : NIST defines SHA256 from Crypto.Hash import SHA256 def _ConcatKDF(Z, dkLen, otherInfo, digest_method=SHA256): def _src(counter_bytes): return b("").join([counter_bytes, Z, otherInfo]) from math import ceil from struct import pack dkm = b'' # Derived Key Material counter = 0 klen = int(ceil(dkLen / 8.0)) while len(dkm) < klen: counter += 1 counter_b = pack("!I", counter) dkm += digest_method.new(_src(counter_b)).digest() return dkm[:klen] _derived_key_u = _ConcatKDF(Zu, 16 * 8, oi_u) # Party V recive Epemeral Public Key v_epk = u_epk.get_verifying_key() Zv = long_to_bytes(ecdsa_dhZ(v_epk, v_stc), block_size) _derived_key_v = _ConcatKDF(Zv, 16 * 8, oi_u) self.assertEqual(_derived_key_u, _derived_key_v) kd_jwa = [ 86, 170, 141, 234, 248, 35, 109, 32, 92, 34, 40, 205, 113, 167, 16, 26] self.assertEqual(_ilist(_derived_key_u), kd_jwa) self.assertEqual(b("VqqN6vgjbSBcIijNcacQGg"), base64.base64url_encode(_derived_key_u))