diff --git a/client/client.go b/client/client.go index 010e26e7..4a8fbed8 100644 --- a/client/client.go +++ b/client/client.go @@ -20,6 +20,7 @@ import ( "github.com/Mrs4s/MiraiGo/binary/jce" "github.com/Mrs4s/MiraiGo/client/pb/msg" "github.com/Mrs4s/MiraiGo/message" + "github.com/Mrs4s/MiraiGo/protocol/crypto" "github.com/Mrs4s/MiraiGo/protocol/packets" "github.com/Mrs4s/MiraiGo/utils" jsoniter "github.com/json-iterator/go" @@ -163,6 +164,7 @@ func NewClient(uin int64, password string) *QQClient { } func NewClientMd5(uin int64, passwordMd5 [16]byte) *QQClient { + crypto.ECDH.FetchPubKey(uin) cli := &QQClient{ Uin: uin, PasswordMd5: passwordMd5, diff --git a/protocol/crypto/crypto.go b/protocol/crypto/crypto.go index 27d58075..bfe7be6e 100644 --- a/protocol/crypto/crypto.go +++ b/protocol/crypto/crypto.go @@ -4,14 +4,18 @@ import ( "crypto/elliptic" "crypto/md5" "crypto/rand" - "math/big" + "encoding/hex" + "net/http" + "strconv" "github.com/Mrs4s/MiraiGo/binary" + jsoniter "github.com/json-iterator/go" ) type EncryptECDH struct { InitialShareKey []byte PublicKey []byte + PublicKeyVer uint16 } type EncryptSession struct { @@ -20,33 +24,28 @@ type EncryptSession struct { var ECDH = &EncryptECDH{} -var tenKeyX = new(big.Int).SetBytes([]byte{ - 0xEB, 0xCA, 0x94, 0xD7, 0x33, 0xE3, 0x99, 0xB2, - 0xDB, 0x96, 0xEA, 0xCD, 0xD3, 0xF6, 0x9A, 0x8B, - 0xB0, 0xF7, 0x42, 0x24, 0xE2, 0xB4, 0x4E, 0x33, - 0x57, 0x81, 0x22, 0x11, 0xD2, 0xE6, 0x2E, 0xFB, -}) - -var tenKeyY = new(big.Int).SetBytes([]byte{ - 0xC9, 0x1B, 0xB5, 0x53, 0x09, 0x8E, 0x25, 0xE3, - 0x3A, 0x79, 0x9A, 0xDC, 0x7F, 0x76, 0xFE, 0xB2, - 0x08, 0xDA, 0x7C, 0x65, 0x22, 0xCD, 0xB0, 0x71, - 0x9A, 0x30, 0x51, 0x80, 0xCC, 0x54, 0xA8, 0x2E, -}) +const serverPublicKey = "04EBCA94D733E399B2DB96EACDD3F69A8BB0F74224E2B44E3357812211D2E62EFBC91BB553098E25E33A799ADC7F76FEB208DA7C6522CDB0719A305180CC54A82E" func init() { + ECDH.PublicKeyVer = 1 + ECDH.generateKey(serverPublicKey) +} + +func (e *EncryptECDH) generateKey(sPubKey string) { + pub, err := hex.DecodeString(sPubKey) + if err != nil { + panic(err) + } p256 := elliptic.P256() key, sx, sy, err := elliptic.GenerateKey(p256, rand.Reader) if err != nil { - panic("Can't Create ECDH key pair") + panic(err) } - x, _ := p256.ScalarMult(tenKeyX, tenKeyY, key) + tx, ty := elliptic.Unmarshal(p256, pub) + x, _ := p256.ScalarMult(tx, ty, key) hash := md5.Sum(x.Bytes()[:16]) - ECDH.InitialShareKey = hash[:] - ECDH.PublicKey = make([]byte, 65)[:0] - ECDH.PublicKey = append(ECDH.PublicKey, 0x04) - ECDH.PublicKey = append(ECDH.PublicKey, sx.Bytes()...) - ECDH.PublicKey = append(ECDH.PublicKey, sy.Bytes()...) + e.InitialShareKey = hash[:] + e.PublicKey = elliptic.Marshal(p256, sx, sy) } func (e *EncryptECDH) DoEncrypt(d, k []byte) []byte { @@ -55,7 +54,7 @@ func (e *EncryptECDH) DoEncrypt(d, k []byte) []byte { w.WriteByte(0x01) w.Write(k) w.WriteUInt16(0x01_31) - w.WriteUInt16(0x00_01) + w.WriteUInt16(e.PublicKeyVer) w.WriteUInt16(uint16(len(ECDH.PublicKey))) w.Write(ECDH.PublicKey) w.EncryptAndWrite(ECDH.InitialShareKey, d) @@ -82,3 +81,26 @@ func (e *EncryptSession) DoEncrypt(d, k []byte) []byte { func (e *EncryptSession) Id() byte { return 69 } + +type pubKeyResp struct { + Meta struct { + PubKeyVer uint16 `json:"KeyVer"` + PubKey string `json:"PubKey"` + } `json:"PubKeyMeta"` +} + +// FetchPubKey 从服务器获取PubKey +func (e *EncryptECDH) FetchPubKey(uin int64) { + resp, err := http.Get("https://keyrotate.qq.com/rotate_key?cipher_suite_ver=305&uin=" + strconv.FormatInt(uin, 10)) + if err != nil { + return + } + defer resp.Body.Close() + var pubKey = pubKeyResp{} + err = jsoniter.NewDecoder(resp.Body).Decode(&pubKey) + if err != nil { + return + } + e.PublicKeyVer = pubKey.Meta.PubKeyVer + e.generateKey(pubKey.Meta.PubKey) // todo check key sign +}