first commit

This commit is contained in:
2026-02-17 13:06:23 +08:00
commit 7cbd3d061d
349 changed files with 126558 additions and 0 deletions

117
clientsdk/mmtls/mmcrypto.go Normal file
View File

@@ -0,0 +1,117 @@
package mmtls
import (
"crypto/aes"
"crypto/cipher"
"crypto/ecdsa"
"crypto/hmac"
"crypto/sha256"
"crypto/x509"
"encoding/asn1"
"encoding/pem"
"xiawan/wx/clientsdk/baseutils"
)
var verifyPubKey = []byte(`-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE8uOhBSSfVijKin+SZO/0IXUrmf8l
9sa7VgqOIH/AO3Xb1MF4Xm25bBSb5znHsknQsNPSye3vVo80NUi2gEHw8g==
-----END PUBLIC KEY-----`)
// Sha256 Sha256
func Sha256(data []byte) []byte {
hash256 := sha256.New()
hash256.Write(data)
hashRet := hash256.Sum(nil)
return hashRet
}
// HmacHash256 HmacHash256
func HmacHash256(key []byte, data []byte) []byte {
hmacTool := hmac.New(sha256.New, key)
hmacTool.Write(data)
return hmacTool.Sum(nil)
}
// HkdfExpand HkdfExpand
func HkdfExpand(key, message []byte, outLen int) []byte {
result := make([]byte, 0)
count := outLen / 32
if outLen%32 != 0 {
count = count + 1
}
for i := 1; i <= count; i++ {
h := hmac.New(sha256.New, key)
tmp := append(message, byte(i))
tmp = append(result, tmp...)
h.Write(tmp)
result = append(result, h.Sum(nil)...)
}
return result[:outLen]
}
// AesGcmEncrypt AesGcmEncrypt
func AesGcmEncrypt(key, nonce, aad, data []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return []byte{}, err
}
aesgcm, err := cipher.NewGCM(block)
if err != nil {
return []byte{}, nil
}
ciphertext := aesgcm.Seal(nil, nonce, data, aad)
return ciphertext, nil
}
// AesGcmDecrypt AesGcmDecrypt
func AesGcmDecrypt(key, nonce, aad, data []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
aesgcm, err := cipher.NewGCM(block)
if err != nil {
return nil, err
}
plain, err := aesgcm.Open(nil, nonce, data, aad)
if err != nil {
return nil, err
}
return plain, nil
}
// GetNonce GetNonce
func GetNonce(data []byte, seq uint32) []byte {
ret := make([]byte, len(data))
copy(ret, data)
seqBytes := baseutils.Int32ToBytes(seq)
baseOffset := 8
for index := 0; index < 4; index++ {
ret[baseOffset+index] = ret[baseOffset+index] ^ byte(seqBytes[index])
}
return ret
}
// ECDSAVerifyData 校验服务端握手数据
func ECDSAVerifyData(message []byte, signature []byte) (bool, error) {
block, _ := pem.Decode(verifyPubKey)
publicStream, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
return false, err
}
//接口转换成公钥
publicKey := publicStream.(*ecdsa.PublicKey)
// 反序列化ecdsaSignature
ecdsaSignature := &EcdsaSignature{}
_, err = asn1.Unmarshal(signature, ecdsaSignature)
if err != nil {
return false, err
}
flag := ecdsa.Verify(publicKey, Sha256(message), ecdsaSignature.R, ecdsaSignature.S)
return flag, nil
}

View File

@@ -0,0 +1,271 @@
package mmtls
import (
"xiawan/wx/clientsdk/baseutils"
)
// RecordHeadSerialize 序列化RecordHead
func RecordHeadSerialize(recordHead *RecordHead) []byte {
retBytes := make([]byte, 0)
// Type
retBytes = append(retBytes, recordHead.Type)
// Tag
retBytes = append(retBytes, baseutils.Int16ToBytesBigEndian(recordHead.Tag)[0:]...)
// size
retBytes = append(retBytes, baseutils.Int16ToBytesBigEndian(recordHead.Size)[0:]...)
return retBytes
}
// ClientHelloSerialize 序列化ClientHello
func ClientHelloSerialize(clientHello *ClientHello) []byte {
bodyData := make([]byte, 0)
// Type
bodyData = append(bodyData, ClientHelloType)
// Version
bodyData = append(bodyData, baseutils.Int16ToBytesLittleEndian(clientHello.Version)[0:]...)
// suiteCount
suiteCount := byte(len(clientHello.CipherSuiteList))
bodyData = append(bodyData, suiteCount)
// suiteList
suiteList := clientHello.CipherSuiteList
for index := 0; index < int(suiteCount); index++ {
// suiteCode
bodyData = append(bodyData, baseutils.Int16ToBytesBigEndian(suiteList[index].SuiteCode)[0:]...)
}
// RandomBytes
bodyData = append(bodyData, clientHello.RandomBytes[0:]...)
// ClientGmtTime
bodyData = append(bodyData, baseutils.Int32ToBytes(clientHello.ClientGmtTime)[0:]...)
// Extensions
extensionsData := ExtensionsSerialize(clientHello.ExtensionList)
bodyData = append(bodyData, extensionsData[0:]...)
// 返回数据
retBytes := make([]byte, 0)
totalLength := uint32(len(bodyData))
retBytes = append(retBytes, baseutils.Int32ToBytes(totalLength)[0:]...)
retBytes = append(retBytes, bodyData[0:]...)
return retBytes
}
// ExtensionsSerialize 序列化Extensions
func ExtensionsSerialize(extensionList []*Extension) []byte {
retBytes := make([]byte, 0)
// bodyData
bodyData := make([]byte, 0)
// MapSize
extensionCount := byte(len(extensionList))
bodyData = append(bodyData, extensionCount)
for index := 0; index < int(extensionCount); index++ {
// Extension TotalLength
extensionLength := uint32(len(extensionList[index].ExtensionData))
bodyData = append(bodyData, baseutils.Int32ToBytes(extensionLength)[0:]...)
// extensionData
bodyData = append(bodyData, extensionList[index].ExtensionData[0:]...)
}
// Extensions Size
extensionsSize := uint32(len(bodyData))
retBytes = append(retBytes, baseutils.Int32ToBytes(extensionsSize)[0:]...)
// ExtensionsData
retBytes = append(retBytes, bodyData[0:]...)
return retBytes
}
// PskSerialize 序列化Psk
func PskSerialize(psk *Psk) []byte {
// BodyData
bodyData := make([]byte, 0)
// Type
bodyData = append(bodyData, psk.Type)
// TicketLifeTimeHint
bodyData = append(bodyData, baseutils.Int32ToBytes(psk.TicketKLifeTimeHint)[0:]...)
// MacValue
macValueLen := uint16(len(psk.MacValue))
bodyData = append(bodyData, baseutils.Int16ToBytesBigEndian(macValueLen)[0:]...)
bodyData = append(bodyData, psk.MacValue[0:]...)
// KeyVersion
bodyData = append(bodyData, baseutils.Int32ToBytes(psk.KeyVersion)[0:]...)
// IV
ivLen := uint16(len(psk.Iv))
bodyData = append(bodyData, baseutils.Int16ToBytesBigEndian(ivLen)[0:]...)
bodyData = append(bodyData, psk.Iv[0:]...)
// EncryptTicket
encryptTicketLen := uint16(len(psk.EncryptedTicket))
bodyData = append(bodyData, baseutils.Int16ToBytesBigEndian(encryptTicketLen)[0:]...)
bodyData = append(bodyData, psk.EncryptedTicket[0:]...)
// 返回数据
retBytes := make([]byte, 0)
bodyLen := uint32(len(bodyData))
retBytes = append(retBytes, baseutils.Int32ToBytes(bodyLen)[0:]...)
retBytes = append(retBytes, bodyData[0:]...)
return retBytes
}
// ClientKeyOfferSerialize 序列化ClientKeyOffer
func ClientKeyOfferSerialize(clientKeyOffer *ClientKeyOffer) []byte {
// BodyData
bodyData := make([]byte, 0)
// Version
bodyData = append(bodyData, baseutils.Int32ToBytes(clientKeyOffer.Version)[0:]...)
// PublicValue
publicValueLen := uint16(len(clientKeyOffer.PublicValue))
bodyData = append(bodyData, baseutils.Int16ToBytesBigEndian(publicValueLen)[0:]...)
if publicValueLen > 0 {
bodyData = append(bodyData, clientKeyOffer.PublicValue[0:]...)
}
// 返回数据
retBytes := make([]byte, 0)
bodyDataLen := uint32(len(bodyData))
retBytes = append(retBytes, baseutils.Int32ToBytes(bodyDataLen)[0:]...)
retBytes = append(retBytes, bodyData[0:]...)
return retBytes
}
// EncryptedExtensionsSerialize 序列化EncryptedExtensions
func EncryptedExtensionsSerialize(encryptedExtensions *EncryptedExtensions) []byte {
bodyData := make([]byte, 0)
// Type
bodyData = append(bodyData, EncryptedExtensionsType)
// ExtensionList
extensionsData := ExtensionsSerialize(encryptedExtensions.ExtensionList)
bodyData = append(bodyData, extensionsData[0:]...)
// 返回数据
retBytes := make([]byte, 0)
bodyDataLen := uint32(len(bodyData))
retBytes = append(retBytes, baseutils.Int32ToBytes(bodyDataLen)[0:]...)
retBytes = append(retBytes, bodyData[0:]...)
return retBytes
}
// HTTPHandlerSerialize 序列化HTTPHandler
func HTTPHandlerSerialize(httpHandler *HTTPHandler) []byte {
bodyData := make([]byte, 0)
// URL
urlLength := uint16(len(httpHandler.URL))
bodyData = append(bodyData, baseutils.Int16ToBytesBigEndian(urlLength)[0:]...)
bodyData = append(bodyData, []byte(httpHandler.URL)[0:]...)
// Host
hostLength := uint16(len(httpHandler.Host))
bodyData = append(bodyData, baseutils.Int16ToBytesBigEndian(hostLength)[0:]...)
bodyData = append(bodyData, []byte(httpHandler.Host)[0:]...)
// MMPkg
mmpkgLength := uint32(len(httpHandler.MMPkg))
bodyData = append(bodyData, baseutils.Int32ToBytes(mmpkgLength)[0:]...)
bodyData = append(bodyData, httpHandler.MMPkg[0:]...)
// 返回数据
retBytes := make([]byte, 0)
bodyDataLen := uint32(len(bodyData))
retBytes = append(retBytes, baseutils.Int32ToBytes(bodyDataLen)[0:]...)
retBytes = append(retBytes, bodyData[0:]...)
return retBytes
}
// FinishedSerialize 序列化Finished包
func FinishedSerialize(finished *Finished) []byte {
bodyData := make([]byte, 0)
// Type
bodyData = append(bodyData, FinishedType)
// VerifyData
verifyDataLen := uint16(uint32(len(finished.VerifyData)))
bodyData = append(bodyData, baseutils.Int16ToBytesBigEndian(verifyDataLen)[0:]...)
bodyData = append(bodyData, finished.VerifyData[0:]...)
// 返回数据
retBytes := make([]byte, 0)
bodyDataLen := uint32(len(bodyData))
retBytes = append(retBytes, baseutils.Int32ToBytes(bodyDataLen)[0:]...)
retBytes = append(retBytes, bodyData[0:]...)
return retBytes
}
// --------------- 各类Extension的序列化 ---------------
// PreSharedKeyExtensionSerialize 序列化PreSharedKeyExtension
func PreSharedKeyExtensionSerialize(preSharedKeyExtension *PreSharedKeyExtension) *Extension {
// ExtensionBytes
extensionBytes := make([]byte, 0)
// PreSharedKeyExtensionType
extensionBytes = append(extensionBytes, baseutils.Int16ToBytesBigEndian(PreSharedKeyExtensionType)[0:]...)
// pskCount
pskCount := byte(len(preSharedKeyExtension.PskList))
extensionBytes = append(extensionBytes, pskCount)
// PskList
for index := 0; index < int(pskCount); index++ {
psk := preSharedKeyExtension.PskList[index]
pskData := PskSerialize(psk)
extensionBytes = append(extensionBytes, pskData[0:]...)
}
// 返回数据
retExtension := &Extension{}
retExtension.ExtensionType = PreSharedKeyExtensionType
retExtension.ExtensionData = extensionBytes
return retExtension
}
// ClientKeyShareExtensionSerialize 序列化ClientKeyShareExtension
func ClientKeyShareExtensionSerialize(clientKeyShareExtension *ClientKeyShareExtension) *Extension {
// ExtensionBytes
extensionBytes := make([]byte, 0)
// ClientKeyShareType
extensionBytes = append(extensionBytes, baseutils.Int16ToBytesBigEndian(ClientKeyShareType)[0:]...)
// KeyOfferCount
keyOfferCount := byte(len(clientKeyShareExtension.ClientKeyOfferList))
extensionBytes = append(extensionBytes, keyOfferCount)
// KeyOfferList
for index := 0; index < int(keyOfferCount); index++ {
keyOffer := clientKeyShareExtension.ClientKeyOfferList[index]
keyOfferData := ClientKeyOfferSerialize(keyOffer)
extensionBytes = append(extensionBytes, keyOfferData[0:]...)
}
// CertificateVersion
extensionBytes = append(extensionBytes, baseutils.Int32ToBytes(clientKeyShareExtension.CertificateVersion)[0:]...)
// 返回数据
retExtension := &Extension{}
retExtension.ExtensionType = ClientKeyShareType
retExtension.ExtensionData = extensionBytes
return retExtension
}
// EarlyEncryptDataExtensionSerialize 序列化EarlyEncryptDataExtension
func EarlyEncryptDataExtensionSerialize(earlyEncryptDataExtension *EarlyEncryptDataExtension) *Extension {
// ExtensionBytes
extensionBytes := make([]byte, 0)
// ClientKeyShareType
extensionBytes = append(extensionBytes, baseutils.Int16ToBytesBigEndian(EarlyEncryptDataType)[0:]...)
// ClientGmtTime
extensionBytes = append(extensionBytes, baseutils.Int32ToBytes(earlyEncryptDataExtension.ClientGmtTime)[0:]...)
// 返回数据
retExtension := &Extension{}
retExtension.ExtensionType = EarlyEncryptDataType
retExtension.ExtensionData = extensionBytes
return retExtension
}
// LongPackHeaderInfoSerialize 序列化LongPackHeaderInfo
func LongPackHeaderInfoSerialize(packTagInfo *LongPackHeaderInfo) []byte {
retBytes := make([]byte, 0)
// Type
retBytes = append(retBytes, baseutils.Int16ToBytesBigEndian(packTagInfo.HeaderLen)[0:]...)
// Version
retBytes = append(retBytes, baseutils.Int16ToBytesBigEndian(packTagInfo.Version)[0:]...)
// Operation
retBytes = append(retBytes, baseutils.Int32ToBytes(packTagInfo.Operation)[0:]...)
// SequenceNumber
retBytes = append(retBytes, baseutils.Int32ToBytes(packTagInfo.SequenceNumber)[0:]...)
return retBytes
}

