def test_session(): initiator = RLPxSession(ECCx(raw_privkey=mk_privkey('secret1')), is_initiator=True) initiator_pubk = initiator.ecc.raw_pubkey responder = RLPxSession(ECCx(raw_privkey=mk_privkey('secret2'))) responder_pubk = responder.ecc.raw_pubkey auth_msg = initiator.create_auth_message(remote_pubkey=responder_pubk) auth_msg_ct = initiator.encrypt_auth_message(auth_msg, responder_pubk) responder.decode_authentication(auth_msg_ct) auth_ack_msg = responder.create_auth_ack_message() auth_ack_msg_ct = responder.encrypt_auth_ack_message( auth_ack_msg, initiator_pubk) initiator.decode_auth_ack_message(auth_ack_msg_ct) initiator.setup_cipher() responder.setup_cipher() assert responder.ecdhe_shared_secret == initiator.ecdhe_shared_secret assert responder.token == initiator.token assert responder.aes_secret == initiator.aes_secret assert responder.mac_secret == initiator.mac_secret assert responder.egress_mac.digest() == initiator.ingress_mac.digest() assert responder.egress_mac.digest() == initiator.ingress_mac.digest() assert responder.ingress_mac.digest() == initiator.egress_mac.digest() assert responder.ingress_mac.digest() == initiator.egress_mac.digest() assert responder.mac_secret == initiator.mac_secret return initiator, responder
def test_auth_ack_is_eip8_for_eip8_auth(): responder = RLPxSession(ECCx(raw_privkey=eip8_values['key_b'])) responder.decode_authentication(eip8_handshakes[1]['auth']) assert responder.got_eip8_auth ack = responder.create_auth_ack_message(version=55) ack_ct = responder.encrypt_auth_ack_message(ack) initiator = RLPxSession(ECCx(raw_privkey=eip8_values['key_a']), is_initiator=True) initiator.decode_auth_ack_message(ack_ct) assert initiator.got_eip8_ack assert initiator.remote_version == 55
def test_ecies_decrypt(): tv = test_values from devp2p.crypto import ECCx e = ECCx(raw_privkey=tv['receiver_private_key']) _dec = e.ecies_decrypt(tv['auth_ciphertext']) assert len(_dec) == len(tv['auth_plaintext']) assert _dec == tv['auth_plaintext']
def test_pyelliptic_sig(): priv_seed = 'test' priv_key = mk_privkey(priv_seed) my_pubkey = privtopub(priv_key) e = ECCx(my_pubkey, priv_key) msg = 'a' s = pyelliptic.ECC.sign(e, msg) assert s == pyelliptic.ECC.sign(e, msg) # deterministic
def __init__(self, ecc, is_initiator=False, token_by_pubkey=dict(), ephemeral_privkey=None): self.ecc = ecc self.is_initiator = is_initiator self.token_by_pubkey = token_by_pubkey self.ephemeral_ecc = ECCx(raw_privkey=ephemeral_privkey)
def test_pyelliptic_sig(): priv_seed = 'test' priv_key = mk_privkey(priv_seed) my_pubkey = privtopub(priv_key) e = ECCx(raw_privkey=priv_key) msg = 'a' s = pyelliptic.ECC.sign(e, msg) s2 = pyelliptic.ECC.sign(e, msg) assert s != s2 # non deterministic
def test_eip8_handshake_messages(): initiator = RLPxSession(ECCx(raw_privkey=eip8_values['key_a']), is_initiator=True) responder = RLPxSession(ECCx(raw_privkey=eip8_values['key_b'])) for handshake in eip8_handshakes: ack_rest = initiator.decode_auth_ack_message(handshake['ack']) assert initiator.remote_ephemeral_pubkey == eip8_values['eph_pub_b'] assert initiator.responder_nonce == eip8_values['nonce_b'] assert initiator.got_eip8_ack == handshake['eip8_format'] assert initiator.remote_version == handshake['ack_version'] assert ack_rest == b'' auth_rest = responder.decode_authentication(handshake['auth']) assert responder.remote_ephemeral_pubkey == eip8_values['eph_pub_a'] assert responder.initiator_nonce == eip8_values['nonce_a'] assert responder.remote_pubkey == eip8_values['pub_a'] assert responder.got_eip8_auth == handshake['eip8_format'] assert auth_rest == b''
def __init__(self, app): super(RNOService, self).__init__(app) log.info('Initializing RNO') self.config = app.config self.interrupt = Event() self.tx_queue = Queue() # thread safe self.privkey_hex = self.config['eth']['privkey_hex'].decode('hex') self.my_addr = privtoaddr(self.privkey_hex) self.eccx = ECCx(None, self.privkey_hex)
def create_auth_message(self, remote_pubkey, token=None, ephemeral_privkey=None, nonce=None): """ 1. initiator generates ecdhe-random and nonce and creates auth 2. initiator connects to remote and sends auth New: E(remote-pubk, S(ephemeral-privk, ecdh-shared-secret ^ nonce) || H(ephemeral-pubk) || pubk || nonce || 0x0 ) Known: E(remote-pubk, S(ephemeral-privk, token ^ nonce) || H(ephemeral-pubk) || pubk || nonce || 0x1) """ if not token: # new ecdh_shared_secret = self.node.get_ecdh_key(remote_pubkey) token = ecdh_shared_secret flag = 0x0 else: flag = 0x1 nonce = nonce or ienc(random.randint(0, 2**256 - 1)) assert len(nonce) == 32 token_xor_nonce = sxor(token, nonce) assert len(token_xor_nonce) == 32 # generate session ephemeral key if not ephemeral_privkey: ephemeral_privkey = sha3(ienc(random.randint(0, 2**256 - 1))) self.ephemeral_ecc = ECCx(raw_privkey=ephemeral_privkey) ephemeral_pubkey = self.ephemeral_ecc.raw_pubkey assert len(ephemeral_pubkey) == 512 / 8 # S(ephemeral-privk, ecdh-shared-secret ^ nonce) S = self.ephemeral_ecc.sign(token_xor_nonce) assert len(S) == 65 # S || H(ephemeral-pubk) || pubk || nonce || 0x0 auth_message = S + sha3( ephemeral_pubkey) + self.node.raw_pubkey + nonce + chr(flag) assert len(auth_message) == 65 + 32 + 64 + 32 + 1 == 194 return auth_message
def test_eip8_key_derivation(): responder = RLPxSession(ECCx(raw_privkey=eip8_values['key_b']), ephemeral_privkey=eip8_values['eph_key_b']) responder.decode_authentication(eip8_handshakes[1]['auth']) ack = responder.create_auth_ack_message(nonce=eip8_values['nonce_b']) responder.encrypt_auth_ack_message(ack) responder.setup_cipher() want_aes_secret = decode_hex( b'80e8632c05fed6fc2a13b0f8d31a3cf645366239170ea067065aba8e28bac487') want_mac_secret = decode_hex( b'2ea74ec5dae199227dff1af715362700e989d889d7a493cb0639691efb8e5f98') assert responder.aes_secret == want_aes_secret assert responder.mac_secret == want_mac_secret responder.ingress_mac.update(b'foo') mac_digest = responder.ingress_mac.digest() want_mac_digest = decode_hex( b'0c7ec6340062cc46f5e9f1e3cf86f8c8c403c5a0964f5df0ebd34a75ddc86db5') assert mac_digest == want_mac_digest
def __init__(self, ecc, is_initiator=False, ephemeral_privkey=None): self.ecc = ecc self.is_initiator = is_initiator self.ephemeral_ecc = ECCx(raw_privkey=ephemeral_privkey)
def test_handshake(): tv = test_values initiator = RLPxSession(ECCx(raw_privkey=tv['initiator_private_key']), is_initiator=True, ephemeral_privkey=tv['initiator_ephemeral_private_key']) initiator_pubkey = initiator.ecc.raw_pubkey responder = RLPxSession(ECCx(raw_privkey=tv['receiver_private_key']), ephemeral_privkey=tv['receiver_ephemeral_private_key']) responder_pubkey = responder.ecc.raw_pubkey # test encryption _enc = initiator.encrypt_auth_message(tv['auth_plaintext'], responder_pubkey) assert len(_enc) == len(tv['auth_ciphertext']) assert len(tv['auth_ciphertext']) == 113 + len(tv['auth_plaintext']) # len # test auth_msg plain auth_msg = initiator.create_auth_message(remote_pubkey=responder_pubkey, ephemeral_privkey=tv['initiator_ephemeral_private_key'], nonce=tv['initiator_nonce']) # test auth_msg plain assert len(auth_msg) == len(tv['auth_plaintext']) == 194 assert auth_msg[65:] == tv['auth_plaintext'][65:] # starts with non deterministic k _auth_msg_cipher = initiator.encrypt_auth_message(auth_msg, responder_pubkey) # test shared responder.ecc.get_ecdh_key(initiator_pubkey) == \ initiator.ecc.get_ecdh_key(responder_pubkey) # test decrypt assert auth_msg == responder.ecc.ecies_decrypt(_auth_msg_cipher) # check receive responder_ephemeral_pubkey = privtopub(tv['receiver_ephemeral_private_key']) auth_msg_cipher = tv['auth_ciphertext'] auth_msg = responder.ecc.ecies_decrypt(auth_msg_cipher) assert auth_msg[65:] == tv['auth_plaintext'][65:] # starts with non deterministic k responder.decode_authentication(auth_msg_cipher) auth_ack_msg = responder.create_auth_ack_message(responder_ephemeral_pubkey, nonce=tv['receiver_nonce']) assert auth_ack_msg == tv['authresp_plaintext'] auth_ack_msg_cipher = responder.encrypt_auth_ack_message(auth_ack_msg, remote_pubkey=responder.remote_pubkey) # set auth ack msg cipher (needed later for mac calculation) responder.auth_ack = tv['authresp_ciphertext'] responder.setup_cipher() assert responder.ecdhe_shared_secret == tv['ecdhe_shared_secret'] assert len(responder.token) == len(tv['token']) assert responder.token == tv['token'] assert responder.aes_secret == tv['aes_secret'] assert responder.mac_secret == tv['mac_secret'] assert responder.initiator_nonce == tv['initiator_nonce'] assert responder.responder_nonce == tv['receiver_nonce'] assert responder.auth_init == tv['auth_ciphertext'] assert responder.auth_ack == tv['authresp_ciphertext'] # test values are from initiator perspective? assert responder.ingress_mac.digest() == tv['initial_egress_MAC'] assert responder.ingress_mac.digest() == tv['initial_egress_MAC'] assert responder.egress_mac.digest() == tv['initial_ingress_MAC'] assert responder.egress_mac.digest() == tv['initial_ingress_MAC'] r = responder.decrypt(tv['initiator_hello_packet']) # unpack hello packet import struct import rlp import rlp.sedes as sedes from rlp.codec import consume_item header = r['header'] frame_length = struct.unpack(b'>I', b'\x00' + header[:3])[0] header_sedes = sedes.List([sedes.big_endian_int, sedes.big_endian_int]) header_data = rlp.decode(header[3:], strict=False, sedes=header_sedes) print('header', repr(header_data)) # frame frame = r['frame'] # normal: rlp(packet-type) [|| rlp(packet-data)] || padding packet_type, end = consume_item(frame, start=0) packet_type = rlp.decode(frame, sedes=sedes.big_endian_int, strict=False) print('packet_type', repr(packet_type)) # decode hello body _sedes_capabilites_tuple = sedes.List([sedes.binary, sedes.big_endian_int]) structure = [ ('version', sedes.big_endian_int), ('client_version_string', sedes.big_endian_int), ('capabilities', sedes.CountableList(_sedes_capabilites_tuple)), ('listen_port', sedes.big_endian_int), ('remote_pubkey', sedes.binary) ] hello_sedes = sedes.List([x[1] for x in structure]) frame_data = rlp.decode(frame[end:], sedes=hello_sedes) frame_data = dict((structure[i][0], x) for i, x in enumerate(frame_data)) print('frame', frame_data)
def __init__(self, privkey): self.ecc = ECCx(raw_privkey=privkey)