[core] decode SsoEstablishShareKey

This commit is contained in:
StageGuard 2023-06-17 10:29:17 +08:00 committed by Karlatemp
parent ff96dce35d
commit 1dacce61cd
No known key found for this signature in database
GPG Key ID: BA173CA2B9956C59
6 changed files with 106 additions and 36 deletions

View File

@ -18,6 +18,7 @@ import net.mamoe.mirai.internal.network.components.PacketCodecException.Kind.*
import net.mamoe.mirai.internal.network.handler.selector.NetworkException
import net.mamoe.mirai.internal.network.protocol.packet.*
import net.mamoe.mirai.internal.network.protocol.packet.login.WtLogin
import net.mamoe.mirai.internal.network.protocol.packet.sso.PREFIX_TRPC_SSO
import net.mamoe.mirai.internal.utils.crypto.Ecdh
import net.mamoe.mirai.internal.utils.crypto.TEA
import net.mamoe.mirai.utils.*
@ -95,6 +96,17 @@ internal class PacketCodecException(
// }
}
internal enum class IncomingPacketType(val value: Int) {
Login(0x0A),
Simple(0x0B),
Unknown(-1)
;
companion object {
internal fun of(value: Int) = enumValues<IncomingPacketType>().find { it.value == value } ?: Unknown
}
}
internal class PacketCodecImpl : PacketCodec {
override fun decodeRaw(
@ -102,15 +114,15 @@ internal class PacketCodecImpl : PacketCodec {
input: ByteReadPacket
): RawIncomingPacket = input.run {
// packet type
val type = readInt()
val packetType = IncomingPacketType.of(readInt())
PacketLogger.verbose { "开始处理一个包" }
val encryptMethod = readByte().toInt()
val encryptMethod = PacketEncryptType.of(readByte().toInt())
val flag3 = readByte().toInt()
val flag3Exception = if (flag3 != 0) {
PacketCodecException(
"Illegal flag3. Expected 0, whereas got $flag3. packet type=$type, encrypt method=$encryptMethod. ",
"Illegal flag3. Expected 0, whereas got $flag3. packet type=$packetType, encrypt method=$encryptMethod. ",
kind = PROTOCOL_UPDATED
)
} else null
@ -122,10 +134,8 @@ internal class PacketCodecImpl : PacketCodec {
val raw = try {
when (encryptMethod) {
// empty key
2 -> TEA.decrypt(buffer, DECRYPTER_16_ZERO, size)
// d2 key
1 -> {
PacketEncryptType.Empty -> TEA.decrypt(buffer, DECRYPTER_16_ZERO, size)
PacketEncryptType.D2 -> {
TEA.decrypt(buffer, kotlin.runCatching { client.wLoginSigInfo.d2Key }.getOrElse {
throw PacketCodecException(
"Received packet needed d2Key to decrypt but d2Key doesn't existed, ignoring. Please report to https://github.com/mamoe/mirai/issues/new/choose if you see anything abnormal",
@ -133,17 +143,18 @@ internal class PacketCodecImpl : PacketCodec {
)
}, size)
}
// no encrypt
0 -> buffer
PacketEncryptType.NoEncrypt -> buffer
else -> throw PacketCodecException("Unknown encrypt type=$encryptMethod", PROTOCOL_UPDATED)
}.let { decryptedData ->
when (type) {
// login
0x0A -> parseSsoFrame(client, decryptedData)
// simple
0x0B -> parseSsoFrame(client, decryptedData) // 这里可能是 uni?? 但测试时候发现结构跟 sso 一样.
when (packetType) {
IncomingPacketType.Login -> parseSsoFrame(client, decryptedData)
IncomingPacketType.Simple -> parseSsoFrame(
client,
decryptedData
) // 这里可能是 uni?? 但测试时候发现结构跟 sso 一样.
else -> throw PacketCodecException(
"unknown packet type: ${type.toByte().toUHexString()}",
"unknown packet type: ${packetType.value.toUHexString()}",
PROTOCOL_UPDATED
)
}
@ -163,25 +174,39 @@ internal class PacketCodecImpl : PacketCodec {
"which may means protocol is updated.",
flag3Exception
)
} else if (raw.commandName.startsWith(PREFIX_TRPC_SSO)) {
PacketLogger.verbose { "received a trpc native packet: ${raw.commandName}" }
} else {
throw flag3Exception
}
}
when (encryptMethod) {
0, 1 -> RawIncomingPacket(raw.commandName, raw.sequenceId, raw.body.readBytes())
2 -> RawIncomingPacket(
PacketEncryptType.NoEncrypt,
PacketEncryptType.D2 -> RawIncomingPacket(
raw.commandName,
raw.sequenceId,
raw.body.withUse {
try {
parseOicqResponse(client, raw.commandName)
} catch (e: Throwable) {
throw PacketCodecException(e, PacketCodecException.Kind.OTHER)
}
}
raw.body.readBytes()
)
PacketEncryptType.Empty -> {
RawIncomingPacket(
raw.commandName,
raw.sequenceId,
raw.body.withUse {
if (raw.commandName.startsWith(PREFIX_TRPC_SSO)) {
readBytes()
} else {
try {
parseOicqResponse(client, raw.commandName)
} catch (e: Throwable) {
throw PacketCodecException(e, PacketCodecException.Kind.OTHER)
}
}
}
)
}
else -> error("unreachable")
}
}

View File

@ -16,7 +16,7 @@ import net.mamoe.mirai.internal.network.*
import net.mamoe.mirai.internal.network.components.EcdhInitialPublicKeyUpdater
import net.mamoe.mirai.internal.network.protocol.data.proto.SSOReserveField
import net.mamoe.mirai.internal.network.protocol.packet.chat.receive.MessageSvcPbSendMsg
import net.mamoe.mirai.internal.network.protocol.packet.login.WtLogin
import net.mamoe.mirai.internal.network.protocol.packet.sso.SsoEstablishShareKey
import net.mamoe.mirai.internal.spi.EncryptService
import net.mamoe.mirai.internal.spi.EncryptServiceContext
import net.mamoe.mirai.internal.utils.io.encryptAndWrite
@ -75,25 +75,34 @@ internal class IncomingPacket private constructor(
}
}
internal enum class PacketEncryptType {
NoEncrypt { // 0x00
internal enum class PacketEncryptType(val value: Int) {
NoEncrypt(0x00) { // 0x00
override fun defaultKey(client: QQAndroidClient): ByteArray = NO_ENCRYPT
},
D2 { //0x01
D2(0x01) { //0x01
override fun defaultKey(client: QQAndroidClient): ByteArray {
return client.wLoginSigInfo.d2Key
}
},
Empty { // 16 zeros,// 0x02
Empty(0x02) { // 16 zeros,// 0x02
override fun defaultKey(client: QQAndroidClient): ByteArray {
return KEY_16_ZEROS
}
},
Unknown(-1) {
override fun defaultKey(client: QQAndroidClient): ByteArray {
error("unreachable")
}
}
;
inline val codec: Byte get() = ordinal.toByte()
abstract fun defaultKey(client: QQAndroidClient): ByteArray
companion object {
internal fun of(value: Int) = enumValues<PacketEncryptType>().find { it.value == value } ?: Unknown
}
}
@ -251,9 +260,9 @@ internal fun createChannelProxy(client: QQAndroidClient): EncryptService.Channel
uin: Long,
data: ByteArray
): EncryptService.ChannelResult? {
if (commandName == "trpc.o3.ecdh_access.EcdhAccess.SsoEstablishShareKey") {
val packet = client.bot.network.sendAndExpect<Packet>(
WtLogin.Login.buildLoginOutgoingPacket(
if (commandName == SsoEstablishShareKey.commandName) {
val packet = client.bot.network.sendAndExpect(
SsoEstablishShareKey.buildLoginOutgoingPacket(
client = client,
encryptMethod = PacketEncryptType.Empty,
uin = uin.toString(),
@ -268,7 +277,7 @@ internal fun createChannelProxy(client: QQAndroidClient): EncryptService.Channel
)
}
)
TODO("parse packet to ChannelResult")
return EncryptService.ChannelResult(SsoEstablishShareKey.commandName, packet.data)
}
return null
}

View File

@ -26,11 +26,11 @@ import net.mamoe.mirai.internal.network.protocol.packet.login.ConfigPushSvc
import net.mamoe.mirai.internal.network.protocol.packet.login.Heartbeat
import net.mamoe.mirai.internal.network.protocol.packet.login.StatSvc
import net.mamoe.mirai.internal.network.protocol.packet.login.WtLogin
import net.mamoe.mirai.internal.network.protocol.packet.sso.SsoEstablishShareKey
import net.mamoe.mirai.internal.network.protocol.packet.summarycard.ChangeFriendRemark
import net.mamoe.mirai.internal.network.protocol.packet.summarycard.SummaryCard
import net.mamoe.mirai.utils.DeprecatedSinceMirai
import net.mamoe.mirai.utils.MiraiLoggerWithSwitch
import kotlin.jvm.JvmName
internal sealed class PacketFactory<TPacket : Packet?> {
/**
@ -132,6 +132,7 @@ internal object KnownPacketFactories {
WtLogin.Login,
WtLogin.ExchangeEmp,
WtLogin.TransEmp,
SsoEstablishShareKey,
StatSvc.Register,
StatSvc.GetOnlineStatus,
StatSvc.SimpleGet,

View File

@ -0,0 +1,25 @@
/*
* Copyright 2019-2023 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/dev/LICENSE
*/
package net.mamoe.mirai.internal.network.protocol.packet.sso
import io.ktor.utils.io.core.*
import net.mamoe.mirai.internal.QQAndroidBot
import net.mamoe.mirai.internal.network.Packet
import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacketFactory
internal object SsoEstablishShareKey : OutgoingPacketFactory<SsoEstablishShareKey.RawData>(
"trpc.o3.ecdh_access.EcdhAccess.SsoEstablishShareKey"
) {
internal class RawData(val data: ByteArray) : Packet
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): RawData {
return RawData(readBytes())
}
}

View File

@ -0,0 +1,12 @@
/*
* Copyright 2019-2023 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/dev/LICENSE
*/
package net.mamoe.mirai.internal.network.protocol.packet.sso
internal const val PREFIX_TRPC_SSO = "trpc.o3"

View File

@ -72,8 +72,6 @@ public interface EncryptService : BaseService {
public class ChannelResult(
public val cmd: String,
public val data: ByteArray,
public val success: Int,
public val callbackId: Long
)
public interface ChannelProxy {