View File

@@ -0,0 +1,555 @@
package mmtls
import (
"errors"
"xiawan/wx/clientsdk/baseutils"
)
// DataPackerDeserialize 反序列化数据
func DataPackerDeserialize(data []byte) {
totalLength := uint32(len(data))
current := uint32(0)
for current < totalLength {
// recordHead
recordHead := RecordHeadDeSerialize(data[current:])
baseutils.ShowObjectValue(recordHead)
current = current + 5
offset := uint32(0)
// tmpType
pkgSize := baseutils.BytesToInt32(data[current+offset : current+offset+4])
offset = offset + 4
tmpType := data[current+offset]
// ClientHelloType
if tmpType == ClientHelloType {
clientHello, _ := ClientHelloDeSerialize(data[current+offset : current+offset+pkgSize])
baseutils.ShowObjectValue(clientHello)
ShowMMTLSExtensions(clientHello.ExtensionList)
}
// ServerHelloType
if tmpType == ServerHelloType {
serverHello, _ := ServerHelloDeSerialize(data[current+offset : current+offset+pkgSize])
baseutils.ShowObjectValue(serverHello)
ShowMMTLSExtensions(serverHello.ExtensionList)
}
offset = offset + pkgSize
current = current + offset
}
}
// GetCipherSuiteInfoByCode 返回code对应的 CipherSuiteInfo
func GetCipherSuiteInfoByCode(code uint16) *CipherSuite {
if code == 0xc02b {
cipherSuite := &CipherSuite{}
// SuiteCode
cipherSuite.SuiteCode = code
// cipherSuiteInfo
cipherSuiteInfo := &CipherSuiteInfo{}
cipherSuiteInfo.SuiteCode = code
cipherSuiteInfo.Clipher1 = "ECDHE"
cipherSuiteInfo.Clipher2 = "ECDSA"
cipherSuiteInfo.Clipher3 = "SHA256"
cipherSuiteInfo.Clipher4 = "AES_128_GCM"
cipherSuiteInfo.Clipher5 = "AEAD"
cipherSuiteInfo.Length1 = 16
cipherSuiteInfo.Length2 = 0
cipherSuiteInfo.Length3 = 12
cipherSuite.SuiteInfo = cipherSuiteInfo
return cipherSuite
}
if code == 0x00a8 {
cipherSuite := &CipherSuite{}
// SuiteCode
cipherSuite.SuiteCode = code
// cipherSuiteInfo
cipherSuiteInfo := &CipherSuiteInfo{}
cipherSuiteInfo.SuiteCode = code
cipherSuiteInfo.Clipher1 = "PSK"
cipherSuiteInfo.Clipher2 = "ECDSA"
cipherSuiteInfo.Clipher3 = "SHA256"
cipherSuiteInfo.Clipher4 = "AES_128_GCM"
cipherSuiteInfo.Clipher5 = "AEAD"
cipherSuiteInfo.Length1 = 16
cipherSuiteInfo.Length2 = 0
cipherSuiteInfo.Length3 = 12
cipherSuite.SuiteInfo = cipherSuiteInfo
return cipherSuite
}
return nil
}
// RecordHeadDeSerialize 反序列化RecordHead
func RecordHeadDeSerialize(data []byte) *RecordHead {
retRecordHead := &RecordHead{}
// 偏移
current := uint32(0)
// Type
retRecordHead.Type = data[current]
current = current + 1
// Tag
retRecordHead.Tag = baseutils.BytesToUint16BigEndian(data[current : current+2])
current = current + 2
// Size
retRecordHead.Size = baseutils.BytesToUint16BigEndian(data[current : current+2])
return retRecordHead
}
// ClientHelloDeSerialize 反序列化ClientHello
func ClientHelloDeSerialize(data []byte) (*ClientHello, error) {
current := uint32(0)
clientHello := &ClientHello{}
tmptype := data[current]
if tmptype != ClientHelloType {
return nil, errors.New("ClientHelloDeSerialize err: not ClientHelloType")
}
current = current + 1
// Version
clientHello.Version = baseutils.BytesToUint16LittleEndian(data[current : current+2])
current = current + 2
// ciphersuiteSize
ciphersuiteSize := data[current]
current = current + 1
// CipherSuiteList
clientHello.CipherSuiteList = make([]*CipherSuite, ciphersuiteSize)
for index := 0; index < int(ciphersuiteSize); index++ {
suitecode := baseutils.BytesToUint16BigEndian(data[current : current+2])
current = current + 2
clientHello.CipherSuiteList[index] = GetCipherSuiteInfoByCode(suitecode)
}
// RandomBytes
clientHello.RandomBytes = data[current : current+32]
current = current + 32
// ClientGmtTime
clientHello.ClientGmtTime = baseutils.BytesToInt32(data[current : current+4])
current = current + 4
// ExtensionList
clientHello.ExtensionList = ExtensionsDeSerialize(data[current:])
return clientHello, nil
}
// ExtensionsDeSerialize 反序列号Extensions
func ExtensionsDeSerialize(data []byte) []*Extension {
// 初始化返回数组
retExtensions := make([]*Extension, 0)
// 初始化索引
current := uint32(0)
// totalLength
totalLength := baseutils.BytesToInt32(data[current : current+4])
current = current + 4
// extensionCount := data[current]
current = current + 1
// ExtensionList
for current-4 < totalLength {
extension := &Extension{}
// ExtensionData
extensionLength := baseutils.BytesToInt32(data[current : current+4])
current = current + 4
// ExtensionType
extension.ExtensionType = baseutils.BytesToUint16BigEndian(data[current : current+2])
// ExtensionData
extension.ExtensionData = data[current : current+extensionLength]
// 放入列表
retExtensions = append(retExtensions, extension)
current = current + extensionLength
}
return retExtensions
}
// PskDeSerialize 反序列化Psk
func PskDeSerialize(data []byte) (*Psk, error) {
tmpPsk := &Psk{}
// current
current := uint32(0)
// Type
tmpPsk.Type = data[current]
current = current + 1
// TicketKLifeTimeHint
tmpPsk.TicketKLifeTimeHint = baseutils.BytesToInt32(data[current : current+4])
current = current + 4
// MacValue
macValueLength := uint32(baseutils.BytesToUint16BigEndian(data[current : current+2]))
current = current + 2
tmpPsk.MacValue = data[current : current+macValueLength]
current = current + macValueLength
// KeyVersion
tmpPsk.KeyVersion = baseutils.BytesToInt32(data[current : current+4])
current = current + 4
// IV
ivLength := uint32(baseutils.BytesToUint16BigEndian(data[current : current+2]))
current = current + 2
tmpPsk.Iv = data[current : current+ivLength]
current = current + ivLength
// EncryptedTicket
encryptedTicketLength := uint32(baseutils.BytesToUint16BigEndian(data[current : current+2]))
current = current + 2
tmpPsk.EncryptedTicket = data[current : current+encryptedTicketLength]
current = current + encryptedTicketLength
if current != uint32(len(data)) {
return nil, errors.New("PskDeSerialize err: current - startPos != pskTotalLength")
}
return tmpPsk, nil
}
// EncryptedExtensionsDeSerialize 反序列化EncryptedExtensions
func EncryptedExtensionsDeSerialize(data []byte) (*EncryptedExtensions, error) {
current := uint32(0)
retEncryptedExtensions := &EncryptedExtensions{}
// Type
tmptype := data[current]
if tmptype != EncryptedExtensionsType {
return nil, errors.New("EncryptedExtensionsDeSerialize err: not ServerHelloType")
}
current = current + 1
// ExtensionList
retEncryptedExtensions.ExtensionList = ExtensionsDeSerialize(data[current:])
return retEncryptedExtensions, nil
}
// ServerHelloDeSerialize 反序列化ServerHello
func ServerHelloDeSerialize(data []byte) (*ServerHello, error) {
current := uint32(0)
serverHello := &ServerHello{}
tmptype := data[current]
if tmptype != ServerHelloType {
return nil, errors.New("ServerHelloDeSerialize err: not ServerHelloType")
}
current = current + 1
// Version
serverHello.Version = baseutils.BytesToUint16LittleEndian(data[current : current+2])
current = current + 2
// CipherSuite
suiteCode := baseutils.BytesToUint16BigEndian(data[current : current+2])
current = current + 2
serverHello.CipherSuite = GetCipherSuiteInfoByCode(suiteCode)
// RandomBytes
serverHello.RandomBytes = data[current : current+32]
current = current + 32
// ExtensionList
serverHello.ExtensionList = ExtensionsDeSerialize(data[current:])
return serverHello, nil
}
// NewSessionTicketDeSerialize 反序列化NewSessionTicket
func NewSessionTicketDeSerialize(data []byte) (*NewSessionTicket, error) {
retNewSessionTicket := &NewSessionTicket{}
// current
current := uint32(0)
// tmpType
tmpType := data[current]
if tmpType != NewSessionTicketType {
return nil, errors.New("NewSessionTicketDeSerialize err: not NewSessionTicketType")
}
current = current + 1
// pskListSize
pskListSize := data[current]
current = current + 1
// PskList
retNewSessionTicket.PskList = make([]*Psk, pskListSize)
for index := 0; index < int(pskListSize); index++ {
// pskTotalLength
pskTotalLength := baseutils.BytesToInt32(data[current : current+4])
current = current + 4
// PskDeSerialize
retPsk, err := PskDeSerialize(data[current : current+pskTotalLength])
if err != nil {
return nil, err
}
// Add to PskList
retNewSessionTicket.PskList[index] = retPsk
current = current + pskTotalLength
}
return retNewSessionTicket, nil
}
// CertificateVerifyDeSerialize CertificateVerifyDeSerialize
func CertificateVerifyDeSerialize(data []byte) (*CertificateVerify, error) {
retCertificateVerify := &CertificateVerify{}
// current
current := uint32(0)
// tmpType
tmpType := data[current]
if tmpType != CertificateVerifyType {
return nil, errors.New("CertificateVerifyDeSerialize err: not CertificateVerifyType")
}
current = current + 1
// SignatureSize
size := uint32(baseutils.BytesToUint16BigEndian(data[current : current+2]))
current = current + 2
// Signature
retCertificateVerify.Signature = data[current : current+size]
current = current + size
// 判断数据是否完整解析
if current != uint32(len(data)) {
return nil, errors.New("CertificateVerifyDeSerialize err: current != uint32(len(data)")
}
return retCertificateVerify, nil
}
// HTTPHandlerDeSerialize 反序列化HttpHandler
func HTTPHandlerDeSerialize(data []byte) (*HTTPHandler, error) {
retHTTPHandler := &HTTPHandler{}
current := 0
// URL
urlLength := int(baseutils.BytesToUint16BigEndian(data[current : current+2]))
current = current + 2
if urlLength > 0 {
retHTTPHandler.URL = string(data[current : current+urlLength])
current = current + int(urlLength)
}
// Host
hostLength := int(baseutils.BytesToUint16BigEndian(data[current : current+2]))
current = current + 2
if urlLength > 0 {
retHTTPHandler.Host = string(data[current : current+hostLength])
current = current + int(hostLength)
}
// MMPkg
mmpkgLength := int(baseutils.BytesToInt32(data[current : current+4]))
current = current + 4
if mmpkgLength > 0 {
retHTTPHandler.MMPkg = data[current : current+int(mmpkgLength)]
current = current + mmpkgLength
}
// 判断数据是否正常完整解析
if current != len(data) {
return nil, errors.New("HTTPHandlerDeSerialize err: current != len(data)")
}
return retHTTPHandler, nil
}
// FinishedDeSerialize 反序列化 Finished
func FinishedDeSerialize(data []byte) (*Finished, error) {
retFinished := &Finished{}
// current
current := uint32(0)
// tmpType
tmpType := data[current]
if tmpType != FinishedType {
return nil, errors.New("FinishedDeSerialize err: not FinishedType")
}
current = current + 1
// VerifyData
verifyDataLen := uint32(baseutils.BytesToUint16BigEndian(data[current : current+2]))
current = current + 2
retFinished.VerifyData = data[current : current+verifyDataLen]
current = current + verifyDataLen
// 判断数据是否完整解析
if current != uint32(len(data)) {
return nil, errors.New("FinishedDeSerialize err: current != uint32(len(data)")
}
return retFinished, nil
}
// ------------------ 各类Extension反序列化 ------------------
// PreSharedKeyExtensionDeSerialize 反序列化PreSharedKeyExtension
func PreSharedKeyExtensionDeSerialize(data []byte) (*PreSharedKeyExtension, error) {
retPreSharedKeyExtensions := &PreSharedKeyExtension{}
current := uint32(0)
tmpType := baseutils.BytesToUint16BigEndian(data[current : current+2])
if tmpType != PreSharedKeyExtensionType {
return nil, errors.New("PreSharedKeyExtensionDeSerialize err: not PreSharedKeyExtensionType")
}
current = current + 2
// pskCount
pskCount := data[current]
current = current + 1
// PskList
retPreSharedKeyExtensions.PskList = make([]*Psk, pskCount)
for index := 0; index < int(pskCount); index++ {
// pskTotalLength
pskTotalLength := baseutils.BytesToInt32(data[current : current+4])
current = current + 4
// PskDeSerialize
retPsk, err := PskDeSerialize(data[current : current+pskTotalLength])
if err != nil {
return nil, err
}
// Add to PskList
retPreSharedKeyExtensions.PskList[index] = retPsk
current = current + pskTotalLength
}
return retPreSharedKeyExtensions, nil
}
// ClientKeyShareExtensionDeSerialize 解析ClientKeyShareExtension
func ClientKeyShareExtensionDeSerialize(data []byte) (*ClientKeyShareExtension, error) {
retClientKeyShareExtension := &ClientKeyShareExtension{}
current := uint32(0)
tmpType := baseutils.BytesToUint16BigEndian(data[current : current+2])
if tmpType != ClientKeyShareType {
return nil, errors.New("ClientKeyShareExtensionDeSerialize err: tmpType != ClientKeyShareType")
}
current = current + 2
// clientKeyOfferCount
clientKeyOfferCount := data[current]
current = current + 1
retClientKeyShareExtension.ClientKeyOfferList = make([]*ClientKeyOffer, clientKeyOfferCount)
// ClientKeyOfferList
for index := 0; index < int(clientKeyOfferCount); index++ {
clientKeyOffer := &ClientKeyOffer{}
clientKeyOfferTotalLength := baseutils.BytesToInt32(data[current : current+4])
current = current + 4
startPos := current
// Version
clientKeyOffer.Version = baseutils.BytesToInt32(data[current : current+4])
current = current + 4
// PublicValue
publicValueSize := uint32(baseutils.BytesToUint16BigEndian(data[current : current+2]))
current = current + 2
clientKeyOffer.PublicValue = data[current : current+publicValueSize]
current = current + publicValueSize
if current-startPos != clientKeyOfferTotalLength {
return nil, errors.New("ClientKeyShareExtensionDeSerialize err: current - startPos != clientKeyOfferTotalLength")
}
retClientKeyShareExtension.ClientKeyOfferList[index] = clientKeyOffer
}
// CertificateVersion
retClientKeyShareExtension.CertificateVersion = baseutils.BytesToInt32(data[current : current+4])
return retClientKeyShareExtension, nil
}
// ServerKeyShareExtensionDeSerialize 反序列化ServerKeyShareExtension
func ServerKeyShareExtensionDeSerialize(data []byte) (*ServerKeyShareExtension, error) {
retServerKeyShareExtension := &ServerKeyShareExtension{}
// 索引
current := uint32(0)
// tmpType
tmpType := baseutils.BytesToUint16BigEndian(data[current : current+2])
if tmpType != ServerKeyShareType {
return nil, errors.New("ServerKeyShareExtensionDeSerialize err: tmpType != ServerKeyShareType")
}
current = current + 2
// KeyOfferNameGroup
retServerKeyShareExtension.KeyOfferNameGroup = baseutils.BytesToInt32(data[current : current+4])
current = current + 4
// PublicValue
publicValueSize := uint32(baseutils.BytesToUint16BigEndian(data[current : current+2]))
current = current + 2
retServerKeyShareExtension.PublicValue = data[current : current+publicValueSize]
return retServerKeyShareExtension, nil
}
// EarlyEncryptedDataExtensionDeSerialize 反序列化EarlyEncryptedDataExtension
func EarlyEncryptedDataExtensionDeSerialize(data []byte) (*EarlyEncryptDataExtension, error) {
retEarlyEncryptDataExtension := &EarlyEncryptDataExtension{}
// 索引
current := uint32(0)
// Type
tmpType := baseutils.BytesToUint16BigEndian(data[current : current+2])
if tmpType != EarlyEncryptDataType {
return nil, errors.New("EarlyEncryptedDataExtensionDeSerialize err: tmpType != EarlyEncryptDataType")
}
current = current + 2
// ClientGmtTime
retEarlyEncryptDataExtension.ClientGmtTime = baseutils.BytesToInt32(data[current : current+4])
return retEarlyEncryptDataExtension, nil
}
// LongPackHeaderInfoDeSerialize 序列化LongPackHeaderInfo
func LongPackHeaderInfoDeSerialize(data []byte) (*LongPackHeaderInfo, error) {
retLongPackHeaderInfo := &LongPackHeaderInfo{}
current := 0
// HeaderLen
retLongPackHeaderInfo.HeaderLen = baseutils.BytesToUint16BigEndian(data[current : current+2])
current = current + 2
// Version
retLongPackHeaderInfo.Version = baseutils.BytesToUint16BigEndian(data[current : current+2])
current = current + 2
// Operation
retLongPackHeaderInfo.Operation = baseutils.BytesToInt32(data[current : current+4])
current = current + 4
// SequenceNumber
retLongPackHeaderInfo.SequenceNumber = baseutils.BytesToInt32(data[current : current+4])
current = current + 4
if current != len(data) {
return retLongPackHeaderInfo, errors.New("LongPackHeaderInfoDeSerialize err: current != len(data)")
}
return retLongPackHeaderInfo, nil
}

