diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidClient.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidClient.kt index 9cbfbdb2b..03454cf6c 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidClient.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidClient.kt @@ -50,7 +50,7 @@ internal open class QQAndroidClient( val context by context.unsafeWeakRef() val bot: QQAndroidBot by bot.unsafeWeakRef() - val tgtgtKey: ByteArray = ByteArray(16) // generateTgtgtKey(device.guid) + var tgtgtKey: ByteArray = ByteArray(16) // generateTgtgtKey(device.guid) val randomKey: ByteArray = ByteArray(16) // 加密使用 var miscBitMap: Int = 184024956 // 也可能是 150470524 ? diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/EncryptMethod.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/EncryptMethod.kt new file mode 100644 index 000000000..02bd0fb4f --- /dev/null +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/EncryptMethod.kt @@ -0,0 +1,100 @@ +package net.mamoe.mirai.qqandroid.network.protocol.packet + +import kotlinx.io.core.BytePacketBuilder +import kotlinx.io.core.ByteReadPacket +import kotlinx.io.core.buildPacket +import kotlinx.io.core.writeFully +import net.mamoe.mirai.qqandroid.network.QQAndroidClient +import net.mamoe.mirai.utils.cryptor.ECDH +import net.mamoe.mirai.utils.io.encryptAndWrite +import net.mamoe.mirai.utils.io.writeShortLVByteArray + +/** + * Encryption method to be used for packet body. + */ +@UseExperimental(ExperimentalUnsignedTypes::class) +internal interface EncryptMethod { + val id: Int + + fun makeBody(client: QQAndroidClient, body: BytePacketBuilder.() -> Unit): ByteReadPacket +} + +internal interface EncryptMethodSessionKey : EncryptMethod { + override val id: Int get() = 69 + val currentLoginState: Int + val sessionKey: ByteArray + + /** + * buildPacket{ + * byte 1 + * byte if (currentLoginState == 2) 3 else 2 + * fully key + * short 258 + * short 0 + * fully encrypted + * } + */ + override fun makeBody(client: QQAndroidClient, body: BytePacketBuilder.() -> Unit): ByteReadPacket = + buildPacket { + require(currentLoginState == 2 || currentLoginState == 3) { "currentLoginState must be either 2 or 3" } + writeByte(1) // const + writeByte(if (currentLoginState == 2) 3 else 2) + writeFully(sessionKey) + writeShort(258) // const + writeShort(0) // const, length of publicKey + encryptAndWrite(sessionKey, body) + } +} + +inline class EncryptMethodSessionKeyLoginState2(override val sessionKey: ByteArray) : + EncryptMethodSessionKey { + override val currentLoginState: Int get() = 2 +} + +inline class EncryptMethodSessionKeyLoginState3(override val sessionKey: ByteArray) : + EncryptMethodSessionKey { + override val currentLoginState: Int get() = 3 +} + +inline class EncryptMethodECDH135(override val ecdh: ECDH) : + EncryptMethodECDH { + override val id: Int get() = 135 +} + +inline class EncryptMethodECDH7(override val ecdh: ECDH) : + EncryptMethodECDH { + override val id: Int get() = 7 +} + +internal interface EncryptMethodECDH : EncryptMethod { + val ecdh: ECDH + + /** + * **Packet Structure** + * byte 1 + * byte 1 + * byte[] [ECDH.privateKey] + * short 258 + * short [ECDH.publicKey].size + * byte[] [ECDH.publicKey] + * byte[] encrypted `body()` by [ECDH.shareKey] + */ + override fun makeBody(client: QQAndroidClient, body: BytePacketBuilder.() -> Unit): ByteReadPacket = + buildPacket { + writeByte(1) // const + writeByte(1) // const + writeFully(client.randomKey) + writeShort(258) // const + + // writeShortLVByteArray("04 CB 36 66 98 56 1E 93 6E 80 C1 57 E0 74 CA B1 3B 0B B6 8D DE B2 82 45 48 A1 B1 8D D4 FB 61 22 AF E1 2F E4 8C 52 66 D8 D7 26 9D 76 51 A8 EB 6F E7".hexToBytes()) + + writeShortLVByteArray(ecdh.keyPair.publicKey.getEncoded().drop(23).take(49).toByteArray().also { + // it.toUHexString().debugPrint("PUBLIC KEY") + check(it[0].toInt() == 0x04) { "Bad publicKey generated. Expected first element=0x04, got${it[0]}" } + //check(ecdh.calculateShareKeyByPeerPublicKey(it.adjustToPublicKey()).contentEquals(ecdh.keyPair.shareKey)) { "PublicKey Validation failed" } + }) + + // encryptAndWrite("26 33 BA EC 86 EB 79 E6 BC E0 20 06 5E A9 56 6C".hexToBytes(), body) + encryptAndWrite(ecdh.keyPair.shareKey, body) + } +} \ No newline at end of file diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/OutgoingPacketAndroid.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/OutgoingPacketAndroid.kt index 3ea42a591..2f215e3f3 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/OutgoingPacketAndroid.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/OutgoingPacketAndroid.kt @@ -9,7 +9,6 @@ import net.mamoe.mirai.qqandroid.network.QQAndroidClient import net.mamoe.mirai.qqandroid.network.protocol.packet.login.PacketId 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.io.* @@ -186,90 +185,6 @@ internal inline fun PacketFactory<*, *>.buildSessionOutgoingPacket( } } -/** - * Encryption method to be used for packet body. - */ -@UseExperimental(ExperimentalUnsignedTypes::class) -internal interface EncryptMethod { - val id: Int - - fun makeBody(client: QQAndroidClient, body: BytePacketBuilder.() -> Unit): ByteReadPacket -} - -internal interface EncryptMethodSessionKey : EncryptMethod { - override val id: Int get() = 69 - val currentLoginState: Int - val sessionKey: ByteArray - - /** - * buildPacket{ - * byte 1 - * byte if (currentLoginState == 2) 3 else 2 - * fully key - * short 258 - * short 0 - * fully encrypted - * } - */ - override fun makeBody(client: QQAndroidClient, body: BytePacketBuilder.() -> Unit): ByteReadPacket = buildPacket { - require(currentLoginState == 2 || currentLoginState == 3) { "currentLoginState must be either 2 or 3" } - writeByte(1) // const - writeByte(if (currentLoginState == 2) 3 else 2) - writeFully(sessionKey) - writeShort(258) // const - writeShort(0) // const, length of publicKey - encryptAndWrite(sessionKey, body) - } -} - -inline class EncryptMethodSessionKeyLoginState2(override val sessionKey: ByteArray) : EncryptMethodSessionKey { - override val currentLoginState: Int get() = 2 -} - -inline class EncryptMethodSessionKeyLoginState3(override val sessionKey: ByteArray) : EncryptMethodSessionKey { - override val currentLoginState: Int get() = 3 -} - -inline class EncryptMethodECDH135(override val ecdh: ECDH) : EncryptMethodECDH { - override val id: Int get() = 135 -} - -inline class EncryptMethodECDH7(override val ecdh: ECDH) : EncryptMethodECDH { - override val id: Int get() = 7 -} - -internal interface EncryptMethodECDH : EncryptMethod { - val ecdh: ECDH - - /** - * **Packet Structure** - * byte 1 - * byte 1 - * byte[] [ECDH.privateKey] - * short 258 - * short [ECDH.publicKey].size - * byte[] [ECDH.publicKey] - * byte[] encrypted `body()` by [ECDH.shareKey] - */ - override fun makeBody(client: QQAndroidClient, body: BytePacketBuilder.() -> Unit): ByteReadPacket = buildPacket { - writeByte(1) // const - writeByte(1) // const - writeFully(client.randomKey) - writeShort(258) // const - - // writeShortLVByteArray("04 CB 36 66 98 56 1E 93 6E 80 C1 57 E0 74 CA B1 3B 0B B6 8D DE B2 82 45 48 A1 B1 8D D4 FB 61 22 AF E1 2F E4 8C 52 66 D8 D7 26 9D 76 51 A8 EB 6F E7".hexToBytes()) - - writeShortLVByteArray(ecdh.keyPair.publicKey.getEncoded().drop(23).take(49).toByteArray().also { - // it.toUHexString().debugPrint("PUBLIC KEY") - check(it[0].toInt() == 0x04) { "Bad publicKey generated. Expected first element=0x04, got${it[0]}" } - //check(ecdh.calculateShareKeyByPeerPublicKey(it.adjustToPublicKey()).contentEquals(ecdh.keyPair.shareKey)) { "PublicKey Validation failed" } - }) - - // encryptAndWrite("26 33 BA EC 86 EB 79 E6 BC E0 20 06 5E A9 56 6C".hexToBytes(), body) - encryptAndWrite(ecdh.keyPair.shareKey, body) - } -} - /** * Writes a request packet * This is the innermost packet structure diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotImpl.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotImpl.kt index 1a34d7e9a..be0e43a38 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotImpl.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotImpl.kt @@ -55,7 +55,7 @@ abstract class BotImpl constructor( final override val network: N get() = _network - private lateinit var _network: N + internal lateinit var _network: N final override suspend fun login() = reinitializeNetworkHandler(null)