예제 #1
0
def test_eth_sign(web3, skip_if_testrpc):
    skip_if_testrpc(web3)

    private_key_hex = '0x5e95384d8050109aab08c1922d3c230739bc16976553c317e5d0b87b59371f2a'
    private_key = decode_hex(private_key_hex)

    # This imports the private key into the running geth instance and unlocks
    # the account so that it can sign things.
    # `0xa5df35f30ba0ce878b1061ae086289adff3ba1e0`
    address = web3.personal.importRawKey(private_key, "password")
    web3.personal.unlockAccount(address, "password")

    assert add_0x_prefix(encode_hex(privtoaddr(private_key))) == add_0x_prefix(address)
    assert address == '0xa5df35f30ba0ce878b1061ae086289adff3ba1e0'

    # the data to be signed
    data = b'1234567890abcdefghijklmnopqrstuvwxyz'
    # the hash of the data `0x089c33d56ed10bd8b571a0f493cedb28db1ae0f40c6cd266243001528c06eab3`
    data_hash = web3.sha3(data, encoding=None)
    data_hash_bytes = decode_hex(data_hash)

    assert force_bytes(data_hash) == sha3(data)

    priv_key = PrivateKey(flags=ALL_FLAGS)
    priv_key.set_raw_privkey(private_key)

    # sanit check the extract_ecdsa_signer function works as expected.
    vector_sig = priv_key.ecdsa_sign_recoverable(data_hash_bytes, raw=True, digest=sha3_256)
    vector_sig_bytes, rec_id = priv_key.ecdsa_recoverable_serialize(vector_sig)
    vector_sig_bytes_full = vector_sig_bytes + force_bytes(chr(rec_id))
    vector_address = force_text(extract_ecdsa_signer(data_hash_bytes, vector_sig_bytes_full))

    assert vector_address == address

    # Now have geth sign some data.
    signature_hex = web3.eth.sign(address, data)
    signature_bytes = decode_hex(signature_hex)

    actual_signer = extract_ecdsa_signer(data_hash_bytes, signature_bytes)

    assert actual_signer == address

    # Verify the signature against the public key derived from the
    # original private key.  It fails.
    rec_id = signature_bytes[64]
    if is_string(rec_id):
        rec_id = ord(rec_id)
    recoverable_signature = priv_key.ecdsa_recoverable_deserialize(
        signature_bytes[:64],
        rec_id,
    )
    signature = priv_key.ecdsa_recoverable_convert(recoverable_signature)
    is_valid = priv_key.pubkey.ecdsa_verify(
        msg=data,
        raw_sig=signature,
        digest=sha3_256,
    )

    assert is_valid