135
clientsdk/mmtls/mmhttp.go Normal file
View File

@@ -0,0 +1,135 @@
package mmtls
import (
"bytes"
"io/ioutil"
"net"
"net/http"
"time"
"xiawan/wx/clientsdk/baseutils"
)
// MMHTTPPost mmtls方式发送数据包
func MMHTTPPost(mmInfo *MMInfo, data []byte) ([]byte, error) {
requestURL := "http://" + mmInfo.ShortHost + mmInfo.ShortURL
request, err := http.NewRequest("POST", requestURL, bytes.NewReader(data))
if err != nil {
return nil, err
}
request.Header.Add("UserAgent", "MicroMessenger Client")
request.Header.Add("Accept", "*/*")
request.Header.Add("Cache-Control", "no-cache")
request.Header.Add("Connection", "close")
request.Header.Add("content-type", "application/octet-stream")
request.Header.Add("Upgrade", "mmtls")
request.Header.Add("Host", mmInfo.ShortHost)
//fmt.Println(mmInfo.ShortHost)//szshort.weixin.qq.com
// 发送请求
httpTransport := &http.Transport{
Dial: func(network, addr string) (net.Conn, error) {
conn, err := net.DialTimeout(network, addr, time.Second*15) //设置建立连接超时
if err != nil {
return nil, err
}
conn.SetDeadline(time.Now().Add(time.Second * 15)) //设置发送接受数据超时
return conn, nil
},
ResponseHeaderTimeout: time.Second * 15,
MaxIdleConnsPerHost: -1, //禁用连接池缓存
DisableKeepAlives: true, //禁用客户端连接缓存到连接池
}
// 如果有代理
if mmInfo.Dialer != nil {
httpTransport.Dial = mmInfo.Dialer.Dial
}
client := &http.Client{Transport: httpTransport}
resp, err := client.Do(request)
if err != nil {
baseutils.PrintLog(err.Error())
return nil, err
}
// 接收响应
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
// 返回响应数据
return body, nil
}
// MMHTTPPostData mmtls短链接方式发送请求数据包
func MMHTTPPostData(mmInfo *MMInfo, url string, data []byte) ([]byte, error) {
// 创建HttpHandler
httpHandler := &HTTPHandler{}
httpHandler.URL = url
httpHandler.Host = mmInfo.ShortHost
httpHandler.MMPkg = data
// 创建发送请求项列表
sendItems, err := CreateSendPackItems(mmInfo, httpHandler)
if err != nil {
return []byte{}, err
}
// MMTLS-加密要发送的数据
packData, err := MMHTTPPackData(mmInfo, sendItems)
if err != nil {
return []byte{}, err
}
// 发送数据
respData, err := MMHTTPPost(mmInfo, packData)
// 解包响应数据
decodeData, err := MMDecodeResponseData(mmInfo, sendItems, respData)
if err != nil {
baseutils.PrintLog(err.Error())
return nil, err
}
return decodeData, nil
}
/*
*
纯Http请求
*/
func HTTPPost(mmInfo *MMInfo, cgi string, data []byte) ([]byte, error) {
requestURL := "http://" + mmInfo.ShortURL + cgi
request, err := http.NewRequest("POST", requestURL, bytes.NewReader(data))
if err != nil {
return nil, err
}
request.Header.Add("UserAgent", "MicroMessenger Client")
request.Header.Add("Accept", "*/*")
request.Header.Add("Cache-Control", "no-cache")
request.Header.Add("Connection", "Keep-Alive")
request.Header.Add("content-type", "application/octet-stream")
// 发送请求
httpTransport := &http.Transport{}
// 如果有代理
if mmInfo.Dialer != nil {
httpTransport.Dial = mmInfo.Dialer.Dial
}
client := &http.Client{Transport: httpTransport}
resp, err := client.Do(request)
if err != nil {
baseutils.PrintLog(err.Error())
return nil, err
}
// 接收响应
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
// 返回响应数据
return body, nil
}

