Exemplo n.º 1
0
    def receive_find_neighbors(self, addr, pubkey, fn):
        remote_id = keccak256(pubkey)
        if time.time() - self.last_pong_received.get(remote_id,
                                                     0) > K_BOND_EXPIRATION:
            # lost origin or origin is off
            return

        target_id = keccak256(fn.target)
        closest = self.table.closest(target_id, BUCKET_SIZE)

        # sent neighbours in chunks
        ns = Neighbors([], time.time() + K_EXPIRATION)
        sent = False
        node_to = Node(EndPoint(addr[0], addr[1], addr[1]), pubkey)
        for c in closest:
            ns.nodes.append(c)

            if len(ns.nodes) == K_MAX_NEIGHBORS:
                self.send_sock(ns, node_to)
                LOGGER.info("{:5} {}@{}:{} {}".format(
                    '---->',
                    binascii.hexlify(node_to.node_id)[:8], addr[0], addr[1],
                    ns))
                ns.nodes = []
                sent = True

        if len(ns.nodes) > 0 or not sent:
            self.send_sock(ns, node_to)
            LOGGER.info("{:5} {}@{}:{} {}".format(
                '---->',
                binascii.hexlify(node_to.node_id)[:8], addr[0], addr[1], ns))
Exemplo n.º 2
0
    def handlePacket(self, data, addr):
        # print("received message[" +  str(addr) + "]")
        msg_hash = data[:32]  # 32 Byte Hash
        raw_sig = data[32:97]  # 64 Byte + 1 Byte Signature
        ptype = data[97]  # 1 Byte packet_type
        pdata = data[98:]  # Rest is rlp-encoded data
        decdata = rlp.decode(pdata)
        signedData = data[97:]

        # Verify hash
        if msg_hash != keccak256(data[32:]):
            print("Invalid message hash!")
            exit(0)

        # Verify signature
        deserialized_sig = self.priv_key.ecdsa_recoverable_deserialize(
            raw_sig[:64], raw_sig[64])
        remote_pubkey = self.priv_key.ecdsa_recover(keccak256(signedData),
                                                    deserialized_sig,
                                                    raw=True)
        pub = PublicKey()
        pub.public_key = remote_pubkey
        verified = pub.ecdsa_verify(
            keccak256(signedData),
            pub.ecdsa_recoverable_convert(deserialized_sig),
            raw=True)

        if not verified:
            print("Signature invalid!")
            exit(0)
        else:
            print("Public Key: " + pub.serialize().hex())

        packet_type = bytes([ptype])
        if packet_type == PingPacket.packet_type:
            print("Got ping.")
            recv_ping = PingPacket.unpack(rlp.decode(pdata))
            print(str(recv_ping))
            # self.pong(msg_hash, recv_ping.To())
            # TODO: Find out the correct endpoint
            self.pong(self.theirEndpoint, msg_hash)

        if packet_type == PongPacket.packet_type:
            print("Got pong.")
            recv_pong = PongPacket.unpack(decdata)
            print(str(recv_pong))
            # self.ping(self.theirEndpoint)

        if packet_type == FindNodePacket.packet_type:
            print("Got FindNodePacket.")
            recv_findnode = FindNodePacket.unpack(rlp.decode(pdata))
            target = recv_findnode.target
            print("Target: " + str(target.hex()))
            self.neighbors(self.theirEndpoint, target)

        if packet_type == NeighborsPacket.packet_type:
            print("Got NeighborsPacket.")
            recv_neighbors = NeighborsPacket.unpack(rlp.decode(pdata))
            print("# Neighbors: " + str(len(recv_neighbors.neighbors)))
Exemplo n.º 3
0
    def wrap_packet(self, packet):
        payload = packet.packet_type + rlp.encode(packet.pack())
        sig = self.priv_key.ecdsa_sign_recoverable(keccak256(payload),
                                                   raw=True)
        sig_serialized = self.priv_key.ecdsa_recoverable_serialize(sig)
        payload = sig_serialized[0] + chr(sig_serialized[1]) + payload

        payload_hash = keccak256(payload)
        return payload_hash + payload
