def test_dhZ(self): from ecdsa.keys import SigningKey # VerifyingKey from ecdsa.curves import NIST521p # Party V(recepient) declares a satic key pair curve = NIST521p v_stc = SigningKey.generate(curve=curve) # and advertise to Party U(Sender) ( U <--(pub key)-- V) v_pub = v_stc.get_verifying_key() self.assertEqual(v_pub.curve, curve) print(v_pub.curve) # Party U provides a ephemeral key u_epk = SigningKey.generate(curve=v_pub.curve) from jose.jwa import ec # Compute ECDH as shared secret # This shared secret itself is NOT have to be exchanged. shared_secret_u = ec.ecdsa_dhZ(v_pub, u_epk) # Party V recive Epemeral Public Key ( U --(pub key)--> V) v_epk = u_epk.get_verifying_key() # Party V compute shared_secret_v = ec.ecdsa_dhZ(v_epk, v_stc) # Secrete Agreeed! self.assertEqual(shared_secret_u, shared_secret_v)
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))