View File

@@ -0,0 +1,162 @@
package mmtls
import (
"bufio"
"errors"
"fmt"
"io"
"net"
"strconv"
"time"
"xiawan/wx/clientsdk/baseutils"
)
// MMLongConnect 链接MMtls服务器
func MMLongConnect(mmInfo *MMInfo) error {
strPort := strconv.Itoa(int(mmInfo.LONGPort))
serverAddr := mmInfo.LongHost + ":" + strPort
fmt.Println("MMLongConnect serverAddr: ", serverAddr)
mminfoDialer := "0"
if mmInfo.Dialer != nil {
mminfoDialer = "1"
}
// 打印 mmInfo.Dialer
fmt.Println("MMLongConnect mmInfo.Dialer: ", mminfoDialer)
// 定义
var conn net.Conn
var err error
for i := 0; i < 30; i++ {
if mmInfo.Dialer != nil {
conn, err = mmInfo.Dialer.Dial("tcp4", serverAddr)
if err != nil {
baseutils.PrintLog(fmt.Sprintf("MMLongConnect attempt %d failed: %s", i+1, err.Error()))
// 等待 500 毫秒重时 (最大 30 次)
time.Sleep(500 * time.Millisecond)
continue
}
mmInfo.Conn = conn
mmInfo.reader = bufio.NewReader(conn)
fmt.Println("MMLongConnect success!")
return nil
}
// 没有使用代理
conn, err = net.Dial("tcp4", serverAddr)
if err != nil {
baseutils.PrintLog(fmt.Sprintf("MMLongConnect attempt %d failed: %s", i+1, err.Error()))
// 等待 500 毫秒重时 (最大 30 次)
time.Sleep(500 * time.Millisecond)
continue
}
mmInfo.Conn = conn
mmInfo.reader = bufio.NewReader(conn)
return nil
}
if err != nil {
return err
}
return nil
}
// MMTCPSendData MMTCPSendData 长链接发送数据
func MMTCPSendData(mmInfo *MMInfo, data []byte) error {
// 连接服务器
if mmInfo.Conn == nil {
// 提前设置好长链接Host Port
err := MMLongConnect(mmInfo)
if err != nil {
return err
}
}
// 发送数据
length, err := mmInfo.Conn.Write(data)
// 判断是否出错
if err != nil {
return err
}
// 判断数据是否发送完毕
if length != len(data) {
return errors.New("MMTCPSendData err: length != len(data)")
}
return nil
}
// MMTCPRecvItems 循环接收长链接数据
// Deprecated
func MMTCPRecvItems(mmInfo *MMInfo) ([]*PackItem, error) {
// 接收返回数据
recvBuf := make([]byte, 10240)
recvLen, err := mmInfo.Conn.Read(recvBuf)
if err != nil {
return nil, err
}
retData := recvBuf[0:recvLen]
retItems, err := ParserMMtlsResponseData(retData)
if err != nil {
return nil, err
}
return retItems, nil
}
// MMTCPRecvOneItem
func MMTCPRecvOneItem(mmInfo *MMInfo) (*PackItem, error) {
if mmInfo == nil || mmInfo.Conn == nil || mmInfo.reader == nil {
return nil, errors.New("mmInfo.Conn or mmInfo.reader is nil")
}
// 读取头部数据
recordHeadData := make([]byte, 5)
if _, err := io.ReadFull(mmInfo.reader, recordHeadData); err != nil {
return nil, err
}
// 读取Content
recordHead := RecordHeadDeSerialize(recordHeadData)
bodyData := make([]byte, recordHead.Size)
if _, err := io.ReadFull(mmInfo.reader, bodyData); err != nil {
return nil, err
}
return &PackItem{
RecordHead: recordHeadData,
PackData: bodyData,
}, nil
}
// MMTCPSendReq 长链接发送请求
func MMTCPSendReq(mmInfo *MMInfo, opCode uint32, data []byte) error {
sendData, err := MMLongPackData(mmInfo, opCode, data)
if err != nil {
return err
}
// 发送数据
err = MMTCPSendData(mmInfo, sendData)
if err != nil {
return err
}
return nil
}
// MMTCPRecvData 接受MMTLS信息
func MMTCPRecvData(mmInfo *MMInfo) (*LongRecvInfo, error) {
// 接收响应数据
recvItem, err := MMTCPRecvOneItem(mmInfo)
if err != nil {
fmt.Println("MMTCPRecvData err", err.Error())
// log.("接收mmtls长链接响应失败", err.Error())
return nil, err
}
// 解包响应数据
recvInfo, err := MMLongUnPackData(mmInfo, recvItem)
if err != nil {
fmt.Println("MMTCPRecvData err", err.Error())
//log.Info("解包响应数据失败", err.Error())
return nil, err
}
return recvInfo, nil
}

View File

@@ -0,0 +1,218 @@
package mmtls
import (
"errors"
"sync/atomic"
"xiawan/wx/clientsdk/baseutils"
"golang.org/x/net/proxy"
)
// InitMMTLSInfoLong 初始化MMTLS信息通过长链接
func InitMMTLSInfoLong(dialer proxy.Dialer, longHostName string, shortHostName string, pskList []*Psk) (*MMInfo, error) {
// 初始化MMInfo
mmInfo := CreateNewMMInfo()
mmInfo.ShortHost = shortHostName
mmInfo.LongHost = longHostName
mmInfo.Dialer = dialer
// 第一次设置为空后面设置成前面握手返回的Psk列表
mmInfo.ShortPskList = pskList
// 随机生成ClientEcdhKeys,握手用
mmInfo.ClientEcdhKeys = CreateClientEcdhKeys()
// 开始握手
err := MMHandShakeByLongLink(mmInfo)
if err != nil {
return nil, err
}
// 发送一次心跳包
err = SendHeartBeat(mmInfo)
if err != nil {
return nil, err
}
// 握手成功设置短链接的HOST 和 新的URL
shortURL := []byte("/mmtls/")
mmInfo.ShortURL = string(append(shortURL, []byte(baseutils.RandomSmallHexString(8))[0:]...))
return mmInfo, nil
}
// MMHandShakeByLongLink 长链接握手(与短链接握手类似,只需选择其中一种握手方式,微信是采用长链接握手,每次登陆前都需要握手)
func MMHandShakeByLongLink(mmInfo *MMInfo) error {
// 发送握手请求 - ClientHello
clientHelloData := CreateHandShakeClientHelloData(mmInfo)
sendData := CreateRecordData(ServerHandShakeType, clientHelloData)
// 发送ClientHello
err := MMTCPSendData(mmInfo, sendData)
if err != nil {
return err
}
// 接收响应
retItems, err := MMTCPRecvItems(mmInfo)
if err != nil {
return err
}
// 处理握手信息
clientFinishedData, err := DealHandShakePackItems(mmInfo, retItems, clientHelloData)
if err != nil {
return err
}
// 发送clientFinished, 长链接必须要发送,但服务器不会响应
err = MMTCPSendData(mmInfo, clientFinishedData)
if err != nil {
return err
}
return nil
}
// SendHeartBeat 发送心跳包
func SendHeartBeat(mmInfo *MMInfo) error {
// 发送心跳包
heartData, err := GetHeartBeatData(mmInfo)
err = MMTCPSendData(mmInfo, heartData)
if err != nil {
return err
}
// 接收心跳包响应
retItem, err := MMTCPRecvOneItem(mmInfo)
if err != nil {
return err
}
// 解析心跳包响应数据,但不需处理
_, err = MMLongUnPackData(mmInfo, retItem)
if err != nil {
return err
}
return nil
}
// GetHeartBeatData 获取心跳包数据
func GetHeartBeatData(mmInfo *MMInfo) ([]byte, error) {
retBytes := make([]byte, 0)
bodyData := make([]byte, 0)
// LongPackTagInfo
packTagInfo := &LongPackHeaderInfo{}
packTagInfo.HeaderLen = 16
packTagInfo.Version = MMLongVersion
packTagInfo.Operation = MMLongOperationSmartHeartBeat
packTagInfo.SequenceNumber = 0xffffffff
tagInfoBytes := LongPackHeaderInfoSerialize(packTagInfo)
// BodyData
dataLength := uint32(len(tagInfoBytes) + 4)
bodyData = append(bodyData, baseutils.Int32ToBytes(dataLength)[0:]...)
bodyData = append(bodyData, tagInfoBytes[0:]...)
// RecordHead
tmpLen := uint16(dataLength + 16)
recordHeader := GetRecordDataByLength(BodyType, tmpLen)
clientSeq := atomic.AddUint32(&mmInfo.LONGClientSeq, 1) - 1
// 加密
tmpNonce := GetNonce(mmInfo.LongHdkfKey.EncodeNonce, uint32(clientSeq))
tmpAad := []byte{0x00, 0x00, 0x00, 0x00}
tmpAad = append(tmpAad, baseutils.Int32ToBytes(uint32(clientSeq))...)
tmpAad = append(tmpAad, recordHeader...)
encodeData, err := AesGcmEncrypt(mmInfo.LongHdkfKey.EncodeAesKey, tmpNonce, tmpAad, bodyData)
if err != nil {
return retBytes, err
}
// 组包
retBytes = append(retBytes, recordHeader...)
retBytes = append(retBytes, encodeData...)
return retBytes, nil
}
// MMLongPackData 长链接方式 打包请求数据
func MMLongPackData(mmInfo *MMInfo, opCode uint32, data []byte) ([]byte, error) {
retBytes := make([]byte, 0)
bodyData := make([]byte, 0)
// LongPackTagInfo
packTagInfo := &LongPackHeaderInfo{}
packTagInfo.HeaderLen = 16
packTagInfo.Version = MMLongVersion
packTagInfo.Operation = opCode
packTagInfo.SequenceNumber = atomic.LoadUint32(&mmInfo.LONGClientSeq)
tagInfoBytes := LongPackHeaderInfoSerialize(packTagInfo)
// BodyData
dataLength := uint32(len(data) + len(tagInfoBytes) + 4)
bodyData = append(bodyData, baseutils.Int32ToBytes(dataLength)[0:]...)
bodyData = append(bodyData, tagInfoBytes[0:]...)
bodyData = append(bodyData, data[0:]...)
// RecordHead
tmpLen := uint16(dataLength + 16)
recordHeader := GetRecordDataByLength(BodyType, tmpLen)
// 加密
tmpNonce := GetNonce(mmInfo.LongHdkfKey.EncodeNonce, atomic.LoadUint32(&mmInfo.LONGClientSeq))
tmpAad := []byte{0x00, 0x00, 0x00, 0x00}
tmpAad = append(tmpAad, baseutils.Int32ToBytes(atomic.LoadUint32(&mmInfo.LONGClientSeq))...)
tmpAad = append(tmpAad, recordHeader...)
encodeData, err := AesGcmEncrypt(mmInfo.LongHdkfKey.EncodeAesKey, tmpNonce, tmpAad, bodyData)
if err != nil {
return retBytes, err
}
// 组包ClientSeq 索引值+1
atomic.AddUint32(&mmInfo.LONGClientSeq, 1)
//mmInfo.LONGClientSeq++
retBytes = append(retBytes, recordHeader...)
retBytes = append(retBytes, encodeData...)
return retBytes, nil
}
// MMLongUnPackData 长链接方式 解包数据
func MMLongUnPackData(mmInfo *MMInfo, packItem *PackItem) (*LongRecvInfo, error) {
// 解密
tmpNonce := GetNonce(mmInfo.LongHdkfKey.DecodeNonce, atomic.LoadUint32(&mmInfo.LONGServerSeq))
tmpAad := []byte{0x00, 0x00, 0x00, 0x00}
tmpAad = append(tmpAad, baseutils.Int32ToBytes(atomic.LoadUint32(&mmInfo.LONGServerSeq))...)
tmpAad = append(tmpAad, packItem.RecordHead...)
DecodeData, err := AesGcmDecrypt(mmInfo.LongHdkfKey.DecodeAesKey, tmpNonce, tmpAad, packItem.PackData)
if err != nil {
return nil, err
}
// TotalLength
current := 0
totalLength := baseutils.BytesToInt32(DecodeData[current : current+4])
current = current + 4
if totalLength != uint32(len(DecodeData)) {
return nil, errors.New("MMLongUnPackData err: totalLength != uint32(len(DecodeData))")
}
headerInfo, err := LongPackHeaderInfoDeSerialize(DecodeData[current : current+12])
current = current + 12
if err != nil {
return nil, err
}
retLongRecvInfo := &LongRecvInfo{}
retLongRecvInfo.HeaderInfo = headerInfo
// 如果大于 说明是业务包,如果等于则是长链接心跳包
if totalLength > uint32(headerInfo.HeaderLen) {
retLongRecvInfo.RespData = DecodeData[current:]
}
// ServerSeq 索引值+1
//mmInfo.LONGServerSeq = mmInfo.LONGServerSeq + 1
atomic.AddUint32(&mmInfo.LONGServerSeq, 1)
return retLongRecvInfo, nil
}

View File

