mirror of
https://github.com/Mrs4s/MiraiGo.git
synced 2025-05-04 11:07:40 +08:00
internal/oicq: refactor & support unmarshal
This commit is contained in:
parent
5dfa4528dd
commit
24b75e45c7
@ -9,15 +9,14 @@ import (
|
|||||||
"github.com/Mrs4s/MiraiGo/binary"
|
"github.com/Mrs4s/MiraiGo/binary"
|
||||||
"github.com/Mrs4s/MiraiGo/binary/jce"
|
"github.com/Mrs4s/MiraiGo/binary/jce"
|
||||||
"github.com/Mrs4s/MiraiGo/client/internal/auth"
|
"github.com/Mrs4s/MiraiGo/client/internal/auth"
|
||||||
"github.com/Mrs4s/MiraiGo/client/internal/codec"
|
|
||||||
"github.com/Mrs4s/MiraiGo/client/internal/network"
|
"github.com/Mrs4s/MiraiGo/client/internal/network"
|
||||||
|
"github.com/Mrs4s/MiraiGo/client/internal/oicq"
|
||||||
"github.com/Mrs4s/MiraiGo/client/pb"
|
"github.com/Mrs4s/MiraiGo/client/pb"
|
||||||
"github.com/Mrs4s/MiraiGo/client/pb/cmd0x352"
|
"github.com/Mrs4s/MiraiGo/client/pb/cmd0x352"
|
||||||
"github.com/Mrs4s/MiraiGo/client/pb/msg"
|
"github.com/Mrs4s/MiraiGo/client/pb/msg"
|
||||||
"github.com/Mrs4s/MiraiGo/client/pb/oidb"
|
"github.com/Mrs4s/MiraiGo/client/pb/oidb"
|
||||||
"github.com/Mrs4s/MiraiGo/client/pb/profilecard"
|
"github.com/Mrs4s/MiraiGo/client/pb/profilecard"
|
||||||
"github.com/Mrs4s/MiraiGo/client/pb/structmsg"
|
"github.com/Mrs4s/MiraiGo/client/pb/structmsg"
|
||||||
"github.com/Mrs4s/MiraiGo/internal/crypto"
|
|
||||||
"github.com/Mrs4s/MiraiGo/internal/packets"
|
"github.com/Mrs4s/MiraiGo/internal/packets"
|
||||||
"github.com/Mrs4s/MiraiGo/internal/proto"
|
"github.com/Mrs4s/MiraiGo/internal/proto"
|
||||||
"github.com/Mrs4s/MiraiGo/internal/tlv"
|
"github.com/Mrs4s/MiraiGo/internal/tlv"
|
||||||
@ -426,12 +425,11 @@ func (c *QQClient) buildRequestTgtgtNopicsigPacket() (uint16, []byte) {
|
|||||||
w.Write(tlv.T545([]byte(c.deviceInfo.IMEI)))
|
w.Write(tlv.T545([]byte(c.deviceInfo.IMEI)))
|
||||||
})
|
})
|
||||||
|
|
||||||
oicq := codec.OICQ{
|
m := oicq.Message{
|
||||||
Uin: uint32(c.Uin),
|
Uin: uint32(c.Uin),
|
||||||
Command: 0x810,
|
Command: 0x810,
|
||||||
EncryptMethod: crypto.NewEncryptSession(c.sig.T133),
|
EncryptionMethod: oicq.EM_ST,
|
||||||
Key: c.sig.WtSessionTicketKey,
|
Body: req,
|
||||||
Body: req,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nreq := network.Request{
|
nreq := network.Request{
|
||||||
@ -440,7 +438,7 @@ func (c *QQClient) buildRequestTgtgtNopicsigPacket() (uint16, []byte) {
|
|||||||
Uin: c.Uin,
|
Uin: c.Uin,
|
||||||
SequenceID: int32(seq),
|
SequenceID: int32(seq),
|
||||||
CommandName: "wtlogin.exchange_emp",
|
CommandName: "wtlogin.exchange_emp",
|
||||||
Body: oicq.Encode(),
|
Body: c.oicq.Marshal(&m),
|
||||||
}
|
}
|
||||||
return seq, c.transport.PackPacket(&nreq)
|
return seq, c.transport.PackPacket(&nreq)
|
||||||
}
|
}
|
||||||
|
@ -18,8 +18,8 @@ import (
|
|||||||
"github.com/Mrs4s/MiraiGo/client/internal/auth"
|
"github.com/Mrs4s/MiraiGo/client/internal/auth"
|
||||||
"github.com/Mrs4s/MiraiGo/client/internal/highway"
|
"github.com/Mrs4s/MiraiGo/client/internal/highway"
|
||||||
"github.com/Mrs4s/MiraiGo/client/internal/network"
|
"github.com/Mrs4s/MiraiGo/client/internal/network"
|
||||||
|
"github.com/Mrs4s/MiraiGo/client/internal/oicq"
|
||||||
"github.com/Mrs4s/MiraiGo/client/pb/msg"
|
"github.com/Mrs4s/MiraiGo/client/pb/msg"
|
||||||
"github.com/Mrs4s/MiraiGo/internal/crypto"
|
|
||||||
"github.com/Mrs4s/MiraiGo/utils"
|
"github.com/Mrs4s/MiraiGo/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -54,6 +54,7 @@ type QQClient struct {
|
|||||||
ConnectTime time.Time
|
ConnectTime time.Time
|
||||||
|
|
||||||
transport *network.Transport
|
transport *network.Transport
|
||||||
|
oicq *oicq.Codec
|
||||||
|
|
||||||
// internal state
|
// internal state
|
||||||
handlers HandlerMap
|
handlers HandlerMap
|
||||||
@ -64,7 +65,6 @@ type QQClient struct {
|
|||||||
version *auth.AppVersion
|
version *auth.AppVersion
|
||||||
deviceInfo *auth.Device
|
deviceInfo *auth.Device
|
||||||
alive bool
|
alive bool
|
||||||
ecdh *crypto.EncryptECDH
|
|
||||||
|
|
||||||
// session info
|
// session info
|
||||||
qwebSeq atomic.Int64
|
qwebSeq atomic.Int64
|
||||||
@ -161,7 +161,6 @@ func NewClientMd5(uin int64, passwordMd5 [16]byte) *QQClient {
|
|||||||
Uin: uin,
|
Uin: uin,
|
||||||
PasswordMd5: passwordMd5,
|
PasswordMd5: passwordMd5,
|
||||||
AllowSlider: true,
|
AllowSlider: true,
|
||||||
RandomKey: make([]byte, 16),
|
|
||||||
TCP: &network.TCPListener{},
|
TCP: &network.TCPListener{},
|
||||||
sig: &auth.SigInfo{
|
sig: &auth.SigInfo{
|
||||||
OutPacketSessionID: []byte{0x02, 0xB0, 0x5B, 0x8B},
|
OutPacketSessionID: []byte{0x02, 0xB0, 0x5B, 0x8B},
|
||||||
@ -172,7 +171,6 @@ func NewClientMd5(uin int64, passwordMd5 [16]byte) *QQClient {
|
|||||||
onlinePushCache: utils.NewCache(time.Second * 15),
|
onlinePushCache: utils.NewCache(time.Second * 15),
|
||||||
servers: []*net.TCPAddr{},
|
servers: []*net.TCPAddr{},
|
||||||
alive: true,
|
alive: true,
|
||||||
ecdh: crypto.NewEcdh(),
|
|
||||||
highwaySession: new(highway.Session),
|
highwaySession: new(highway.Session),
|
||||||
|
|
||||||
version: new(auth.AppVersion),
|
version: new(auth.AppVersion),
|
||||||
@ -184,7 +182,7 @@ func NewClientMd5(uin int64, passwordMd5 [16]byte) *QQClient {
|
|||||||
Version: cli.version,
|
Version: cli.version,
|
||||||
Device: cli.deviceInfo,
|
Device: cli.deviceInfo,
|
||||||
}
|
}
|
||||||
|
cli.oicq = oicq.NewCodec(cli.Uin)
|
||||||
{ // init atomic values
|
{ // init atomic values
|
||||||
cli.SequenceId.Store(0x3635)
|
cli.SequenceId.Store(0x3635)
|
||||||
cli.requestPacketRequestID.Store(1921334513)
|
cli.requestPacketRequestID.Store(1921334513)
|
||||||
@ -194,7 +192,6 @@ func NewClientMd5(uin int64, passwordMd5 [16]byte) *QQClient {
|
|||||||
}
|
}
|
||||||
cli.highwaySession.Uin = strconv.FormatInt(cli.Uin, 10)
|
cli.highwaySession.Uin = strconv.FormatInt(cli.Uin, 10)
|
||||||
cli.GuildService = &GuildService{c: cli}
|
cli.GuildService = &GuildService{c: cli}
|
||||||
cli.ecdh.FetchPubKey(uin)
|
|
||||||
cli.UseDevice(SystemDeviceInfo)
|
cli.UseDevice(SystemDeviceInfo)
|
||||||
sso, err := getSSOAddress()
|
sso, err := getSSOAddress()
|
||||||
if err == nil && len(sso) > 0 {
|
if err == nil && len(sso) > 0 {
|
||||||
@ -300,7 +297,7 @@ func (c *QQClient) TokenLogin(token []byte) error {
|
|||||||
c.sig.SrmToken = r.ReadBytesShort()
|
c.sig.SrmToken = r.ReadBytesShort()
|
||||||
c.sig.T133 = r.ReadBytesShort()
|
c.sig.T133 = r.ReadBytesShort()
|
||||||
c.sig.EncryptedA1 = r.ReadBytesShort()
|
c.sig.EncryptedA1 = r.ReadBytesShort()
|
||||||
c.sig.WtSessionTicketKey = r.ReadBytesShort()
|
c.oicq.WtSessionTicketKey = r.ReadBytesShort()
|
||||||
c.sig.OutPacketSessionID = r.ReadBytesShort()
|
c.sig.OutPacketSessionID = r.ReadBytesShort()
|
||||||
// SystemDeviceInfo.TgtgtKey = r.ReadBytesShort()
|
// SystemDeviceInfo.TgtgtKey = r.ReadBytesShort()
|
||||||
c.deviceInfo.TgtgtKey = r.ReadBytesShort()
|
c.deviceInfo.TgtgtKey = r.ReadBytesShort()
|
||||||
@ -448,7 +445,7 @@ func (c *QQClient) GenToken() []byte {
|
|||||||
w.WriteBytesShort(c.sig.SrmToken)
|
w.WriteBytesShort(c.sig.SrmToken)
|
||||||
w.WriteBytesShort(c.sig.T133)
|
w.WriteBytesShort(c.sig.T133)
|
||||||
w.WriteBytesShort(c.sig.EncryptedA1)
|
w.WriteBytesShort(c.sig.EncryptedA1)
|
||||||
w.WriteBytesShort(c.sig.WtSessionTicketKey)
|
w.WriteBytesShort(c.oicq.WtSessionTicketKey)
|
||||||
w.WriteBytesShort(c.sig.OutPacketSessionID)
|
w.WriteBytesShort(c.sig.OutPacketSessionID)
|
||||||
w.WriteBytesShort(c.deviceInfo.TgtgtKey)
|
w.WriteBytesShort(c.deviceInfo.TgtgtKey)
|
||||||
})
|
})
|
||||||
|
@ -113,17 +113,16 @@ type SigInfo struct {
|
|||||||
TGT []byte
|
TGT []byte
|
||||||
TGTKey []byte
|
TGTKey []byte
|
||||||
|
|
||||||
SrmToken []byte // study room manager | 0x16a
|
SrmToken []byte // study room manager | 0x16a
|
||||||
T133 []byte
|
T133 []byte
|
||||||
EncryptedA1 []byte
|
EncryptedA1 []byte
|
||||||
UserStKey []byte
|
UserStKey []byte
|
||||||
UserStWebSig []byte
|
UserStWebSig []byte
|
||||||
SKey []byte
|
SKey []byte
|
||||||
SKeyExpiredTime int64
|
SKeyExpiredTime int64
|
||||||
D2 []byte
|
D2 []byte
|
||||||
D2Key []byte
|
D2Key []byte
|
||||||
WtSessionTicketKey []byte
|
DeviceToken []byte
|
||||||
DeviceToken []byte
|
|
||||||
|
|
||||||
PsKeyMap map[string][]byte
|
PsKeyMap map[string][]byte
|
||||||
Pt4TokenMap map[string][]byte
|
Pt4TokenMap map[string][]byte
|
||||||
|
@ -1,40 +0,0 @@
|
|||||||
package codec
|
|
||||||
|
|
||||||
import "github.com/Mrs4s/MiraiGo/binary"
|
|
||||||
|
|
||||||
type Encryptor interface {
|
|
||||||
Encrypt([]byte, []byte) []byte
|
|
||||||
ID() byte
|
|
||||||
}
|
|
||||||
|
|
||||||
type OICQ struct {
|
|
||||||
Uin uint32
|
|
||||||
Command uint16
|
|
||||||
EncryptMethod Encryptor
|
|
||||||
Key []byte
|
|
||||||
Body []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *OICQ) Encode() []byte {
|
|
||||||
body := m.EncryptMethod.Encrypt(m.Body, m.Key)
|
|
||||||
|
|
||||||
p := binary.SelectWriter()
|
|
||||||
defer binary.PutWriter(p)
|
|
||||||
|
|
||||||
p.WriteByte(0x02)
|
|
||||||
p.WriteUInt16(27 + 2 + uint16(len(body)))
|
|
||||||
p.WriteUInt16(8001)
|
|
||||||
p.WriteUInt16(m.Command)
|
|
||||||
p.WriteUInt16(1)
|
|
||||||
p.WriteUInt32(m.Uin)
|
|
||||||
p.WriteByte(3)
|
|
||||||
p.WriteByte(m.EncryptMethod.ID())
|
|
||||||
p.WriteByte(0)
|
|
||||||
p.WriteUInt32(2)
|
|
||||||
p.WriteUInt32(0)
|
|
||||||
p.WriteUInt32(0)
|
|
||||||
p.Write(body)
|
|
||||||
p.WriteByte(0x03)
|
|
||||||
|
|
||||||
return append([]byte(nil), p.Bytes()...)
|
|
||||||
}
|
|
130
client/internal/oicq/oicq.go
Normal file
130
client/internal/oicq/oicq.go
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
package oicq
|
||||||
|
|
||||||
|
import (
|
||||||
|
goBinary "encoding/binary"
|
||||||
|
"math/rand"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
|
"github.com/Mrs4s/MiraiGo/binary"
|
||||||
|
"github.com/Mrs4s/MiraiGo/internal/crypto"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Codec struct {
|
||||||
|
ecdh *crypto.ECDH
|
||||||
|
randomKey []byte
|
||||||
|
|
||||||
|
WtSessionTicketKey []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCodec(uin int64) *Codec {
|
||||||
|
c := &Codec{
|
||||||
|
ecdh: crypto.NewECDH(),
|
||||||
|
randomKey: make([]byte, 16),
|
||||||
|
}
|
||||||
|
rand.Read(c.randomKey)
|
||||||
|
c.ecdh.FetchPubKey(uin)
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
type EncryptionMethod byte
|
||||||
|
|
||||||
|
const (
|
||||||
|
EM_ECDH EncryptionMethod = iota
|
||||||
|
EM_ST
|
||||||
|
)
|
||||||
|
|
||||||
|
type Message struct {
|
||||||
|
Uin uint32
|
||||||
|
Command uint16
|
||||||
|
EncryptionMethod EncryptionMethod
|
||||||
|
Body []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Codec) Marshal(m *Message) []byte {
|
||||||
|
w := binary.SelectWriter()
|
||||||
|
defer binary.PutWriter(w)
|
||||||
|
|
||||||
|
w.WriteByte(0x02)
|
||||||
|
w.WriteUInt16(0) // len 占位
|
||||||
|
w.WriteUInt16(8001) // version?
|
||||||
|
w.WriteUInt16(m.Command)
|
||||||
|
w.WriteUInt16(1)
|
||||||
|
w.WriteUInt32(m.Uin)
|
||||||
|
w.WriteByte(0x03)
|
||||||
|
switch m.EncryptionMethod {
|
||||||
|
case EM_ECDH:
|
||||||
|
w.WriteByte(0x87)
|
||||||
|
case EM_ST:
|
||||||
|
w.WriteByte(0x45)
|
||||||
|
}
|
||||||
|
w.WriteByte(0)
|
||||||
|
w.WriteUInt32(2)
|
||||||
|
w.WriteUInt32(0)
|
||||||
|
w.WriteUInt32(0)
|
||||||
|
|
||||||
|
switch m.EncryptionMethod {
|
||||||
|
case EM_ECDH:
|
||||||
|
w.WriteByte(0x02)
|
||||||
|
w.WriteByte(0x01)
|
||||||
|
w.Write(c.randomKey)
|
||||||
|
w.WriteUInt16(0x01_31)
|
||||||
|
w.WriteUInt16(c.ecdh.SvrPublicKeyVer)
|
||||||
|
w.WriteUInt16(uint16(len(c.ecdh.PublicKey)))
|
||||||
|
w.Write(c.ecdh.PublicKey)
|
||||||
|
w.EncryptAndWrite(c.ecdh.ShareKey, m.Body)
|
||||||
|
|
||||||
|
case EM_ST:
|
||||||
|
w.WriteByte(0x01)
|
||||||
|
w.WriteByte(0x03)
|
||||||
|
w.Write(c.randomKey)
|
||||||
|
w.WriteUInt16(0x0102)
|
||||||
|
w.WriteUInt16(0x0000)
|
||||||
|
w.EncryptAndWrite(c.randomKey, m.Body)
|
||||||
|
}
|
||||||
|
w.WriteByte(0x03)
|
||||||
|
|
||||||
|
buf := append([]byte(nil), w.Bytes()...)
|
||||||
|
goBinary.BigEndian.PutUint16(buf[1:3], uint16(len(buf)))
|
||||||
|
return buf
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrUnknownFlag = errors.New("unknown flag")
|
||||||
|
ErrUnknownEncryptType = errors.New("unknown encrypt type")
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *Codec) Unmarshal(data []byte) (*Message, error) {
|
||||||
|
reader := binary.NewReader(data)
|
||||||
|
if flag := reader.ReadByte(); flag != 2 {
|
||||||
|
return nil, ErrUnknownFlag
|
||||||
|
}
|
||||||
|
m := new(Message)
|
||||||
|
reader.ReadUInt16() // len
|
||||||
|
reader.ReadUInt16() // version?
|
||||||
|
m.Command = reader.ReadUInt16()
|
||||||
|
reader.ReadUInt16() // 1?
|
||||||
|
m.Uin = uint32(reader.ReadInt32())
|
||||||
|
reader.ReadByte()
|
||||||
|
encryptType := reader.ReadByte()
|
||||||
|
reader.ReadByte()
|
||||||
|
switch encryptType {
|
||||||
|
case 0:
|
||||||
|
m.Body = func() (decrypted []byte) {
|
||||||
|
d := reader.ReadBytes(reader.Len() - 1)
|
||||||
|
defer func() {
|
||||||
|
if pan := recover(); pan != nil {
|
||||||
|
tea := binary.NewTeaCipher(c.randomKey)
|
||||||
|
decrypted = tea.Decrypt(d)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return binary.NewTeaCipher(c.ecdh.ShareKey).Decrypt(d)
|
||||||
|
}()
|
||||||
|
case 3:
|
||||||
|
d := reader.ReadBytes(reader.Len() - 1)
|
||||||
|
m.Body = binary.NewTeaCipher(c.WtSessionTicketKey).Decrypt(d)
|
||||||
|
default:
|
||||||
|
return nil, ErrUnknownEncryptType
|
||||||
|
}
|
||||||
|
return m, nil
|
||||||
|
}
|
@ -306,7 +306,7 @@ func (c *QQClient) netLoop() {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if pkt.Flag2 == 2 {
|
if pkt.Flag2 == 2 {
|
||||||
pkt.Payload, err = pkt.DecryptPayload(c.ecdh.InitialShareKey, c.RandomKey, c.sig.WtSessionTicketKey)
|
m, err := c.oicq.Unmarshal(pkt.Payload)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Error("decrypt payload error: %v", err)
|
c.Error("decrypt payload error: %v", err)
|
||||||
if errors.Is(err, packets.ErrUnknownFlag) {
|
if errors.Is(err, packets.ErrUnknownFlag) {
|
||||||
@ -314,6 +314,7 @@ func (c *QQClient) netLoop() {
|
|||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
pkt.Payload = m.Body
|
||||||
}
|
}
|
||||||
errCount = 0
|
errCount = 0
|
||||||
c.Debug("rev pkt: %v seq: %v", pkt.CommandName, pkt.SequenceId)
|
c.Debug("rev pkt: %v seq: %v", pkt.CommandName, pkt.SequenceId)
|
||||||
|
@ -1,20 +1,19 @@
|
|||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/Mrs4s/MiraiGo/client/internal/codec"
|
|
||||||
"github.com/Mrs4s/MiraiGo/client/internal/network"
|
"github.com/Mrs4s/MiraiGo/client/internal/network"
|
||||||
|
"github.com/Mrs4s/MiraiGo/client/internal/oicq"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:noinline
|
//go:noinline
|
||||||
func (c *QQClient) buildOicqRequestPacket(uin int64, command uint16, body []byte) []byte {
|
func (c *QQClient) buildOicqRequestPacket(uin int64, command uint16, body []byte) []byte {
|
||||||
req := codec.OICQ{
|
req := oicq.Message{
|
||||||
Uin: uint32(uin),
|
Uin: uint32(uin),
|
||||||
Command: command,
|
Command: command,
|
||||||
EncryptMethod: c.ecdh,
|
EncryptionMethod: oicq.EM_ECDH,
|
||||||
Key: c.RandomKey,
|
Body: body,
|
||||||
Body: body,
|
|
||||||
}
|
}
|
||||||
return req.Encode()
|
return c.oicq.Marshal(&req)
|
||||||
}
|
}
|
||||||
|
|
||||||
//go:noinline
|
//go:noinline
|
||||||
|
@ -89,6 +89,8 @@ func (c *QQClient) decodeT119(data, ek []byte) {
|
|||||||
// readT138(t138) // chg time
|
// readT138(t138) // chg time
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c.oicq.WtSessionTicketKey = utils.Select(m[0x134], c.oicq.WtSessionTicketKey)
|
||||||
|
|
||||||
// we don't use `c.sigInfo = &auth.SigInfo{...}` here,
|
// we don't use `c.sigInfo = &auth.SigInfo{...}` here,
|
||||||
// because we need keep other fields in `c.sigInfo`
|
// because we need keep other fields in `c.sigInfo`
|
||||||
s := c.sig
|
s := c.sig
|
||||||
@ -104,7 +106,6 @@ func (c *QQClient) decodeT119(data, ek []byte) {
|
|||||||
s.SKeyExpiredTime = time.Now().Unix() + 21600
|
s.SKeyExpiredTime = time.Now().Unix() + 21600
|
||||||
s.D2 = m[0x143]
|
s.D2 = m[0x143]
|
||||||
s.D2Key = m[0x305]
|
s.D2Key = m[0x305]
|
||||||
s.WtSessionTicketKey = utils.Select(m[0x134], s.WtSessionTicketKey)
|
|
||||||
s.DeviceToken = m[0x322]
|
s.DeviceToken = m[0x322]
|
||||||
|
|
||||||
s.PsKeyMap = psKeyMap
|
s.PsKeyMap = psKeyMap
|
||||||
|
@ -8,14 +8,12 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/Mrs4s/MiraiGo/binary"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type EncryptECDH struct {
|
type ECDH struct {
|
||||||
InitialShareKey []byte
|
SvrPublicKeyVer uint16
|
||||||
PublicKey []byte
|
PublicKey []byte
|
||||||
PublicKeyVer uint16
|
ShareKey []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
type EncryptSession struct {
|
type EncryptSession struct {
|
||||||
@ -24,65 +22,25 @@ type EncryptSession struct {
|
|||||||
|
|
||||||
const serverPublicKey = "04EBCA94D733E399B2DB96EACDD3F69A8BB0F74224E2B44E3357812211D2E62EFBC91BB553098E25E33A799ADC7F76FEB208DA7C6522CDB0719A305180CC54A82E"
|
const serverPublicKey = "04EBCA94D733E399B2DB96EACDD3F69A8BB0F74224E2B44E3357812211D2E62EFBC91BB553098E25E33A799ADC7F76FEB208DA7C6522CDB0719A305180CC54A82E"
|
||||||
|
|
||||||
func NewEcdh() *EncryptECDH {
|
func NewECDH() *ECDH {
|
||||||
e := &EncryptECDH{
|
e := &ECDH{
|
||||||
PublicKeyVer: 1,
|
SvrPublicKeyVer: 1,
|
||||||
}
|
}
|
||||||
e.generateKey(serverPublicKey)
|
e.generateKey(serverPublicKey)
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *EncryptECDH) generateKey(sPubKey string) {
|
func (e *ECDH) generateKey(sPubKey string) {
|
||||||
pub, err := hex.DecodeString(sPubKey)
|
pub, _ := hex.DecodeString(sPubKey)
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
p256 := elliptic.P256()
|
p256 := elliptic.P256()
|
||||||
key, sx, sy, err := elliptic.GenerateKey(p256, rand.Reader)
|
key, sx, sy, _ := elliptic.GenerateKey(p256, rand.Reader)
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
tx, ty := elliptic.Unmarshal(p256, pub)
|
tx, ty := elliptic.Unmarshal(p256, pub)
|
||||||
x, _ := p256.ScalarMult(tx, ty, key)
|
x, _ := p256.ScalarMult(tx, ty, key)
|
||||||
hash := md5.Sum(x.Bytes()[:16])
|
hash := md5.Sum(x.Bytes()[:16])
|
||||||
e.InitialShareKey = hash[:]
|
e.ShareKey = hash[:]
|
||||||
e.PublicKey = elliptic.Marshal(p256, sx, sy)
|
e.PublicKey = elliptic.Marshal(p256, sx, sy)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *EncryptECDH) Encrypt(d, k []byte) []byte {
|
|
||||||
w := binary.SelectWriter()
|
|
||||||
w.WriteByte(0x02)
|
|
||||||
w.WriteByte(0x01)
|
|
||||||
w.Write(k)
|
|
||||||
w.WriteUInt16(0x01_31)
|
|
||||||
w.WriteUInt16(e.PublicKeyVer)
|
|
||||||
w.WriteUInt16(uint16(len(e.PublicKey)))
|
|
||||||
w.Write(e.PublicKey)
|
|
||||||
w.EncryptAndWrite(e.InitialShareKey, d)
|
|
||||||
return w.Bytes()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *EncryptECDH) ID() byte {
|
|
||||||
return 0x87
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewEncryptSession(t133 []byte) *EncryptSession {
|
|
||||||
return &EncryptSession{T133: t133}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *EncryptSession) Encrypt(d, k []byte) []byte {
|
|
||||||
return binary.NewWriterF(func(w *binary.Writer) {
|
|
||||||
encrypt := binary.NewTeaCipher(k).Encrypt(d)
|
|
||||||
w.WriteUInt16(uint16(len(e.T133)))
|
|
||||||
w.Write(e.T133)
|
|
||||||
w.Write(encrypt)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *EncryptSession) ID() byte {
|
|
||||||
return 69
|
|
||||||
}
|
|
||||||
|
|
||||||
type pubKeyResp struct {
|
type pubKeyResp struct {
|
||||||
Meta struct {
|
Meta struct {
|
||||||
PubKeyVer uint16 `json:"KeyVer"`
|
PubKeyVer uint16 `json:"KeyVer"`
|
||||||
@ -91,7 +49,7 @@ type pubKeyResp struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FetchPubKey 从服务器获取PubKey
|
// FetchPubKey 从服务器获取PubKey
|
||||||
func (e *EncryptECDH) FetchPubKey(uin int64) {
|
func (e *ECDH) FetchPubKey(uin int64) {
|
||||||
resp, err := http.Get("https://keyrotate.qq.com/rotate_key?cipher_suite_ver=305&uin=" + strconv.FormatInt(uin, 10))
|
resp, err := http.Get("https://keyrotate.qq.com/rotate_key?cipher_suite_ver=305&uin=" + strconv.FormatInt(uin, 10))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
@ -102,6 +60,6 @@ func (e *EncryptECDH) FetchPubKey(uin int64) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
e.PublicKeyVer = pubKey.Meta.PubKeyVer
|
e.SvrPublicKeyVer = pubKey.Meta.PubKeyVer
|
||||||
e.generateKey(pubKey.Meta.PubKey) // todo check key sign
|
e.generateKey(pubKey.Meta.PubKey) // todo check key sign
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user