Updated network

This commit is contained in:
Him188moe 2019-09-13 12:51:14 +08:00
parent 96a9e6f386
commit 37fa8055b5
27 changed files with 349 additions and 401 deletions

View File

@ -185,7 +185,7 @@ internal class BotNetworkHandlerImpl(private val bot: Bot) : BotNetworkHandler {
* Not async * Not async
*/ */
@Synchronized @Synchronized
@ExperimentalUnsignedTypes
override fun sendPacket(packet: ClientPacket) { override fun sendPacket(packet: ClientPacket) {
checkNotNull(socket) { "network closed" } checkNotNull(socket) { "network closed" }
if (socket!!.isClosed) { if (socket!!.isClosed) {

View File

@ -1,3 +1,5 @@
@file:Suppress("EXPERIMENTAL_API_USAGE")
package net.mamoe.mirai.network package net.mamoe.mirai.network
import java.net.InetAddress import java.net.InetAddress
@ -72,7 +74,7 @@ object Protocol {
private val hexToByteArrayCacheMap: MutableMap<Int, ByteArray> = mutableMapOf() private val hexToByteArrayCacheMap: MutableMap<Int, ByteArray> = mutableMapOf()
@ExperimentalUnsignedTypes
fun hexToBytes(hex: String): ByteArray { fun hexToBytes(hex: String): ByteArray {
hex.hashCode().let { id -> hex.hashCode().let { id ->
if (hexToByteArrayCacheMap.containsKey(id)) { if (hexToByteArrayCacheMap.containsKey(id)) {
@ -86,7 +88,7 @@ object Protocol {
} }
} }
@ExperimentalUnsignedTypes
fun hexToUBytes(hex: String): UByteArray = Arrays fun hexToUBytes(hex: String): UByteArray = Arrays
.stream(hex.split(" ".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()) .stream(hex.split(" ".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray())
.map { value -> value.trim { it <= ' ' } } .map { value -> value.trim { it <= ' ' } }

View File

@ -31,7 +31,7 @@ class ActionPacketHandler(session: LoginSession) : PacketHandler(session) {
private var sKeyRefresherFuture: ScheduledFuture<*>? = null private var sKeyRefresherFuture: ScheduledFuture<*>? = null
@ExperimentalUnsignedTypes
override fun onPacketReceived(packet: ServerPacket) { override fun onPacketReceived(packet: ServerPacket) {
when (packet) { when (packet) {
is ServerCanAddFriendResponsePacket -> { is ServerCanAddFriendResponsePacket -> {
@ -74,12 +74,12 @@ class ActionPacketHandler(session: LoginSession) : PacketHandler(session) {
} }
} }
@ExperimentalUnsignedTypes
fun addFriend(qqNumber: Long, message: Supplier<String>) { fun addFriend(qqNumber: Long, message: Supplier<String>) {
addFriend(qqNumber, lazy { message.get() }) addFriend(qqNumber, lazy { message.get() })
} }
@ExperimentalUnsignedTypes
@JvmSynthetic @JvmSynthetic
fun addFriend(qqNumber: Long, message: Lazy<String> = lazyOf("")): CompletableFuture<AddFriendResult> { fun addFriend(qqNumber: Long, message: Lazy<String> = lazyOf("")): CompletableFuture<AddFriendResult> {
val future = CompletableFuture<AddFriendResult>() val future = CompletableFuture<AddFriendResult>()
@ -89,12 +89,12 @@ class ActionPacketHandler(session: LoginSession) : PacketHandler(session) {
return future return future
} }
@ExperimentalUnsignedTypes
fun requestSKey() { fun requestSKey() {
session.socket.sendPacket(ClientSKeyRequestPacket(session.bot.account.qqNumber, session.sessionKey)) session.socket.sendPacket(ClientSKeyRequestPacket(session.bot.account.qqNumber, session.sessionKey))
} }
@ExperimentalUnsignedTypes
fun requestAccountInfo() { fun requestAccountInfo() {
session.socket.sendPacket(ClientAccountInfoRequestPacket(session.bot.account.qqNumber, session.sessionKey)) session.socket.sendPacket(ClientAccountInfoRequestPacket(session.bot.account.qqNumber, session.sessionKey))
} }
@ -111,7 +111,7 @@ class ActionPacketHandler(session: LoginSession) : PacketHandler(session) {
) : Closeable { ) : Closeable {
lateinit var id: ByteArray lateinit var id: ByteArray
@ExperimentalUnsignedTypes
fun onPacketReceived(packet: ServerPacket) { fun onPacketReceived(packet: ServerPacket) {
if (!::id.isInitialized) { if (!::id.isInitialized) {
return return
@ -164,7 +164,7 @@ class ActionPacketHandler(session: LoginSession) : PacketHandler(session) {
) : Closeable { ) : Closeable {
lateinit var id: ByteArray lateinit var id: ByteArray
@ExperimentalUnsignedTypes
fun onPacketReceived(packet: ServerPacket) { fun onPacketReceived(packet: ServerPacket) {
if (!::id.isInitialized) { if (!::id.isInitialized) {
return return
@ -201,7 +201,7 @@ class ActionPacketHandler(session: LoginSession) : PacketHandler(session) {
} }
} }
@ExperimentalUnsignedTypes
fun sendAddRequest() { fun sendAddRequest() {
session.socket.sendPacket(ClientCanAddFriendPacket(session.bot.account.qqNumber, qq, session.sessionKey).also { this.id = it.packetIdLast }) session.socket.sendPacket(ClientCanAddFriendPacket(session.bot.account.qqNumber, qq, session.sessionKey).also { this.id = it.packetIdLast })
} }

View File

@ -16,7 +16,7 @@ interface DataPacketSocket : Closeable {
fun distributePacket(packet: ServerPacket) fun distributePacket(packet: ServerPacket)
@ExperimentalUnsignedTypes
fun sendPacket(packet: ClientPacket) fun sendPacket(packet: ClientPacket)
fun isClosed(): Boolean fun isClosed(): Boolean

View File

@ -74,7 +74,7 @@ class MessagePacketHandler(session: LoginSession) : PacketHandler(session) {
session.socket.sendPacket(ClientSendFriendMessagePacket(session.bot.account.qqNumber, qq.number, session.sessionKey, message)) session.socket.sendPacket(ClientSendFriendMessagePacket(session.bot.account.qqNumber, qq.number, session.sessionKey, message))
} }
fun sendGroupMessage(group: Group, message: Message): Unit { fun sendGroupMessage(group: Group, message: Message) {
TODO() TODO()
//sendPacket(ClientSendGroupMessagePacket(group.groupId, bot.account.qqNumber, sessionKey, message)) //sendPacket(ClientSendGroupMessagePacket(group.groupId, bot.account.qqNumber, sessionKey, message))
} }

View File

@ -1,3 +1,5 @@
@file:Suppress("EXPERIMENTAL_API_USAGE", "EXPERIMENTAL_UNSIGNED_LITERALS")
package net.mamoe.mirai.network.packet package net.mamoe.mirai.network.packet
import lombok.Getter import lombok.Getter
@ -12,12 +14,12 @@ import java.security.MessageDigest
/** /**
* @author Him188moe * @author Him188moe
*/ */
@ExperimentalUnsignedTypes
abstract class ClientPacket : ByteArrayDataOutputStream(), Packet { abstract class ClientPacket : ByteArrayDataOutputStream(), Packet {
@Getter @Getter
val idHex: String val idHex: String
var encoded: Boolean = false private var encoded: Boolean = false
init { init {
val annotation = this.javaClass.getAnnotation(PacketId::class.java) val annotation = this.javaClass.getAnnotation(PacketId::class.java)
@ -84,7 +86,6 @@ abstract class ClientPacket : ByteArrayDataOutputStream(), Packet {
} }
@ExperimentalUnsignedTypes
@Throws(IOException::class) @Throws(IOException::class)
fun DataOutputStream.writeIP(ip: String) { fun DataOutputStream.writeIP(ip: String) {
for (s in ip.trim().split("\\.".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()) { for (s in ip.trim().split("\\.".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()) {
@ -97,10 +98,9 @@ fun DataOutputStream.writeTime() {
this.writeInt(System.currentTimeMillis().toInt()) this.writeInt(System.currentTimeMillis().toInt())
} }
@ExperimentalUnsignedTypes
@Throws(IOException::class) @Throws(IOException::class)
fun DataOutputStream.writeHex(hex: String) { fun DataOutputStream.writeHex(uHex: String) {
for (s in hex.trim().split(" ".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()) { for (s in uHex.trim().split(" ".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()) {
if (s.isEmpty()) { if (s.isEmpty()) {
continue continue
} }
@ -116,12 +116,10 @@ fun DataOutputStream.encryptAndWrite(key: ByteArray, encoder: (ByteArrayDataOutp
this.write(TEA.encrypt(ByteArrayDataOutputStream().also(encoder).toByteArray(), key)) this.write(TEA.encrypt(ByteArrayDataOutputStream().also(encoder).toByteArray(), key))
} }
@ExperimentalUnsignedTypes
fun DataOutputStream.encryptAndWrite(keyHex: String, encoder: (ByteArrayDataOutputStream) -> Unit) { fun DataOutputStream.encryptAndWrite(keyHex: String, encoder: (ByteArrayDataOutputStream) -> Unit) {
this.encryptAndWrite(keyHex.hexToBytes(), encoder) this.encryptAndWrite(keyHex.hexToBytes(), encoder)
} }
@ExperimentalUnsignedTypes
@Throws(IOException::class) @Throws(IOException::class)
fun DataOutputStream.writeTLV0006(qq: Long, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray) { fun DataOutputStream.writeTLV0006(qq: Long, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray) {
ByteArrayDataOutputStream().let { ByteArrayDataOutputStream().let {
@ -146,12 +144,10 @@ fun DataOutputStream.writeTLV0006(qq: Long, password: String, loginTime: Int, lo
} }
} }
@ExperimentalUnsignedTypes @Tested
@TestedSuccessfully
fun DataOutputStream.writeCRC32() = writeCRC32(getRandomByteArray(16)) fun DataOutputStream.writeCRC32() = writeCRC32(getRandomByteArray(16))
@ExperimentalUnsignedTypes
fun DataOutputStream.writeCRC32(key: ByteArray) { fun DataOutputStream.writeCRC32(key: ByteArray) {
key.let { key.let {
write(it)//key write(it)//key
@ -159,8 +155,8 @@ fun DataOutputStream.writeCRC32(key: ByteArray) {
} }
} }
@ExperimentalUnsignedTypes
@TestedSuccessfully @Tested
fun DataOutputStream.writeDeviceName(random: Boolean = false) { fun DataOutputStream.writeDeviceName(random: Boolean = false) {
val deviceName: String = if (random) { val deviceName: String = if (random) {
String(getRandomByteArray(10)) String(getRandomByteArray(10))
@ -185,7 +181,7 @@ fun Int.toByteArray(): ByteArray = byteArrayOf(
/** /**
* 255u -> 00 00 00 FF * 255u -> 00 00 00 FF
*/ */
@ExperimentalUnsignedTypes
fun UInt.toByteArray(): ByteArray = byteArrayOf( fun UInt.toByteArray(): ByteArray = byteArrayOf(
(this.shr(24) and 255u).toByte(), (this.shr(24) and 255u).toByte(),
(this.shr(16) and 255u).toByte(), (this.shr(16) and 255u).toByte(),
@ -193,24 +189,14 @@ fun UInt.toByteArray(): ByteArray = byteArrayOf(
(this.shr(0) and 255u).toByte() (this.shr(0) and 255u).toByte()
) )
/**
* 255 -> FF 00 00 00
*/
fun Int.toLByteArray(): ByteArray = byteArrayOf(
(this.ushr(0) and 0xFF).toByte(),
(this.ushr(8) and 0xFF).toByte(),
(this.ushr(16) and 0xFF).toByte(),
(this.ushr(24) and 0xFF).toByte()
)
@ExperimentalUnsignedTypes
fun Int.toUHexString(separator: String = " "): String = this.toByteArray().toUHexString(separator) fun Int.toUHexString(separator: String = " "): String = this.toByteArray().toUHexString(separator)
internal fun md5(str: String): ByteArray = MessageDigest.getInstance("MD5").digest(str.toByteArray()) internal fun md5(str: String): ByteArray = MessageDigest.getInstance("MD5").digest(str.toByteArray())
internal fun md5(byteArray: ByteArray): ByteArray = MessageDigest.getInstance("MD5").digest(byteArray) internal fun md5(byteArray: ByteArray): ByteArray = MessageDigest.getInstance("MD5").digest(byteArray)
@ExperimentalUnsignedTypes
@Throws(IOException::class) @Throws(IOException::class)
fun DataOutputStream.writeZero(count: Int) { fun DataOutputStream.writeZero(count: Int) {
repeat(count) { repeat(count) {
@ -225,13 +211,13 @@ fun DataOutputStream.writeRandom(length: Int) {
} }
} }
@ExperimentalUnsignedTypes
@Throws(IOException::class) @Throws(IOException::class)
fun DataOutputStream.writeQQ(qq: Long) { fun DataOutputStream.writeQQ(qq: Long) {
this.write(qq.toUInt().toByteArray()) this.write(qq.toUInt().toByteArray())
} }
@ExperimentalUnsignedTypes
@Throws(IOException::class) @Throws(IOException::class)
fun DataOutputStream.writeGroup(groupIdOrGroupNumber: Long) { fun DataOutputStream.writeGroup(groupIdOrGroupNumber: Long) {
this.write(groupIdOrGroupNumber.toUInt().toByteArray()) this.write(groupIdOrGroupNumber.toUInt().toByteArray())

View File

@ -9,7 +9,7 @@ import java.io.DataInputStream
* *
* @author Him188moe * @author Him188moe
*/ */
@ExperimentalUnsignedTypes
@PacketId("00 5C") @PacketId("00 5C")
class ClientAccountInfoRequestPacket( class ClientAccountInfoRequestPacket(
private val qq: Long, private val qq: Long,

View File

@ -7,7 +7,7 @@ import java.io.IOException
/** /**
* @author Him188moe * @author Him188moe
*/ */
@ExperimentalUnsignedTypes
@PacketId("00 58") @PacketId("00 58")
class ClientHeartbeatPacket( class ClientHeartbeatPacket(
private val qq: Long, private val qq: Long,

View File

@ -10,7 +10,7 @@ import java.io.DataInputStream
* *
* @author Him188moe * @author Him188moe
*/ */
@ExperimentalUnsignedTypes
@PacketId("00 1D") @PacketId("00 1D")
class ClientSKeyRequestPacket( class ClientSKeyRequestPacket(
private val qq: Long, private val qq: Long,
@ -31,7 +31,7 @@ class ClientSKeyRequestPacket(
* @author Him188moe * @author Him188moe
*/ */
@PacketId("00 1D") @PacketId("00 1D")
@ExperimentalUnsignedTypes
class ClientSKeyRefreshmentRequestPacket( class ClientSKeyRefreshmentRequestPacket(
private val qq: Long, private val qq: Long,
private val sessionKey: ByteArray private val sessionKey: ByteArray

View File

@ -1,3 +1,5 @@
@file:Suppress("EXPERIMENTAL_API_USAGE")
package net.mamoe.mirai.network.packet package net.mamoe.mirai.network.packet
import net.mamoe.mirai.message.FaceID import net.mamoe.mirai.message.FaceID
@ -22,7 +24,7 @@ import java.util.zip.GZIPInputStream
abstract class ServerEventPacket(input: DataInputStream, val packetId: ByteArray, val eventIdentity: ByteArray) : ServerPacket(input) { abstract class ServerEventPacket(input: DataInputStream, val packetId: ByteArray, val eventIdentity: ByteArray) : ServerPacket(input) {
@PacketId("00 17") @PacketId("00 17")
class Raw(input: DataInputStream, private val packetId: ByteArray) : ServerPacket(input) { class Raw(input: DataInputStream, private val packetId: ByteArray) : ServerPacket(input) {
@ExperimentalUnsignedTypes
fun distribute(): ServerEventPacket { fun distribute(): ServerEventPacket {
val eventIdentity = this.input.readNBytes(16) val eventIdentity = this.input.readNBytes(16)
val type = this.input.goto(18).readNBytes(2) val type = this.input.goto(18).readNBytes(2)
@ -80,6 +82,7 @@ class ServerGroupUploadFileEventPacket(input: DataInputStream, packetId: ByteArr
}//todo test }//todo test
} }
@Suppress("EXPERIMENTAL_API_USAGE")
class ServerGroupMessageEventPacket(input: DataInputStream, packetId: ByteArray, eventIdentity: ByteArray) : ServerEventPacket(input, packetId, eventIdentity) { class ServerGroupMessageEventPacket(input: DataInputStream, packetId: ByteArray, eventIdentity: ByteArray) : ServerEventPacket(input, packetId, eventIdentity) {
var groupNumber: Long = 0 var groupNumber: Long = 0
var qq: Long = 0 var qq: Long = 0
@ -100,16 +103,16 @@ class ServerGroupMessageEventPacket(input: DataInputStream, packetId: ByteArray,
OTHER, OTHER,
} }
@ExperimentalUnsignedTypes
override fun decode() { override fun decode() {
groupNumber = this.input.goto(51).readInt().toLong() groupNumber = this.input.goto(51).readInt().toLong()
qq = this.input.goto(56).readLong().toUInt().toLong() qq = this.input.goto(56).readLong()
val fontLength = this.input.goto(108).readShort() val fontLength = this.input.goto(108).readShort()
//println(this.input.goto(110 + fontLength).readNBytesAt(2).toUHexString())//always 00 00 //println(this.input.goto(110 + fontLength).readNBytesAt(2).toUHexString())//always 00 00
messageType = when (val id = this.input.goto(110 + fontLength + 2).readByte().toInt()) { messageType = when (val id = this.input.goto(110 + fontLength + 2).readByte().toInt()) {
0x13 -> MessageType.NORMAL 0x13 -> MessageType.NORMAL
0xE -> MessageType.XML 0x0E -> MessageType.XML
0x06 -> MessageType.AT 0x06 -> MessageType.AT
@ -188,7 +191,7 @@ class ServerFriendMessageEventPacket(input: DataInputStream, packetId: ByteArray
var qq: Long = 0 var qq: Long = 0
lateinit var message: MessageChain lateinit var message: MessageChain
@ExperimentalUnsignedTypes
override fun decode() { override fun decode() {
input.goto(0) input.goto(0)
println() println()
@ -291,7 +294,7 @@ B1 89 BE 09 8F 00 1A E5 00 0B 03 A2 09 90 BB 7A 1F 40 00 A6 00 00 00 20 00 05 00
* 告知服务器已经收到数据 * 告知服务器已经收到数据
*/ */
@PacketId("")//随后写入 @PacketId("")//随后写入
@ExperimentalUnsignedTypes
class ClientMessageResponsePacket( class ClientMessageResponsePacket(
private val qq: Long, private val qq: Long,
private val packetIdFromServer: ByteArray,//4bytes private val packetIdFromServer: ByteArray,//4bytes
@ -329,7 +332,7 @@ class ServerFriendMessageEventPacket(input: DataInputStream, packetId: ByteArray
lateinit var message: String lateinit var message: String
@ExperimentalUnsignedTypes
override fun decode() { override fun decode() {
//start at Sep1.0:27 //start at Sep1.0:27
qq = input.readIntAt(0) qq = input.readIntAt(0)

View File

@ -2,7 +2,6 @@ package net.mamoe.mirai.network.packet
import net.mamoe.mirai.network.Protocol import net.mamoe.mirai.network.Protocol
import net.mamoe.mirai.utils.TEA import net.mamoe.mirai.utils.TEA
import net.mamoe.mirai.utils.getRandomByteArray
import net.mamoe.mirai.utils.lazyEncode import net.mamoe.mirai.utils.lazyEncode
import java.io.DataInputStream import java.io.DataInputStream
import java.net.InetAddress import java.net.InetAddress
@ -10,7 +9,7 @@ import java.net.InetAddress
/** /**
* @author Him188moe * @author Him188moe
*/ */
@ExperimentalUnsignedTypes
@PacketId("08 28 04 34") @PacketId("08 28 04 34")
class ClientSessionRequestPacket( class ClientSessionRequestPacket(
private val qq: Long, private val qq: Long,
@ -48,12 +47,12 @@ class ClientSessionRequestPacket(
it.writeHex("01 0B 00 85 00 02") it.writeHex("01 0B 00 85 00 02")
it.writeHex("B9 ED EF D7 CD E5 47 96 7A B5 28 34 CA 93 6B 5C")//fix2 it.writeHex("B9 ED EF D7 CD E5 47 96 7A B5 28 34 CA 93 6B 5C")//fix2
it.write(getRandomByteArray(1)) it.writeRandom(1)
it.writeHex("10 00 00 00 00 00 00 00 02") it.writeHex("10 00 00 00 00 00 00 00 02")
//fix3 //fix3
it.writeHex("00 63 3E 00 63 02 04 03 06 02 00 04 00 52 D9 00 00 00 00 A9 58 3E 6D 6D 49 AA F6 A6 D9 33 0A E7 7E 36 84 03 01 00 00 68 20 15 8B 00 00 01 02 00 00 03 00 07 DF 00 0A 00 0C 00 01 00 04 00 03 00 04 20 5C 00") it.writeHex("00 63 3E 00 63 02 04 03 06 02 00 04 00 52 D9 00 00 00 00 A9 58 3E 6D 6D 49 AA F6 A6 D9 33 0A E7 7E 36 84 03 01 00 00 68 20 15 8B 00 00 01 02 00 00 03 00 07 DF 00 0A 00 0C 00 01 00 04 00 03 00 04 20 5C 00")
it.write(getRandomByteArray(32))//md5 32 it.writeRandom(32)//md5 32
it.writeHex("68") it.writeHex("68")
it.writeHex("00 00 00 00 00 2D 00 06 00 01") it.writeHex("00 00 00 00 00 2D 00 06 00 01")
@ -70,7 +69,7 @@ class ServerSessionKeyResponsePacket(inputStream: DataInputStream, private val d
lateinit var sessionKey: ByteArray lateinit var sessionKey: ByteArray
lateinit var tlv0105: ByteArray lateinit var tlv0105: ByteArray
@ExperimentalUnsignedTypes
override fun decode() { override fun decode() {
when (dataLength) { when (dataLength) {
407 -> { 407 -> {

View File

@ -1,6 +1,7 @@
package net.mamoe.mirai.network.packet package net.mamoe.mirai.network.packet
import net.mamoe.mirai.network.Protocol import net.mamoe.mirai.network.Protocol
import net.mamoe.mirai.network.packet.login.ClientPasswordSubmissionPacket
import net.mamoe.mirai.utils.ByteArrayDataOutputStream import net.mamoe.mirai.utils.ByteArrayDataOutputStream
import net.mamoe.mirai.utils.TEA import net.mamoe.mirai.utils.TEA
import net.mamoe.mirai.utils.hexToBytes import net.mamoe.mirai.utils.hexToBytes
@ -11,11 +12,12 @@ import java.io.IOException
/** /**
* A packet received when logging in, used to redirect server address * A packet received when logging in, used to redirect server address
* *
* @see net.mamoe.mirai.network.packet.client.login.ClientServerRedirectionPacket * @see ClientServerRedirectionPacket
* @see net.mamoe.mirai.network.packet.client.login.ClientPasswordSubmissionPacket * @see ClientPasswordSubmissionPacket
* *
* @author Him188moe * @author Him188moe
*/ */
@Suppress("EXPERIMENTAL_API_USAGE")
@PacketId("08 25 31 01") @PacketId("08 25 31 01")
class ServerTouchResponsePacket(inputStream: DataInputStream) : ServerPacket(inputStream) { class ServerTouchResponsePacket(inputStream: DataInputStream) : ServerPacket(inputStream) {
var serverIP: String? = null var serverIP: String? = null
@ -29,9 +31,9 @@ class ServerTouchResponsePacket(inputStream: DataInputStream) : ServerPacket(inp
TYPE_08_25_31_02, TYPE_08_25_31_02,
} }
@ExperimentalUnsignedTypes
override fun decode() { override fun decode() {
when (val id = input.readByte().toUByte().toInt()) { when (val id = input.readByte().toInt()) {
0xFE -> { 0xFE -> {
input.skip(94) input.skip(94)
serverIP = input.readIP() serverIP = input.readIP()
@ -52,7 +54,7 @@ class ServerTouchResponsePacket(inputStream: DataInputStream) : ServerPacket(inp
} }
class Encrypted(private val type: Type, inputStream: DataInputStream) : ServerPacket(inputStream) { class Encrypted(private val type: Type, inputStream: DataInputStream) : ServerPacket(inputStream) {
@ExperimentalUnsignedTypes
fun decrypt(): ServerTouchResponsePacket = ServerTouchResponsePacket(decryptBy(when (type) { fun decrypt(): ServerTouchResponsePacket = ServerTouchResponsePacket(decryptBy(when (type) {
Type.TYPE_08_25_31_02 -> Protocol.redirectionKey.hexToBytes() Type.TYPE_08_25_31_02 -> Protocol.redirectionKey.hexToBytes()
Type.TYPE_08_25_31_01 -> Protocol.key0825.hexToBytes() Type.TYPE_08_25_31_01 -> Protocol.key0825.hexToBytes()
@ -65,10 +67,10 @@ class ServerTouchResponsePacket(inputStream: DataInputStream) : ServerPacket(inp
* *
* @author Him188moe * @author Him188moe
*/ */
@ExperimentalUnsignedTypes
@PacketId("08 25 31 01") @PacketId("08 25 31 01")
class ClientTouchPacket(private val qq: Long, private val serverIp: String) : ClientPacket() { class ClientTouchPacket(private val qq: Long, private val serverIp: String) : ClientPacket() {
@ExperimentalUnsignedTypes
@Throws(IOException::class) @Throws(IOException::class)
override fun encode() { override fun encode() {
this.writeQQ(qq) this.writeQQ(qq)
@ -80,7 +82,7 @@ class ClientTouchPacket(private val qq: Long, private val serverIp: String) : Cl
it.writeHex(Protocol.constantData2) it.writeHex(Protocol.constantData2)
it.writeQQ(qq) it.writeQQ(qq)
it.writeHex("00 00 00 00 03 09 00 08 00 01") it.writeHex("00 00 00 00 03 09 00 08 00 01")
it.writeIP(serverIp); it.writeIP(serverIp)
it.writeHex("00 02 00 36 00 12 00 02 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 14 00 1D 01 02 00 19") it.writeHex("00 02 00 36 00 12 00 02 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 14 00 1D 01 02 00 19")
it.writeHex(Protocol.publicKey) it.writeHex(Protocol.publicKey)
} }
@ -92,10 +94,10 @@ class ClientTouchPacket(private val qq: Long, private val serverIp: String) : Cl
* *
* @author Him188moe * @author Him188moe
*/ */
@ExperimentalUnsignedTypes
@PacketId("08 25 31 02") @PacketId("08 25 31 02")
class ClientServerRedirectionPacket(private val serverIP: String, private val qq: Long) : ClientPacket() { class ClientServerRedirectionPacket(private val serverIP: String, private val qq: Long) : ClientPacket() {
@ExperimentalUnsignedTypes
override fun encode() { override fun encode() {
this.writeQQ(qq) this.writeQQ(qq)
this.writeHex(Protocol.fixVer) this.writeHex(Protocol.fixVer)

View File

@ -2,14 +2,14 @@ package net.mamoe.mirai.network.packet
import net.mamoe.mirai.network.Protocol import net.mamoe.mirai.network.Protocol
import net.mamoe.mirai.utils.TEA import net.mamoe.mirai.utils.TEA
import net.mamoe.mirai.utils.TestedSuccessfully import net.mamoe.mirai.utils.Tested
import net.mamoe.mirai.utils.hexToBytes import net.mamoe.mirai.utils.hexToBytes
import java.io.DataInputStream import java.io.DataInputStream
/** /**
* 客户端请求验证码图片数据的第几部分 * 客户端请求验证码图片数据的第几部分
*/ */
@ExperimentalUnsignedTypes
@PacketId("00 BA 31") @PacketId("00 BA 31")
class ClientVerificationCodeTransmissionRequestPacket( class ClientVerificationCodeTransmissionRequestPacket(
private val packetId: Int, private val packetId: Int,
@ -18,7 +18,7 @@ class ClientVerificationCodeTransmissionRequestPacket(
private val verificationSequence: Int, private val verificationSequence: Int,
private val token00BA: ByteArray private val token00BA: ByteArray
) : ClientPacket() { ) : ClientPacket() {
@TestedSuccessfully @Tested
override fun encode() { override fun encode() {
this.writeByte(packetId)//part of packet id this.writeByte(packetId)//part of packet id
@ -46,7 +46,7 @@ class ClientVerificationCodeTransmissionRequestPacket(
* 提交验证码 * 提交验证码
*/ */
@PacketId("00 BA 32") @PacketId("00 BA 32")
@ExperimentalUnsignedTypes
class ClientVerificationCodeSubmitPacket( class ClientVerificationCodeSubmitPacket(
private val packetIdLast: Int, private val packetIdLast: Int,
private val qq: Long, private val qq: Long,
@ -93,7 +93,7 @@ class ClientVerificationCodeSubmitPacket(
* 刷新验证码 * 刷新验证码
*/ */
@PacketId("00 BA 31") @PacketId("00 BA 31")
@ExperimentalUnsignedTypes
class ClientVerificationCodeRefreshPacket( class ClientVerificationCodeRefreshPacket(
private val packetIdLast: Int, private val packetIdLast: Int,
private val qq: Long, private val qq: Long,
@ -142,7 +142,7 @@ open class ServerVerificationCodeTransmissionPacket(input: DataInputStream, priv
lateinit var token00BA: ByteArray//40 bytes lateinit var token00BA: ByteArray//40 bytes
var packetIdLast: Int = 0 var packetIdLast: Int = 0
@ExperimentalUnsignedTypes
override fun decode() { override fun decode() {
this.verificationToken = this.input.readNBytesAt(10, 56) this.verificationToken = this.input.readNBytesAt(10, 56)
@ -181,7 +181,7 @@ class ServerVerificationCodeCorrectPacket(input: DataInputStream) : ServerVerifi
lateinit var token00BA: ByteArray//56 bytes lateinit var token00BA: ByteArray//56 bytes
@ExperimentalUnsignedTypes
override fun decode() { override fun decode() {
token00BA = this.input.readNBytesAt(10, 56) token00BA = this.input.readNBytesAt(10, 56)
} }
@ -191,7 +191,7 @@ abstract class ServerVerificationCodePacket(input: DataInputStream) : ServerPack
@PacketId("00 BA") @PacketId("00 BA")
class Encrypted(input: DataInputStream, private val id: String) : ServerPacket(input) { class Encrypted(input: DataInputStream, private val id: String) : ServerPacket(input) {
@ExperimentalUnsignedTypes
fun decrypt(): ServerVerificationCodePacket { fun decrypt(): ServerVerificationCodePacket {
this.input goto 14 this.input goto 14
val data = TEA.decrypt(this.input.readAllBytes().cutTail(1), Protocol.key00BA.hexToBytes()) val data = TEA.decrypt(this.input.readAllBytes().cutTail(1), Protocol.key00BA.hexToBytes())

View File

@ -1,3 +1,5 @@
@file:Suppress("EXPERIMENTAL_API_USAGE", "EXPERIMENTAL_UNSIGNED_LITERALS")
package net.mamoe.mirai.network.packet.action package net.mamoe.mirai.network.packet.action
import net.mamoe.mirai.network.Protocol import net.mamoe.mirai.network.Protocol
@ -13,7 +15,7 @@ import java.util.*
* @author Him188moe * @author Him188moe
*/ */
@PacketId("00 A7") @PacketId("00 A7")
@ExperimentalUnsignedTypes
class ClientCanAddFriendPacket( class ClientCanAddFriendPacket(
val bot: Long, val bot: Long,
val qq: Long, val qq: Long,
@ -47,7 +49,7 @@ class ServerCanAddFriendResponsePacket(input: DataInputStream) : ServerPacket(in
FAILED, FAILED,
} }
@ExperimentalUnsignedTypes
override fun decode() { override fun decode() {
val data = input.goto(0).readAllBytes() val data = input.goto(0).readAllBytes()
if (data.size == 99) { if (data.size == 99) {
@ -78,7 +80,7 @@ class ServerCanAddFriendResponsePacket(input: DataInputStream) : ServerPacket(in
* 请求添加好友 * 请求添加好友
*/ */
@PacketId("00 AE") @PacketId("00 AE")
@ExperimentalUnsignedTypes
class ClientAddFriendPacket( class ClientAddFriendPacket(
val bot: Long, val bot: Long,
val qq: Long, val qq: Long,

View File

@ -10,7 +10,7 @@ import java.io.DataInputStream
* @author Him188moe * @author Him188moe
*/ */
@PacketId("00 CD") @PacketId("00 CD")
@ExperimentalUnsignedTypes
class ClientSendFriendMessagePacket( class ClientSendFriendMessagePacket(
private val botQQ: Long, private val botQQ: Long,
private val targetQQ: Long, private val targetQQ: Long,

View File

@ -9,7 +9,7 @@ import java.io.DataInputStream
* @author Him188moe * @author Him188moe
*/ */
@PacketId("00 02") @PacketId("00 02")
@ExperimentalUnsignedTypes
class ClientSendGroupMessagePacket( class ClientSendGroupMessagePacket(
private val groupId: Long,//不是 number private val groupId: Long,//不是 number
private val botQQ: Long, private val botQQ: Long,

View File

@ -1,3 +1,5 @@
@file:Suppress("EXPERIMENTAL_API_USAGE", "EXPERIMENTAL_UNSIGNED_LITERALS")
package net.mamoe.mirai.network.packet.image package net.mamoe.mirai.network.packet.image
import net.mamoe.mirai.network.packet.* import net.mamoe.mirai.network.packet.*
@ -15,7 +17,7 @@ import java.io.DataInputStream
* @author Him188moe * @author Him188moe
*/ */
@PacketId("03 88") @PacketId("03 88")
@ExperimentalUnsignedTypes
class ClientTryGetGroupImageIDPacket( class ClientTryGetGroupImageIDPacket(
private val bot: Long, private val bot: Long,
private val sessionKey: ByteArray, private val sessionKey: ByteArray,
@ -108,7 +110,7 @@ abstract class ServerTryUploadGroupImageResponsePacket(input: DataInputStream) :
class ServerTryUploadGroupImageSuccessPacket(input: DataInputStream) : ServerTryUploadGroupImageResponsePacket(input) { class ServerTryUploadGroupImageSuccessPacket(input: DataInputStream) : ServerTryUploadGroupImageResponsePacket(input) {
lateinit var uKey: ByteArray lateinit var uKey: ByteArray
@ExperimentalUnsignedTypes
override fun decode() { override fun decode() {
uKey = this.input.gotoWhere(ubyteArrayOf(0x42u, 0x80u, 0x01u)).readNBytes(128) uKey = this.input.gotoWhere(ubyteArrayOf(0x42u, 0x80u, 0x01u)).readNBytes(128)
} }

View File

@ -9,7 +9,7 @@ import net.mamoe.mirai.utils.ClientLoginStatus
* *
* @author Him188moe * @author Him188moe
*/ */
@ExperimentalUnsignedTypes
@PacketId("00 EC") @PacketId("00 EC")
class ClientChangeOnlineStatusPacket( class ClientChangeOnlineStatusPacket(
private val qq: Long, private val qq: Long,

View File

@ -4,7 +4,7 @@ import net.mamoe.mirai.network.Protocol
import net.mamoe.mirai.network.packet.* import net.mamoe.mirai.network.packet.*
import net.mamoe.mirai.utils.ByteArrayDataOutputStream import net.mamoe.mirai.utils.ByteArrayDataOutputStream
import net.mamoe.mirai.utils.TEA import net.mamoe.mirai.utils.TEA
import net.mamoe.mirai.utils.TestedSuccessfully import net.mamoe.mirai.utils.Tested
import net.mamoe.mirai.utils.hexToBytes import net.mamoe.mirai.utils.hexToBytes
import java.io.DataOutputStream import java.io.DataOutputStream
@ -14,8 +14,8 @@ import java.io.DataOutputStream
* @author Him188moe * @author Him188moe
*/ */
@PacketId("08 36 31 03") @PacketId("08 36 31 03")
@ExperimentalUnsignedTypes
@TestedSuccessfully @Tested
class ClientPasswordSubmissionPacket( class ClientPasswordSubmissionPacket(
private val qq: Long, private val qq: Long,
private val password: String, private val password: String,
@ -24,7 +24,7 @@ class ClientPasswordSubmissionPacket(
private val tgtgtKey: ByteArray, private val tgtgtKey: ByteArray,
private val token0825: ByteArray private val token0825: ByteArray
) : ClientPacket() { ) : ClientPacket() {
@ExperimentalUnsignedTypes
override fun encode() { override fun encode() {
this.writeQQ(qq) this.writeQQ(qq)
this.writeHex(Protocol.passwordSubmissionKey1) this.writeHex(Protocol.passwordSubmissionKey1)
@ -40,21 +40,21 @@ class ClientPasswordSubmissionPacket(
} }
@PacketId("08 36 31 04") @PacketId("08 36 31 04")
@ExperimentalUnsignedTypes
class ClientLoginResendPacket3104(qq: Long, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray, token0825: ByteArray, token00BA: ByteArray, tlv0006: ByteArray? = null) class ClientLoginResendPacket3104(qq: Long, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray, token0825: ByteArray, token00BA: ByteArray, tlv0006: ByteArray? = null)
: ClientLoginResendPacket(qq, password, loginTime, loginIP, tgtgtKey, token0825, token00BA, tlv0006) : ClientLoginResendPacket(qq, password, loginTime, loginIP, tgtgtKey, token0825, token00BA, tlv0006)
@PacketId("08 36 31 05") @PacketId("08 36 31 05")
@ExperimentalUnsignedTypes
class ClientLoginResendPacket3105(qq: Long, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray, token0825: ByteArray, token00BA: ByteArray) class ClientLoginResendPacket3105(qq: Long, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray, token0825: ByteArray, token00BA: ByteArray)
: ClientLoginResendPacket(qq, password, loginTime, loginIP, tgtgtKey, token0825, token00BA, null) : ClientLoginResendPacket(qq, password, loginTime, loginIP, tgtgtKey, token0825, token00BA, null)
@PacketId("08 36 31 06") @PacketId("08 36 31 06")
@ExperimentalUnsignedTypes
class ClientLoginResendPacket3106(qq: Long, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray, token0825: ByteArray, token00BA: ByteArray, tlv0006: ByteArray? = null) class ClientLoginResendPacket3106(qq: Long, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray, token0825: ByteArray, token00BA: ByteArray, tlv0006: ByteArray? = null)
: ClientLoginResendPacket(qq, password, loginTime, loginIP, tgtgtKey, token0825, token00BA, tlv0006) : ClientLoginResendPacket(qq, password, loginTime, loginIP, tgtgtKey, token0825, token00BA, tlv0006)
@ExperimentalUnsignedTypes
open class ClientLoginResendPacket internal constructor( open class ClientLoginResendPacket internal constructor(
val qq: Long, val qq: Long,
val password: String, val password: String,
@ -93,7 +93,7 @@ open class ClientLoginResendPacket internal constructor(
/** /**
* @author Him188moe * @author Him188moe
*/ */
@ExperimentalUnsignedTypes
private fun DataOutputStream.writePart1(qq: Long, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray, token0825: ByteArray, tlv0006: ByteArray? = null) { private fun DataOutputStream.writePart1(qq: Long, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray, token0825: ByteArray, tlv0006: ByteArray? = null) {
//this.writeInt(System.currentTimeMillis().toInt()) //this.writeInt(System.currentTimeMillis().toInt())
@ -130,7 +130,7 @@ private fun DataOutputStream.writePart1(qq: Long, password: String, loginTime: I
this.writeHex("60 C9 5D A7 45 70 04 7F 21 7D 84 50 5C 66 A5 C6")//key this.writeHex("60 C9 5D A7 45 70 04 7F 21 7D 84 50 5C 66 A5 C6")//key
} }
@ExperimentalUnsignedTypes
private fun DataOutputStream.writePart2() { private fun DataOutputStream.writePart2() {
this.writeHex("03 12")//tag this.writeHex("03 12")//tag

View File

@ -4,7 +4,7 @@ import net.mamoe.mirai.network.Protocol
import net.mamoe.mirai.network.packet.PacketId import net.mamoe.mirai.network.packet.PacketId
import net.mamoe.mirai.network.packet.ServerPacket import net.mamoe.mirai.network.packet.ServerPacket
import net.mamoe.mirai.network.packet.goto import net.mamoe.mirai.network.packet.goto
import net.mamoe.mirai.utils.TestedSuccessfully import net.mamoe.mirai.utils.Tested
import java.io.DataInputStream import java.io.DataInputStream
/** /**
@ -23,7 +23,7 @@ class ServerLoginResponseKeyExchangePacket(input: DataInputStream, val flag: Fla
var tokenUnknown: ByteArray? = null var tokenUnknown: ByteArray? = null
lateinit var tgtgtKey: ByteArray//16bytes lateinit var tgtgtKey: ByteArray//16bytes
@TestedSuccessfully @Tested
override fun decode() { override fun decode() {
this.input.skip(5) this.input.skip(5)
tgtgtKey = this.input.readNBytes(16)//22 tgtgtKey = this.input.readNBytes(16)//22
@ -46,8 +46,8 @@ class ServerLoginResponseKeyExchangePacket(input: DataInputStream, val flag: Fla
} }
class Encrypted(input: DataInputStream, private val flag: Flag) : ServerPacket(input) { class Encrypted(input: DataInputStream, private val flag: Flag) : ServerPacket(input) {
@ExperimentalUnsignedTypes
@TestedSuccessfully @Tested
fun decrypt(tgtgtKey: ByteArray): ServerLoginResponseKeyExchangePacket { fun decrypt(tgtgtKey: ByteArray): ServerLoginResponseKeyExchangePacket {
return ServerLoginResponseKeyExchangePacket(this.decryptBy(Protocol.shareKey, tgtgtKey), flag).setId(this.idHex) return ServerLoginResponseKeyExchangePacket(this.decryptBy(Protocol.shareKey, tgtgtKey), flag).setId(this.idHex)
} }

View File

@ -1,3 +1,5 @@
@file:Suppress("EXPERIMENTAL_API_USAGE")
package net.mamoe.mirai.network.packet.login package net.mamoe.mirai.network.packet.login
import net.mamoe.mirai.network.Protocol import net.mamoe.mirai.network.Protocol
@ -5,7 +7,7 @@ import net.mamoe.mirai.network.packet.ServerPacket
import net.mamoe.mirai.network.packet.goto import net.mamoe.mirai.network.packet.goto
import net.mamoe.mirai.network.packet.readNBytesAt import net.mamoe.mirai.network.packet.readNBytesAt
import net.mamoe.mirai.network.packet.readString import net.mamoe.mirai.network.packet.readString
import net.mamoe.mirai.utils.TestedSuccessfully import net.mamoe.mirai.utils.Tested
import net.mamoe.mirai.utils.toUHexString import net.mamoe.mirai.utils.toUHexString
import java.io.DataInputStream import java.io.DataInputStream
@ -21,8 +23,8 @@ class ServerLoginResponseSuccessPacket(input: DataInputStream) : ServerPacket(in
lateinit var encryptionKey: ByteArray lateinit var encryptionKey: ByteArray
@TestedSuccessfully @Tested
@ExperimentalUnsignedTypes
override fun decode() { override fun decode() {
this.input.skip(7)//8 this.input.skip(7)//8
this.encryptionKey = this.input.readNBytes(16)//24 this.encryptionKey = this.input.readNBytes(16)//24
@ -52,7 +54,7 @@ class ServerLoginResponseSuccessPacket(input: DataInputStream) : ServerPacket(in
class Encrypted(input: DataInputStream) : ServerPacket(input) { class Encrypted(input: DataInputStream) : ServerPacket(input) {
@ExperimentalUnsignedTypes
fun decrypt(tgtgtKey: ByteArray): ServerLoginResponseSuccessPacket { fun decrypt(tgtgtKey: ByteArray): ServerLoginResponseSuccessPacket {
input goto 14 input goto 14
return ServerLoginResponseSuccessPacket(this.decryptBy(Protocol.shareKey, tgtgtKey)).setId(this.idHex) return ServerLoginResponseSuccessPacket(this.decryptBy(Protocol.shareKey, tgtgtKey)).setId(this.idHex)

View File

@ -1,10 +1,12 @@
@file:Suppress("EXPERIMENTAL_API_USAGE")
package net.mamoe.mirai.network.packet.login package net.mamoe.mirai.network.packet.login
import net.mamoe.mirai.network.Protocol import net.mamoe.mirai.network.Protocol
import net.mamoe.mirai.network.packet.ServerPacket import net.mamoe.mirai.network.packet.ServerPacket
import net.mamoe.mirai.network.packet.dataInputStream import net.mamoe.mirai.network.packet.dataInputStream
import net.mamoe.mirai.network.packet.goto import net.mamoe.mirai.network.packet.goto
import net.mamoe.mirai.utils.TestedSuccessfully import net.mamoe.mirai.utils.Tested
import net.mamoe.mirai.utils.hexToUBytes import net.mamoe.mirai.utils.hexToUBytes
import java.io.DataInputStream import java.io.DataInputStream
@ -20,8 +22,8 @@ class ServerLoginResponseVerificationCodeInitPacket(input: DataInputStream, priv
var unknownBoolean: Boolean? = null var unknownBoolean: Boolean? = null
@TestedSuccessfully @Tested
@ExperimentalUnsignedTypes
override fun decode() { override fun decode() {
val verifyCodeLength = this.input.goto(78).readShort()//2bytes val verifyCodeLength = this.input.goto(78).readShort()//2bytes
this.verifyCodePart1 = this.input.readNBytes(verifyCodeLength.toInt()) this.verifyCodePart1 = this.input.readNBytes(verifyCodeLength.toInt())
@ -39,7 +41,7 @@ class ServerLoginResponseVerificationCodeInitPacket(input: DataInputStream, priv
} }
@ExperimentalUnsignedTypes
fun decrypt(): ServerLoginResponseVerificationCodeInitPacket { fun decrypt(): ServerLoginResponseVerificationCodeInitPacket {
this.input goto 14 this.input goto 14
val data = this.decryptBy(Protocol.shareKey).goto(0).readAllBytes() val data = this.decryptBy(Protocol.shareKey).goto(0).readAllBytes()

View File

@ -1,277 +1,269 @@
package net.mamoe.mirai.utils package net.mamoe.mirai.utils
import net.mamoe.mirai.network.Protocol
import java.nio.ByteBuffer import java.nio.ByteBuffer
import java.util.* import java.util.*
import kotlin.experimental.and import kotlin.experimental.and
import kotlin.experimental.xor import kotlin.experimental.xor
/**
* @author Him188moe
*/
/** /**
* TEA 加密 * TEA 加密
* *
* @author iweiz https://github.com/iweizime/StepChanger/blob/master/app/src/main/java/me/iweizi/stepchanger/qq/Cryptor.java * @author iweiz https://github.com/iweizime/StepChanger/blob/master/app/src/main/java/me/iweizi/stepchanger/qq/Cryptor.java
*/ */
class TEA(private val key: ByteArray) { object TEA {
private const val UINT32_MASK = 0xffffffffL
private fun doOption(data: ByteArray, key: ByteArray, encrypt: Boolean): ByteArray {
val mRandom = Random()
lateinit var mOutput: ByteArray
lateinit var mInBlock: ByteArray
var mIndexPos: Int
lateinit var mIV: ByteArray
var mOutPos = 0
var mPreOutPos = 0
var isFirstBlock = true
companion object { val mKey = LongArray(4)
val CRYPTOR_SHARE_KEY = TEA(Protocol.hexToBytes(Protocol.shareKey))
val CRYPTOR_0825KEY = TEA(Protocol.hexToBytes(Protocol.key0825))
private val UINT32_MASK = 0xffffffffL for (i in 0..3) {
mKey[i] = pack(key, i * 4, 4)
}
fun doOption(data: ByteArray, key: ByteArray, encrypt: Boolean): ByteArray { fun rand(): Int {
val mRandom = Random() return mRandom.nextInt()
lateinit var mOutput: ByteArray }
lateinit var mInBlock: ByteArray
var mIndexPos: Int
lateinit var mIV: ByteArray
var mOutPos = 0
var mPreOutPos = 0
var isFirstBlock: Boolean = true
val mKey = LongArray(4) fun encode(bytes: ByteArray): ByteArray {
var v0 = pack(bytes, 0, 4)
var v1 = pack(bytes, 4, 4)
var sum: Long = 0
val delta = 0x9e3779b9L
for (i in 0..15) {
sum = sum + delta and UINT32_MASK
v0 += (v1 shl 4) + mKey[0] xor v1 + sum xor v1.ushr(5) + mKey[1]
v0 = v0 and UINT32_MASK
v1 += (v0 shl 4) + mKey[2] xor v0 + sum xor v0.ushr(5) + mKey[3]
v1 = v1 and UINT32_MASK
}
return ByteBuffer.allocate(8).putInt(v0.toInt()).putInt(v1.toInt()).array()
}
for (i in 0..3) { fun decode(bytes: ByteArray, offset: Int): ByteArray {
mKey[i] = pack(key, i * 4, 4) var v0 = pack(bytes, offset, 4)
var v1 = pack(bytes, offset + 4, 4)
val delta = 0x9e3779b9L
var sum = delta shl 4 and UINT32_MASK
for (i in 0..15) {
v1 -= (v0 shl 4) + mKey[2] xor v0 + sum xor v0.ushr(5) + mKey[3]
v1 = v1 and UINT32_MASK
v0 -= (v1 shl 4) + mKey[0] xor v1 + sum xor v1.ushr(5) + mKey[1]
v0 = v0 and UINT32_MASK
sum = sum - delta and UINT32_MASK
}
return ByteBuffer.allocate(8).putInt(v0.toInt()).putInt(v1.toInt()).array()
}
fun encodeOneBlock() {
mIndexPos = 0
while (mIndexPos < 8) {
mInBlock[mIndexPos] = if (isFirstBlock)
mInBlock[mIndexPos]
else
(mInBlock[mIndexPos] xor mOutput[mPreOutPos + mIndexPos])
mIndexPos++
} }
fun rand(): Int { System.arraycopy(encode(mInBlock), 0, mOutput, mOutPos, 8)
return mRandom.nextInt() mIndexPos = 0
while (mIndexPos < 8) {
val outPos = mOutPos + mIndexPos
mOutput[outPos] = (mOutput[outPos] xor mIV[mIndexPos])
mIndexPos++
} }
System.arraycopy(mInBlock, 0, mIV, 0, 8)
mPreOutPos = mOutPos
mOutPos += 8
mIndexPos = 0
isFirstBlock = false
}
fun encode(bytes: ByteArray): ByteArray { fun decodeOneBlock(ciphertext: ByteArray, offset: Int, len: Int): Boolean {
var v0 = pack(bytes, 0, 4) mIndexPos = 0
var v1 = pack(bytes, 4, 4) while (mIndexPos < 8) {
var sum: Long = 0 if (mOutPos + mIndexPos < len) {
val delta = 0x9e3779b9L mIV[mIndexPos] = (mIV[mIndexPos] xor ciphertext[mOutPos + offset + mIndexPos])
for (i in 0..15) {
sum = sum + delta and UINT32_MASK
v0 += (v1 shl 4) + mKey[0] xor v1 + sum xor v1.ushr(5) + mKey[1]
v0 = v0 and UINT32_MASK
v1 += (v0 shl 4) + mKey[2] xor v0 + sum xor v0.ushr(5) + mKey[3]
v1 = v1 and UINT32_MASK
}
return ByteBuffer.allocate(8).putInt(v0.toInt()).putInt(v1.toInt()).array()
}
fun decode(bytes: ByteArray, offset: Int): ByteArray {
var v0 = pack(bytes, offset, 4)
var v1 = pack(bytes, offset + 4, 4)
val delta = 0x9e3779b9L
var sum = delta shl 4 and UINT32_MASK
for (i in 0..15) {
v1 -= (v0 shl 4) + mKey[2] xor v0 + sum xor v0.ushr(5) + mKey[3]
v1 = v1 and UINT32_MASK
v0 -= (v1 shl 4) + mKey[0] xor v1 + sum xor v1.ushr(5) + mKey[1]
v0 = v0 and UINT32_MASK
sum = sum - delta and UINT32_MASK
}
return ByteBuffer.allocate(8).putInt(v0.toInt()).putInt(v1.toInt()).array()
}
fun encodeOneBlock() {
mIndexPos = 0
while (mIndexPos < 8) {
mInBlock[mIndexPos] = if (isFirstBlock)
mInBlock[mIndexPos]
else
(mInBlock[mIndexPos] xor mOutput[mPreOutPos + mIndexPos])
mIndexPos++ mIndexPos++
continue
} }
System.arraycopy(encode(mInBlock), 0, mOutput, mOutPos, 8)
mIndexPos = 0
while (mIndexPos < 8) {
val out_pos = mOutPos + mIndexPos
mOutput[out_pos] = (mOutput[out_pos] xor mIV[mIndexPos])
mIndexPos++
}
System.arraycopy(mInBlock, 0, mIV, 0, 8)
mPreOutPos = mOutPos
mOutPos += 8
mIndexPos = 0
isFirstBlock = false
}
fun decodeOneBlock(ciphertext: ByteArray, offset: Int, len: Int): Boolean {
mIndexPos = 0
while (mIndexPos < 8) {
if (mOutPos + mIndexPos < len) {
mIV[mIndexPos] = (mIV[mIndexPos] xor ciphertext[mOutPos + offset + mIndexPos])
mIndexPos++
continue
}
return true
}
mIV = decode(mIV, 0)
mOutPos += 8
mIndexPos = 0
return true return true
} }
fun encrypt(plaintext: ByteArray, offset: Int, len: Int): ByteArray { mIV = decode(mIV, 0)
var len = len; mOutPos += 8
var offset = offset; mIndexPos = 0
mInBlock = ByteArray(8) return true
mIV = ByteArray(8)
mOutPos = 0
mPreOutPos = 0
isFirstBlock = true
mIndexPos = (len + 10) % 8
if (mIndexPos != 0) {
mIndexPos = 8 - mIndexPos
}
mOutput = ByteArray(mIndexPos + len + 10)
mInBlock[0] = (rand() and 0xf8 or mIndexPos).toByte()
for (i in 1..mIndexPos) {
mInBlock[i] = (rand() and 0xff).toByte()
}
++mIndexPos
for (i in 0..7) {
mIV[i] = 0
}
var g = 0 }
while (g < 2) {
if (mIndexPos < 8) {
mInBlock[mIndexPos++] = (rand() and 0xff).toByte()
++g
}
if (mIndexPos == 8) {
encodeOneBlock()
}
}
while (len > 0) { @Suppress("NAME_SHADOWING")
if (mIndexPos < 8) { fun encrypt(plaintext: ByteArray, offset: Int, len: Int): ByteArray {
mInBlock[mIndexPos++] = plaintext[offset++] var len = len
} var offset = offset
if (mIndexPos == 8) { mInBlock = ByteArray(8)
encodeOneBlock() mIV = ByteArray(8)
} mOutPos = 0
len-- mPreOutPos = 0
} isFirstBlock = true
g = 0 mIndexPos = (len + 10) % 8
while (g < 7) { if (mIndexPos != 0) {
if (mIndexPos < 8) { mIndexPos = 8 - mIndexPos
mInBlock[mIndexPos++] = 0.toByte() }
} mOutput = ByteArray(mIndexPos + len + 10)
if (mIndexPos == 8) { mInBlock[0] = (rand() and 0xf8 or mIndexPos).toByte()
encodeOneBlock() for (i in 1..mIndexPos) {
} mInBlock[i] = (rand() and 0xff).toByte()
g++ }
} ++mIndexPos
return mOutput for (i in 0..7) {
mIV[i] = 0
} }
fun decrypt(cipherText: ByteArray, offset: Int, len: Int): ByteArray? { var g = 0
require(!(len % 8 != 0 || len < 16)) { "must len % 8 == 0 && len >= 16" } while (g < 2) {
mIV = decode(cipherText, offset) if (mIndexPos < 8) {
mIndexPos = (mIV[0] and 7).toInt() mInBlock[mIndexPos++] = (rand() and 0xff).toByte()
var plen = len - mIndexPos - 10 ++g
isFirstBlock = true
if (plen < 0) {
return null
} }
mOutput = ByteArray(plen) if (mIndexPos == 8) {
mPreOutPos = 0 encodeOneBlock()
mOutPos = 8
++mIndexPos
var g = 0
while (g < 2) {
if (mIndexPos < 8) {
++mIndexPos
++g
}
if (mIndexPos == 8) {
isFirstBlock = false
if (!decodeOneBlock(cipherText, offset, len)) {
throw RuntimeException("Unable to decode")
}
}
} }
}
var outpos = 0 while (len > 0) {
while (plen != 0) { if (mIndexPos < 8) {
if (mIndexPos < 8) { mInBlock[mIndexPos++] = plaintext[offset++]
mOutput[outpos++] = if (isFirstBlock) }
mIV[mIndexPos] if (mIndexPos == 8) {
else encodeOneBlock()
(cipherText[mPreOutPos + offset + mIndexPos] xor mIV[mIndexPos]) }
len--
}
g = 0
while (g < 7) {
if (mIndexPos < 8) {
mInBlock[mIndexPos++] = 0.toByte()
}
if (mIndexPos == 8) {
encodeOneBlock()
}
g++
}
return mOutput
}
fun decrypt(cipherText: ByteArray, offset: Int, len: Int): ByteArray? {
require(!(len % 8 != 0 || len < 16)) { "must len % 8 == 0 && len >= 16" }
mIV = decode(cipherText, offset)
mIndexPos = (mIV[0] and 7).toInt()
var plen = len - mIndexPos - 10
isFirstBlock = true
if (plen < 0) {
return null
}
mOutput = ByteArray(plen)
mPreOutPos = 0
mOutPos = 8
++mIndexPos
var g = 0
while (g < 2) {
if (mIndexPos < 8) {
++mIndexPos
++g
}
if (mIndexPos == 8) {
isFirstBlock = false
if (!decodeOneBlock(cipherText, offset, len)) {
throw RuntimeException("Unable to decode")
}
}
}
var outpos = 0
while (plen != 0) {
if (mIndexPos < 8) {
mOutput[outpos++] = if (isFirstBlock)
mIV[mIndexPos]
else
(cipherText[mPreOutPos + offset + mIndexPos] xor mIV[mIndexPos])
++mIndexPos
}
if (mIndexPos == 8) {
mPreOutPos = mOutPos - 8
isFirstBlock = false
if (!decodeOneBlock(cipherText, offset, len)) {
throw RuntimeException("Unable to decode")
}
}
plen--
}
g = 0
while (g < 7) {
if (mIndexPos < 8) {
if (cipherText[mPreOutPos + offset + mIndexPos].xor(mIV[mIndexPos]).toInt() != 0) {
throw RuntimeException()
} else {
++mIndexPos ++mIndexPos
} }
if (mIndexPos == 8) {
mPreOutPos = mOutPos - 8
isFirstBlock = false
if (!decodeOneBlock(cipherText, offset, len)) {
throw RuntimeException("Unable to decode")
}
}
plen--
} }
g = 0
while (g < 7) { if (mIndexPos == 8) {
if (mIndexPos < 8) { mPreOutPos = mOutPos
if (cipherText[mPreOutPos + offset + mIndexPos].xor(mIV[mIndexPos]).toInt() != 0) { if (!decodeOneBlock(cipherText, offset, len)) {
throw RuntimeException() throw RuntimeException("Unable to decode")
} else {
++mIndexPos
}
} }
if (mIndexPos == 8) {
mPreOutPos = mOutPos
if (!decodeOneBlock(cipherText, offset, len)) {
throw RuntimeException("Unable to decode")
}
}
g++
} }
return mOutput g++
} }
return mOutput
}
return if (encrypt) { return if (encrypt) {
encrypt(data, 0, data.size) encrypt(data, 0, data.size)
} else { } else {
try { try {
return decrypt(data, 0, data.size)!! return decrypt(data, 0, data.size)!!
} catch (e: Exception) { } catch (e: Exception) {
println("Source: " + data.toUHexString(" ")) println("Source: " + data.toUHexString(" "))
println("Key: " + key.toUHexString(" ")) println("Key: " + key.toUHexString(" "))
throw e throw e
}
} }
} }
}
fun encrypt(source: ByteArray, key: ByteArray): ByteArray {
return doOption(source, key, true) fun encrypt(source: ByteArray, key: ByteArray): ByteArray {
} return doOption(source, key, true)
}
fun encrypt(source: ByteArray, keyHex: String): ByteArray {
return encrypt(source, keyHex.hexToBytes()) @Suppress("unused")
} fun encrypt(source: ByteArray, keyHex: String): ByteArray {
return encrypt(source, keyHex.hexToBytes())
fun decrypt(source: ByteArray, key: ByteArray): ByteArray { }
return doOption(source, key, false)
} fun decrypt(source: ByteArray, key: ByteArray): ByteArray {
return doOption(source, key, false)
fun decrypt(source: ByteArray, keyHex: String): ByteArray { }
return decrypt(source, keyHex.hexToBytes())
} fun decrypt(source: ByteArray, keyHex: String): ByteArray {
return decrypt(source, keyHex.hexToBytes())
private fun pack(bytes: ByteArray, offset: Int, len: Int): Long { }
var result: Long = 0
val max_offset = if (len > 8) offset + 8 else offset + len @Suppress("SameParameterValue")
for (index in offset until max_offset) { private fun pack(bytes: ByteArray, offset: Int, len: Int): Long {
result = result shl 8 or (bytes[index].toLong() and 0xffL) var result: Long = 0
} val maxOffset = if (len > 8) offset + 8 else offset + len
return result shr 32 or (result and UINT32_MASK) for (index in offset until maxOffset) {
} result = result shl 8 or (bytes[index].toLong() and 0xffL)
}
return result shr 32 or (result and UINT32_MASK)
} }
} }

View File

@ -5,4 +5,4 @@ package net.mamoe.mirai.utils
* *
* @author Him188moe * @author Him188moe
*/ */
internal annotation class TestedSuccessfully internal annotation class Tested

View File

@ -1,3 +1,5 @@
@file:Suppress("EXPERIMENTAL_API_USAGE", "EXPERIMENTAL_UNSIGNED_LITERALS")
package net.mamoe.mirai.utils package net.mamoe.mirai.utils
import net.mamoe.mirai.network.Protocol import net.mamoe.mirai.network.Protocol
@ -26,14 +28,14 @@ fun ByteArray.toHexString(separator: String = " "): String = this.joinToString(s
return@joinToString ret return@joinToString ret
} }
@ExperimentalUnsignedTypes
fun ByteArray.toUHexString(separator: String = " "): String = this.toUByteArray().toUHexString(separator) fun ByteArray.toUHexString(separator: String = " "): String = this.toUByteArray().toUHexString(separator)
@ExperimentalUnsignedTypes
@JvmSynthetic @JvmSynthetic
fun ByteArray.toUHexString(): String = this.toUByteArray().toUHexString() fun ByteArray.toUHexString(): String = this.toUByteArray().toUHexString()
@ExperimentalUnsignedTypes
@JvmSynthetic @JvmSynthetic
fun UByteArray.toUHexString(separator: String = " "): String { fun UByteArray.toUHexString(separator: String = " "): String {
return this.joinToString(separator) { return this.joinToString(separator) {
@ -45,36 +47,36 @@ fun UByteArray.toUHexString(separator: String = " "): String {
} }
} }
@ExperimentalUnsignedTypes
@JvmSynthetic @JvmSynthetic
fun UByteArray.toUHexString(): String = this.toUHexString(" ") fun UByteArray.toUHexString(): String = this.toUHexString(" ")
@ExperimentalUnsignedTypes
fun Byte.toUHexString(): String = this.toUByte().toString(16) fun Byte.toUHexString(): String = this.toUByte().toString(16)
@ExperimentalUnsignedTypes
fun String.hexToBytes(): ByteArray = Protocol.hexToBytes(this) fun String.hexToBytes(): ByteArray = Protocol.hexToBytes(this)
@ExperimentalUnsignedTypes
fun String.hexToUBytes(): UByteArray = Protocol.hexToUBytes(this) fun String.hexToUBytes(): UByteArray = Protocol.hexToUBytes(this)
@ExperimentalUnsignedTypes
fun String.hexToInt(): Int = hexToBytes().toUInt().toInt() fun String.hexToInt(): Int = hexToBytes().toUInt().toInt()
@ExperimentalUnsignedTypes
fun ByteArray.toUInt(): UInt = fun ByteArray.toUInt(): UInt =
this[0].toUInt().and(255u).shl(24) + this[1].toUInt().and(255u).shl(16) + this[2].toUInt().and(255u).shl(8) + this[3].toUInt().and(255u).shl(0) this[0].toUInt().and(255u).shl(24) + this[1].toUInt().and(255u).shl(16) + this[2].toUInt().and(255u).shl(8) + this[3].toUInt().and(255u).shl(0)
open class ByteArrayDataOutputStream : DataOutputStream(ByteArrayOutputStream()) { open class ByteArrayDataOutputStream : DataOutputStream(ByteArrayOutputStream()) {
open fun toByteArray(): ByteArray = (out as ByteArrayOutputStream).toByteArray() open fun toByteArray(): ByteArray = (out as ByteArrayOutputStream).toByteArray()
@ExperimentalUnsignedTypes
open fun toUByteArray(): UByteArray = (out as ByteArrayOutputStream).toByteArray().toUByteArray() open fun toUByteArray(): UByteArray = (out as ByteArrayOutputStream).toByteArray().toUByteArray()
} }
@JvmSynthetic @JvmSynthetic
fun lazyEncode(t: (ByteArrayDataOutputStream) -> Unit): ByteArray = ByteArrayDataOutputStream().also(t).toByteArray() fun lazyEncode(t: (ByteArrayDataOutputStream) -> Unit): ByteArray = ByteArrayDataOutputStream().also(t).toByteArray()
@ExperimentalUnsignedTypes
fun getRandomByteArray(length: Int): ByteArray { fun getRandomByteArray(length: Int): ByteArray {
val bytes = LinkedList<Byte>() val bytes = LinkedList<Byte>()
repeat(length) { bytes.add((Math.random() * 255).toByte()) } repeat(length) { bytes.add((Math.random() * 255).toByte()) }

View File

@ -1,4 +1,5 @@
@file:JvmName("Varint") @file:JvmName("Varint")
@file:Suppress("EXPERIMENTAL_API_USAGE")
package net.mamoe.mirai.utils package net.mamoe.mirai.utils
@ -21,7 +22,7 @@ fun encodeZigZag32(signedInt: Int): Long {
return (signedInt shl 1 xor (signedInt shr 31)).toLong() return (signedInt shl 1 xor (signedInt shr 31)).toLong()
} }
@ExperimentalUnsignedTypes
@JvmSynthetic @JvmSynthetic
fun decodeZigZag32(uint: UInt): Int { fun decodeZigZag32(uint: UInt): Int {
return decodeZigZag32(uint.toLong()) return decodeZigZag32(uint.toLong())
@ -39,25 +40,25 @@ fun decodeZigZag64(signedLong: Long): Long {
return signedLong.ushr(1) xor -(signedLong and 1) return signedLong.ushr(1) xor -(signedLong and 1)
} }
@ExperimentalUnsignedTypes
@Throws(IOException::class) @Throws(IOException::class)
fun DataInputStream.readVarInt(): Int { fun DataInputStream.readVarInt(): Int {
return decodeZigZag32(this.readUnsignedVarInt()) return decodeZigZag32(this.readUnsignedVarInt())
} }
@ExperimentalUnsignedTypes
@Throws(IOException::class) @Throws(IOException::class)
fun DataInputStream.readUnsignedVarInt(): UInt { fun DataInputStream.readUnsignedVarInt(): UInt {
return read(this, 5).toUInt() return read(this, 5).toUInt()
} }
@ExperimentalUnsignedTypes
@Throws(IOException::class) @Throws(IOException::class)
fun DataInputStream.readVarLong(): Long { fun DataInputStream.readVarLong(): Long {
return decodeZigZag64(readUnsignedVarLong().toLong()) return decodeZigZag64(readUnsignedVarLong().toLong())
} }
@ExperimentalUnsignedTypes
@Throws(IOException::class) @Throws(IOException::class)
fun DataInputStream.readUnsignedVarLong(): ULong { fun DataInputStream.readUnsignedVarLong(): ULong {
return read(this, 10).toULong() return read(this, 10).toULong()
@ -68,7 +69,7 @@ fun DataOutputStream.writeVarInt(signedInt: Int) {
this.writeUVarInt(encodeZigZag32(signedInt)) this.writeUVarInt(encodeZigZag32(signedInt))
} }
@ExperimentalUnsignedTypes
@Throws(IOException::class) @Throws(IOException::class)
fun DataOutputStream.writeUVarInt(uint: UInt) { fun DataOutputStream.writeUVarInt(uint: UInt) {
return writeUVarInt(uint.toLong()) return writeUVarInt(uint.toLong())

View File

@ -1,47 +0,0 @@
import net.mamoe.mirai.network.packet.login.ClientPasswordSubmissionPacket
import net.mamoe.mirai.utils.toUHexString
@ExperimentalUnsignedTypes
fun main(){
/*
val data = "00 37 13 08 25 31 01 EB 10 08 30 69 50 1C 84 A9 C2 16 D7 52 B9 1C 79 CA 5A CF FD BC EB 10 08 30 69 50 1C 84 A9 C2 16 D7 52 B9 1C 79 CA 5A CF FD BC AE D8 A6 BB DC 21 6E 79 26 E1 A2 23 11 AA B0 9A AE D8 A6 BB DC 21 6E 79 26 E1 A2 23 11 AA B0 9A 76 E4 B8 DD 03 00 00 00 01 2E 01 00 00 68 52 00 00 00 00 A4 F1 91 88 C9 82 14 99 0C 9E 56 55 91 23 C8 3D C3 47 F0 25 A1 8E 74 EF 1E 0B 32 5B 20 8A FA 3B 0B 52 8F 86 E6 04 F1 D6 F8 63 75 60 8C 0C 7D 06 D1 E0 22 F8 49 EF AF 61 EE 7E 69 72 EB 10 08 30 69 50 1C 84 A9 C2 16 D7 52 B9 1C 79 CA 5A CF FD BC AE D8 A6 BB DC 21 6E 79 26 E1 A2 23 11 AA B0 9A 49 39 72 ED 61 12 B6 88 4D A2 56 23 E9 92 11 92 27 4A 70 00 C9 01 7B 03";
val s = DataInputStream(data.hexToBytes().inputStream())
val packet = ServerTouchResponsePacket(ServerTouchResponsePacket.Type.TYPE_08_25_31_01, s)
packet.decode()
System.out.println(packet.token.toUByteArray().toUHexString(" "))
System.out.println(packet.loginTime.toUHexString(" "))
System.out.println(packet.loginIP)
*/
// val packet = ClientPasswordSubmissionPacket(1994701021,"xiaoqqq",)
/*
val data = "00 01 09 00 70 00 01 5C 71 80 A6 BA 20 62 2E C1 BE BF F2 47 37 40 A1 00 38 91 25 85 58 18 D3 67 77 2C 4D 02 D8 66 A6 F7 3E 57 D8 CE 01 47 7F D0 8F 13 C8 3A E5 19 A2 60 BC 4C 9A 35 4E 92 9F 21 48 6C 67 68 36 6B 94 C1 6F 11 8D 55 6B 04 9A 22 C3 00 20 29 7E D4 A7 16 02 07 14 41 90 3A 65 06 AC CB 28 AB 90 DB 46 33 C9 C0 1D 06 44 7A 92 17 C3 A5 F3 00 00 01 03 00 14 00 01 00 10 60 C9 5D A7 45 70 04 7F 21 7D 84 50 5C 66 A5 C6 01 07 01 D3 00 01 00 16 00 00 00 01 00 00 00 64 00 00 0D B6 00 09 3A 80 00 00 00 3C 00 02 2E 29 4E 47 5F 68 78 2C 47 25 5F 59 50 65 60 5D 00 88 00 04 5D 59 45 17 B7 5F F8 D4 00 00 00 00 00 78 38 E0 3B 23 4A C5 0E 93 CB C1 66 96 37 8B 46 B2 86 23 3F 2D 09 45 E0 16 1C E9 9C 11 7A FA 2D A8 50 47 42 74 01 06 84 76 0E 5F C6 04 29 1A 4A 65 AA 93 49 DF BD 00 ED 80 B8 26 CA 80 E8 20 6D 15 43 DD D8 E6 48 C2 8A 5A F8 70 6B 51 3A E2 2D 21 95 4B 6A 75 A8 90 CA B1 C0 E5 73 99 D7 59 D8 DD 3D C9 5C E4 49 61 22 11 60 85 48 C4 7D E0 84 62 AD B3 13 84 61 C1 9E 19 35 41 44 44 37 3F 21 33 64 4B 37 5D 77 6D 61 3F 00 78 00 01 5D 59 45 17 00 70 A4 D9 44 9E 95 51 B4 B0 91 CC 1E DB 34 F9 F7 13 8B 30 08 C0 AE 33 22 9C FF 87 CF 9B A2 B0 E5 E1 D0 E0 AD DD 8F E9 F6 1E 01 1F AA 74 46 66 B4 81 54 B9 29 E5 FC 0B 7F C9 13 AE 32 BA D6 55 2E B0 A1 30 24 B6 F2 E7 62 F9 2E 00 E4 51 61 50 7C D1 36 E8 61 96 36 FF B7 32 74 3C 2A F7 74 63 DA 7D 57 84 18 ED 84 E9 D8 87 6D 66 1D D5 84 D4 23 99 00 83 01 63 2A 69 2E 25 79 28 3B 29 33 29 40 28 54 7E 21 00 70 00 01 5D 59 45 17 00 68 6F 1F FB 31 7B D7 B7 D8 91 32 D7 20 8B 8A F6 02 C8 22 E5 24 8C 25 F2 6A C5 B0 ED 35 01 BF AF 42 72 33 4E FB 3F D3 02 BA F4 46 2B 68 20 0B E3 39 81 B1 D3 8A E0 1B 0F 69 D1 70 AE 49 A5 24 4F BB 58 4F F8 31 A0 37 4C CD F1 12 35 80 99 7D 25 CA F9 E9 45 B6 B0 57 56 66 61 C5 7B 90 57 BF E2 2C 94 91 80 1A B0 D7 21 A8 44 2C 33 4A 29 77 5F 71 40 41 38 3D 7A 41 65 33 01 08 00 29 00 01 00 25 00 1D 02 5B 14 28 E0 B9 91 E2 80 A2 CC 80 CF 89 E2 80 A2 CC 81 E0 B9 91 29 02 13 80 02 00 05 00 04 00 00 00 01 01 15 00 10 F9 86 85 81 30 F6 1B E0 E7 97 98 F6 46 C3 4F B2"
val s = DataInputStream(data.hexToBytes().inputStream())
val packet = ServerLoginResponseSuccessPacket(s,(data.length+1)/3)
packet.decode()
System.out.println("0828key: \n" + packet._0828_rec_decr_key.toUByteArray().toUHexString(" "))
System.out.println("token88: \n" + packet.token88.toUByteArray().toUHexString(" "))
System.out.println("token38: \n" + packet.token38.toUByteArray().toUHexString(" "))
System.out.println("enckey: \n" + packet.encryptionKey.toUByteArray().toUHexString(" "))
System.out.println("nick: " + packet.nick)
System.out.println("age: " + packet.age)
System.out.println("gender: " + packet.gender)
*/
/*
val data = "FB 01 04 03 33 00 01 00 BA 02 03 2C 13 00 05 01 00 00 01 23 00 38 F5 C3 CF F4 B4 27 C5 8F 9B D3 ED 18 73 7D E9 CB 43 1F 57 43 BE D3 1B 9A F5 26 2B F4 D9 43 14 9A ED 3B C3 6C E5 7F 4E B0 0C BA 55 57 18 06 78 E1 13 A7 B2 A8 7F 47 E1 1C 02 BC 89 50 4E 47 0D 0A 1A 0A 00 00 00 0D 49 48 44 52 00 00 00 82 00 00 00 35 08 03 00 00 00 BA 12 C3 02 00 00 00 04 67 41 4D 41 00 00 B1 8F 0B FC 61 05 00 00 00 01 73 52 47 42 00 AE CE 1C E9 00 00 00 6C 50 4C 54 45 F6 F8 F4 E3 EE FD E5 FD FF EE FD F0 F6 F9 E7 F7 F9 EC F4 FE FF F7 F7 F9 F5 F4 FF EC F7 FF E6 F4 E0 F5 FC F8 49 5B 8F CB DB FA BB C9 F5 2B 40 7C D6 E6 FF FD FB FF ED F1 F0 2A 43 B3 D6 F6 FF FC F1 FC 1C 38 91 A7 BD F6 63 74 BD 70 8B CC 34 4F A5 DE F3 F1 75 88 E7 A4 B7 D3 73 82 A1 8C A3 DC F3 FB D8 4D 68 B9 94 A8 FB 8D 9C B6 CB 42 B0 8E 00 00 0A 6F 49 44 41 54 58 C3 B4 57 89 76 EB 2A 12 14 20 B1 09 10 42 68 DF 2C FB FF FF 71 0A 79 49 E2 E4 CE CC 79 37 8F 13 59 B6 72 EC 2E AA BB AB 9A 2C FB 61 89 8F 95 E5 79 A9 70 CB B2 22 C7 2A 65 DB 5E 72 21 F1 A9 90 B2 28 C4 F9 AF 5F 5F 05 30 9C 28 D2 4B C6 58 F9 8C 92 17 39 13 6D 9B FF EB 10 8A 3B 0F 2F 10 52 64 45 51 64 42 A6 37 79 21 DA FC F2 6F 40 08 9F AE B7 9C A4 C8 27 31 F2 C4 50 A4 D4 9C F9 01 BC A2 90 0F 08 E1 2F AE 1F E3 7E 7D 24 52 F4 67 2C 91 02 E3 CA 13 2F 78 97 00 86 DF 4E C4 23 56 F1 F8 7B 10 90 42 3D D2 93 EE 27 04 F1 80 F0 4B 99 10 4F 62 5E D9 2D EE 57 8A F1 A0 E1 64 20 2B 55 F9 C8 C3 67 08 F8 81 7F F2 F7 BE FD 67 1D 9E 9B 4F EB 89 25 21 28 19 63 09 5D A9 94 2A 59 AA 87 B3 32 4E 84 FF 3C 13 8F AF 06 F1 29 FD E2 C1 02 54 E0 8C 5E 5C 2E A5 72 43 65 F4 E5 72 61 5C 4A 45 81 41 97 79 0A 9E FF 62 22 C2 EB 7E 42 48 45 80 2B 0F 58 B9 66 D6 1C 63 75 D3 97 BC F4 08 0F 08 5C 6B 8D CC 14 1F 10 C4 5F B4 C3 37 66 EE E5 78 CF 42 12 05 CD F5 4D 29 EB 36 AD 19 82 CF 76 35 C6 86 B2 94 A7 36 FC 62 39 BE A8 B8 D7 02 78 08 8F 66 E4 44 45 DF BB AB A3 34 92 14 DF 54 C6 32 1D 00 21 7F 41 08 7F C9 7F F8 28 88 4F B5 90 89 3A 21 90 9E DF E8 DE 34 4D 8C D1 EF C6 AC 6B 7F 74 8E B1 FA 84 90 7F B0 F0 CF 5A E2 27 4C AF 8E 28 EF 24 48 B2 AF B1 9A 96 3E F6 43 75 38 6F 29 5D 1A C7 59 78 87 F0 1B B2 F0 95 05 3C 93 B2 26 B6 9F BA 18 AB AE 59 EC 88 17 17 A9 8F 4B B3 CE 60 A1 CD F2 CB 03 42 10 7F D9 06 1F 76 80 8E 4F 6D 9F 56 99 05 25 A5 DD AA EB 62 7A 6F 87 E6 B8 0E 5D 33 C6 99 C6 C4 02 24 EB 74 8C 87 98 64 F8 5E A9 9E 1E F7 72 FB FF B3 21 8A A4 00 01 00 28 F9 59 C5 E6 34 43 53 95 C8 17 2E 62 78 BF E8 27 BF 20 BA 11 5A 74 D1 7C D0 95 6C F6 A3 41 D2 84 BD 7D F6 64 BC 27 40 50 01 15 00 10 44 98 EB B8 30 3B DE 7D 2B CC 4C 41 B3 1C 92 86"
val s = DataInputStream(data.hexToBytes().inputStream())
val packet = ServerLoginResponseVerificationCodePacket(s,(data.length+1)/3)
packet.decode()
println(packet.token00BA.toUByteArray().toUHexString(" "))
println(packet.verifyCode.toUByteArray().toUHexString(" "))
println(packet.verifyCodeLength)
File(System.getProperty("user.dir") + "/5.png").createNewFile()
packet.verifyCode.inputStream().transferTo(FileOutputStream(System.getProperty("user.dir") + "/5.png"))
*/
val packet = ClientPasswordSubmissionPacket(1994701021, "xiaoqqq", 131513, "123.123.123.123", "tgtgtKey".toByteArray(), "".toByteArray())
packet.encodeToByteArray().toUByteArray().toUHexString(" ")
}