@@ -0,0 +1,627 @@
package mmtls
import (
"crypto/elliptic"
"crypto/rand"
"errors"
"fmt"
"sync/atomic"
"golang.org/x/net/proxy"
"xiawan/wx/clientsdk/baseutils"
"github.com/micro/go-micro/util/log"
"github.com/wsddn/go-ecdh"
)
// CreateNewMMInfo 创建新的MMInfo
func CreateNewMMInfo() *MMInfo {
mmInfo := &MMInfo{}
mmInfo.ShortHost = "szshort.weixin.qq.com"
mmInfo.LongHost = "szlong.weixin.qq.com"
mmInfo.LONGPort = 8080
mmInfo.LONGClientSeq = 1
mmInfo.LONGServerSeq = 1
return mmInfo
}
// InitMMTLSInfoShort 如果使用MMTLS每次登陆前都需要初始化MMTLSInfo信息
// pskList: 之前握手服务端返回的,要保存起来,后面握手时使用, 第一次握手传空数组即可
func InitMMTLSInfoShort(dialer proxy.Dialer, hostName string, pskList []*Psk) *MMInfo {
// 初始化MMInfo
mmInfo := CreateNewMMInfo()
mmInfo.ShortPskList = pskList
// 随机生成ClientEcdhKeys
mmInfo.ClientEcdhKeys = CreateClientEcdhKeys()
mmInfo.ShortHost = hostName
mmInfo.Dialer = dialer
// 握手
mmInfo, err := MMHandShakeByShortLink(mmInfo, hostName)
// 如果握手失败 就不使用MMTLS
if err != nil {
log.Info(err)
return nil
}
// 握手成功设置好HOST 和 新的URL
shortURL := []byte("/mmtls/")
mmInfo.ShortHost = hostName
mmInfo.ShortURL = string(append(shortURL, []byte(baseutils.RandomSmallHexString(8))[0:]...))
return mmInfo
}
// CreateClientEcdhKeys 创建新的ClientEcdhKeys
func CreateClientEcdhKeys() *ClientEcdhKeys {
// 随机
clientEcdhKeys := &ClientEcdhKeys{}
e := ecdh.NewEllipticECDH(elliptic.P256())
priKey1, pubKey1, _ := e.GenerateKey(rand.Reader)
priKey2, pubKey2, _ := e.GenerateKey(rand.Reader)
clientEcdhKeys.PriKey1 = priKey1
clientEcdhKeys.PriKey2 = priKey2
clientEcdhKeys.PubKeyBuf1 = e.Marshal(pubKey1)
clientEcdhKeys.PubKeyBuf2 = e.Marshal(pubKey2)
return clientEcdhKeys
}
// MMHandShakeByShortLink 通过短链接握手
func MMHandShakeByShortLink(mmInfo *MMInfo, hostName string) (*MMInfo, error) {
shortURL := []byte("/mmtls/")
mmURL := append(shortURL, []byte(baseutils.RandomSmallHexString(8))[0:]...)
mmInfo.ShortURL = string(mmURL)
// 发送握手请求 - ClientHello
clientHelloData := CreateHandShakeClientHelloData(mmInfo)
sendData := CreateRecordData(ServerHandShakeType, clientHelloData)
retBytes, err := MMHTTPPost(mmInfo, sendData)
if err != nil {
return nil, err
}
// 解析握手相应数据
retItems, err := ParserMMtlsResponseData(retBytes)
if err != nil {
return nil, err
}
// 处理握手信息
clientFinishData, err := DealHandShakePackItems(mmInfo, retItems, clientHelloData)
_ = clientFinishData
return mmInfo, nil
}
// ParserMMtlsResponseData 解析mmtls响应数据
func ParserMMtlsResponseData(data []byte) ([]*PackItem, error) {
// RecodeHead *RecodeHead
retItems := make([]*PackItem, 0)
// 总数据大小
totalLength := uint32(len(data))
current := uint32(0)
// 解析所有包
for current < totalLength {
packItem := &PackItem{}
// recordHead
if current+5 > totalLength {
return retItems, errors.New("ParserMMtlsResponseData err: current+5 >= totalLength")
}
recordHead := RecordHeadDeSerialize(data[current:])
packItem.RecordHead = data[current : current+5]
current = current + 5
// PackData
// 判断数据是否有问题
if current+uint32(recordHead.Size) > totalLength {
return retItems, errors.New("ParserMMtlsResponseData err: current+uint32(recordHead.Size) >= totalLength")
}
packItem.PackData = data[current : current+uint32(recordHead.Size)]
// current
current = current + uint32(recordHead.Size)
retItems = append(retItems, packItem)
}
return retItems, nil
}
// DealHandShakePackItems 解密packItems
func DealHandShakePackItems(mmInfo *MMInfo, packItems []*PackItem, clientHelloReq []byte) ([]byte, error) {
retClientFinishData := make([]byte, 0)
// 先解析 ServerHello
secretKey, err := DealServerHello(mmInfo, packItems[0])
if err != nil {
return retClientFinishData, err
}
// 计算HashRet
hashData := make([]byte, 0)
hashData = append(hashData, clientHelloReq[0:]...)
hashData = append(hashData, packItems[0].PackData...)
hashRet := Sha256(hashData)
// 密钥扩展
message := []byte("handshake key expansion")
message = append(message, hashRet...)
aesKeyExpand := HkdfExpand(secretKey, message, 56)
gcmAesKey := aesKeyExpand[0x10:0x20]
oriNonce := aesKeyExpand[0x2c:]
// 解密后面的包
count := len(packItems)
for index := 1; index < count; index++ {
tmpPackItem := packItems[index]
// 解密数据
tmpNonce := GetNonce(oriNonce, uint32(index))
tmpAad := []byte{0x00, 0x00, 0x00, 0x00}
tmpAad = append(tmpAad, baseutils.Int32ToBytes(atomic.LoadUint32(&mmInfo.LONGServerSeq))...)
tmpAad = append(tmpAad, tmpPackItem.RecordHead...)
decodeData, err := AesGcmDecrypt(gcmAesKey, tmpNonce, tmpAad, tmpPackItem.PackData)
// 设置解密后的数据
tmpPackItem.PackData = decodeData
if err != nil {
return retClientFinishData, err
}
atomic.AddUint32(&mmInfo.LONGServerSeq, 1)
//mmInfo.LONGServerSeq++
// 处理CertificateVerifyType
tmpType := decodeData[4]
if tmpType == CertificateVerifyType {
// 校验服务器
flag, err := DealCertificateVerify(clientHelloReq, packItems[0].PackData, decodeData)
if err != nil {
return retClientFinishData, err
}
if !flag {
return retClientFinishData, errors.New("DealHandShakePackItems err: CertificateVerify failed")
}
}
// 处理NewSessionTicketType
if tmpType == NewSessionTicketType {
err := DealNewSessionTicket(mmInfo, decodeData)
if err != nil {
return retClientFinishData, err
}
}
// 处理Server FinishType
if tmpType == FinishedType {
// 第一步验证ServerFinished数据
tmpHashData := make([]byte, 0)
tmpHashData = append(tmpHashData, clientHelloReq[0:]...)
tmpHashData = append(tmpHashData, packItems[0].PackData[0:]...)
tmpHashData = append(tmpHashData, packItems[1].PackData[0:]...)
tmpHashData = append(tmpHashData, packItems[2].PackData[0:]...)
tmpHashValue := Sha256(tmpHashData)
serverFinished, err := FinishedDeSerialize(tmpPackItem.PackData[4:])
if err != nil {
return retClientFinishData, err
}
bSuccess := VerifyFinishedData(secretKey, tmpHashValue, serverFinished.VerifyData)
if !bSuccess {
return retClientFinishData, errors.New("DealHandShakePackItems err: Finished verify failed")
}
// 第二步生成ClientFinished数据然后加密
hkdfClientFinish := HkdfExpand(secretKey, []byte("client finished"), 32)
hmacRet := HmacHash256(hkdfClientFinish, tmpHashValue)
aesGcmParam := &AesGcmParam{}
aesGcmParam.AesKey = aesKeyExpand[0x00:0x10]
aesGcmParam.Nonce = aesKeyExpand[0x20:0x2c]
// 创建Finished
finished := CreateFinished(hmacRet)
// 加密
finishedData := FinishedSerialize(finished)
clientSeq := atomic.AddUint32(&mmInfo.LONGClientSeq, 1) - 1
encodeData, err := EncryptedReqData(aesGcmParam, finishedData, ServerHandShakeType, clientSeq)
if err != nil {
return retClientFinishData, err
}
retClientFinishData = CreateRecordData(ServerHandShakeType, encodeData)
//mmInfo.LONGClientSeq++
//atomic.AddUint32(&mmInfo.LONGClientSeq, 1)
break
}
}
// 计算扩展出来的用于后续加密的Key
tmpExpandHashData := make([]byte, 0)
tmpExpandHashData = append(tmpExpandHashData, clientHelloReq[0:]...)
tmpExpandHashData = append(tmpExpandHashData, packItems[0].PackData[0:]...)
tmpExpandHashData = append(tmpExpandHashData, packItems[1].PackData[0:]...)
tmpExpandHashValue := Sha256(tmpExpandHashData)
// PskAccessKey 短连接MMTLS密钥
expandPskAccessData := []byte("PSK_ACCESS")
expandPskAccessData = append(expandPskAccessData, tmpExpandHashValue[0:]...)
mmInfo.PskAccessKey = HkdfExpand(secretKey, expandPskAccessData, 32)
// AppDataKeyExtension 长链接MMTLS密钥
tmpExpandHashData = append(tmpExpandHashData, packItems[2].PackData[0:]...)
tmpLongHashValue := Sha256(tmpExpandHashData)
expandedSecret := append([]byte("expanded secret"), tmpLongHashValue[0:]...)
retExpandSecret := HkdfExpand(secretKey, expandedSecret, 32)
appDataKeyData := append([]byte("application data key expansion"), tmpLongHashValue[0:]...)
appDataKeyExtension := HkdfExpand(retExpandSecret, appDataKeyData, 56)
mmInfo.LongHdkfKey = &HkdfKey56{}
mmInfo.LongHdkfKey.EncodeAesKey = appDataKeyExtension[0x00:0x10]
mmInfo.LongHdkfKey.DecodeAesKey = appDataKeyExtension[0x10:0x20]
mmInfo.LongHdkfKey.EncodeNonce = appDataKeyExtension[0x20:0x2c]
mmInfo.LongHdkfKey.DecodeNonce = appDataKeyExtension[0x2c:]
// 返回ClientFinishData
return retClientFinishData, nil
}
// DealServerHello 处理ServerHello
func DealServerHello(mmInfo *MMInfo, packItem *PackItem) ([]byte, error) {
// 解析ServerHello
serverHello, err := ServerHelloDeSerialize(packItem.PackData[4:])
if err != nil {
return []byte{}, err
}
// 解析ServerKeyShare
serverKeyShareExtension, err := ServerKeyShareExtensionDeSerialize(serverHello.ExtensionList[0].ExtensionData)
if err != nil {
return []byte{}, err
}
// 解析ServerPublicKey
ecdhTool := ecdh.NewEllipticECDH(elliptic.P256())
serverPubKey, isOk := ecdhTool.Unmarshal(serverKeyShareExtension.PublicValue)
if !isOk {
return []byte{}, errors.New("DecodePackItems ecdhTool.Unmarshal(serverKeyShareExtension.PublicValue) failed")
}
// 根据NameGroup 决定使用哪个Privakey
ecdhPriKey := mmInfo.ClientEcdhKeys.PriKey1
if serverKeyShareExtension.KeyOfferNameGroup == 2 {
ecdhPriKey = mmInfo.ClientEcdhKeys.PriKey2
}
// 协商密钥
secretKey, err := ecdhTool.GenerateSharedSecret(ecdhPriKey, serverPubKey) //服务器公钥和本地第一个私钥协商出安全密钥
if err != nil {
return []byte{}, err
}
return Sha256(secretKey), nil
}
// DealCertificateVerify 处理CertificateVerify数据: 校验服务器-判断是不是微信服务器,请求返回数据有没有被串改
func DealCertificateVerify(clientHelloData []byte, serverHelloData []byte, data []byte) (bool, error) {
// 解析数据
totalSize := baseutils.BytesToInt32(data[0:4])
certificateVerify, err := CertificateVerifyDeSerialize(data[4 : 4+totalSize])
if err != nil {
return false, err
}
// 合并请求数据
message := make([]byte, 0)
message = append(message, clientHelloData[0:]...)
message = append(message, serverHelloData[0:]...)
message = Sha256(message)
// 校验数据
flag, err := ECDSAVerifyData(message, certificateVerify.Signature)
if err != nil {
return false, err
}
return flag, nil
}
// DealNewSessionTicket 处理NewSessionTicket数据
func DealNewSessionTicket(mmInfo *MMInfo, data []byte) error {
// 解析数据
totalSize := baseutils.BytesToInt32(data[0:4])
newSessionTicket, err := NewSessionTicketDeSerialize(data[4 : 4+totalSize])
if err != nil {
return err
}
mmInfo.ShortPskList = newSessionTicket.PskList
return nil
}
// ----------- 上面是握手阶段 -----------
// ----------- 接下来是发送请求 -----------
// EncryptedReqData EncryptedReqData
func EncryptedReqData(aesGcmParam *AesGcmParam, data []byte, recordHeadType byte, clientSeq uint32) ([]byte, error) {
tmpNonce := GetNonce(aesGcmParam.Nonce, clientSeq)
tmpHead := GetRecordDataByLength(recordHeadType, uint16(len(data)+0x10))
tmpAad := []byte{0x00, 0x00, 0x00, 0x00}
tmpAad = append(tmpAad, baseutils.Int32ToBytes(clientSeq)...)
tmpAad = append(tmpAad, tmpHead[0:]...)
encodeData, err := AesGcmEncrypt(aesGcmParam.AesKey, tmpNonce, tmpAad, data)
if err != nil {
return []byte{}, err
}
return encodeData, nil
}
// DecryptedRecvData 解析响应数据包
func DecryptedRecvData(aesGcmParam *AesGcmParam, recvItem *PackItem, serverSeq uint32) ([]byte, error) {
tmpNonce := GetNonce(aesGcmParam.Nonce, serverSeq)
tmpAad := []byte{0x00, 0x00, 0x00, 0x00}
tmpAad = append(tmpAad, baseutils.Int32ToBytes(serverSeq)...)
tmpAad = append(tmpAad, recvItem.RecordHead[0:]...)
encodeData, err := AesGcmDecrypt(aesGcmParam.AesKey, tmpNonce, tmpAad, recvItem.PackData)
if err != nil {
return []byte{}, err
}
return encodeData, nil
}
// CreateSendPackItems 创建发送的请求项列表
func CreateSendPackItems(mmInfo *MMInfo, httpHandler *HTTPHandler) ([]*PackItem, error) {
retItems := make([]*PackItem, 0)
// ClientHelloItem
clientHelloItem := &PackItem{}
clientHello, err := CreateClientHelloData(mmInfo)
if err != nil {
return nil, err
}
clientHelloData := ClientHelloSerialize(clientHello)
clientHelloItem.RecordHead = GetRecordDataByLength(ClientHandShakeType, uint16(len(clientHelloData)))
clientHelloItem.PackData = clientHelloData
// EncryptedExtensionsItem
encryptedExtensionsItem := &PackItem{}
encryptedExtensions := CreateEncryptedExtensions()
encryptedExtensionsData := EncryptedExtensionsSerialize(encryptedExtensions)
encryptedExtensionsItem.RecordHead = GetRecordDataByLength(ClientHandShakeType, uint16(len(encryptedExtensionsData)))
encryptedExtensionsItem.PackData = encryptedExtensionsData
// HTTPHandlerItem
httpHandlerItem := &PackItem{}
httpHandlerData := HTTPHandlerSerialize(httpHandler)
httpHandlerItem.RecordHead = GetRecordDataByLength(BodyType, uint16(len(httpHandlerData)))
httpHandlerItem.PackData = httpHandlerData
// AlertItem
alertItem := &PackItem{}
alertData := GetAlertData()
alertItem.RecordHead = GetRecordDataByLength(AlertType, uint16(len(alertData)))
alertItem.PackData = alertData
// 返回数据
retItems = append(retItems, clientHelloItem)
retItems = append(retItems, encryptedExtensionsItem)
retItems = append(retItems, httpHandlerItem)
retItems = append(retItems, alertItem)
return retItems, nil
}
// MMHTTPPackData MMPackData
func MMHTTPPackData(mmInfo *MMInfo, items []*PackItem) ([]byte, error) {
// 密钥扩展
sha256Value := Sha256(items[0].PackData)
expandSecretData := []byte("early data key expansion")
expandSecretData = append(expandSecretData, sha256Value[0:]...)
tmpHkdfValue := HkdfExpand(mmInfo.PskAccessKey, expandSecretData, 28)
aesGcmParam := &AesGcmParam{}
aesGcmParam.AesKey = tmpHkdfValue[0x00:0x10]
aesGcmParam.Nonce = tmpHkdfValue[0x10:0x1c]
// 加密EncryptedExtensions
encryptData, err := EncryptedReqData(aesGcmParam, items[1].PackData, ClientHandShakeType, 1)
if err != nil {
return []byte{}, err
}
partData2 := CreateRecordData(ClientHandShakeType, encryptData)
// 加密HTTPHandler
httpHandlerEncryptData, err := EncryptedReqData(aesGcmParam, items[2].PackData, BodyType, 2)
if err != nil {
return []byte{}, err
}
partData3 := CreateRecordData(BodyType, httpHandlerEncryptData)
// 加密Alert
alertDataEncryptData, err := EncryptedReqData(aesGcmParam, items[3].PackData, AlertType, 3)
if err != nil {
return []byte{}, err
}
partData4 := CreateRecordData(AlertType, alertDataEncryptData)
// 返回数据
retData := make([]byte, 0)
retData = append(retData, items[0].RecordHead[0:]...)
retData = append(retData, items[0].PackData[0:]...)
retData = append(retData, partData2[0:]...)
retData = append(retData, partData3[0:]...)
retData = append(retData, partData4[0:]...)
return retData, err
}
// MMDecodeResponseData 解码响应数据
// func MMDecodeResponseData(mmInfo *MMInfo, sendItems []*PackItem, respData []byte) ([]byte, error) {
// retData := make([]byte, 0)
// // 解析 对响应数据进行分包
// recvItems, err := ParserMMtlsResponseData(respData)
// if err != nil {
// return retData, err
// }
// if len(recvItems) < 4 {
// return retData, errors.New("MMDecodeResponseData err: recvItems Length < 4")
// }
// // 密钥扩展 用于后面的解密
// shaData := make([]byte, 0)
// shaData = append(shaData, sendItems[0].PackData[0:]...)
// shaData = append(shaData, sendItems[1].PackData[0:]...)
// shaData = append(shaData, recvItems[0].PackData[0:]...)
// sha256Value := Sha256(shaData)
// expandSecretData := []byte("handshake key expansion")
// expandSecretData = append(expandSecretData, sha256Value[0:]...)
// tmpHkdfValue := HkdfExpand(mmInfo.PskAccessKey, expandSecretData, 28)
// aesGcmParam := &AesGcmParam{}
// aesGcmParam.AesKey = tmpHkdfValue[0x00:0x10]
// aesGcmParam.Nonce = tmpHkdfValue[0x10:0x1c]
// // 解密剩下的包
// count := len(recvItems)
// for index := 1; index < count; index++ {
// // 解密Finished数据包
// decodeData, err := DecryptedRecvData(aesGcmParam, recvItems[index], uint32(index))
// if err != nil {
// return retData, err
// }
// // RecordHeadType
// recordHeadType := recvItems[index].RecordHead[0]
// // ServerHandShakeType 校验收到的数据是否完整,是否又被串改
// if recordHeadType == ServerHandShakeType {
// // 判断数据长度是否正常
// current := 0
// totalLength := int(baseutils.BytesToInt32(decodeData[current : current+4]))
// current = current + 4
// if totalLength < 0 {
// return retData, errors.New("MMDecodeResponseData err: totalLength < 0")
// }
// // ReceiveSubType
// subType := decodeData[current]
// // FinishedType 校验数据是否正常
// if subType == FinishedType {
// // 反序列化
// finished, err := FinishedDeSerialize(decodeData[current : current+totalLength])
// if err != nil {
// return retData, err
// }
// bSuccess := VerifyFinishedData(mmInfo.PskAccessKey, sha256Value, finished.VerifyData)
// if !bSuccess {
// return retData, errors.New("MMDecodeResponseData err: VerifyFinishedData failed")
// }
// }
// }
// // 解析响应数据
// if recordHeadType == BodyType {
// retData = append(retData, decodeData[0:]...)
// }
// // 解析AlertType
// if recordHeadType == AlertType {
// // 关闭连接的数据包(对长链接有用) 固定为0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x01
// }
// }
// return retData, nil
// }
// MMDecodeResponseData 解码响应数据
func MMDecodeResponseData(mmInfo *MMInfo, sendItems []*PackItem, respData []byte) ([]byte, error) {
var retData []byte
defer func() {
if r := recover(); r != nil {
fmt.Printf("Recovered from panic: %v\n", r)
// 这里可以记录日志或者执行其他的恢复操作
return
}
}()
// 解析响应数据
recvItems, err := ParserMMtlsResponseData(respData)
if err != nil {
return retData, fmt.Errorf("failed to parse response data: %w", err)
}
if len(recvItems) < 4 {
return retData, errors.New("MMDecodeResponseData err: recvItems Length < 4")
}
if len(sendItems) < 2 || sendItems[0] == nil || sendItems[1] == nil {
return retData, errors.New("MMDecodeResponseData err: sendItems Length < 2 or contains nil")
}
// 密钥扩展 用于后面的解密, 确保 sendItems 和 recvItems 有效
shaData := append(sendItems[0].PackData, sendItems[1].PackData...)
shaData = append(shaData, recvItems[0].PackData...)
sha256Value := Sha256(shaData)
expandSecretData := append([]byte("handshake key expansion"), sha256Value...)
tmpHkdfValue := HkdfExpand(mmInfo.PskAccessKey, expandSecretData, 28)
aesGcmParam := &AesGcmParam{
AesKey: tmpHkdfValue[:0x10],
Nonce: tmpHkdfValue[0x10:0x1c],
}
// 解密每个包
for index := 1; index < len(recvItems); index++ {
decodeData, err := DecryptedRecvData(aesGcmParam, recvItems[index], uint32(index))
if err != nil {
return retData, fmt.Errorf("error decrypting packet %d: %w", index, err)
}
recordHeadType := recvItems[index].RecordHead[0]
if recordHeadType == ServerHandShakeType {
if len(decodeData) < 4 {
return retData, errors.New("MMDecodeResponseData err: decodeData Length < 4")
}
current := 4
totalLength := int(baseutils.BytesToInt32(decodeData[:current]))
if totalLength < 0 || len(decodeData) < totalLength {
return retData, errors.New("MMDecodeResponseData err: invalid total length")
}
subType := decodeData[current]
if subType == FinishedType {
finished, err := FinishedDeSerialize(decodeData[current : current+totalLength])
if err != nil {
return retData, fmt.Errorf("failed to deserialize finished data: %w", err)
}
bSuccess := VerifyFinishedData(mmInfo.PskAccessKey, sha256Value, finished.VerifyData)
if !bSuccess {
return retData, errors.New("MMDecodeResponseData err: VerifyFinishedData failed")
}
}
}
if recordHeadType == BodyType {
retData = append(retData, decodeData...)
}
if recordHeadType == AlertType {
// 如果是告警数据包,可以在此处理
}
}
return retData, nil
}
// VerifyFinishedData 校验服务端返回数据是否正确
func VerifyFinishedData(aesKey []byte, shaValue []byte, finishedData []byte) bool {
count := len(finishedData)
message := []byte("server finished")
tmpHkdfValue := HkdfExpand(aesKey, message, count)
verifyData := HmacHash256(tmpHkdfValue, shaValue)
// 比对结果是否一致
for index := 0; index < count; index++ {
if verifyData[index] != finishedData[index] {
return false
}
}
return true
}