예제 #2
0
class PingServer(object):
    def __init__(self, my_endpoint):
        self.endpoint = my_endpoint

        ## get private key
        priv_key_file = open('priv_key', 'r')
        priv_key_serialized = priv_key_file.read()
        priv_key_file.close()

        self.priv_key = PrivateKey()
        self.priv_key.deserialize(priv_key_serialized)

        # bind socket
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.sock.bind(('0.0.0.0', self.endpoint.udpPort))

        # bind tcp socket
        self.tcpsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.tcpsock.bind(('0.0.0.0', self.endpoint.tcpPort))
        self.tcpsock.listen(10)



    # p2p is the based network
    # so, when the p2p network close
    # the system need to send a quit blockchain msg to Discover server
    def __del__(self):
        pass

    # # hash || signature || packet-type || packet-data
    def wrap_packet(self, packet):
        payload = packet.packet_type + rlp.encode(packet.pack())
        temp = keccak256(payload)
        sig = self.priv_key.ecdsa_sign_recoverable(temp, raw = True)
        sig_serialized = self.priv_key.ecdsa_recoverable_serialize(sig)
        # signature || packet-type || packet-data
        payload = sig_serialized[0] + chr(sig_serialized[1]) + payload
        # hash
        payload_hash = keccak256(payload)
        return payload_hash + payload

    def verifyData(self, data):
        # 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 False
        else:
            print " Verified signature."
            return True

    def recvfrom(self):
        try:
            print "listening..."
            while True :
                data, addr = self.sock.recvfrom(1024)
                print "recvived mssage[", addr, "]"

                res = self.verifyData(data)
                if res:
                    self.dispatch_data(data)
        except:
            traceback.print_exc()
            raise RuntimeError('recvfrom error')

    def recvtcpfrom(self, sock):
        try:
            print "tcp socket listening..."
            while (True):
                data = sock.recv(1024)
                print "【TCP】: get data, data's length is: %d"%len(data)
                res = self.verifyData(data)
                if res:
                    self.dispatch_data(data)
        except:
            traceback.print_exc()
            raise RuntimeError('recvtcpfrom error')

    # 分裂一个进程
    def tcp_listern(self):
        try:
            while True:
                sock, addr = self.tcpsock.accept()
                t = threading.Thread(target=self.recvtcpfrom, args=(sock,))
                t.setDaemon(True)
                t.start()
        except:
            traceback.print_exc()
            raise RuntimeError('tcp_listern error')

    # 分裂一个线程来进行对tcp监听
    def start_tcp_listern(self):
        t = threading.Thread(target=self.tcp_listern)
        t.setDaemon(True)
        t.start()

    def start_udp_listern(self):
        # udp listern
        listern_thread = self.udp_listen()
        listern_thread.start()


    def udp_listen(self):
        thread = threading.Thread(target= self.recvfrom,)
        thread.setDaemon(True)
        return thread

    def rawsendudpmsg(self, endpoint,  message):
        self.sock.sendto(message, (endpoint.address.exploded, endpoint.udpPort))

    # ping send a hello msg
    def ping(self, endpoint):
        ping = PingProtrol(self.endpoint, endpoint, time.time())
        message = self.wrap_packet(ping)
        self.rawsendudpmsg(endpoint, message)

    def pong(self, pongNode):
        message = self.wrap_packet(pongNode)
        self.rawsendudpmsg(pongNode.to, message)


    def dispatch_data(self, data):
        response_types = {
            PingProtrol.packet_type: self.receive_ping,
            PongProtrol.packet_type: self.receive_pong,
            JoinProtrol.packet_type: self.receive_join,
            WelcomeProtrol.packet_type: self.receive_welcome,
            InitNodeProtrol.packet_type: self.receive_initnode,
            ChainMsgProtrol.packet_type: self.receive_msg
        }

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

        payload = data[98:]
        dispatch(payload)

    # the function need overrided
    def receive_pong(self, payload):
        print " received Pong"
        print "", PongProtrol.unpack(rlp.decode(payload))

    def receive_ping(self, payload):
        print " received Ping"
        print "", PingProtrol.unpack(rlp.decode(payload))

    def receive_join(self, payload):
        print " received Join"
        print "", JoinProtrol.unpack(rlp.decode(payload))

    def receive_welcome(self, payload):
        print " received welcome"
        print "", JoinProtrol.unpack(rlp.decode(payload))

    def receive_initnode(self, payload):
        print " received initNode"
        print "", JoinProtrol.unpack(rlp.decode(payload))

    def receive_msg(self, payload):
        print " received msg"
        print "", JoinProtrol.unpack(rlp.decode(payload))


    # common function
    @staticmethod
    def SpecialEncode(endpoint):
        temp = {
            'ip': endpoint.address.exploded,
            'port': endpoint.tcpPort
        }
        return json.dumps(temp)

    @staticmethod
    def SpecialDecode(msg):
        return json.loads(msg)
예제 #3
0
def test_eth_sign(web3, skip_if_testrpc):
    skip_if_testrpc(web3)

    private_key_hex = '0x5e95384d8050109aab08c1922d3c230739bc16976553c317e5d0b87b59371f2a'
    private_key = decode_hex(private_key_hex)

    # This imports the private key into the running geth instance and unlocks
    # the account so that it can sign things.
    # address = '0xa5df35f30ba0ce878b1061ae086289adff3ba1e0'
    address = web3.personal.importRawKey(private_key, "password")
    web3.personal.unlockAccount(address, "password")

    assert add_0x_prefix(encode_hex(
        privtoaddr(private_key))) == add_0x_prefix(address)
    assert address == '0xa5df35f30ba0ce878b1061ae086289adff3ba1e0'

    # the data to be signed
    data = b'1234567890abcdefghijklmnopqrstuvwxyz'
    # the hash of the data `0x089c33d56ed10bd8b571a0f493cedb28db1ae0f40c6cd266243001528c06eab3`
    data_hash = web3.sha3(data, encoding=None)
    data_hash_bytes = decode_hex(data_hash)

    assert force_bytes(data_hash) == sha3(data)

    priv_key = PrivateKey(flags=ALL_FLAGS)
    priv_key.set_raw_privkey(private_key)

    # sanit check the extract_ecdsa_signer function works as expected.
    vector_sig = priv_key.ecdsa_sign_recoverable(data_hash_bytes,
                                                 raw=True,
                                                 digest=hashlib.sha3_256)
    vector_sig_bytes, rec_id = priv_key.ecdsa_recoverable_serialize(vector_sig)
    vector_sig_bytes_full = vector_sig_bytes + force_bytes(chr(rec_id))
    vector_address = force_text(
        extract_ecdsa_signer(data_hash_bytes, vector_sig_bytes_full))

    assert vector_address == address

    # Now have geth sign some data.
    signature_hex = web3.eth.sign(address, data)
    signature_bytes = decode_hex(signature_hex)

    # geth prefix message before signing
    geth_prefix_data = eth_message_prefix_hash(web3, data.decode())

    actual_signer = extract_ecdsa_signer(force_bytes(geth_prefix_data),
                                         signature_bytes)

    assert actual_signer == address

    # Verify the signature against the public key derived from the
    # original private key.  It fails.
    rec_id = signature_bytes[64]
    if is_string(rec_id):
        rec_id = ord(rec_id)
    recoverable_signature = priv_key.ecdsa_recoverable_deserialize(
        signature_bytes[:64],
        rec_id,
    )
    signature = priv_key.ecdsa_recoverable_convert(recoverable_signature)
    is_valid = priv_key.pubkey.ecdsa_verify(
        msg=data,
        raw_sig=signature,
        digest=hashlib.sha3_256,
    )

    assert is_valid
