Him188 6 лет назад
Родитель
Сommit
48850d7389

+ 10 - 0
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/event/PacketReceivedEvent.kt

@@ -0,0 +1,10 @@
+package net.mamoe.mirai.qqandroid.event
+
+import net.mamoe.mirai.data.Packet
+import net.mamoe.mirai.event.Cancellable
+import net.mamoe.mirai.event.Event
+
+/**
+ * 接收到数据包
+ */
+class PacketReceivedEvent(val packet: Packet) : Event(), Cancellable

+ 54 - 38
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt

@@ -1,40 +1,41 @@
 package net.mamoe.mirai.qqandroid.network
 
 import kotlinx.coroutines.*
-import kotlinx.io.core.*
-import kotlinx.io.pool.useInstance
+import kotlinx.io.core.use
+import net.mamoe.mirai.data.Packet
+import net.mamoe.mirai.event.broadcast
 import net.mamoe.mirai.network.BotNetworkHandler
 import net.mamoe.mirai.qqandroid.QQAndroidBot
+import net.mamoe.mirai.qqandroid.event.PacketReceivedEvent
+import net.mamoe.mirai.qqandroid.network.protocol.packet.KnownPacketFactories
+import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket
 import net.mamoe.mirai.qqandroid.network.protocol.packet.login.LoginPacket
-import net.mamoe.mirai.utils.io.*
+import net.mamoe.mirai.qqandroid.network.protocol.packet.login.PacketId
+import net.mamoe.mirai.utils.LockFreeLinkedList
+import net.mamoe.mirai.utils.MiraiInternalAPI
+import net.mamoe.mirai.utils.io.ClosedChannelException
+import net.mamoe.mirai.utils.io.PlatformDatagramChannel
+import net.mamoe.mirai.utils.io.ReadPacketInternalException
+import net.mamoe.mirai.utils.io.debugPrint
 import kotlin.coroutines.CoroutineContext
 