View File

@@ -0,0 +1,157 @@
package mmtls
import (
"errors"
"time"
"xiawan/wx/clientsdk/baseutils"
)
// CreateRecordData 根据请求创建完整的mmtls数据包
func CreateRecordData(recordType byte, data []byte) []byte {
recordHead := &RecordHead{}
recordHead.Type = recordType
recordHead.Tag = 0xF103
recordHead.Size = uint16(len(data))
// 组包返回
retBytes := make([]byte, 0)
retBytes = append(retBytes, RecordHeadSerialize(recordHead)[0:]...)
retBytes = append(retBytes, data[0:]...)
return retBytes
}
// GetRecordDataByLength 根据长度获取RecordData
func GetRecordDataByLength(recordType byte, len uint16) []byte {
recordHead := &RecordHead{}
recordHead.Type = recordType
recordHead.Tag = 0xF103
recordHead.Size = len
return RecordHeadSerialize(recordHead)
}
// CreateHandShakeClientHelloData 创建ClientHello数据包
func CreateHandShakeClientHelloData(mmInfo *MMInfo) []byte {
clientHello := &ClientHello{}
// Version
clientHello.Version = 0xF103
// CipherSuiteList
clientHello.CipherSuiteList = make([]*CipherSuite, 2)
cipherSuite1 := &CipherSuite{}
cipherSuite1.SuiteCode = 0xC02B
clientHello.CipherSuiteList[0] = cipherSuite1
cipherSuite2 := &CipherSuite{}
cipherSuite2.SuiteCode = 0xA8
clientHello.CipherSuiteList[1] = cipherSuite2
// RandomBytes
clientHello.RandomBytes = baseutils.RandomBytes(32)
// ClientGmtTime
clientHello.ClientGmtTime = (uint32)(time.Now().UnixNano() / 1000000000)
// ExtensionList
extensionList := make([]*Extension, 0)
pskCount := len(mmInfo.ShortPskList)
if pskCount > 1 {
// 握手是用最后一个
extensionList = append(extensionList, CreatePreSharedKeyExtensionData(mmInfo.ShortPskList[pskCount-1]))
}
// 随机生成两队ECDHKey
extensionList = append(extensionList, CreateClientKeyShareExtensionData(mmInfo.ClientEcdhKeys))
clientHello.ExtensionList = extensionList
return ClientHelloSerialize(clientHello)
}
// CreatePreSharedKeyExtensionData 创建CreatePreSharedKeyExtension数据
func CreatePreSharedKeyExtensionData(psk *Psk) *Extension {
preSharedKeyExtension := &PreSharedKeyExtension{}
preSharedKeyExtension.PskList = make([]*Psk, 1)
// 选取前面协商的最后一个Psk
preSharedKeyExtension.PskList[0] = psk
// 序列化
retExtension := PreSharedKeyExtensionSerialize(preSharedKeyExtension)
return retExtension
}
// CreateClientKeyShareExtensionData 创建ClientKeyShareExtension数据
func CreateClientKeyShareExtensionData(clientEcdhKeys *ClientEcdhKeys) *Extension {
// retExtension
clientKeyShareExtension := &ClientKeyShareExtension{}
// ClientKeyOfferList
clientKeyShareExtension.ClientKeyOfferList = make([]*ClientKeyOffer, 2)
// 随机第一个EcdhKey
clientKeyShareExtension.ClientKeyOfferList[0] = CreateClientKeyOfferData(1, clientEcdhKeys.PubKeyBuf1)
// 随机第一个EcdhKey
clientKeyShareExtension.ClientKeyOfferList[1] = CreateClientKeyOfferData(2, clientEcdhKeys.PubKeyBuf2)
// CertificateVersion
clientKeyShareExtension.CertificateVersion = 1
// 返回序列化的ClientKeyShareExtension
return ClientKeyShareExtensionSerialize(clientKeyShareExtension)
}
// CreateClientKeyOfferData 创建CreateClientKeyOffer数据
func CreateClientKeyOfferData(version uint32, publicKey []byte) *ClientKeyOffer {
clientKeyOffser := &ClientKeyOffer{}
clientKeyOffser.PublicValue = publicKey
clientKeyOffser.Version = version
return clientKeyOffser
}
// CreateClientHelloData 创建ClientHello数据包
func CreateClientHelloData(mmInfo *MMInfo) (*ClientHello, error) {
clientHello := &ClientHello{}
// Version
clientHello.Version = 0xF103
// CipherSuiteList
clientHello.CipherSuiteList = make([]*CipherSuite, 1)
cipherSuite := &CipherSuite{}
cipherSuite.SuiteCode = 0xA8
clientHello.CipherSuiteList[0] = cipherSuite
// RandomBytes
clientHello.RandomBytes = baseutils.RandomBytes(32)
// ClientGmtTime
clientHello.ClientGmtTime = (uint32)(time.Now().UnixNano() / 1000000000)
// ExtensionList
extensionList := make([]*Extension, 0)
pskCount := len(mmInfo.ShortPskList)
if pskCount <= 0 {
return nil, errors.New("CreateClientHelloData error: mmInfo.PskList empty")
}
extensionList = append(extensionList, CreatePreSharedKeyExtensionData(mmInfo.ShortPskList[0]))
clientHello.ExtensionList = extensionList
return clientHello, nil
}
// CreateEarlyEncryptDataExtension 创建EarlyEncryptDataExtension
func CreateEarlyEncryptDataExtension() *Extension {
retEarlyEncryptDataExtension := &EarlyEncryptDataExtension{}
retEarlyEncryptDataExtension.ClientGmtTime = (uint32)(time.Now().UnixNano() / 1000000000)
return EarlyEncryptDataExtensionSerialize(retEarlyEncryptDataExtension)
}
// CreateEncryptedExtensions 创建EncryptedExtensions
func CreateEncryptedExtensions() *EncryptedExtensions {
retEncryptedExtensions := &EncryptedExtensions{}
// ExtensionList
retEncryptedExtensions.ExtensionList = make([]*Extension, 1)
retEncryptedExtensions.ExtensionList[0] = CreateEarlyEncryptDataExtension()
return retEncryptedExtensions
}
// CreateFinished 创建Finish包
func CreateFinished(verifyData []byte) *Finished {
retFinished := &Finished{}
retFinished.VerifyData = verifyData
return retFinished
}
// GetAlertData 获取Alert数据
func GetAlertData() []byte {
return []byte{0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x01}
}

