簡體   English   中英

套接字-與python和java不同的字節

[英]Sockets — Different bytes from python and java

我最近一直在進行一個網絡項目,以恢復死的mmo游戲供個人學習,我有一個python實現,可使用河豚(pypi / pycryptodome)解碼游戲數據,並希望將此“服務器”傳輸到Java中項目。

最初在Java中使用河豚解密(B​​ouncyCastle和Cipher-默認),我在java和python之間得到了完全不同的結果。 通過一些研究,我發現Java(以及其他大多數東西)實際上使用了兼容河豚的big endian。

這個python庫似乎是唯一可以正確解碼數據的庫。 接下來,我決定使用python asyncio服務器作為中間中繼,僅用於加密和解密。 現在,網絡流如下所示:

GameClient -> Java SocketServer -> Python server (decryption) -> Java SocketServer

原始的Python實現產生以下十六進制格式的字節:

32004a815f49367cc3691be26d7b668132506dc972d5a6bbad38299640c6e222c6e55096f50ff33711250675431633ca9ede

Java實現以十六進制格式生成這些結果(使用apache commons Hex.encodeHexString())

32004a815f49367cc3691be26d7b668132506dc972d5a6bbad38299640c6e222c6e5c65830d65f9b4d60eb26730685f486d7

這兩個十六進制表示形式都是Python中的河豚預解密,它們只是從游戲客戶端發送的原始字節。

我的問題是,為什么這些字節以相同的開頭,然后似乎Java落后了? python結果是經過測試和工作的正確結果。 我嘗試將字節包裝在緩沖區中的Java中,然后調用flip()但是這也未產生正確的結果。 使用另一個stackoverflow帖子(對不起,我沒有鏈接),我嘗試將此byte []強制轉換為BigInteger,這也未產生正確的結果。

任何幫助是極大的贊賞。

Python實現

#!/usr/bin/env python3

import asyncio
import binascii
import blowfish
import ipaddress
import os
import struct
import sys

AUTH_BLOWFISHKEY = b"[;'.]94-31==-%&@!^+]\000"
bf = blowfish.Cipher(AUTH_BLOWFISHKEY, byte_order="little")


class EncryptionRelay(asyncio.Protocol):
    def connection_made(self, transport):
        self.transport = transport
        self.client = (transport.get_extra_info('peername')[0] + ":"    # IP
        + str(transport.get_extra_info('peername')[1]))             # port
        print("Connection from: " + self.client)


    def connection_lost(self, exc):
        print("Connection closed: " + self.client)


    def data_received(self, data):
        print(data.hex()) #python output above
        pt = b''.join(bf.decrypt_ecb(data[2:]))
        self.transport.write(pt)

    def closeSocket(self, reason):
        print(reason)
        self.transport.close()


def main():
    loop = asyncio.get_event_loop()
    coroutine = loop.create_server(EncryptionRelay, host=None, port=54556)
    server = loop.run_until_complete(coroutine)

    for socket in server.sockets:
        print("Listening on: " + socket.getsockname()[0] + ":" +
        str(socket.getsockname()[1]))
    try:
        loop.run_forever()
    except KeyboardInterrupt:
        pass

    server.close()
    loop.run_until_complete(server.wait_closed())
    loop.close()


if __name__ == "__main__":
    main()

Java實現

public AuthServer(int port) {
    serverGUI = new AuthServerGUI(port);

    try {
        serverSocket = new ServerSocket(port);
        relay = new PythonEncryptionRelay(this);
        new Thread(relay).start();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

@Override
public void run() {
    while(true) {
        try {
            Socket socket = serverSocket.accept();
            onConnection(socket); //sends an init packet to client -- irrelevant to question 

            byte[] incomingData = new byte[0];
            byte[] temp = new byte[1024];
            int k = -1;

            while((k = socket.getInputStream().read(temp, 0, temp.length)) > -1) {
                byte[] tbuff = new byte[incomingData.length + k];
                System.arraycopy(incomingData, 0, tbuff, 0, incomingData.length);
                System.arraycopy(temp, 0, tbuff, incomingData.length, k);
                incomingData = tbuff;

                receiveData(socket, incomingData);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

public void receiveData(Socket socket, byte[] data) {
    int lenLo = (int) (data[0]);
    int lenHi = (int) (data[1]);
    int length = lenHi * 256 + lenLo;


    if(lenHi < 0) {
        System.out.println("Invalid Packet Length");
    }

    if(data.length != length) {
        System.out.println("Incomplete Packet Received");
    }

    serverGUI.serverDebug("DATA RECEIVED");
    serverGUI.serverDebug(Hex.encodeHexString(data)); //this is the java ouput above serverGUI is simply a jframe i built no data manipulation
    serverGUI.serverDebug("DATA_RECEIVED DONE");
    this.relay.sendData(data); //this function sends the data from socket server to the python asyncio server
}

public void receiveDataFromPythonRelay(Socket socket, byte[] data) {
    serverGUI.debugPythonRelay("DATA RECEIVED");
    serverGUI.debugPythonRelay(Hex.encodeHexString(data)); //this will be the output from the python script aka data decrypted. 
//The data byte[] is created in the exact same way the incomingData array is built in the AuthServer run function
    serverGUI.debugPythonRelay("DATA_RECEIVED DONE");
}

另外,我從套接字導入數據byte []的方式也這樣編程,因為客戶端不發送endl,因此readLine將無法從流中工作。

一個字節有8位,這意味着您最多可以將0xff作為值。

但是Java使用帶符號的字節,這意味着msb保留用於帶符號的位。 這樣您的值只剩下7位,因此您可以將最大值(0x7f)存儲在變量的字節類型中。 大於0x07f的任何數字都將導致溢出。

嘗試使用int數組。 由於int使用4字節(32位),因此總會有8位空間。

使用byte []從流中讀取,然后將內容復制到int []中,使用int intArr[i] = byteArr[i] & 0xFF; 從byte []中獲得第i個值,以避免由於字節溢出而產生負數

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM