Example #1
0
def parse_message(msg: bytes, conn, dir_):
    size = unpack("<I", msg[:4])[0]
    msg_type = unpack("<I", msg[4:8])[0]
    message_type = message_type_table[msg_type]
    end = -(len(msg) - size - 8)
    if end == 0:
        end = None
    msg = msg[8:end]
    buf = Buffer()
    buf.write(msg)
    message = message_type.unpack(buf)
    logging.info(("\033[36mSEND >>> \033[0m" if dir_ ==
                  1 else "\033[32mRECV <<< \033[0m") + repr(message))
    action = message_action_table.get(msg_type, None)
    if action is not None and conn is not None:
        action(message, conn)
Example #2
0
class Connection:
    def __init__(self, ip, port):
        self.stream = Buffer()
        self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.s.connect((ip, port))
        raw_pk = self.s.recv(33)
        self.pk = GraphenePublicKey(raw_pk.hex())
        sk = PrivateKey()
        point = self.pk.point() * int.from_bytes(bytes(sk), "big")
        x: int = point.x()
        raw_data = x.to_bytes(32, "big")
        self.shared_secret = sha512(raw_data).digest()
        key = sha256(self.shared_secret).digest()
        crc = cityhash.CityHash128(self.shared_secret)
        data = crc.to_bytes(16, "little")
        iv = data[8:16] + data[:8]
        self.s.sendall(bytes.fromhex(repr(sk.pubkey)))
        self.encryptor = AES.new(key, AES.MODE_CBC, iv)
        self.test = AES.new(key, AES.MODE_CBC, iv)
        self.decryptor = AES.new(key, AES.MODE_CBC, iv)
        self.worker_thread = threading.Thread(target=self.worker)
        self.worker_thread.start()
        self.send(
            5006, {
                "user_agent":
                "Haruka Mock Client",
                "core_protocol_version":
                106,
                "inbound_address":
                "0.0.0.0",
                "inbound_port":
                0,
                "outbound_port":
                0,
                "node_public_key":
                sk.pubkey,
                "signed_shared_secret":
                ecdsa.sign_message(self.shared_secret, str(sk)),
                "chain_id":
                bytes.fromhex(
                    "4018d7844c78f6a6c41c6a552b898022310fc5dec06da467ee7905a8dad512c8"
                ),
                "user_data": {
                    "platform": String("unknown")
                }
            })

    def send(self, msg_type, data: dict):
        message_type = message_type_table[msg_type]
        message = message_type(data)
        res = message.pack()
        # for name, type_ in definition.items():
        #     res.extend(pack_field(data.get(name, None), type_))
        length = len(res)
        if length % 16 != 8:
            pad_length = (8 - length % 16)
            if pad_length < 0:
                pad_length += 16
            res += b"\x00" * pad_length
        res = pack("<II", length, msg_type) + res
        data = self.encryptor.encrypt(res)
        logging.debug("SEND >>> %s" % res)
        parse_message(res, None, 1)
        self.s.sendall(data)

    def worker(self):
        data = bytearray()
        while True:
            data.extend(self.s.recv(65535))
            if len(data) % 16 == 0:
                msg = self.decryptor.decrypt(bytes(data))
            else:
                continue
            data = bytearray()
            self.stream.write(msg)
            if len(msg) == 0:
                break
            logging.debug("RECV <<< %s" % msg)
            while self.stream.count():
                size = unpack("<I", self.stream.peek(4))[0]
                expect = size + 8 + (16 - (size + 8) % 16) % 16
                logging.debug("expect %s have %s" %
                              (expect, self.stream.count()))
                if expect <= self.stream.count():
                    parse_message(self.stream.read(expect), self, 2)
                else:
                    break