View File

@@ -0,0 +1,246 @@
package mmtls
import (
"bufio"
"crypto"
"math/big"
"net"
"golang.org/x/net/proxy"
)
// AesGcmParam AesGcm加密解密参数
type AesGcmParam struct {
AesKey []byte
Nonce []byte
}
// ClientEcdhKeys 客户端随机的两个EcdhKey私钥
type ClientEcdhKeys struct {
PriKey1 crypto.PrivateKey
PubKeyBuf1 []byte
PriKey2 crypto.PrivateKey
PubKeyBuf2 []byte
}
// HkdfKey28 HkdfKey28
type HkdfKey28 struct {
AesKey []byte
Nonce []byte
}
// HkdfKey56 HkdfKey56
type HkdfKey56 struct {
EncodeAesKey []byte
EncodeNonce []byte
DecodeAesKey []byte
DecodeNonce []byte
}
// MMInfo MMInfo
type MMInfo struct {
// 短链接 属性
// mmtls 协议host 例如hkextshort.weixin.qq.com这个需要保存这数据库
ShortHost string
// mmtls路径 -- 例如:/mmtls/12345678(随机8位16进制字符串),每次握手都随机一个
ShortURL string
// 短链接会话票据(服务端返回, 第一次握手不设置), 下一次握手选择其中一个发给服务器, 需要保存到数据库
ShortPskList []*Psk
// 握手扩展出来的用于后续加密的Key
PskAccessKey []byte
// 长链接 属性
LongHost string
LONGPort uint32
// Deprecated:
LONGClientSeq uint32 `json:"-"` // 不持久化
// Deprecated:
LONGServerSeq uint32 `json:"-"` // 不持久化
// Deprecated:
Conn net.Conn `json:"-"` // 不持久化
reader *bufio.Reader
LongHdkfKey *HkdfKey56
// ClientEcdhKeys
ClientEcdhKeys *ClientEcdhKeys
// 代理
Dialer proxy.Dialer
}
// EcdsaSignature 服务端传过来的校验数据
type EcdsaSignature struct {
R, S *big.Int
}
// CipherSuiteInfo CipherSuiteInfo
type CipherSuiteInfo struct {
SuiteCode uint16
Clipher1 string
Clipher2 string
Clipher3 string
Clipher4 string
Clipher5 string
Length1 uint32
Length2 uint32
Length3 uint32
}
// CipherSuite CipherSuite
type CipherSuite struct {
SuiteCode uint16
SuiteInfo *CipherSuiteInfo
}
// ClientKeyOffer ClientKeyOffer
type ClientKeyOffer struct {
Version uint32
PublicValue []byte
}
// CertificateVerify CertificateVerify
type CertificateVerify struct {
Signature []byte
}
// ClientKeyShareExtension ClientKeyShareExtension
type ClientKeyShareExtension struct {
ClientKeyOfferList []*ClientKeyOffer
CertificateVersion uint32
}
// EarlyEncryptDataExtension EarlyEncryptDataExtension
type EarlyEncryptDataExtension struct {
ClientGmtTime uint32
}
// PreSharedKeyExtension PreSharedKeyExtension
type PreSharedKeyExtension struct {
PskList []*Psk
}
// ServerKeyShareExtension ServerKeyShareExtension
type ServerKeyShareExtension struct {
KeyOfferNameGroup uint32
PublicValue []byte
}
// Extension Extension
type Extension struct {
ExtensionType uint16
ExtensionData []byte
}
// EncryptedExtensions EncryptedExtensions
type EncryptedExtensions struct {
ExtensionList []*Extension
}
// ClientHello ClientHello
type ClientHello struct {
Version uint16
CipherSuiteList []*CipherSuite
RandomBytes []byte
ClientGmtTime uint32
ExtensionList []*Extension
}
// ServerHello ServerHello
type ServerHello struct {
Version uint16
CipherSuite *CipherSuite
RandomBytes []byte
ExtensionList []*Extension
}
// Psk Psk
type Psk struct {
Type byte
TicketKLifeTimeHint uint32
MacValue []byte
KeyVersion uint32
Iv []byte
EncryptedTicket []byte
}
// ClientPsk CLientPsk
type ClientPsk struct {
Psk *Psk
PskExpiredTime uint64
PreSharedKey []byte
}
// Finished Finished
type Finished struct {
VerifyData []byte
}
// HTTPHandler HttpHandler
type HTTPHandler struct {
URL string
Host string
MMPkg []byte
}
// KeyPair ECDH信息
type KeyPair struct {
Version uint32
Nid uint32
PublicKey []byte
PrivateKey []byte
}
// NewSessionTicket NewSessionTicket
type NewSessionTicket struct {
PskList []*Psk
}
// PskTicket PskTicket
type PskTicket struct {
Version byte
MMTlsVersion uint16
CipherSuite *CipherSuite
KeyVersion uint32
TicketKLifeTimeHint uint32
PreSharedKey []byte
MacKey []byte
ClientGmtTime uint32
ServerGmtTime uint32
EcdhVersion uint32
Valid byte
}
// RecordHead RecordHead
type RecordHead struct {
Type byte
Tag uint16
Size uint16
}
// Alert Alert
type Alert struct {
AlertLevel byte
AlertType uint16
FallBackURL []byte
SignatureURL []byte
}
// PackItem 包数量
type PackItem struct {
RecordHead []byte
PackData []byte
}
// LongPackHeaderInfo 长链接请求包头部信息
type LongPackHeaderInfo struct {
HeaderLen uint16
Version uint16
Operation uint32
SequenceNumber uint32
}
// LongRecvInfo 长链接接收信息
type LongRecvInfo struct {
HeaderInfo *LongPackHeaderInfo
RespData []byte
}

View File

@@ -0,0 +1,33 @@
package mmtls
import (
"fmt"
"xiawan/wx/clientsdk/baseutils"
)
// ShowMMTLSExtensions 打印Extensions
func ShowMMTLSExtensions(extensionList []*Extension) {
fmt.Println("--------------- ShowMMTLSExtensions in ---------------")
extensionLength := len(extensionList)
for index := 0; index < extensionLength; index++ {
// PreSharedKeyExtensionType
if extensionList[index].ExtensionType == PreSharedKeyExtensionType {
tmpExtension, _ := PreSharedKeyExtensionDeSerialize(extensionList[index].ExtensionData)
baseutils.ShowObjectValue(tmpExtension)
}
// ClientKeyShareType
if extensionList[index].ExtensionType == ClientKeyShareType {
tmpExtension, _ := ClientKeyShareExtensionDeSerialize(extensionList[index].ExtensionData)
baseutils.ShowObjectValue(tmpExtension)
}
// ServerKeyShareType
if extensionList[index].ExtensionType == ServerKeyShareType {
tmpExtension, _ := ServerKeyShareExtensionDeSerialize(extensionList[index].ExtensionData)
baseutils.ShowObjectValue(tmpExtension)
}
}
fmt.Println("--------------- ShowMMTLSExtensions out ---------------")
}

View File

@@ -0,0 +1,82 @@
package mmtls
const (
// ClientHandShakeType ClientHandShakeType
ClientHandShakeType byte = 25
// ServerHandShakeType ServerHandShakeType
ServerHandShakeType byte = 22
// BodyType BodyType
BodyType byte = 23
// AlertType AlertType
AlertType byte = 21
// ClientHelloType ClientHelloType
ClientHelloType byte = 1
// ServerHelloType ServerHelloType
ServerHelloType byte = 2
// NewSessionTicketType NewSessionTicketType
NewSessionTicketType byte = 4
// EncryptedExtensionsType EncryptedExtensionsType
EncryptedExtensionsType byte = 8
// CertificateVerifyType CertificateVerifyType
CertificateVerifyType byte = 15
// FinishedType FinishedType
FinishedType byte = 20
// PreSharedKeyExtensionType PreSharedKeyExtensionType
PreSharedKeyExtensionType uint16 = 15
// ClientKeyShareType ClientKeyShareType
ClientKeyShareType uint16 = 16
// ServerKeyShareType ServerKeyShareType
ServerKeyShareType uint16 = 17
// EarlyEncryptDataType EarlyEncryptDataType
EarlyEncryptDataType uint16 = 18
// MaxCipherSuiteSize MaxCipherSuiteSize
MaxCipherSuiteSize uint32 = 2
// FixedRandomSize FixedRandomSize
FixedRandomSize uint32 = 32
// MaxNewSessionTicketPskSize MaxNewSessionTicketPskSize
MaxNewSessionTicketPskSize uint32 = 2
// MaxSignatureSize MaxSignatureSize
MaxSignatureSize uint32 = 2048
// MaxFinishedVerifyDataSize MaxFinishedVerifyDataSize
MaxFinishedVerifyDataSize uint32 = 2048
// MaxDataPackSize MaxDataPackSize
MaxDataPackSize uint32 = 0x8000000
// MaxExtensionSize MaxExtensionSize
MaxExtensionSize uint32 = 256
// MaxKeyOfferSize MaxKeyOfferSize
MaxKeyOfferSize uint32 = 256
// MaxPublicValueSize MaxPublicValueSize
MaxPublicValueSize uint32 = 256
// FixedRecordHeadSize FixedRecordHeadSize
FixedRecordHeadSize uint32 = 5
// MMLongVersion 长链接版本号
MMLongVersion uint16 = 1
// MMLongOperationSmartHeartBeat 心跳包
MMLongOperationSmartHeartBeat uint32 = 0x06
// MMLongOperationSmartHeartBeatBackUp 心跳包请求-备用
MMLongOperationSmartHeartBeatBackUp uint32 = 0x0c
// MMLongOperationServerPush 服务端推送消息
MMLongOperationServerPush uint32 = 0x7a
// MMLongOperationGetOnlineInfo 发起GetOnlineInfo请求
MMLongOperationGetOnlineInfo uint32 = 0xcd
// MMLongOperationCheckQrcode 检测二维码状态请求
MMLongOperationCheckQrcode uint32 = 0xe9
// MMLongOperationRequest 发起请求
MMLongOperationRequest uint32 = 0xed
// MMLongOperationHeartBeat 发送心跳包请求
MMLongOperationHeartBeat uint32 = 0xee
//MMLongOperationSystemPush 系统推送
MMLongOperationSystemPush uint32 = 0x18
// MMLongSystemPushTypeSync 系统推送:需要同步
MMLongSystemPushTypeSync int32 = 2
// MMLongSystemPushTypeLogout 系统推送:被退出登陆
MMLongSystemPushTypeLogout int32 = -1
)