github.com/LagrangeDev/LagrangeGo@v0.0.0-20240512064304-ad4a85e10cb4/client/internal/oicq/ecdh.go (about)

     1  package oicq
     2  
     3  // from https://github.com/Mrs4s/MiraiGo/blob/master/client/internal/oicq/ecdh.go
     4  
     5  import (
     6  	"crypto/ecdh"
     7  	"crypto/md5"
     8  	"crypto/rand"
     9  	"encoding/hex"
    10  	"encoding/json"
    11  	"net/http"
    12  	"strconv"
    13  )
    14  
    15  // session is ecdh session in oicq.
    16  type session struct {
    17  	SvrPublicKeyVer uint16
    18  	PublicKey       []byte
    19  	ShareKey        []byte
    20  }
    21  
    22  const serverPublicKey = "04EBCA94D733E399B2DB96EACDD3F69A8BB0F74224E2B44E3357812211D2E62EFBC91BB553098E25E33A799ADC7F76FEB208DA7C6522CDB0719A305180CC54A82E"
    23  
    24  func newSession() *session {
    25  	e := &session{
    26  		SvrPublicKeyVer: 1,
    27  	}
    28  	key, _ := hex.DecodeString(serverPublicKey)
    29  	e.init(key)
    30  	return e
    31  }
    32  
    33  type pubKeyResp struct {
    34  	Meta struct {
    35  		PubKeyVer uint16 `json:"KeyVer"`
    36  		PubKey    string `json:"PubKey"`
    37  	} `json:"PubKeyMeta"`
    38  }
    39  
    40  // fetchPubKey 从服务器获取PubKey
    41  func (e *session) fetchPubKey(uin int64) {
    42  	resp, err := http.Get("https://keyrotate.qq.com/rotate_key?cipher_suite_ver=305&uin=" + strconv.FormatInt(uin, 10))
    43  	if err != nil {
    44  		return
    45  	}
    46  	defer func() { _ = resp.Body.Close() }()
    47  	pubKey := pubKeyResp{}
    48  	err = json.NewDecoder(resp.Body).Decode(&pubKey)
    49  	if err != nil {
    50  		return
    51  	}
    52  	e.SvrPublicKeyVer = pubKey.Meta.PubKeyVer
    53  	key, _ := hex.DecodeString(pubKey.Meta.PubKey)
    54  	e.init(key) // todo check key sign
    55  }
    56  
    57  func (e *session) init(svrPubKey []byte) {
    58  	p256 := ecdh.P256()
    59  	local, _ := p256.GenerateKey(rand.Reader)
    60  	remote, _ := p256.NewPublicKey(svrPubKey)
    61  	share, _ := local.ECDH(remote)
    62  
    63  	hash := md5.New()
    64  	hash.Write(share[:16])
    65  	e.ShareKey = hash.Sum(nil)
    66  	e.PublicKey = local.PublicKey().Bytes()
    67  }