Exemplo n.º 4
0
    def receive(self, data, addr):
        """
        macSize  = 256 / 8 = 32
        sigSize  = 520 / 8 = 65
        headSize = macSize + sigSize = 97
        hash, sig, sigdata := buf[:macSize], buf[macSize:headSize], buf[headSize:]
        shouldhash := crypto.Sha3(buf[macSize:])
        """
        # verify hash
        msg_hash = data[:32]
        if msg_hash != keccak256(data[32:]):
            print " First 32 bytes are not keccak256 hash of the rest."
            return
        else:
            print " Verified message hash."

        # verify signature
        signature = data[32:97]
        signed_data = data[97:]
        deserialized_sig = self.priv_key.ecdsa_recoverable_deserialize(signature[:64],
                                                                       ord(signature[64]))

        remote_pubkey = self.priv_key.ecdsa_recover(keccak256(signed_data),
                                                    deserialized_sig,
                                                    raw=True)

        pub = PublicKey()
        pub.public_key = remote_pubkey

        verified = pub.ecdsa_verify(keccak256(signed_data),
                                    pub.ecdsa_recoverable_convert(deserialized_sig),
                                    raw=True)

        if not verified:
            print " Signature invalid"
            return
        else:
            print " Verified signature."

        response_types = {
            PingNode.packet_type: self.receive_ping,
            Pong.packet_type: self.receive_pong,
            FindNeighbors.packet_type: self.receive_find_neighbors,
            Neighbors.packet_type: self.receive_neighbors
        }

        try:
            packet_type = data[97]
            dispatch = response_types[packet_type]
        except KeyError:
            print " Unknown message type: " + data[97]
            return

        payload = data[98:]
        dispatch(payload, msg_hash, addr)
Exemplo n.º 5
0
    def receive(self):

        print "listening..."
        data, addr = self.sock.recvfrom(1024)
        print "received message[", addr, "]"

        ## verify hash
        msg_hash = data[:32]
        if msg_hash != keccak256(data[32:]):
            print " First 32 bytes are not keccak256 hash of the rest."
            return
        else:
            print " Verified message hash."

        ## verify signature
        signature = data[32:97]
        signed_data = data[97:]
        deserialized_sig = self.priv_key.ecdsa_recoverable_deserialize(
            signature[:64], ord(signature[64]))

        remote_pubkey = self.priv_key.ecdsa_recover(keccak256(signed_data),
                                                    deserialized_sig,
                                                    raw=True)

        pub = PublicKey()
        pub.public_key = remote_pubkey

        verified = pub.ecdsa_verify(
            keccak256(signed_data),
            pub.ecdsa_recoverable_convert(deserialized_sig),
            raw=True)

        if not verified:
            print " Signature invalid"
            return
        else:
            print " Verified signature."

        response_types = {
            PingNode.packet_type: self.receive_ping,
            Pong.packet_type: self.receive_pong
        }

        try:
            packet_type = data[97]
            dispatch = response_types[packet_type]
        except KeyError:
            print " Unknown message type: " + data[97]
            return

        payload = data[98:]
        dispatch(payload)
Exemplo n.º 6
0
    def handle_reply(self,
                     addr,
                     pubkey,
                     packet_type,
                     packet,
                     match_callback=None):
        remote_id = keccak256(pubkey)
        is_match = False
        for pending in self.pending_hold:
            if pending.is_alive and packet_type == pending.packet_type:
                if remote_id == pending.from_id:
                    is_match = True
                    pending.emit(packet)
                    match_callback and match_callback()
                elif pending.ep is not None and pending.ep == addr:
                    LOGGER.error('{:5} {}@{}:{} mismatch request {}'.format(
                        '',
                        binascii.hexlify(remote_id)[:8], addr[0], addr[1],
                        binascii.hexlify(pending.from_id)[:8]))
                    # is_match = True
                    # pending.emit(packet)
                    # match_callback and match_callback()
                    # for bucket in self.table.buckets:
                    #     for node in bucket.nodes:
                    #         if node.node_id == pending.from_id:
                    #             node.set_pubkey(pubkey)

        if not is_match:
            LOGGER.warning('{:5} {}@{}:{} ({}) unsolicited response'.format(
                '<-//-',
                binascii.hexlify(remote_id)[:8], addr[0], addr[1],
                PACKET_TYPES.get(packet.packet_type)))
Exemplo n.º 7
0
def eth_checksum_encode( addr ): # hex address
    o = ''
    v = int.from_bytes( keccak256( addr.encode('utf-8') ), 'big')
    for i, c in enumerate( addr ):
        if c in '0123456789':
            o += c
        else:
            o += c.upper() if (v & (1 << (255 - 4*i))) else c.lower()
    return Constants.ETH_PREFIX + o
Exemplo n.º 8
0
    def receive_pong(self, addr, pubkey, pong):
        remote_id = keccak256(pubkey)
        # response to ping
        last_pong_received = self.last_pong_received

        def match_callback():
            # solicited reply
            last_pong_received[remote_id] = time.time()

        self.handle_reply(addr, pubkey, Pong.packet_type, pong, match_callback)
