def __init__(self, cred_idr, cred, auth_key): super().__init__() # test with static connection identifier and static ephemeral key self.ephemeral_key = OKP( crv=CoseEllipticCurves.X25519, x=unhexlify( "71a3d599c21da18902a1aea810b2b6382ccd8d5f9bf0195281754c5ebcaf301e" ), d=unhexlify( "fd8cd877c9ea386e6af34ff7e606c4b64ca831c8ba33134fd4cd7167cabaecda" )) self.cred_idr = cred_idr self.cred = cred self.auth_key = auth_key self.supported = [ CipherSuite.SUITE_0, CipherSuite.SUITE_1, CipherSuite.SUITE_2, CipherSuite.SUITE_3 ] self.resp = self.create_responder() with open(self.cred_store, 'rb') as h: self.credentials_storage = pickle.load(h)
def remote_pubkey(self) -> Key: """ Returns the remote ephemeral public key. """ if self.cipher_suite.dh_curve in [CoseEllipticCurves.X448, CoseEllipticCurves.X25519]: return OKP(x=self.g_x, crv=self.cipher_suite.dh_curve) else: # TODO: implement NIST curves pass
def setup_dh_key(selected_cipher: int, private_bytes: bytes): if CipherSuite(selected_cipher).dh_curve in [ CoseEllipticCurves.X448, CoseEllipticCurves.X25519 ]: return OKP(d=private_bytes, crv=CipherSuite(selected_cipher).dh_curve) elif CipherSuite(selected_cipher).dh_curve in [CoseEllipticCurves.P_256]: return EC2(d=private_bytes, crv=CipherSuite(selected_cipher).sign_curve) else: raise ValueError("Illegal DH keys.")
def local_pubkey(self) -> Key: """ Returns the local ephemeral public key. """ if self.cipher_suite.dh_curve in [ CoseEllipticCurves.X448, CoseEllipticCurves.X25519 ]: return OKP(x=self.g_x, crv=self.cipher_suite.dh_curve) else: # TODO: pass
def setup_sign_key(selected_cipher: int, private_bytes: bytes): if CipherSuite(selected_cipher).sign_curve in [ CoseEllipticCurves.ED448, CoseEllipticCurves.ED25519 ]: return OKP(d=private_bytes, crv=CipherSuite(selected_cipher).sign_curve, alg=CipherSuite(selected_cipher).sign_alg) elif CipherSuite(selected_cipher).sign_alg == CoseAlgorithms.ES256: return EC2(d=private_bytes, alg=CoseAlgorithms.ES256, crv=CipherSuite(selected_cipher).sign_curve) else: raise ValueError("Illegal signing keys.")
def test_initiator_message3(initiator, test_vectors): initiator.msg_1 = MessageOne.decode(test_vectors['I']['message_1']) initiator.msg_2 = MessageTwo.decode(test_vectors['R']['message_2']) crv = CoseEllipticCurves(CipherSuite(initiator._selected_cipher).dh_curve) hash_func = config_cose(CipherSuite(initiator._selected_cipher).hash).hash assert initiator.data_2 == test_vectors['R']['data_2'] assert initiator._th2_input == test_vectors['R']['input_th_2'] assert initiator._prk2e == test_vectors['R']['prk_2e'] assert initiator._prk3e2m == test_vectors['R']['prk_3e2m'] assert initiator.transcript( hash_func, initiator._th2_input) == test_vectors['R']['th_2'] assert initiator._decrypt( initiator.msg_2.ciphertext) == test_vectors['R']['p_2e'] assert initiator.shared_secret(initiator.ephemeral_key, OKP(x=initiator.g_y, crv=crv)) == test_vectors['S']['g_xy'] assert initiator.data_3 == test_vectors['I']['data_3'] assert initiator._th3_input == test_vectors['I']['input_th_3'] assert initiator.transcript( hash_func, initiator._th3_input) == test_vectors['I']['th_3'] assert initiator.cred_id == test_vectors['I']['id_cred'] assert initiator._prk4x3m == test_vectors['I']['prk_4x3m'] assert initiator._external_aad( initiator._th3_input, initiator.aad3_cb) == test_vectors['I']['eaad_3m'] assert initiator._hkdf3(16, 'K_3m', initiator._prk4x3m) == test_vectors['I']['k_3m'] assert initiator._hkdf3(13, 'IV_3m', initiator._prk4x3m) == test_vectors['I']['iv_3m'] assert initiator._mac(initiator._hkdf3, 'K_3m', 16, 'IV_3m', 13, initiator._th3_input, initiator._prk4x3m, initiator.aad2_cb) == test_vectors['I']['mac3'] assert initiator.signature_or_mac3( test_vectors['I']['mac3']) == test_vectors['I']['sign_or_mac3'] assert initiator._p_3ae == test_vectors['I']['p_3ae'] assert initiator._hkdf3(16, 'K_3ae', initiator._prk3e2m) == test_vectors['I']['k_3ae'] assert initiator._hkdf3(13, 'IV_3ae', initiator._prk3e2m) == test_vectors['I']['iv_3ae'] assert initiator.ciphertext_3 == test_vectors['I']['ciphertext_3'] assert initiator.create_message_three( test_vectors['R']['message_2']) == test_vectors['I']['message_3']
def test_responder_message2(responder, test_vectors): responder.msg_1 = MessageOne.decode(test_vectors['I']['message_1']) hash_func = config_cose(CipherSuite( responder.msg_1.selected_cipher).hash).hash crv = CoseEllipticCurves( CipherSuite(responder.msg_1.selected_cipher).dh_curve) assert responder.shared_secret(responder.ephemeral_key, OKP(x=responder.g_x, crv=crv)) == test_vectors['S']['g_xy'] assert responder._prk2e == test_vectors['R']['prk_2e'] assert responder._prk3e2m == test_vectors['R']['prk_3e2m'] assert responder.data_2 == test_vectors['R']['data_2'] assert responder._th2_input == test_vectors['R']['input_th_2'] assert responder.cred_id == test_vectors['R']['id_cred'] assert responder.transcript( hash_func, responder._th2_input) == test_vectors['R']['th_2'] assert responder._external_aad( responder._th2_input, responder.aad2_cb) == test_vectors['R']['eaad_2m'] assert responder._hkdf2( 16, 'K_2m', prk=responder._prk3e2m) == test_vectors['R']['k_2m'] assert responder._hkdf2( 13, 'IV_2m', prk=responder._prk3e2m) == test_vectors['R']['iv_2m'] assert responder._mac(responder._hkdf2, 'K_2m', 16, 'IV_2m', 13, responder._th2_input, responder._prk3e2m, responder.aad2_cb) == test_vectors['R']['mac2'] assert responder.signature_or_mac2( test_vectors['R']['mac2']) == test_vectors['R']['sign_or_mac2'] assert responder._p_2e == test_vectors['R']['p_2e'] assert responder._hkdf2(len(responder._p_2e), 'K_2e', prk=responder._prk2e) == test_vectors['R']['k_2e'] assert responder.ciphertext_2 == test_vectors['R']['ciphertext_2'] assert responder.create_message_two( test_vectors['I']['message_1']) == test_vectors['R']['message_2']
def _generate_ephemeral_key(self) -> None: """ Generate a new ephemeral key if the key was not already set. :return: None """ if self.ephemeral_key is not None: return chosen_suite = CipherSuite(self.cipher_suite) if chosen_suite.dh_curve in [ CoseEllipticCurves.X25519, CoseEllipticCurves.X448 ]: self.ephemeral_key = OKP.generate_key( CoseAlgorithms.DIRECT, curve_type=chosen_suite.dh_curve, key_ops=KeyOps.SIGN) else: self.ephemeral_key = EC2.generate_key( CoseAlgorithms.DIRECT, curve_type=chosen_suite.dh_curve, key_ops=KeyOps.SIGN)
async def main(): parser = argparse.ArgumentParser() # 51.75.194.248 parser.add_argument("ip", help="IP address of EDHOC responder", type=str) parser.add_argument("--epk", help="Use a preset ephemeral key", action="store_true") args = parser.parse_args() context = await Context.create_client_context() supported = [CipherSuite.SUITE_0] if args.epk: ephemeral_key = OKP( crv=CoseEllipticCurves.X25519, x=unhexlify( "898ff79a02067a16ea1eccb90fa52246f5aa4dd6ec076bba0259d904b7ec8b0c" ), d=unhexlify( "8f781a095372f85b6d9f6109ae422611734d7dbfa0069a2df2935bb2e053bf35" )) else: ephemeral_key = None init = Initiator(corr=Correlation.CORR_1, method=Method.SIGN_SIGN, conn_idi=unhexlify(b''), cred_idi=cred_id, auth_key=private_key, cred=cert, peer_cred=get_peer_cred, supported_ciphers=supported, selected_cipher=CipherSuite.SUITE_0, ephemeral_key=ephemeral_key) msg_1 = init.create_message_one() # assert msg_1 == unhexlify(b"01005820898ff79a02067a16ea1eccb90fa52246f5aa4dd6ec076bba0259d904b7ec8b0c40") request = Message(code=Code.POST, payload=msg_1, uri=f"coap://{args.ip}/.well-known/edhoc") logging.info("POST (%s) %s", init.edhoc_state, request.payload) response = await context.request(request).response logging.info("CHANGED (%s) %s", init.edhoc_state, response.payload) msg_3 = init.create_message_three(response.payload) # assert msg_3 == unhexlify(_msg_3) logging.info("POST (%s) %s", init.edhoc_state, request.payload) request = Message(code=Code.POST, payload=msg_3, uri=f"coap://{args.ip}/.well-known/edhoc") response = await context.request(request).response conn_idi, conn_idr, aead, hashf = init.finalize() logging.info('EDHOC key exchange successfully completed:') logging.info(f" - connection IDr: {conn_idr}") logging.info(f" - connection IDi: {conn_idi}") logging.info(f" - aead algorithm: {CoseAlgorithms(aead)}") logging.info(f" - hash algorithm: {CoseAlgorithms(hashf)}") logging.info( f" - OSCORE secret : {init.exporter('OSCORE Master Secret', 16)}") logging.info( f" - OSCORE salt : {init.exporter('OSCORE Master Salt', 8)}")
from aiocoap.numbers.codes import Code from cose import CoseEllipticCurves, CoseAlgorithms, OKP, CoseHeaderKeys from edhoc.definitions import CipherSuite, Correlation, Method from edhoc.roles.edhoc import CoseHeaderMap from edhoc.roles.initiator import Initiator logging.basicConfig(level=logging.INFO) _msg_3 = b'1358582d88ff86da47482c0dfa559ac824a4a783d870c9dba47805e8aafbad6974c49646586503fa9bbf3e00012c037eaf56e45' \ b'e301920839b813a53f6d4c557480f6c797d5b76f0e462f5f57a3db6d2b50c32319f340f4ac5af9a' # private signature key private_key = OKP( crv=CoseEllipticCurves.ED25519, alg=CoseAlgorithms.EDDSA, d=unhexlify( "2ffce7a0b2b825d397d0cb54f746e3da3f27596ee06b5371481dc0e012bc34d7")) # certificate (should contain the pubkey but is just a random string) cert = "5865fa34b22a9ca4a1e12924eae1d1766088098449cb848ffc795f88afc49cbe8afdd1ba009f21675e8f6c77a4a2c30195601f6f0a" \ "0852978bd43d28207d44486502ff7bdda632c788370016b8965bdb2074bff82e5a20e09bec21f8406e86442b87ec3ff245b7" cert = unhexlify(cert) cred_id = cbor2.loads(unhexlify(b"a11822822e485b786988439ebcf2")) with open("cred_store.pickle", 'rb') as h: credentials_storage = pickle.load(h)
def ephemeral_initiator_key(test_vectors): return OKP(x=test_vectors['I']['g_x'], d=test_vectors['I']['x'], crv=CipherSuite(test_vectors['I']['selected']).dh_curve)
def ephemeral_responder_key(test_vectors): return OKP(x=test_vectors['R']['g_y'], d=test_vectors['R']['y'], crv=CipherSuite(test_vectors['I']['selected']).dh_curve)
from edhoc.definitions import CipherSuite, EdhocState from edhoc.exceptions import EdhocException from edhoc.roles.edhoc import CoseHeaderMap from edhoc.roles.responder import Responder logging.basicConfig(level=logging.INFO) logging.getLogger("coap-server").setLevel(logging.INFO) _msg_2 = b"582071a3d599c21da18902a1aea810b2b6382ccd8d5f9bf0195281754c5ebcaf301e13585099d53801a725bfd6a4e71d0484b755e" \ b"c383df77a916ec0dbc02bba7c21a200807b4f585f728b671ad678a43aacd33b78ebd566cd004fc6f1d406f01d9704e705b21552a9" \ b"eb28ea316ab65037d717862e" # private signature key private_key = OKP( crv=CoseEllipticCurves.ED25519, alg=CoseAlgorithms.EDDSA, d=unhexlify( "df69274d713296e246306365372b4683ced5381bfcadcd440a24c391d2fedb94")) # certificate (should contain the pubkey but is just a random string) cert = "586e47624dc9cdc6824b2a4c52e95ec9d6b0534b71c2b49e4bf9031500cee6869979c297bb5a8b381e98db714108415e5c50db78974c" \ "271579b01633a3ef6271be5c225eb28f9cf6180b5a6af31e80209a085cfbf95f3fdcf9b18b693d6c0e0d0ffb8e3f9a32a50859ecd0bf" \ "cff2c218" cert = unhexlify(cert) cred_id = cbor2.loads(unhexlify(b"a11822822e48fc79990f2431a3f5")) class EdhocResponder(resource.Resource): cred_store = "cred_store.pickle"
def test_okp_key_generation(): key = OKP.generate_key(CoseAlgorithms.EDDSA, KeyOps.SIGN, CoseEllipticCurves.X25519) assert isinstance(key, OKP)