套接字——与python和java不同的字节

套接字——与python和java不同的字节,java,python,sockets,Java,Python,Sockets,我最近一直在从事一个网络项目,以恢复一个已死亡的mmo游戏,用于个人学习。我有一个python实现,它使用blowfish(pypi/pycryptodome)对游戏数据进行解码,并希望将此“服务器”转移到一个java项目中 最初在java中使用blowfish解密(BouncyCastle和Cipher——默认值),我得到了java和python之间完全不同的结果。通过一些研究,我发现java(以及大多数东西)实际上使用了blowfish compat big endian 这个python库

我最近一直在从事一个网络项目,以恢复一个已死亡的mmo游戏,用于个人学习。我有一个python实现,它使用blowfish(pypi/pycryptodome)对游戏数据进行解码,并希望将此“服务器”转移到一个java项目中

最初在java中使用blowfish解密(BouncyCastle和Cipher——默认值),我得到了java和python之间完全不同的结果。通过一些研究,我发现java(以及大多数东西)实际上使用了blowfish compat big endian

这个python库似乎是唯一一个正确解码数据的库。接下来,我决定使用python异步IO服务器作为中间中继,仅用于加密和解密。网络流现在如下所示:

GameClient->Java SocketServer->Python服务器(解密)->Java SocketServer

原始的
Python
实现以十六进制格式生成这些字节:

32004a815f49367cc3691be26d7b668132506dc972d5a6bbad38299640c6e222c6e55096f50ff33711250675431633ca9ede
Java实现以十六进制格式生成这些结果(使用ApacheCommons hex.encodeHexString()

这两种十六进制表示都是Python中的预blowfish解密,它们只是从游戏客户端发送的原始字节

我的问题是,为什么这些字节的开头是一样的,而java却似乎落后了?python结果是正确的结果,它们经过测试并正常工作。我曾尝试将java中的字节包装到缓冲区中,然后调用
flip()
,但是这也没有产生正确的结果。使用另一个stackoverflow post(对不起,我没有链接),我尝试将这个字节[]转换为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()
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");
}
Java实现

#!/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()
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");
}
public AuthServer(int端口){
serverGUI=新的AuthServerGUI(端口);
试一试{
serverSocket=新的serverSocket(端口);
继电器=新的PythonEncryptionRelay(本);
新螺纹(继电器).start();
}捕获(IOE异常){
e、 printStackTrace();
}
}
@凌驾
公开募捐{
while(true){
试一试{
Socket=serverSocket.accept();
onConnection(socket);//向客户机发送一个init数据包——与问题无关
字节[]输入数据=新字节[0];
字节[]临时=新字节[1024];
int k=-1;
而((k=socket.getInputStream().read(temp,0,temp.length))>-1){
byte[]tbuff=新字节[incomingData.length+k];
System.arraycopy(incomingData,0,tbuff,0,incomingData.length);
系统阵列副本(温度,0,tbuff,输入数据长度,k);
incomingData=tbuff;
接收数据(插座、输入数据);
}
}捕获(IOE异常){
e、 printStackTrace();
}
}
}
public void receiveData(套接字,字节[]数据){
int lenLo=(int)(数据[0]);
int lenHi=(int)(数据[1]);
int length=lenHi*256+lenLo;
if(lenHi<0){
System.out.println(“无效数据包长度”);
}
if(data.length!=长度){
System.out.println(“接收到不完整的数据包”);
}
serverGUI.serverDebug(“收到的数据”);
serverGUI.serverDebug(Hex.encodeHexString(data));//这是上面的java输出serverGUI只是一个jframe,我没有构建任何数据操作
serverGUI.serverDebug(“数据_接收完毕”);
this.relay.sendData(data);//此函数将数据从套接字服务器发送到python异步IO服务器
}
public void ReceiveDatafromPythonReplay(套接字,字节[]数据){
debugPythonRelay(“接收到的数据”);
serverGUI.debugPythonRelay(Hex.encodeHexString(data));//这将是python脚本aka data decrypted的输出。
//数据字节[]的创建方式与AuthServer运行函数中构建incomingData数组的方式完全相同
debugPythonRelay(“数据_接收完毕”);
}

此外,我从套接字导入数据字节[]的方式是这样编程的,因为客户端不发送endl,因此读线将无法从流中工作。

一个字节有8位,这意味着可以将最大0xff作为值

但Java使用有符号字节,这意味着msb是为有符号位保留的。这使得您的值只有7位,所以您可以在变量的字节类型中存储最大值为0x7f。任何大于0x07f的数字都将导致溢出

尝试使用int数组。由于int使用4个字节(32位),因此总是有8位的空间


使用byte[]从流中读取,然后复制int[]中的内容,使用
int intArr[i]=byteArr[i]&0xFF字节[]的第i个值,以避免由于字节溢出而产生负数

一个字节有8位,这意味着您可以将最大0xff作为值

但Java使用有符号字节,这意味着msb是为有符号位保留的。这使得您的值只有7位,所以您可以在变量的字节类型中存储最大值为0x7f。任何大于0x07f的数字都将导致溢出

尝试使用int数组。由于int使用4个字节(32位),因此总是有8位的空间


使用byte[]从流中读取,然后复制int[]中的内容,使用
int intArr[i]=byteArr[i]&0xFF字节[]的第I个值,以避免由于字节溢出而产生负数

我还没有回家测试这个问题,但我会在有机会时发布更新,尽管考虑到两个十六进制打印输出的长度相同,这可能仍然是个问题吗?当然,我也编辑了我的答案,即如何从字节[]读取到int[]。我希望你能得到一些帮助。我还没有回家测试这个问题,但我会在有机会的时候发布一个更新,尽管考虑到两个十六进制打印输出的长度相同,这可能仍然是个问题吗?当然,我也编辑了我的答案,作为如何阅读t