Exemplo n.º 9
0
    def wrap_packet(self, packet):
        """
        Encode the packet.

        hash || signature || packet-type || packet-data
        """
        # Append the packet type to the RLP encoding of the packet data
        payload = packet.packet_type + rlp.encode(packet.pack())
        # Sign the hashed payload, use raw=True, cause we've already hashed,
        # and otherwise, the function would use its own hash function
        signature = self.private_key.ecdsa_sign_recoverable(
            keccak256(payload),
            raw=True,
        )
        # Creates a tuple
        signature_serialized = self.private_key.ecdsa_recoverable_serialize(signature)
        payload = signature_serialized[0] + chr(signature_serialized[1] + payload)

        payload_hash = keccak256(payload)
        return payload_hash + payload
Exemplo n.º 10
0
 def from_pubkey(self, pubkey, coin):
     assert isinstance(pubkey, PublicKey)
     self.coin = coin
     if coin == "BCH":
         return self( hash160( pubkey.to_ser() ), coin)
     elif coin == "BTC":
         return self( hash160( pubkey.to_ser() ), coin)
     elif coin == "ETH":
         if pubkey.is_compressed():
             pubkey.uncompress()
         return self( keccak256( pubkey.to_ser()[1:] )[-20:], coin )
     else:
         AddressError("wrong coin")        
Exemplo n.º 11
0
    def wrap_packet(self, packet):
        """
        UDP packets are structured as follows:

        hash || signature || packet-type || packet-data
        packet-type: single byte < 2**7 // valid values are [1,4]
        packet-data: RLP encoded list. Packet properties are serialized in the order in
                    which they're defined. See packet-data below.

        Offset  |
        0       | MDC       | Ensures integrity of packet,
        65      | signature | Ensures authenticity of sender, `SIGN(sender-privkey, MDC)`
        97      | type      | Single byte in range [1, 4] that determines the structure of Data
        98      | data      | RLP encoded, see section Packet Data

        The packets are signed and authenticated. The sender's Node ID is determined by
        recovering the public key from the signature.

            sender-pubkey = ECRECOVER(Signature)

        The integrity of the packet can then be verified by computing the
        expected MDC of the packet as:

            MDC = SHA3(sender-pubkey || type || data)

        As an optimization, implementations may look up the public key by
        the UDP sending address and compute MDC before recovering the sender ID.
        If the MDC values do not match, the packet can be dropped.
                """
        payload = packet.packet_type + rlp.encode(packet.pack())
        sig = self.priv_key.ecdsa_sign_recoverable(keccak256(payload),
                                                   raw=True)
        sig_serialized = self.priv_key.ecdsa_recoverable_serialize(sig)
        payload = sig_serialized[0] + chr(sig_serialized[1]) + payload

        payload_hash = keccak256(payload)
        return payload_hash + payload
Exemplo n.º 12
0
    def lookup(self, target_key):
        target_id = keccak256(target_key)
        closest = []
        while not closest:
            closest = self.closest(target_id, BUCKET_SIZE)

            if not closest:
                # add seed nodes
                for bn in self.server.boot_nodes:
                    self.add_node(bn)

        asked = [self.self_node.node_id]
        pending_queries = 0
        reply_queue = Queue()
        while True:
            for n in closest:
                if pending_queries >= KAD_ALPHA:
                    break

                if n.node_id not in asked:
                    asked.append(n.node_id)
                    pending_queries += 1
                    gevent.spawn(self.find_neighbours, n, target_key,
                                 reply_queue)

            if pending_queries == 0:
                break

            ns = reply_queue.get()
            pending_queries -= 1

            if ns:
                for node in ns:
                    farther = find_farther_to_target_than(
                        closest, target_id, node)

                    if farther:
                        closest.remove(farther)

                    if len(closest) < BUCKET_SIZE:
                        closest.append(node)
