github.com/Mrs4s/MiraiGo@v0.0.0-20240226124653-54bdd873e3fe/client/internal/oicq/ecdh.go (about)

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