Separate EncryptionMethod

This commit is contained in:
Him188 2020-01-12 15:54:56 +08:00
parent f238f7d092
commit 26161ef094
4 changed files with 102 additions and 87 deletions

View File

@ -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 ?

View File

@ -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)
}
}

View File

@ -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

View File

@ -55,7 +55,7 @@ abstract class BotImpl<N : BotNetworkHandler> 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)