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

     1  package oicq
     2  
     3  import (
     4  	"crypto/rand"
     5  	goBinary "encoding/binary"
     6  
     7  	"github.com/pkg/errors"
     8  
     9  	"github.com/Mrs4s/MiraiGo/binary"
    10  )
    11  
    12  type Codec struct {
    13  	ecdh      *session
    14  	randomKey []byte
    15  
    16  	WtSessionTicketKey []byte
    17  }
    18  
    19  func NewCodec(uin int64) *Codec {
    20  	c := &Codec{
    21  		ecdh:      newSession(),
    22  		randomKey: make([]byte, 16),
    23  	}
    24  	rand.Read(c.randomKey)
    25  	c.ecdh.fetchPubKey(uin)
    26  	return c
    27  }
    28  
    29  type EncryptionMethod byte
    30  
    31  const (
    32  	EM_ECDH EncryptionMethod = iota
    33  	EM_ST
    34  )
    35  
    36  type Message struct {
    37  	Uin              uint32
    38  	Command          uint16
    39  	EncryptionMethod EncryptionMethod
    40  	Body             []byte
    41  }
    42  
    43  func (c *Codec) Marshal(m *Message) []byte {
    44  	w := binary.SelectWriter()
    45  	defer binary.PutWriter(w)
    46  
    47  	w.WriteByte(0x02)
    48  	w.WriteUInt16(0)    // len 占位
    49  	w.WriteUInt16(8001) // version?
    50  	w.WriteUInt16(m.Command)
    51  	w.WriteUInt16(1)
    52  	w.WriteUInt32(m.Uin)
    53  	w.WriteByte(0x03)
    54  	switch m.EncryptionMethod {
    55  	case EM_ECDH:
    56  		w.WriteByte(0x87)
    57  	case EM_ST:
    58  		w.WriteByte(0x45)
    59  	}
    60  	w.WriteByte(0)
    61  	w.WriteUInt32(2)
    62  	w.WriteUInt32(0)
    63  	w.WriteUInt32(0)
    64  
    65  	switch m.EncryptionMethod {
    66  	case EM_ECDH:
    67  		w.WriteByte(0x02)
    68  		w.WriteByte(0x01)
    69  		w.Write(c.randomKey)
    70  		w.WriteUInt16(0x01_31)
    71  		w.WriteUInt16(c.ecdh.SvrPublicKeyVer)
    72  		w.WriteUInt16(uint16(len(c.ecdh.PublicKey)))
    73  		w.Write(c.ecdh.PublicKey)
    74  		w.EncryptAndWrite(c.ecdh.ShareKey, m.Body)
    75  
    76  	case EM_ST:
    77  		w.WriteByte(0x01)
    78  		w.WriteByte(0x03)
    79  		w.Write(c.randomKey)
    80  		w.WriteUInt16(0x0102)
    81  		w.WriteUInt16(0x0000)
    82  		w.EncryptAndWrite(c.randomKey, m.Body)
    83  	}
    84  	w.WriteByte(0x03)
    85  
    86  	buf := make([]byte, len(w.Bytes()))
    87  	copy(buf, w.Bytes())
    88  	goBinary.BigEndian.PutUint16(buf[1:3], uint16(len(buf)))
    89  	return buf
    90  }
    91  
    92  var (
    93  	ErrUnknownFlag        = errors.New("unknown flag")
    94  	ErrUnknownEncryptType = errors.New("unknown encrypt type")
    95  )
    96  
    97  func (c *Codec) Unmarshal(data []byte) (*Message, error) {
    98  	reader := binary.NewReader(data)
    99  	if flag := reader.ReadByte(); flag != 2 {
   100  		return nil, ErrUnknownFlag
   101  	}
   102  	m := new(Message)
   103  	reader.ReadUInt16() // len
   104  	reader.ReadUInt16() // version?
   105  	m.Command = reader.ReadUInt16()
   106  	reader.ReadUInt16() // 1?
   107  	m.Uin = uint32(reader.ReadInt32())
   108  	reader.ReadByte()
   109  	encryptType := reader.ReadByte()
   110  	reader.ReadByte()
   111  	switch encryptType {
   112  	case 0:
   113  		d := reader.ReadBytes(reader.Len() - 1)
   114  		defer func() {
   115  			if pan := recover(); pan != nil {
   116  				m.Body = binary.NewTeaCipher(c.randomKey).Decrypt(d)
   117  			}
   118  		}()
   119  		m.Body = binary.NewTeaCipher(c.ecdh.ShareKey).Decrypt(d)
   120  	case 3:
   121  		d := reader.ReadBytes(reader.Len() - 1)
   122  		m.Body = binary.NewTeaCipher(c.WtSessionTicketKey).Decrypt(d)
   123  	default:
   124  		return nil, ErrUnknownEncryptType
   125  	}
   126  	return m, nil
   127  }
   128  
   129  type TLV struct {
   130  	Command uint16
   131  	List    [][]byte
   132  }
   133  
   134  func (t *TLV) Marshal() []byte {
   135  	w := binary.SelectWriter()
   136  	defer binary.PutWriter(w)
   137  
   138  	w.WriteUInt16(t.Command)
   139  	w.WriteUInt16(uint16(len(t.List)))
   140  	for _, elem := range t.List {
   141  		w.Write(elem)
   142  	}
   143  
   144  	return append([]byte(nil), w.Bytes()...)
   145  }
   146  
   147  func (t *TLV) Append(b ...[]byte) {
   148  	t.List = append(t.List, b...)
   149  }