+@UseExperimental(MiraiInternalAPI::class)
 internal class QQAndroidBotNetworkHandler(override val bot: QQAndroidBot) : BotNetworkHandler() {
     override val supervisor: CompletableJob = SupervisorJob(bot.coroutineContext[Job])
 
     private val channel: PlatformDatagramChannel = PlatformDatagramChannel("wtlogin.qq.com", 8000)
 
     override suspend fun login() {
-        launch { processReceive() }
+        launch(CoroutineName("Incoming Packet Receiver")) { processReceive() }
 
-        val buffer = IoBuffer.Pool.borrow()
-        buffer.writePacket(LoginPacket(bot.client).delegate)
-        val shouldBeSent = buffer.readRemaining
-        check(channel.send(buffer) == shouldBeSent) {
-            "Buffer is not entirely sent. " +
-                    "Required sent length=$shouldBeSent, but after channel.send, " +
-                    "buffer remains ${buffer.readBytes().toUHexString()}"
-        }
-        buffer.release(IoBuffer.Pool)
+        LoginPacket(bot.client).sendAndExpect<LoginPacket.LoginPacketResponse>()
         println("Login sent")
     }
 
-    private suspend fun processReceive() {
+    private suspend inline fun processReceive() {
         while (channel.isOpen) {
-            val buffer = IoBuffer.Pool.borrow()
-
-            try {
-                channel.read(buffer)// JVM: withContext(IO)
+            val rawInput = try {
+                channel.read()
             } catch (e: ClosedChannelException) {
                 dispose()
                 return
@@ -46,35 +47,50 @@ internal class QQAndroidBotNetworkHandler(override val bot: QQAndroidBot) : BotN
             } catch (e: Throwable) {
                 bot.logger.error("Caught unexpected exceptions", e)
                 continue
-            } finally {
-                if (!buffer.canRead() || buffer.readRemaining == 0) {//size==0
-                    //bot.logger.debug("processReceive: Buffer cannot be read")
-                    buffer.release(IoBuffer.Pool)
-                    continue
-                }// sometimes exceptions are thrown without this `if` clause
             }
 
-            //buffer.resetForRead()
-            launch(CoroutineName("handleServerPacket")) {
-                // `.use`: Ensure that the packet is consumed **totally**
-                // so that all the buffers are released
-                ByteArrayPool.useInstance {
-                    val length = buffer.readRemaining - 1
-                    buffer.readFully(it, 0, length)
-                    buffer.resetForWrite()
-                    buffer.writeFully(it, 0, length)
+            launch(CoroutineName("Incoming Packet handler")) {
+                try {
+                    rawInput.debugPrint("Received")
+                } catch (e: Exception) {
+                    bot.logger.error(e)
                 }
-                ByteReadPacket(buffer, IoBuffer.Pool).use { input ->
-                    try {
-                        input.debugPrint("Received")
-                    } catch (e: Exception) {
-                        bot.logger.error(e)
+            }
+
+            rawInput.use {
+                KnownPacketFactories.parseIncomingPacket(bot, rawInput) { packet: Packet, packetId: PacketId, sequenceId: Int ->
+                    if (PacketReceivedEvent(packet).broadcast().cancelled) {
+                        return
+                    }
+                    packetListeners.forEach { listener ->
+                        if (listener.filter(packetId, sequenceId) && packetListeners.remove(listener)) {
+                            listener.complete(packet)
+                        }
                     }
                 }
             }
         }
     }
 
+    suspend fun <E : Packet> OutgoingPacket.sendAndExpect(): E {
+        val handler = PacketListener(packetId = packetId, sequenceId = sequenceId)
+        packetListeners.addLast(handler)
+        check(channel.send(delegate)) { packetListeners.remove(handler); "Cannot send packet" }
+        @Suppress("UNCHECKED_CAST")
+        return handler.await() as E
+    }
+
+    @PublishedApi
+    internal val packetListeners = LockFreeLinkedList<PacketListener>()
+
+    @PublishedApi
+    internal inner class PacketListener(
+        val packetId: PacketId,
+        val sequenceId: Int
+    ) : CompletableDeferred<Packet> by CompletableDeferred(supervisor) {
+        fun filter(packetId: PacketId, sequenceId: Int) = this.packetId == packetId && this.sequenceId == sequenceId
+    }
+
     override suspend fun awaitDisconnection() {
         while (true) {
             delay(100)

+ 27 - 24
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/OutgoingPacketAndroid.kt

@@ -7,9 +7,9 @@ import kotlinx.io.core.buildPacket
 import kotlinx.io.core.writeFully
 import net.mamoe.mirai.qqandroid.network.QQAndroidClient
 import net.mamoe.mirai.qqandroid.network.protocol.packet.login.PacketId
-import net.mamoe.mirai.qqandroid.utils.ECDH
 import net.mamoe.mirai.utils.MiraiInternalAPI
 import net.mamoe.mirai.utils.cryptor.DecrypterByteArray
+import net.mamoe.mirai.utils.cryptor.ECDH
 import net.mamoe.mirai.utils.cryptor.encryptAndWrite
 import net.mamoe.mirai.utils.cryptor.encryptBy
 import net.mamoe.mirai.utils.io.*
@@ -21,7 +21,12 @@ import net.mamoe.mirai.utils.io.*
 internal class OutgoingPacket constructor(
     name: String?,
     val packetId: PacketId,
-    val sequenceId: Short,
+    val sequenceId: Int,
+    // TODO: 2020/1/6 这个 sequenceId 设计有问题.
+    //  02 03 包里面的那个应该并不是 sequenceId.
+    //  它应该是固定的 0x001.
+    //  应该在这里填入 SSO 的 sequenceId.
+    //  同时考虑修改名称. 这可能不应该叫做 SSO. 它在全程都有
     val delegate: ByteReadPacket
 ) {
     val name: String by lazy {
@@ -52,7 +57,7 @@ internal inline fun PacketFactory<*, *>.buildLoginOutgoingPacket(
     extraData: ByteArray = EMPTY_BYTE_ARRAY,
     name: String? = null,
     id: PacketId = this.id,
-    sequenceId: Short = PacketFactory.atomicNextSequenceId(),
+    sequenceId: Int = PacketFactory.atomicNextSequenceId(),
     body: BytePacketBuilder.() -> Unit
 ): OutgoingPacket = OutgoingPacket(name, id, sequenceId, buildPacket {
     writeIntLVPacket(lengthOffset = { it + 4 }) {
@@ -69,11 +74,6 @@ internal inline fun PacketFactory<*, *>.buildLoginOutgoingPacket(
     }
 })
 
-internal class CommandId(val stringValue: String, val id: Int) {
-    override fun toString(): String = stringValue
-}
-
-
 private val BRP_STUB = ByteReadPacket(EMPTY_BYTE_ARRAY)
 
 /**
@@ -85,7 +85,7 @@ private val BRP_STUB = ByteReadPacket(EMPTY_BYTE_ARRAY)
 internal inline fun BytePacketBuilder.writeLoginSsoPacket(
     client: QQAndroidClient,
     subAppId: Long,
-    commandId: CommandId,
+    packetId: PacketId,
     extraData: ByteReadPacket = BRP_STUB,
     body: BytePacketBuilder.(ssoSequenceId: Int) -> Unit
 ) {
@@ -102,21 +102,25 @@ internal inline fun BytePacketBuilder.writeLoginSsoPacket(
             writeInt((extraData.remaining + 4).toInt())
             writePacket(extraData)
         }
-        writeInt(commandId.stringValue.length + 4)
-        writeStringUtf8(commandId.stringValue)
+        packetId.commandName.let {
+            writeInt(it.length + 4)
+            writeStringUtf8(it)
+        }
 
         writeInt(4 + 4)
         writeInt(45112203) //  02 B0 5B 8B
 
-        val imei = client.device.imei
-        writeInt(imei.length + 4)
-        writeStringUtf8(imei)
+        client.device.imei.let {
+            writeInt(it.length + 4)
+            writeStringUtf8(it)
+        }
 
         writeInt(4)
 
-        val ksid = client.device.ksid
-        writeShort((ksid.length + 2).toShort())
-        writeStringUtf8(ksid)
+        client.device.ksid.let {
+            writeInt(it.length + 4)
+            writeStringUtf8(it)
+        }
 
         writeInt(4)
     }
@@ -226,10 +230,10 @@ internal interface EncryptMethodECDH : EncryptMethod {
     override fun BytePacketBuilder.encryptAndWrite(body: ByteReadPacket) = ecdh.run {
         writeByte(1) // const
         writeByte(1) // const
-        writeFully(privateKey)
+        writeFully(keyPair.privateKey.getEncoded())
         writeShort(258) // const
-        writeShortLVByteArray(publicKey)
-        body.encryptBy(shareKey) { encrypted -> writeFully(encrypted) }
+        writeShortLVByteArray(keyPair.publicKey.getEncoded().drop(23).toByteArray().also { check(it.size == 49) { "Bad publicKey generated. Expected size=49, got${it.size}" } })
+        body.encryptBy(keyPair.shareKey) { encrypted -> writeFully(encrypted) }
     }
 }
 
@@ -256,8 +260,7 @@ internal interface EncryptMethodECDH : EncryptMethod {
 internal inline fun BytePacketBuilder.writeRequestPacket(
     client: QQAndroidClient,
     encryptMethod: EncryptMethod,
-    commandId: CommandId,
-    sequenceId: Short = PacketFactory.atomicNextSequenceId(),
+    packetId: PacketId,
     bodyBlock: BytePacketBuilder.() -> Unit
 ) {
     val body = encryptMethod.run {
@@ -268,8 +271,8 @@ internal inline fun BytePacketBuilder.writeRequestPacket(
         writeByte(0x02) // head
         writeShort((27 + 2 + body.remaining).toShort()) // orthodox algorithm
         writeShort(client.protocolVersion)
-        writeShort(sequenceId)
-        writeShort(commandId.id.toShort())
+        writeShort(1)
+        writeShort(packetId.commandId.toShort())
         writeQQ(client.account.id)
         writeByte(3) // originally const
         writeByte(encryptMethod.id.toByte())

+ 102 - 6
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/PacketFactory.kt

@@ -3,13 +3,21 @@ package net.mamoe.mirai.qqandroid.network.protocol.packet
 import kotlinx.atomicfu.AtomicInt
 import kotlinx.atomicfu.atomic
 import kotlinx.io.core.ByteReadPacket
+import kotlinx.io.core.Closeable
+import kotlinx.io.core.discardExact
+import kotlinx.io.core.readBytes
 import net.mamoe.mirai.data.Packet
-import net.mamoe.mirai.network.BotNetworkHandler
+import net.mamoe.mirai.qqandroid.QQAndroidBot
 import net.mamoe.mirai.qqandroid.network.protocol.packet.login.NullPacketId
+import net.mamoe.mirai.qqandroid.network.protocol.packet.login.NullPacketId.commandName
 import net.mamoe.mirai.qqandroid.network.protocol.packet.login.PacketId
-import net.mamoe.mirai.utils.LockFreeLinkedList
 import net.mamoe.mirai.utils.cryptor.Decrypter
 import net.mamoe.mirai.utils.cryptor.DecrypterType
+import net.mamoe.mirai.utils.cryptor.adjustToPublicKey
+import net.mamoe.mirai.utils.cryptor.decryptBy
+import net.mamoe.mirai.utils.io.*
+import kotlin.contracts.ExperimentalContracts
+import kotlin.contracts.contract
 
 /**
  * 一种数据包的处理工厂. 它可以解密解码服务器发来的这个包, 也可以编码加密要发送给服务器的这个包
@@ -32,21 +40,109 @@ internal abstract class PacketFactory<out TPacket : Packet, TDecrypter : Decrypt
     /**
      * **解码**服务器的回复数据包
      */
-    abstract suspend fun ByteReadPacket.decode(id: PacketId, sequenceId: Short, handler: BotNetworkHandler): TPacket
+    abstract suspend fun ByteReadPacket.decode(bot: QQAndroidBot): TPacket
 
     companion object {
         private val sequenceId: AtomicInt = atomic(1)
 
-        fun atomicNextSequenceId(): Short {
+        fun atomicNextSequenceId(): Int {
+            TODO("使用 SSO ")
             val id = sequenceId.getAndAdd(1)
             if (id > Short.MAX_VALUE.toInt() * 2) {
                 sequenceId.value = 0
                 return atomicNextSequenceId()
             }
-            return id.toShort()
+            // return id.toShort()
         }
     }
 }
 
-internal class KnownPacketFactories : LockFreeLinkedList<PacketFactory<*, *>>() {
+private val DECRYPTER_16_ZERO = ByteArray(16)
+
+internal typealias PacketConsumer = (packet: Packet, packetId: PacketId, ssoSequenceId: Int) -> Unit
+
+internal object KnownPacketFactories : List<PacketFactory<*, *>> by mutableListOf() {
+
+    fun findPacketFactory(commandName: String): PacketFactory<*, *> = this.first { it.id.commandName == commandName }
+
+    fun findPacketFactory(commandId: Int): PacketFactory<*, *> = this.first { it.id.commandName == commandName }
+
+    suspend inline fun parseIncomingPacket(bot: QQAndroidBot, rawInput: ByteReadPacket, consumer: PacketConsumer) =
+        rawInput.debugPrintIfFail("Incoming packet") {
+            require(rawInput.remaining < Int.MAX_VALUE) { "rawInput is too long" }
+            val expectedLength = readInt() - 4
+            check(rawInput.remaining.toInt() == expectedLength) { "Invalid packet length. Expected $expectedLength, got ${rawInput.remaining} Probably packets merged? " }
+            // login
+            when (val flag1 = readInt()) {
+                0x0A -> when (val flag2 = readByte().toInt()) {
+                    0x02 -> {
+                        val flag3 = readByte().toInt()
+                        check(flag3 == 0) { "Illegal flag3. Expected 0, got $flag3" }
+
+                        discardExact(readInt() - 4) // uinAccount
+
+                        parseLoginSsoPacket(bot, decryptBy(DECRYPTER_16_ZERO), consumer)
+                    }
+                    else -> error("Illegal flag2. Expected 0x02, got $flag2")
+                }
+                else -> error("Illegal flag1. Expected 0x0A or 0x0B, got $flag1")
+            }
+        }
+
+    @UseExperimental(ExperimentalUnsignedTypes::class)
+    private suspend inline fun parseLoginSsoPacket(bot: QQAndroidBot, rawInput: ByteReadPacket, consumer: PacketConsumer) =
+        rawInput.debugPrintIfFail("Login sso packet") {
+            val commandName: String
+            val ssoSequenceId: Int
+            readIoBuffer(readInt() - 4).withUse {
+                ssoSequenceId = readInt()
+                check(readInt() == 0)
+                val loginExtraData = readIoBuffer(readInt() - 4)
+
+                commandName = readString(readInt() - 4)
+                val unknown = readBytes(readInt() - 4)
+                if (unknown.toInt() != 0x02B05B8B) DebugLogger.debug("got new unknown: $unknown")
+
+                check(readInt() == 0)
+            }
+
+            val packetFactory = findPacketFactory(commandName)
+
+            val qq: Long
+            val subCommandId: Int
+            readIoBuffer(readInt() - 4).withUse {
+                check(readByte().toInt() == 2)
+                discardExact(2) // 27 + 2 + body.size
+                discardExact(2) // const, =8001
+                readShort() // commandId
+                readShort() // innerSequenceId
+                qq = readInt().toLong()
+
+                discardExact(1) // const = 0
+                val packet = when (val encryptionMethod = readByte().toInt()) {
+                    4 -> { // peer public key, ECDH
+                        packetFactory.run {
+                            bot.client.ecdh.calculateShareKeyByPeerPublicKey(readUShortLVByteArray().adjustToPublicKey()).read {
+                                decode(bot)
+                            }
+                        }
+                    }
+                    else -> error("Illegal encryption method. expected 4, got $encryptionMethod")
+                }
+
+                consumer(packet, packetFactory.id, ssoSequenceId)
+            }
+        }
+}
+
+@UseExperimental(ExperimentalContracts::class)
+internal inline fun <I : Closeable, R> I.withUse(block: I.() -> R): R {
+    contract {
+        callsInPlace(block, kotlin.contracts.InvocationKind.EXACTLY_ONCE)
+    }
+    return try {
+        block(this)
+    } finally {
+        close()
+    }
 }

+ 15 - 18
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/LoginPacket.kt

@@ -5,7 +5,7 @@ import kotlinx.io.core.ByteReadPacket
 import kotlinx.io.core.buildPacket
 import kotlinx.io.core.readBytes
 import net.mamoe.mirai.data.Packet
-import net.mamoe.mirai.network.BotNetworkHandler
+import net.mamoe.mirai.qqandroid.QQAndroidBot
 import net.mamoe.mirai.qqandroid.network.QQAndroidClient
 import net.mamoe.mirai.qqandroid.network.protocol.packet.*
 import net.mamoe.mirai.qqandroid.utils.GuidSource
@@ -21,7 +21,7 @@ class LoginPacketDecrypter(override val value: ByteArray) : DecrypterByteArray {
 
 internal object LoginPacket : PacketFactory<LoginPacket.LoginPacketResponse, LoginPacketDecrypter>(LoginPacketDecrypter) {
     init {
-        this._id = PacketId(CommandId("wtlogin.login", 0x0810), 9)
+        this._id = PacketId(commandId = 0x0810, commandName = "wtlogin.login", subCommandId = 9)
     }
 
     operator fun invoke(
@@ -30,8 +30,8 @@ internal object LoginPacket : PacketFactory<LoginPacket.LoginPacketResponse, Log
         val appId = 16L
         val subAppId = 537062845L
 
-        writeLoginSsoPacket(client, subAppId, _id.commandId) { ssoSequenceId ->
-            writeRequestPacket(client, EncryptMethodECDH135(client.ecdh), _id.commandId) {
+        writeLoginSsoPacket(client, subAppId, id) { ssoSequenceId ->
+            writeRequestPacket(client, EncryptMethodECDH135(client.ecdh), id) {
                 writeShort(9) // subCommand
                 writeShort(LoginType.PASSWORD.value.toShort())
 
@@ -163,30 +163,27 @@ internal object LoginPacket : PacketFactory<LoginPacket.LoginPacketResponse, Log
 
     class LoginPacketResponse : Packet
 
-    @ExperimentalUnsignedTypes
-    override suspend fun ByteReadPacket.decode(id: PacketId, sequenceId: Short, handler: BotNetworkHandler): LoginPacketResponse {
-
-        TODO()
+    override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): LoginPacketResponse {
+        TODO("not implemented")
     }
 }
 
 
 @Suppress("FunctionName")
-internal fun PacketId(commandId: CommandId, subCommandId: Int) = object : PacketId {
-    override val commandId: CommandId
-        get() = commandId
-    override val subCommandId: Int
-        get() = subCommandId
+internal fun PacketId(commandId: Int, commandName: String, subCommandId: Int) = object : PacketId {
+    override val commandId: Int get() = commandId
+    override val commandName: String get() = commandName
+    override val subCommandId: Int get() = subCommandId
 }
 
 internal interface PacketId {
-    val commandId: CommandId // ushort actually
+    val commandId: Int // ushort actually
+    val commandName: String
     val subCommandId: Int // ushort actually
 }
 
 internal object NullPacketId : PacketId {
-    override val commandId: CommandId
-        get() = error("uninitialized")
-    override val subCommandId: Int
-        get() = error("uninitialized")
+    override val commandId: Int get() = error("uninitialized")
+    override val commandName: String get() = error("uninitialized")
+    override val subCommandId: Int get() = error("uninitialized")
 }

+ 0 - 22
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/utils/ECDH.kt

@@ -1,22 +0,0 @@
-package net.mamoe.mirai.qqandroid.utils
-
-/**
- * From QQAndroid 8.2.0
- * `oicq.wlogin_sdk.tools.EcdhCrypt`
- *
- * Constant to avoid calculations
- */
-interface ECDH {
-    /*
-    object Default : ECDH {
-        override val publicKey: ByteArray = "020b03cf3d99541f29ffec281bebbd4ea211292ac1f53d7128".chunkedHexToBytes()
-        override val shareKey: ByteArray = "4da0f614fc9f29c2054c77048a6566d7".chunkedHexToBytes()
-        override val privateKey: ByteArray = ByteArray(16)
-    }*/
-
-    val publicKey: ByteArray
-
-    val shareKey: ByteArray
-
-    val privateKey: ByteArray
-}

+ 2 - 0
mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/handler/DataPacketSocketAdapter.kt

@@ -4,6 +4,7 @@ package net.mamoe.mirai.timpc.network.handler
 
 import kotlinx.io.core.Closeable
 import net.mamoe.mirai.Bot
+import net.mamoe.mirai.utils.MiraiInternalAPI
 import net.mamoe.mirai.utils.io.PlatformDatagramChannel
 
 /**
@@ -25,6 +26,7 @@ interface DataPacketSocketAdapter : Closeable {
     /**
      * UDP 通道
      */
+    @MiraiInternalAPI
     val channel: PlatformDatagramChannel
 
     /**

+ 2 - 2
mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/login/PasswordSubmission.kt

@@ -26,7 +26,7 @@ internal inline class PrivateKey(override val value: ByteArray) : DecrypterByteA
 }
 
 internal inline class SubmitPasswordResponseDecrypter(private val privateKey: PrivateKey) : Decrypter {
-    override fun decrypt(input: ByteReadPacket): ByteReadPacket {
+    override fun decrypt(input: ByteReadPacket, offset: Int, length: Int): ByteReadPacket {
         var decrypted = ShareKey.decrypt(input)
         (decrypted.remaining).let {
             if (it.toInt() % 8 == 0 && it >= 16) {
@@ -263,7 +263,7 @@ internal object SubmitPasswordPacket : PacketFactory<SubmitPasswordPacket.LoginR
 }
 
 internal inline class SessionResponseDecryptionKey(private val delegate: IoBuffer) : Decrypter {
-    override fun decrypt(input: ByteReadPacket): ByteReadPacket = input.decryptBy(delegate)
+    override fun decrypt(input: ByteReadPacket, offset: Int, length: Int): ByteReadPacket = input.decryptBy(delegate)
 
     override fun toString(): String = "SessionResponseDecryptionKey"
 

+ 1 - 1
mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/cryptor/ECDHAndroid.kt

@@ -21,7 +21,7 @@ actual class ECDHKeyPair(
 @Suppress("FunctionName")
 actual fun ECDH() = ECDH(ECDH.generateKeyPair())
 
-actual class ECDH actual constructor(val keyPair: ECDHKeyPair) {
+actual class ECDH actual constructor(actual val keyPair: ECDHKeyPair) {
     actual companion object {
         actual fun generateKeyPair(): ECDHKeyPair {
             return ECDHKeyPair(KeyPairGenerator.getInstance("ECDH").genKeyPair())

+ 3 - 1
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/cryptor/ECDH.kt

@@ -19,6 +19,8 @@ expect class ECDHKeyPair {
 }
 
 expect class ECDH(keyPair: ECDHKeyPair) {
+    val keyPair: ECDHKeyPair
+
     fun calculateShareKeyByPeerPublicKey(peerPublicKey: ECDHPublicKey): ByteArray
 
     companion object {
@@ -47,5 +49,5 @@ fun ByteArray.adjustToPublicKey(): ECDHPublicKey {
                 else (byteArray_04 + this)
     } else this
 
-    return ECDH.constructPublicKey(this)
+    return ECDH.constructPublicKey(key)
 }

+ 1 - 1
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/cryptor/ECDHJvm.kt

@@ -21,7 +21,7 @@ actual class ECDHKeyPair(
 @Suppress("FunctionName")
 actual fun ECDH() = ECDH(ECDH.generateKeyPair())
 
-actual class ECDH actual constructor(val keyPair: ECDHKeyPair) {
+actual class ECDH actual constructor(actual val keyPair: ECDHKeyPair) {
     actual companion object {
         actual fun generateKeyPair(): ECDHKeyPair {
             return ECDHKeyPair(KeyPairGenerator.getInstance("ECDH").genKeyPair())