예제 #4
0
class TestIcxSigner(unittest.TestCase):
    def setUp(self):
        self.test_private_key = PrivateKey()
        self.signer = IcxSigner(self.test_private_key.private_key)

        m = hashlib.sha256()
        m.update(b'message_for_test')
        # prepare massage msg_hash
        self.hashed_message = m.digest()

        # check if signature which sign_recoverable method made is valid
        # use ecdsa_verify. before verify signature, convert sign (recoverable_sig -> normal_sig)
        # check secp256k1 doc: https://github.com/ludbb/secp256k1-py

    def test_sign_recoverable_verify_sig(self):
        # get sign, recovery
        sign, recovery_id = self.signer.sign_recoverable(self.hashed_message)

        # Convert recoverable sig to normal sig
        deserialized_recoverable_sig = self.test_private_key.ecdsa_recoverable_deserialize(
            sign, recovery_id)
        normal_sig = self.test_private_key.ecdsa_recoverable_convert(
            deserialized_recoverable_sig)

        # Check sig
        self.assertTrue(
            self.test_private_key.pubkey.ecdsa_verify(self.hashed_message,
                                                      normal_sig,
                                                      raw=True))

        # Verify using invalid message
        m = hashlib.sha256()
        m.update(b'invalid message')
        invalid_message = m.digest()
        self.assertFalse(
            self.test_private_key.pubkey.ecdsa_verify(invalid_message,
                                                      normal_sig,
                                                      raw=True))

        # Verify using invalid private key
        invalid_privateKey = PrivateKey()
        self.assertFalse(
            invalid_privateKey.pubkey.ecdsa_verify(self.hashed_message,
                                                   normal_sig,
                                                   raw=True))

    def test_sign_base64_encode(self):
        # make signature
        encoded_sign = self.signer.sign(self.hashed_message)
        decoded_sign = base64.b64decode(encoded_sign)

        actual_id = int.from_bytes(decoded_sign[-1:], byteorder='big')
        actual_sig = decoded_sign[:len(decoded_sign) - 1]

        expected_signature, expected_recovery_id = self.signer.sign_recoverable(
            self.hashed_message)
        self.assertEqual(actual_id, expected_recovery_id)
        self.assertEqual(actual_sig, expected_signature)

    def test_key_from_key_store_get_private_key(self):
        # Invalid keystore file path
        self.assertRaises(KeyStoreException, key_from_key_store,
                          './invalid_file_path', 'qwer1234%')

        # Invalid keystore password
        self.assertRaises(KeyStoreException, key_from_key_store,
                          './tests/test_util/test_keystore', 'qwer12')