Exemplo n.º 13
0
    def find_neighbors(self, node, target_key):
        """
        send a find neighbours request to the given node and 
        waits until the node has sent up to k neighbours
        """
        node_id = node.node_id
        if time.time() - self.last_ping_received.get(node_id,
                                                     0) > K_BOND_EXPIRATION:
            send_ping = self.ping(node)
            receive_ping = self.add_pending(
                Pending(node, PingNode.packet_type, lambda _: True))
            # wait until endpoint proof is finished
            gevent.joinall([send_ping, receive_ping])

        fn = FindNeighbors(target_key, time.time() + K_EXPIRATION)

        def reply_call(chunks):
            num_received = 0
            for neighbors in chunks:
                num_received += len(neighbors.nodes)

            if num_received >= BUCKET_SIZE:
                return True

        pending = self.add_pending(
            Pending(node, Neighbors.packet_type, reply_call, timeout=2))
        self.send_sock(fn, node)
        ep = (node.endpoint.address.exploded, node.endpoint.udpPort)
        LOGGER.info("{:5} {}@{}:{} (FN {})".format(
            '---->',
            binascii.hexlify(node.node_id)[:8], ep[0], ep[1],
            binascii.hexlify(keccak256(fn.target))[:8]))
        # block to wait for neighbours
        ret = pending.get()
        if ret:
            neighbor_nodes = []
            for chunk in ret:
                for n in chunk.nodes:
                    neighbor_nodes.append(n)

            return neighbor_nodes
Exemplo n.º 14
0
    def receive_ping(self, addr, pubkey, ping, msg_hash):
        remote_id = keccak256(pubkey)
        endpoint_to = EndPoint(addr[0], ping.endpoint_from.udpPort,
                               ping.endpoint_from.tcpPort)
        pong = Pong(endpoint_to, msg_hash, time.time() + K_EXPIRATION)
        node_to = Node(pong.to, pubkey)
        # sending Pong response
        self.send_sock(pong, node_to)
        LOGGER.info("{:5} {}@{}:{} (Pong)".format(
            '---->',
            binascii.hexlify(node_to.node_id)[:8], addr[0],
            ping.endpoint_from.udpPort))

        self.handle_reply(addr, pubkey, PingNode.packet_type, ping)

        node = Node(endpoint_to, pubkey)
        if time.time() - self.last_pong_received.get(remote_id,
                                                     0) > K_BOND_EXPIRATION:
            self.ping(node, lambda: self.add_table(node))
        else:
            self.add_table(node)

        self.last_ping_received[remote_id] = time.time()
Exemplo n.º 15
0
 def __str__(self):
     return "(FN " + binascii.b2a_hex(keccak256(
         self.target))[:8] + " " + str(self.timestamp) + ")"
Exemplo n.º 16
0
 def set_pubkey(self, pubkey):
     self.node_key = pubkey
     self.node_id = keccak256(self.node_key)
Exemplo n.º 17
0
    def receive(self, data, addr):
        """
        macSize  = 256 / 8 = 32
        sigSize  = 520 / 8 = 65
        headSize = macSize + sigSize = 97
        hash, sig, sigdata := buf[:macSize], buf[macSize:headSize], buf[headSize:]
        shouldhash := crypto.Sha3(buf[macSize:])
        """
        # verify hash
        msg_hash = data[:32]
        assert msg_hash == keccak256(
            data[32:]), "First 32 bytes are not keccak256 hash of the rest"

        # verify signature
        signature = data[32:97]
        signed_data = data[97:]
        deserialized_sig = self.priv_key.ecdsa_recoverable_deserialize(
            signature[:64], ord(signature[64]))

        remote_pubkey = self.priv_key.ecdsa_recover(keccak256(signed_data),
                                                    deserialized_sig,
                                                    raw=True)

        pub = PublicKey()
        pub.public_key = remote_pubkey

        verified = pub.ecdsa_verify(
            keccak256(signed_data),
            pub.ecdsa_recoverable_convert(deserialized_sig),
            raw=True)

        assert verified, "Signature invalid"

        pubkey = pubkey_format(pub)[1:]
        hex_id = binascii.hexlify(keccak256(pubkey))

        packet_type = data[97]
        payload = rlp.decode(data[98:])
        if packet_type == PingNode.packet_type:
            # fake ip in packet
            payload[1][0] = addr[0]
            ping = PingNode.unpack(payload)
            if expired(ping):
                return
            self.receive_ping(addr, pubkey, ping, msg_hash)
        elif packet_type == Pong.packet_type:
            pong = Pong.unpack(payload)
            if expired(pong):
                return
            self.receive_pong(addr, pubkey, pong)
        elif packet_type == FindNeighbors.packet_type:
            fn = FindNeighbors.unpack(payload)
            if expired(fn):
                return
            self.receive_find_neighbors(addr, pubkey, fn)
        elif packet_type == Neighbors.packet_type:
            neighbours = Neighbors.unpack(payload)
            if expired(neighbours):
                return
            self.receive_neighbors(addr, pubkey, neighbours)
        else:
            assert False, " Unknown message type: {}".format(packet_type)