gpt4 book ai didi

java - 套接字——来自 python 和 java 的不同字节

转载 作者:行者123 更新时间:2023-11-30 12:07:25 24 4
gpt4 key购买 nike

我最近一直在做一个网络项目,以恢复一个死掉的 mmo 游戏供个人学习,我有一个 python 实现,它可以使用 blowfish(pypi/pycryptodome) 解码游戏数据,并想转移这个“服务器”进入一个java项目。

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

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

GameClient -> Java SocketServer -> Python 服务器(解密) -> 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 个值避免因字节溢出而产生负数

关于java - 套接字——来自 python 和 java 的不同字节,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54973917/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com