async def _send_handshake_response(self, packet: Packet[MessagePacket], sender_endpoint: Endpoint) -> None: self.logger.debug("%s: sending handshake response", self) try: remote_enr = self._enr_db.get_enr(packet.auth_data.source_node_id) except KeyError: enr_sequence_number = 0 else: enr_sequence_number = remote_enr.sequence_number auth_data = WhoAreYouPacket( id_nonce=cast(IDNonce, secrets.token_bytes(16)), enr_sequence_number=enr_sequence_number, ) self.handshake_response_packet = Packet.prepare( aes_gcm_nonce=packet.header.aes_gcm_nonce, initiator_key=cast(AES128Key, secrets.token_bytes(16)), message=EmptyMessage(), auth_data=auth_data, dest_node_id=packet.auth_data.source_node_id, ) envelope = OutboundEnvelope( packet=self.handshake_response_packet, receiver_endpoint=sender_endpoint, ) await self._events.packet_sent.trigger((self, envelope)) await self._outbound_envelope_send_channel.send(envelope)
def extract_challenge_data(challenge_data): stream = io.BytesIO(challenge_data) masking_iv = stream.read(16) static_header = Header.from_wire_bytes(stream.read(HEADER_PACKET_SIZE)) who_are_you = WhoAreYouPacket.from_wire_bytes( stream.read(WHO_ARE_YOU_PACKET_SIZE)) assert stream.read() == b"" return masking_iv, static_header, who_are_you
def do_who_are_you_packet_fixture_decoding_test(fixture): dest_node_id = decode_hex(fixture["dest-node-id"]) expected_auth_data = WhoAreYouPacket( id_nonce=decode_hex(fixture["packet"]["id-nonce"]), enr_sequence_number=to_int(hexstr=fixture["packet"]["enr-seq"]), ) encoded_packet = decode_hex(fixture["encoded"]) aes_gcm_nonce = decode_hex(fixture["packet"]["request-nonce"]) packet = decode_packet(encoded_packet, dest_node_id) assert packet.auth_data == expected_auth_data assert packet.header.aes_gcm_nonce == aes_gcm_nonce
def test_who_are_you_packet_encoding(): initiator_key = b"\x01" * 16 aes_gcm_nonce = b"\x02" * 12 dest_node_id = b"\x04" * 32 message = PingMessage(b"\x01", 0) auth_data = WhoAreYouPacket(id_nonce=b"\x06" * 16, enr_sequence_number=0x07) packet = Packet.prepare( aes_gcm_nonce=aes_gcm_nonce, initiator_key=initiator_key, message=message, auth_data=auth_data, dest_node_id=dest_node_id, ) packet_wire_bytes = packet.to_wire_bytes() result = decode_packet(packet_wire_bytes, dest_node_id) assert result == packet
def test_who_are_you_packet_encoding(): initiator_key = b"\x01" * 16 nonce = b"\x02" * 12 source_node_id = b"\x03" * 32 dest_node_id = b"\x04" * 32 message = PingMessage(1, 0) auth_data = WhoAreYouPacket(request_nonce=b"\x05" * 12, id_nonce=b"\x06" * 32, enr_sequence_number=0x07) packet = Packet.prepare( nonce=nonce, initiator_key=initiator_key, message=message, auth_data=auth_data, source_node_id=source_node_id, dest_node_id=dest_node_id, ) packet_wire_bytes = packet.to_wire_bytes() result = decode_packet(packet_wire_bytes, dest_node_id) assert result == packet
def do_handshake_packet_fixture_decoding_test(fixture): source_node_id = decode_hex(fixture["src-node-id"]) dest_node_id = decode_hex(fixture["dest-node-id"]) encoded_packet = decode_hex(fixture["encoded"]) ping_enr_seq = to_int(hexstr=fixture["packet"]["message"]["enr-seq"]) who_are_you_enr_seq = to_int( hexstr=fixture["handshake-inputs"]["whoareyou"]["enr-seq"]) if who_are_you_enr_seq == ping_enr_seq and who_are_you_enr_seq != 0: should_have_record = False else: should_have_record = True # ephemeral_private_key = decode_hex(fixture['handshake-inputs']['ephemeral-key']) ephemeral_public_key = decode_hex( fixture["handshake-inputs"]["ephemeral-pubkey"]) # ephemeral_private_key = decode_hex(fixture["handshake-inputs"]["ephemeral-key"]) # request_nonce = decode_hex(fixture['handshake-inputs']['whoareyou']['request-nonce']) challenge_data = decode_hex( fixture["handshake-inputs"]["whoareyou"]["challenge-data"]) masking_iv, static_header, who_are_you = extract_challenge_data( challenge_data) id_nonce = decode_hex(fixture["handshake-inputs"]["whoareyou"]["id-nonce"]) assert who_are_you.id_nonce == id_nonce aes_gcm_nonce = decode_hex(fixture["nonce"]) # TODO: why doesn't this match # assert static_header.aes_gcm_nonce == aes_gcm_nonce signature_inputs = V4HandshakeScheme.signature_inputs_cls( iv=masking_iv, header=static_header, who_are_you=WhoAreYouPacket(id_nonce, who_are_you_enr_seq), ephemeral_public_key=ephemeral_public_key, recipient_node_id=dest_node_id, ) id_nonce_signature = V4HandshakeScheme.create_id_nonce_signature( signature_inputs=signature_inputs, private_key=NODE_KEY_A, ) packet = decode_packet(encoded_packet, dest_node_id) expected_auth_data = HandshakePacket( auth_data_head=HandshakeHeader(source_node_id, 64, 33), id_signature=id_nonce_signature, ephemeral_public_key=ephemeral_public_key, record=packet.auth_data.record, ) assert expected_auth_data == packet.auth_data assert packet.header.aes_gcm_nonce == aes_gcm_nonce if should_have_record: assert packet.auth_data.record is not None assert packet.auth_data.record.node_id == source_node_id else: assert packet.auth_data.record is None expected_message = PingMessage( request_id=decode_hex(fixture["packet"]["message"]["req-id"]), enr_seq=to_int(hexstr=fixture["packet"]["message"]["enr-seq"]), ) actual_message = decode_message( decryption_key=decode_hex(fixture["read-key"]), aes_gcm_nonce=aes_gcm_nonce, message_cipher_text=packet.message_cipher_text, authenticated_data=packet.challenge_data, ) assert expected_message == actual_message
from ddht.tools.factories.v5_1 import HeaderFactory, WhoAreYouPacketFactory from ddht.tools.v5_strategies import iv_st, node_id_st, private_key_st from ddht.v5_1.constants import ID_NONCE_SIGNATURE_PREFIX, WHO_ARE_YOU_PACKET_SIZE from ddht.v5_1.handshake_schemes import SignatureInputs, V4HandshakeScheme from ddht.v5_1.packets import WhoAreYouPacket header_st = st.binary(min_size=12, max_size=12).map(lambda aes_gcm_nonce: HeaderFactory( flag=WhoAreYouPacket.flag, aes_gcm_nonce=aes_gcm_nonce, auth_data_size=WHO_ARE_YOU_PACKET_SIZE, )) who_are_you_st = st.tuples( st.binary(min_size=16, max_size=16), st.integers(min_value=0, max_value=65536), ).map(lambda id_nonce_and_seq_num: WhoAreYouPacket(*id_nonce_and_seq_num)) def test_handshake_key_generation(): private_key, public_key = V4HandshakeScheme.create_handshake_key_pair() V4HandshakeScheme.validate_uncompressed_public_key(public_key) V4HandshakeScheme.validate_handshake_public_key(public_key) assert PrivateKey(private_key).public_key.to_bytes() == public_key @pytest.mark.parametrize("public_key", (b"\x01" * 64, b"\x02" * 64)) def test_handshake_public_key_validation_valid(public_key): V4HandshakeScheme.validate_handshake_public_key(public_key) @pytest.mark.parametrize(