예제 #5
0
class PingServer(object):
    def __init__(self, my_endpoint, remote_endpoint, pingSleep, privKeyFile,
                 kid):
        self.myEndpoint = my_endpoint
        self.theirEndpoint = remote_endpoint
        self.pingSleep = pingSleep
        self.kid = kid

        ## get private key
        pkf = open(privKeyFile, "r")
        priv_key_serialized = pkf.read()
        pkf.close()
        self.priv_key = PrivateKey()
        self.priv_key.deserialize(priv_key_serialized)

        ## init socket
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.sock.bind(
            (self.myEndpoint.address.exploded, self.myEndpoint.udpPort))

    def startPingLoop(self):
        self.pingLoopThread = threading.Thread(target=self._pingLoop).start()

    def startListening(self):
        print("Server " + str(self.kid) + ", start listening")
        self.listenThread = threading.Thread(target=self._listenLoop).start()

    def _pingLoop(self):
        print("pingLoop")
        while True:
            self.ping(self.theirEndpoint)
            self.findnode(
                self.theirEndpoint,
                0x6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0
            )
            # self.neighbors(self.theirEndpoint, 0x6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0)
            time.sleep(self.pingSleep)

    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)
        # print(str(type(sig_serialized[0])) + " " + str(type(sig_serialized[1])) + str(type(payload)))
        # print(sig_serialized[1])
        payload = sig_serialized[0] + bytes([sig_serialized[1]]) + payload

        payload_hash = keccak256(payload)
        return payload_hash + payload

    def _listenLoop(self):
        print("Start Listening...")
        while True:
            data, addr = self.sock.recvfrom(2048)
            print("--------------- New Packet (ID: " + str(self.kid) +
                  ") -------------")
            self.handlePacket(data, addr)

    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)))

    def ping(self, theirEndpoint):
        ping = PingPacket(self.myEndpoint, theirEndpoint, time.time() + 60)
        message = self.wrap_packet(ping)
        print("Sending ping to: " + str(theirEndpoint))
        self.sock.sendto(
            message, (theirEndpoint.address.exploded, theirEndpoint.udpPort))

    def pong(self, theirEndpoint, echo):
        pong = PongPacket(theirEndpoint, echo, time.time() + 60)
        message = self.wrap_packet(pong)
        print("Sending pong to: " + str(theirEndpoint))
        self.sock.sendto(
            message, (theirEndpoint.address.exploded, theirEndpoint.udpPort))

    def findnode(self, theirEndpoint, target):
        findnode = FindNodePacket(target, time.time() + 60)
        message = self.wrap_packet(findnode)
        print("Sending FindNodePacket to: " + str(theirEndpoint))
        self.sock.sendto(
            message, (theirEndpoint.address.exploded, theirEndpoint.udpPort))

    def neighbors(self, theirEndpoint, target):
        # Compute some close neighbors on the fly
        neighbors = self.computeClosestNeighbors(target)
        packet = NeighborsPacket(neighbors, time.time() + 60)
        message = self.wrap_packet(packet)
        print("Sending NeighborsPacket to: " + str(theirEndpoint))
        self.sock.sendto(
            message, (theirEndpoint.address.exploded, theirEndpoint.udpPort))

    def computeClosestNeighbors(self, target):
        # Just return some hard coded IDs for now
        return [
            Node(
                self.myEndpoint.address, self.myEndpoint.udpPort,
                self.myEndpoint.tcpPort,
                0x6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0
            ),
            Node(
                self.myEndpoint.address, self.myEndpoint.udpPort,
                self.myEndpoint.tcpPort,
                0x7f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0
            ),
        ]
예제 #6
0
class Server(object):
    def __init__(self, boot_nodes):
        # the endpoint of this server
        # this is a fake ip address used in packets.
        self.endpoint = EndPoint(u'127.0.0.1', 30303, 30303)
        # boot nodes
        self.boot_nodes = boot_nodes
        # hold all of pending
        self.pending_hold = []
        # last pong received time of the special node id
        self.last_pong_received = {}
        # last ping received time of the special node id
        self.last_ping_received = {}

        # have the private key
        priv_key_file = open('priv_key', 'r')
        priv_key_serialized = priv_key_file.read()
        priv_key_file.close()
        self.priv_key = PrivateKey()
        self.priv_key.deserialize(priv_key_serialized)

        # routing table
        self.table = RoutingTable(
            Node(self.endpoint,
                 pubkey_format(self.priv_key.pubkey)[1:]), self)

        # initialize UDP socket
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.sock.bind(('0.0.0.0', self.endpoint.udpPort))
        # set socket non-blocking mode
        self.sock.setblocking(0)

    def add_table(self, node):
        self.table.add_node(node)

    def add_pending(self, pending):
        pending.start()
        self.pending_hold.append(pending)
        return pending

    def run(self):
        gevent.spawn(self.clean_pending)
        gevent.spawn(self.listen)
        # wait forever
        evt = Event()
        evt.wait()

    def clean_pending(self):
        while True:
            for pending in list(self.pending_hold):
                if not pending.is_alive:
                    self.pending_hold.remove(pending)
            time.sleep(K_REQUEST_TIMEOUT)

    def listen(self):
        LOGGER.info("{:5} listening...".format(''))
        while True:
            ready = select([self.sock], [], [], 1.0)
            if ready[0]:
                data, addr = self.sock.recvfrom(2048)
                # non-block data reading
                gevent.spawn(self.receive, data, addr)

    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)

    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)

    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()

    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))

    def receive_neighbors(self, addr, pubkey, neighbours):
        # response to find neighbours
        self.handle_reply(addr, pubkey, Neighbors.packet_type, neighbours)

    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)))

    def ping(self, node, callback=None):
        """
        send a ping request to the given node and return instantly
        invoke callback while reply arrives
        """
        ping = PingNode(self.endpoint, node.endpoint,
                        time.time() + K_EXPIRATION)
        message = self.wrap_packet(ping)
        msg_hash = message[:32]

        def reply_call(chunks):
            if chunks.pop().echo == msg_hash:
                if callback is not None:
                    callback()

                return True

        ep = (node.endpoint.address.exploded, node.endpoint.udpPort)
        pending = self.add_pending(Pending(node, Pong.packet_type, reply_call))
        self.sock.sendto(message, ep)
        LOGGER.info("{:5} {}@{}:{} (Ping)".format(
            '---->',
            binascii.hexlify(node.node_id)[:8], ep[0], ep[1]))

        return pending

    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

    def send_sock(self, packet, node):
        endpoint = node.endpoint
        message = self.wrap_packet(packet)
        ep = (endpoint.address.exploded, endpoint.udpPort)
        self.sock.sendto(message, ep)

    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
예제 #7
0
class PingServer(object):
    def __init__(self, my_endpoint):
        self.endpoint = my_endpoint

        ## get private key
        priv_key_file = open('priv_key', 'r')
        priv_key_serialized = priv_key_file.read()
        priv_key_file.close()
        self.priv_key = PrivateKey()
        self.priv_key.deserialize(priv_key_serialized)

        ## init socket
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.sock.bind(('0.0.0.0', self.endpoint.udpPort))

    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

    def udp_listen(self):
        return threading.Thread(target=self.receive)

    def ping(self, endpoint):
        ping = PingNode(self.endpoint, endpoint, time.time() + 60)
        message = self.wrap_packet(ping)
        print "sending " + str(ping)
        self.sock.sendto(message,
                         (endpoint.address.exploded, endpoint.udpPort))

    def receive_pong(self, payload):
        print " received Pong"
        print "", Pong.unpack(rlp.decode(payload))

    def receive_ping(self, payload):
        print " received Ping"
        print "", PingNode.unpack(rlp.decode(payload))

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

        ## decode packet below
        ## 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."

        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)
예제 #8
0
class Server(object):
    def __init__(self, my_endpoint):
        self.endpoint = my_endpoint

        # 获取私钥
        priv_key_file = open('priv_key', 'r')
        priv_key_serialized = priv_key_file.read()
        priv_key_file.close()
        self.priv_key = PrivateKey()
        self.priv_key.deserialize(priv_key_serialized)

        # 初始化套接字
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.sock.bind(('0.0.0.0', self.endpoint.udpPort))
        # set socket non-blocking mode
        self.sock.setblocking(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

    def listen(self):
        print "listening..."
        while True:
            ready = select.select([self.sock], [], [], 1.0)
            if ready[0]:
                data, addr = self.sock.recvfrom(2048)
                print "received message[", addr, "]:"
                self.receive(data, addr)

    def listen_thread(self):
        thread = threading.Thread(target=self.listen)
        thread.daemon = True
        return thread

    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)

    def receive_pong(self, payload, msg_hash, addr):
        print " received Pong"
        print "", Pong.unpack(rlp.decode(payload))

    def receive_ping(self, payload, msg_hash, addr):
        print " received Ping"
        ping = PingNode.unpack(rlp.decode(payload))
        endpoint_to = EndPoint(addr[0], ping.endpoint_from.udpPort, ping.endpoint_from.tcpPort)
        pong = Pong(endpoint_to, msg_hash, time.time() + 60)
        print "  sending Pong response: " + str(pong)
        self.send(pong, pong.to)

    def receive_find_neighbors(self, payload, msg_hash, addr):
        print " received FindNeighbors"
        print "", FindNeighbors.unpack(rlp.decode(payload))

    def receive_neighbors(self, payload, msg_hash, addr):
        print " received Neighbors"
        print "", Neighbors.unpack(rlp.decode(payload))

    def ping(self, endpoint):
        ping = PingNode(self.endpoint, endpoint, time.time() + 60)
        message = self.wrap_packet(ping)
        print "sending " + str(ping)
        self.sock.sendto(message, (endpoint.address.exploded, endpoint.udpPort))

    def send(self, packet, endpoint):
        message = self.wrap_packet(packet)
        print "sending " + str(packet)
        self.sock.sendto(message, (endpoint.address.exploded, endpoint.udpPort))