807 lines
28 KiB
Go
807 lines
28 KiB
Go
package clientsdk
|
||
|
||
import (
|
||
"encoding/base64"
|
||
"encoding/binary"
|
||
"encoding/hex"
|
||
"errors"
|
||
"hash/crc32"
|
||
"strconv"
|
||
"strings"
|
||
"time"
|
||
"xiawan/wx/clientsdk/android"
|
||
clientsdk "xiawan/wx/clientsdk/hybrid"
|
||
|
||
"github.com/lunny/log"
|
||
|
||
"xiawan/wx/clientsdk/baseinfo"
|
||
"xiawan/wx/clientsdk/baseutils"
|
||
"xiawan/wx/clientsdk/ccdata"
|
||
"xiawan/wx/clientsdk/proxynet"
|
||
"xiawan/wx/protobuf/wechat"
|
||
|
||
"golang.org/x/net/proxy"
|
||
|
||
"github.com/golang/protobuf/proto"
|
||
)
|
||
|
||
// NewUserInfo 新建一个UserInfo
|
||
func NewUserInfo(uuid string, proxyInfo *proxynet.WXProxyInfo, ClientVersion uint32, dbUserInfo *baseinfo.UserInfo) *baseinfo.UserInfo {
|
||
var WifiInfo = createWifiInfo()
|
||
//随机生成 deviceID
|
||
var userInfo = baseinfo.UserInfo{
|
||
UUID: uuid,
|
||
Uin: 0,
|
||
WxId: "",
|
||
Session: []byte{},
|
||
SessionKey: baseutils.RandomStringByLength(16),
|
||
ShortHost: "szshort.weixin.qq.com",
|
||
LongHost: "szlong.weixin.qq.com",
|
||
ClientVersion: ClientVersion,
|
||
SyncKey: []byte{},
|
||
BalanceVersion: 1589560770,
|
||
DeviceInfo: createDeviceInfo(WifiInfo, ClientVersion, dbUserInfo),
|
||
DeviceInfoA16: createDeviceInfoA16(),
|
||
WifiInfo: WifiInfo,
|
||
ProxyInfo: proxyInfo,
|
||
// 默认登录版本号 135
|
||
LoginRsaVer: baseinfo.DefaultLoginRsaVer,
|
||
|
||
DeviceCreateTime: time.Now(), // 新设备注册时间
|
||
}
|
||
return &userInfo
|
||
}
|
||
|
||
func NewUserInfo_Mac(uuid string, proxyInfo *proxynet.WXProxyInfo, ClientVersion uint32, dbUserInfo *baseinfo.UserInfo) *baseinfo.UserInfo {
|
||
var WifiInfo = createWifiInfo()
|
||
//随机生成 deviceID
|
||
var userInfo = baseinfo.UserInfo{
|
||
UUID: uuid,
|
||
Uin: 0,
|
||
WxId: "",
|
||
Session: []byte{},
|
||
SessionKey: baseutils.RandomStringByLength(16),
|
||
ShortHost: "szshort.weixin.qq.com",
|
||
LongHost: "szlong.weixin.qq.com",
|
||
ClientVersion: ClientVersion,
|
||
SyncKey: []byte{},
|
||
BalanceVersion: 1589560770,
|
||
DeviceInfo: createDeviceInfoMac(WifiInfo, ClientVersion, dbUserInfo),
|
||
DeviceInfoA16: createDeviceInfoA16(),
|
||
WifiInfo: WifiInfo,
|
||
ProxyInfo: proxyInfo,
|
||
// 默认登录版本号 135
|
||
LoginRsaVer: baseinfo.DefaultLoginRsaVer,
|
||
|
||
DeviceCreateTime: time.Now(), // 新设备注册时间
|
||
}
|
||
return &userInfo
|
||
}
|
||
|
||
// 新建Wifi信息
|
||
func createWifiInfo() *baseinfo.WifiInfo {
|
||
retWifiInfo := &baseinfo.WifiInfo{}
|
||
retWifiInfo.Name = "Chinanet-" + string(baseutils.RandomString(4, 7))
|
||
retWifiInfo.WifiBssID = baseutils.RandomBSSID()
|
||
return retWifiInfo
|
||
}
|
||
|
||
// 生成A16设备信息
|
||
func createDeviceInfoA16() *baseinfo.AndroidDeviceInfo {
|
||
deviceInfo := &baseinfo.AndroidDeviceInfo{}
|
||
deviceInfo.BuildBoard = "bullhead"
|
||
return deviceInfo
|
||
}
|
||
|
||
// CreateDeviceInfo 生成新的设备信息 ipad
|
||
func createDeviceInfo(wifiInfo *baseinfo.WifiInfo, ClientVersion uint32, dbUserInfo *baseinfo.UserInfo) *baseinfo.DeviceInfo {
|
||
IPadDeviceName := baseinfo.IPadDeviceName
|
||
IPadModel := baseinfo.IPadModel
|
||
IPadOsVersion := baseinfo.IPadOsVersion
|
||
DeviceTypeIos := baseinfo.DeviceTypeIos
|
||
CoreCount := uint32(2)
|
||
Imei := baseutils.RandomSmallHexString(32)
|
||
tmpDeviceID := baseutils.HexStringToBytes(Imei)
|
||
tmpDeviceID[0] = 0x49
|
||
|
||
if dbUserInfo != nil && dbUserInfo.DeviceInfo != nil {
|
||
IPadDeviceName = dbUserInfo.DeviceInfo.DeviceName
|
||
IPadModel = dbUserInfo.DeviceInfo.IphoneVer
|
||
IPadOsVersion = dbUserInfo.DeviceInfo.OsTypeNumber
|
||
DeviceTypeIos = dbUserInfo.DeviceInfo.OsType
|
||
CoreCount = dbUserInfo.DeviceInfo.CoreCount
|
||
Imei = dbUserInfo.DeviceInfo.Imei
|
||
tmpDeviceID = dbUserInfo.DeviceInfo.DeviceID
|
||
}
|
||
|
||
deviceInfo := &baseinfo.DeviceInfo{}
|
||
deviceInfo.Imei = Imei
|
||
deviceInfo.DeviceID = tmpDeviceID
|
||
deviceInfo.DeviceName = IPadDeviceName //iPad Air 3 对应 iPad11,4 || iPad11,3
|
||
deviceInfo.TimeZone = "8.00"
|
||
deviceInfo.Language = "zh_CN"
|
||
deviceInfo.DeviceBrand = "Apple"
|
||
deviceInfo.RealCountry = "CN"
|
||
deviceInfo.IphoneVer = IPadModel
|
||
deviceInfo.BundleID = "com.tencent.xin"
|
||
// deviceInfo.OsTypeNumber = "15.0.0"
|
||
deviceInfo.OsTypeNumber = IPadOsVersion // "15.7.9"
|
||
deviceInfo.OsType = DeviceTypeIos // "iPad iPadOS" + deviceInfo.OsTypeNumber
|
||
deviceInfo.CoreCount = CoreCount // 2 核
|
||
deviceInfo.AdSource = baseutils.RandomUUID()
|
||
deviceInfo.UUIDOne = baseutils.RandomUUID()
|
||
deviceInfo.UUIDTwo = baseutils.RandomUUID()
|
||
// 运营商名
|
||
deviceInfo.CarrierName = "(null)"
|
||
// deviceInfo.CarrierName = "中国电信"
|
||
deviceInfo.SoftTypeXML = CreateSoftInfoXML(deviceInfo, wifiInfo)
|
||
// ClientCheckDataXML
|
||
deviceInfo.ClientCheckDataXML = ccdata.CreateClientCheckDataXML(deviceInfo, ClientVersion)
|
||
return deviceInfo
|
||
}
|
||
|
||
// CreateDeviceInfo 生成新的设备信息 mac
|
||
func createDeviceInfoMac(wifiInfo *baseinfo.WifiInfo, ClientVersion uint32, dbUserInfo *baseinfo.UserInfo) *baseinfo.DeviceInfo {
|
||
IPadDeviceName := baseinfo.MacDeviceName
|
||
IPadModel := baseinfo.MacModel
|
||
IPadOsVersion := baseinfo.MacOsVersion
|
||
DeviceTypeIos := baseinfo.MacDeviceType
|
||
CoreCount := uint32(2)
|
||
Imei := baseutils.RandomSmallHexString(32)
|
||
tmpDeviceID := baseutils.HexStringToBytes(Imei)
|
||
tmpDeviceID[0] = 0x49
|
||
|
||
if dbUserInfo != nil {
|
||
IPadDeviceName = dbUserInfo.DeviceInfo.DeviceName
|
||
IPadModel = dbUserInfo.DeviceInfo.IphoneVer
|
||
IPadOsVersion = dbUserInfo.DeviceInfo.OsTypeNumber
|
||
DeviceTypeIos = dbUserInfo.DeviceInfo.OsType
|
||
CoreCount = dbUserInfo.DeviceInfo.CoreCount
|
||
Imei = dbUserInfo.DeviceInfo.Imei
|
||
tmpDeviceID = dbUserInfo.DeviceInfo.DeviceID
|
||
}
|
||
deviceInfo := &baseinfo.DeviceInfo{}
|
||
deviceInfo.Imei = Imei
|
||
deviceInfo.DeviceID = tmpDeviceID
|
||
deviceInfo.DeviceName = IPadDeviceName //iPad Air 3 对应 iPad11,4 || iPad11,3
|
||
deviceInfo.TimeZone = "8.00"
|
||
deviceInfo.Language = "zh_CN"
|
||
deviceInfo.DeviceBrand = "Apple"
|
||
deviceInfo.RealCountry = "CN"
|
||
deviceInfo.IphoneVer = IPadModel
|
||
deviceInfo.BundleID = "com.tencent.xin"
|
||
// deviceInfo.OsTypeNumber = "15.0.0"
|
||
deviceInfo.OsTypeNumber = IPadOsVersion // "15.7.9"
|
||
deviceInfo.OsType = DeviceTypeIos // "iPad iPadOS" + deviceInfo.OsTypeNumber
|
||
deviceInfo.CoreCount = CoreCount // 2 核
|
||
deviceInfo.AdSource = baseutils.RandomUUID()
|
||
deviceInfo.UUIDOne = baseutils.RandomUUID()
|
||
deviceInfo.UUIDTwo = baseutils.RandomUUID()
|
||
// 运营商名
|
||
deviceInfo.CarrierName = "(null)"
|
||
// deviceInfo.CarrierName = "中国电信"
|
||
deviceInfo.SoftTypeXML = CreateSoftInfoXML(deviceInfo, wifiInfo)
|
||
// ClientCheckDataXML
|
||
deviceInfo.ClientCheckDataXML = ccdata.CreateClientCheckDataXML(deviceInfo, ClientVersion)
|
||
return deviceInfo
|
||
}
|
||
|
||
// CreateSoftInfoXML CreateSoftInfoXML
|
||
func CreateSoftInfoXML(deviceInfo *baseinfo.DeviceInfo, wifiInfo *baseinfo.WifiInfo) string {
|
||
var retString string
|
||
retString = retString + "<softtype><lctmoc>0</lctmoc><level>0</level><k1>0</k1>"
|
||
retString = retString + "<k3>" + deviceInfo.OsTypeNumber + "</k3>"
|
||
retString = retString + "<k9>" + deviceInfo.DeviceName + "</k9>"
|
||
retString = retString + "<k10>" + strconv.Itoa(int(deviceInfo.CoreCount)) + "</k10>"
|
||
retString = retString + "<k19>" + deviceInfo.UUIDOne + "</k19>"
|
||
retString = retString + "<k20>" + deviceInfo.UUIDTwo + "</k20>"
|
||
// retString = retString + "<k21>" + wifiInfo.Name + "</k21>"
|
||
retString = retString + "<k22>" + deviceInfo.CarrierName + "</k22>"
|
||
// retString = retString + "<k22>" + deviceInfo.CarrierName + "</k22>"
|
||
retString = retString + "<k24>" + baseutils.BuildRandomMac() + "</k24>"
|
||
retString = retString + "<k33>微信</k33>"
|
||
// <k47>: 网络类型 1-wifi
|
||
retString = retString + "<k47>1</k47>"
|
||
// <k50>: 是否越狱 0-非越狱 1-越狱
|
||
retString = retString + "<k50>0</k50>"
|
||
retString = retString + "<k51>" + deviceInfo.BundleID + "</k51>"
|
||
retString = retString + "<k54>" + deviceInfo.IphoneVer + "</k54>"
|
||
// <k61>: 设备UUID是新的设备,还是老的设备
|
||
retString = retString + "<k61>" + strconv.Itoa(1) + "</k61>"
|
||
retString = retString + "</softtype>"
|
||
return retString
|
||
}
|
||
|
||
// GetEncryptUserInfo 获取加密信息
|
||
func GetEncryptUserInfo(userInfo *baseinfo.UserInfo) string {
|
||
if userInfo.WifiInfo == nil {
|
||
userInfo.WifiInfo = createWifiInfo()
|
||
}
|
||
tmpString := "wifissid=" + userInfo.WifiInfo.Name
|
||
tmpString = tmpString + "&wifibssid=" + userInfo.WifiInfo.WifiBssID
|
||
timeStamp := strconv.Itoa(int(time.Now().UnixNano() / 1000))
|
||
tmpString = tmpString + "&ssid_timestamp=" + timeStamp
|
||
srcBytes := []byte(tmpString)
|
||
srcBytes = append(srcBytes, 0)
|
||
userInfo.GenHBKey()
|
||
encData := baseutils.AesEncryptECB(srcBytes, userInfo.HBAesKey)
|
||
return base64.StdEncoding.EncodeToString(encData)
|
||
}
|
||
|
||
// GetDialer 获取代理
|
||
func GetDialer(userInfo *baseinfo.UserInfo) proxy.Dialer {
|
||
if userInfo.Dialer != nil {
|
||
return userInfo.Dialer
|
||
}
|
||
if userInfo.ProxyInfo == nil {
|
||
return nil
|
||
}
|
||
return userInfo.ProxyInfo.GetDialer()
|
||
}
|
||
|
||
// Paser62Data 解析62数据
|
||
func Parse62Data(data62 string) (string, error) {
|
||
retList := strings.Split(strings.ToUpper(data62), "6E756C6C5F1020")
|
||
if len(retList) < 2 {
|
||
return "", errors.New("InitLoginDataInfo err: loginDataInfo.Data Split 6E756C6C5F1020 error")
|
||
}
|
||
|
||
// 截取64位数据
|
||
data64Str := retList[1][0:64]
|
||
// 设置Imei
|
||
return string(baseutils.HexStringToBytes(data64Str)), nil
|
||
}
|
||
|
||
// CreatePackHead 创建包头
|
||
func CreatePackHead(userInfo *baseinfo.UserInfo, compressType byte, urlID uint32, srcData []byte, encodeData []byte, zipLen uint32, encodeType byte, encodeVersion uint32) *baseinfo.PackHeader {
|
||
retHeader := &baseinfo.PackHeader{}
|
||
// Signature
|
||
retHeader.Signature = 0xbf
|
||
retHeader.CompressType = compressType
|
||
retHeader.EncodeType = encodeType << 4
|
||
|
||
retHeader.ServerVersion = userInfo.ClientVersion
|
||
if !(retHeader.ServerVersion > 0) {
|
||
retHeader.ServerVersion = baseinfo.ClientVersion
|
||
}
|
||
|
||
retHeader.Uin = userInfo.Uin
|
||
retHeader.Session = userInfo.Session
|
||
retHeader.URLID = urlID
|
||
retHeader.SrcLen = uint32(len(srcData))
|
||
retHeader.ZipLen = zipLen
|
||
retHeader.EncodeVersion = encodeVersion
|
||
retHeader.HeadDeviceType = baseinfo.MMHeadDeviceTypeIpadUniversal
|
||
retHeader.CheckSum = 0x00
|
||
// 如果有压缩,则计算Sum值
|
||
if retHeader.CompressType == baseinfo.MMPackDataTypeCompressed {
|
||
retHeader.CheckSum = CalcHeadCheckSum(userInfo.Uin, userInfo.CheckSumKey, srcData)
|
||
}
|
||
// test
|
||
/*if retHeader.URLID == 213 {
|
||
retHeader.HeadDeviceType = 0x00
|
||
}*/
|
||
|
||
retHeader.RunState = baseinfo.MMAppRunStateNormal
|
||
// 修改 rqt 版本
|
||
// 旧 rqtx
|
||
// retHeader.RqtCode = SignRqtBufByAutoChosenKey(baseutils.Md5ValueByte(encodeData, false))
|
||
// rqtx 加密
|
||
// retHeader.RqtCode = baseutils.CalcMsgCrcForString_807(baseutils.Md5ValueByte(encodeData, false))
|
||
// 新 rqtx
|
||
retHeader.RqtCode = android.CalcMsgCrcForData_7019(encodeData)
|
||
retHeader.EndFlag = 0x00
|
||
retHeader.Data = encodeData
|
||
|
||
return retHeader
|
||
}
|
||
|
||
// PackHeaderSerialize 序列化PackHeader
|
||
func PackHeaderSerialize(packHeader *baseinfo.PackHeader, needCookie bool) []byte {
|
||
retBytes := make([]byte, 0)
|
||
retBytes = append(retBytes, packHeader.Signature)
|
||
retBytes = append(retBytes, 0)
|
||
encodeType := packHeader.EncodeType
|
||
if needCookie {
|
||
packHeader.EncodeType = packHeader.EncodeType + 0xf
|
||
}
|
||
retBytes = append(retBytes, packHeader.EncodeType)
|
||
retBytes = append(retBytes, baseutils.Int32ToBytes(packHeader.ServerVersion)[0:]...)
|
||
retBytes = append(retBytes, baseutils.Int32ToBytes(packHeader.Uin)[0:]...)
|
||
if needCookie {
|
||
retBytes = append(retBytes, packHeader.Session[0:]...)
|
||
}
|
||
retBytes = append(retBytes, baseutils.EncodeVByte32(packHeader.URLID)[0:]...)
|
||
retBytes = append(retBytes, baseutils.EncodeVByte32(packHeader.SrcLen)[0:]...)
|
||
retBytes = append(retBytes, baseutils.EncodeVByte32(packHeader.ZipLen)[0:]...)
|
||
// hybrid
|
||
if encodeType>>4 == 12 {
|
||
retBytes = append(retBytes, []byte{byte(packHeader.HybridKeyVer)}...)
|
||
}
|
||
|
||
retBytes = append(retBytes, baseutils.EncodeVByte32(packHeader.EncodeVersion)[0:]...)
|
||
retBytes = append(retBytes, packHeader.HeadDeviceType)
|
||
retBytes = append(retBytes, baseutils.EncodeVByte32(packHeader.CheckSum)[0:]...)
|
||
retBytes = append(retBytes, packHeader.RunState)
|
||
retBytes = append(retBytes, baseutils.EncodeVByte32(packHeader.RqtCode)[0:]...)
|
||
retBytes = append(retBytes, packHeader.EndFlag)
|
||
headLen := byte(len(retBytes))
|
||
retBytes[1] = packHeader.CompressType + headLen<<2
|
||
//fmt.Println(hex.EncodeToString(retBytes))
|
||
retBytes = append(retBytes, packHeader.Data[0:]...)
|
||
return retBytes
|
||
}
|
||
|
||
// Pack 打包加密数据
|
||
func Pack(userInfo *baseinfo.UserInfo, src []byte, urlID uint32, encodeType byte) []byte {
|
||
retData := make([]byte, 0)
|
||
if encodeType == 7 || encodeType == 17 {
|
||
//加密类型7
|
||
encodeData := src
|
||
if encodeType == 7 {
|
||
encodeData = baseutils.NoCompressRsaByVer(src, userInfo.GetLoginRsaVer())
|
||
}
|
||
packHeader := CreatePackHead(userInfo, baseinfo.MMPackDataTypeUnCompressed, urlID, src, encodeData, uint32(len(src)), 7, userInfo.GetLoginRsaVer())
|
||
retData = PackHeaderSerialize(packHeader, false)
|
||
} else if encodeType == 5 {
|
||
zipBytes := baseutils.CompressByteArray(src)
|
||
encodeData := baseutils.AesEncrypt(zipBytes, userInfo.SessionKey)
|
||
packHeader := CreatePackHead(userInfo, baseinfo.MMPackDataTypeCompressed, urlID, src, encodeData, uint32(len(zipBytes)), encodeType, 0)
|
||
retData = PackHeaderSerialize(packHeader, true)
|
||
} else if encodeType == 9 {
|
||
// 加密类型9
|
||
encodeData := src
|
||
packHeader := CreatePackHead(userInfo, baseinfo.MMPackDataTypeUnCompressed, urlID, src, encodeData, uint32(len(src)), encodeType, userInfo.GetLoginRsaVer())
|
||
retData = PackHeaderSerialize(packHeader, true)
|
||
} else if encodeType == 1 {
|
||
// 加密类型1
|
||
encodeData := baseutils.NoCompressRsaByVer(src, userInfo.GetLoginRsaVer())
|
||
packHeader := CreatePackHead(userInfo, baseinfo.MMPackDataTypeUnCompressed, urlID, src, encodeData, uint32(len(src)), encodeType, userInfo.GetLoginRsaVer())
|
||
retData = PackHeaderSerialize(packHeader, true)
|
||
} else if encodeType == 12 {
|
||
secKeyMgr := NewSecLoginKeyMgrByVer(146)
|
||
reqData := src
|
||
//加密
|
||
encrypt, epKey, token, ecdhpairkey, err := clientsdk.HybridEncrypt(reqData, secKeyMgr.WeChatPubKey)
|
||
if err != nil {
|
||
log.Error("加密 error", err.Error())
|
||
}
|
||
ecdhPacket := &wechat.EcdhPacket{
|
||
Type: proto.Uint32(1),
|
||
Key: &wechat.BufferT{
|
||
ILen: proto.Uint32(415),
|
||
Buffer: ecdhpairkey.PubKey,
|
||
},
|
||
Token: token,
|
||
Url: proto.String(""),
|
||
ProtobufData: encrypt,
|
||
}
|
||
secKeyMgr.PubKey = ecdhpairkey.PubKey
|
||
secKeyMgr.PriKey = ecdhpairkey.PriKey
|
||
secKeyMgr.SourceData = reqData
|
||
secKeyMgr.FinalSha256 = append(secKeyMgr.FinalSha256, epKey[24:]...)
|
||
secKeyMgr.FinalSha256 = append(secKeyMgr.FinalSha256, reqData...)
|
||
ecdhDataPacket, err := proto.Marshal(ecdhPacket)
|
||
if err != nil {
|
||
log.Error("ecdhDataPacket error", err.Error())
|
||
}
|
||
packHeader := CreatePackHead(userInfo, baseinfo.MMPackDataTypeUnCompressed, urlID, ecdhDataPacket, ecdhDataPacket, uint32(len(ecdhDataPacket)), encodeType, uint32(0x4e))
|
||
//设置Hybrid 加密密钥版本
|
||
packHeader.HybridKeyVer = secKeyMgr.WeChatPubKeyVersion
|
||
//开始组头
|
||
retData := PackHeaderSerialize(packHeader, false)
|
||
//fmt.Println(hex.EncodeToString(retData))
|
||
/*resp, err := mmtls.MMHTTPPostData(userInfo.MMInfo, "/cgi-bin/micromsg-bin/secautoauth", retData)
|
||
if err != nil {
|
||
log.Error("mmtls error", err.Error())
|
||
}*/
|
||
/*packHeader, err = DecodePackHeader(resp, nil)
|
||
if err != nil {
|
||
log.Error("ecdhDataPacket error", err.Error())
|
||
}
|
||
packHeader.Data, err = clientsdk.HybridEcdhDecrypt(packHeader.Data, secKeyMgr.PriKey, secKeyMgr.PubKey, secKeyMgr.FinalSha256)
|
||
if err != nil {
|
||
log.Error("HybridEcdhDecrypt error", err.Error())
|
||
}
|
||
return packHeader, err*/
|
||
return retData
|
||
}
|
||
return retData
|
||
}
|
||
|
||
func PackNoCompressAES(userInfo *baseinfo.UserInfo, src []byte, urlID uint32) []byte {
|
||
encodeData := baseutils.AesEncrypt(src, userInfo.SessionKey)
|
||
packHeader := CreatePackHead(userInfo, baseinfo.MMPackDataTypeUnCompressed, urlID, src, encodeData, uint32(len(src)), 5, 0)
|
||
return PackHeaderSerialize(packHeader, true)
|
||
}
|
||
|
||
// Pack 打包加密数据
|
||
func Pack12(userInfo *baseinfo.UserInfo, src []byte, urlID uint32, encodeType byte) ([]byte, *SecLoginKeyMgr) {
|
||
retData := make([]byte, 0)
|
||
secKeyMgr := NewSecLoginKeyMgrByVer(146)
|
||
reqData := src
|
||
//加密
|
||
encrypt, epKey, token, ecdhpairkey, err := clientsdk.HybridEncrypt(reqData, secKeyMgr.WeChatPubKey)
|
||
if err != nil {
|
||
log.Error("加密 error", err.Error())
|
||
}
|
||
ecdhPacket := &wechat.EcdhPacket{
|
||
Type: proto.Uint32(1),
|
||
Key: &wechat.BufferT{
|
||
ILen: proto.Uint32(415),
|
||
Buffer: ecdhpairkey.PubKey,
|
||
},
|
||
Token: token,
|
||
Url: proto.String(""),
|
||
ProtobufData: encrypt,
|
||
}
|
||
secKeyMgr.PubKey = ecdhpairkey.PubKey
|
||
secKeyMgr.PriKey = ecdhpairkey.PriKey
|
||
secKeyMgr.SourceData = reqData
|
||
secKeyMgr.FinalSha256 = append(secKeyMgr.FinalSha256, epKey[24:]...)
|
||
secKeyMgr.FinalSha256 = append(secKeyMgr.FinalSha256, reqData...)
|
||
ecdhDataPacket, err := proto.Marshal(ecdhPacket)
|
||
if err != nil {
|
||
log.Error("ecdhDataPacket error", err.Error())
|
||
}
|
||
packHeader := CreatePackHead(userInfo, baseinfo.MMPackDataTypeUnCompressed, urlID, ecdhDataPacket, ecdhDataPacket, uint32(len(ecdhDataPacket)), encodeType, uint32(0x4e))
|
||
//设置Hybrid 加密密钥版本
|
||
packHeader.HybridKeyVer = secKeyMgr.WeChatPubKeyVersion
|
||
//开始组头
|
||
retData = PackHeaderSerialize(packHeader, false)
|
||
//fmt.Println(hex.EncodeToString(retData))
|
||
/*resp, err := mmtls.MMHTTPPostData(userInfo.MMInfo, "/cgi-bin/micromsg-bin/secautoauth", retData)
|
||
if err != nil {
|
||
log.Error("mmtls error", err.Error())
|
||
}*/
|
||
/*packHeader, err = DecodePackHeader(resp, nil)
|
||
if err != nil {
|
||
log.Error("ecdhDataPacket error", err.Error())
|
||
}
|
||
packHeader.Data, err = clientsdk.HybridEcdhDecrypt(packHeader.Data, secKeyMgr.PriKey, secKeyMgr.PubKey, secKeyMgr.FinalSha256)
|
||
if err != nil {
|
||
log.Error("HybridEcdhDecrypt error", err.Error())
|
||
}
|
||
return packHeader, err*/
|
||
return retData, secKeyMgr
|
||
}
|
||
|
||
// DecodePackHeader DecodePackHeader
|
||
func DecodePackHeader(respData []byte, reqData []byte) (*baseinfo.PackHeader, error) {
|
||
packHeader := &baseinfo.PackHeader{}
|
||
packHeader.ReqData = reqData
|
||
packHeader.RetCode = 0
|
||
if len(respData) <= 32 {
|
||
packHeader.RetCode = GetRespErrorCode(respData)
|
||
return packHeader, errors.New("DecodePackHeader err: len(respData) <= 32")
|
||
}
|
||
|
||
current := 0
|
||
packHeader.Signature = respData[current]
|
||
current++
|
||
packHeader.HeadLength = (respData[current]) >> 2
|
||
packHeader.CompressType = (respData[current]) & 3
|
||
current++
|
||
packHeader.EncodeType = respData[current] >> 4
|
||
sessionLen := int(respData[current] & 0x0f)
|
||
current++
|
||
packHeader.ServerVersion = baseutils.BytesToInt32(respData[current : current+4])
|
||
current = current + 4
|
||
packHeader.Uin = baseutils.BytesToInt32(respData[current : current+4])
|
||
current = current + 4
|
||
if sessionLen > 0 {
|
||
packHeader.Session = respData[current : current+sessionLen]
|
||
current = current + sessionLen
|
||
}
|
||
retLen := uint32(0)
|
||
packHeader.URLID, retLen = baseutils.DecodeVByte32(respData, uint32(current))
|
||
current = current + int(retLen)
|
||
packHeader.SrcLen, retLen = baseutils.DecodeVByte32(respData, uint32(current))
|
||
current = current + int(retLen)
|
||
packHeader.ZipLen, retLen = baseutils.DecodeVByte32(respData, uint32(current))
|
||
current = current + int(retLen)
|
||
packHeader.EncodeVersion, retLen = baseutils.DecodeVByte32(respData, uint32(current))
|
||
current = current + int(retLen)
|
||
packHeader.HeadDeviceType = respData[current]
|
||
current = current + 1
|
||
packHeader.CheckSum, retLen = baseutils.DecodeVByte32(respData, uint32(current))
|
||
current = current + int(retLen)
|
||
packHeader.RunState = respData[current]
|
||
current = current + 1
|
||
packHeader.RqtCode, retLen = baseutils.DecodeVByte32(respData, uint32(current))
|
||
current = current + int(retLen)
|
||
packHeader.EndFlag = respData[current]
|
||
current = current + 1
|
||
// // 后面还有一个字节-- 可能是7.10新版本增加的一个字节,待后面分析
|
||
// current = current + 1
|
||
// if current != int(packHeader.HeadLength) {
|
||
// return nil, errors.New("DecodePackHeader failed current != int(packHeader.HeadLength")
|
||
// }
|
||
packHeader.Data = respData[packHeader.HeadLength:]
|
||
return packHeader, nil
|
||
}
|
||
|
||
// ParseResponseData 解析相应数据
|
||
func ParseResponseData(userInfo *baseinfo.UserInfo, packHeader *baseinfo.PackHeader, response proto.Message) error {
|
||
// 判断包体长度是否大于0
|
||
if len(packHeader.Data) <= 0 {
|
||
log.Error("ParseResponseData err: len(packHeader.Data) <= 0")
|
||
return errors.New("ParseResponseData err: len(packHeader.Data) <= 0")
|
||
}
|
||
var decptBody []byte
|
||
var err error
|
||
if packHeader.EncodeType == 12 {
|
||
decptBody = packHeader.Data
|
||
} else if packHeader.EncodeType == 5 {
|
||
// 解密
|
||
decptBody, err = baseutils.AesDecrypt(packHeader.Data, userInfo.SessionKey)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
// fmt.Println(hex.EncodeToString(decptBody))
|
||
// 判断是否有压缩
|
||
if packHeader.CompressType == baseinfo.MMPackDataTypeCompressed {
|
||
if decptBody != nil {
|
||
// fmt.Println(hex.EncodeToString(decptBody))
|
||
decptBody, err = baseutils.UnzipByteArray(decptBody)
|
||
if err != nil {
|
||
log.Error("ParseResponseData err:", err.Error(), packHeader.URLID)
|
||
// 打印解密后的数据前100字节用于调试
|
||
if len(decptBody) > 0 {
|
||
debugLen := 100
|
||
if len(decptBody) < debugLen {
|
||
debugLen = len(decptBody)
|
||
}
|
||
log.Error("Decrypted data (first bytes):", hex.EncodeToString(decptBody[:debugLen]))
|
||
}
|
||
return err
|
||
}
|
||
} else {
|
||
return errors.New("decptBody err: len(decptBody) == nil")
|
||
}
|
||
}
|
||
} else {
|
||
// 解密
|
||
decptBody, err = baseutils.AesDecrypt(packHeader.Data, userInfo.SessionKey)
|
||
// fmt.Println(hex.EncodeToString(decptBody))
|
||
if err != nil {
|
||
//log.Error("ParseResponseData err:", err.Error())
|
||
return err
|
||
}
|
||
// 判断是否有压缩
|
||
if packHeader.CompressType == baseinfo.MMPackDataTypeCompressed {
|
||
if decptBody != nil {
|
||
decptBody, err = baseutils.UnzipByteArray(decptBody)
|
||
if err != nil {
|
||
//fmt.Println(hex.EncodeToString(packHeader.Data))
|
||
log.Error("ParseResponseData err:", err.Error(), packHeader.URLID)
|
||
// 打印解密后的数据前100字节用于调试
|
||
if len(decptBody) > 0 {
|
||
debugLen := 100
|
||
if len(decptBody) < debugLen {
|
||
debugLen = len(decptBody)
|
||
}
|
||
log.Error("Decrypted data (first bytes):", hex.EncodeToString(decptBody[:debugLen]))
|
||
}
|
||
return err
|
||
}
|
||
} else {
|
||
return errors.New("decptBody err: len(decptBody) == nil")
|
||
}
|
||
}
|
||
}
|
||
|
||
// 更新UserInfo
|
||
if len(packHeader.Session) > 6 {
|
||
userInfo.Session = packHeader.Session
|
||
}
|
||
|
||
if packHeader.Uin != 0 {
|
||
userInfo.Uin = packHeader.Uin
|
||
}
|
||
// fmt.Println(hex.EncodeToString(decptBody))
|
||
// 解包ProtoBuf
|
||
err = proto.Unmarshal(decptBody, response)
|
||
if err != nil {
|
||
log.Error("ParseResponseData err:", err.Error())
|
||
return err
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// GetBaseRequest 获取baserequest
|
||
func GetBaseRequest(userInfo *baseinfo.UserInfo) *wechat.BaseRequest {
|
||
ret := &wechat.BaseRequest{}
|
||
ret.SessionKey = []byte(userInfo.SessionKey)
|
||
ret.Uin = &userInfo.Uin
|
||
if !strings.HasPrefix(userInfo.LoginDataInfo.LoginData, "A") && userInfo.DeviceInfo != nil {
|
||
ret.DeviceId = userInfo.DeviceInfo.DeviceID
|
||
ret.OsType = &userInfo.DeviceInfo.OsType
|
||
ret.Scene = proto.Uint32(0)
|
||
ret.ClientVersion = &userInfo.ClientVersion
|
||
if !(int(*ret.ClientVersion) > 0) {
|
||
ret.ClientVersion = &baseinfo.ClientVersion
|
||
}
|
||
} else {
|
||
ret.ClientVersion = &baseinfo.AndroidClientVersion
|
||
ret.OsType = &baseinfo.AndroidPadDeviceType
|
||
ret.DeviceId = userInfo.DeviceInfoA16.DeviceId
|
||
ret.Scene = proto.Uint32(1)
|
||
}
|
||
return ret
|
||
}
|
||
|
||
// CalcCheckCode 计算校验码
|
||
// wxId : 微信ID
|
||
// currentTime : 时间
|
||
// return uint32 计算出来的校验码
|
||
func CalcCheckCode(wxID string, currentTime time.Time) uint32 {
|
||
var tmpTime = currentTime.Format("051504010206")
|
||
if len(wxID) <= 0 {
|
||
tmpTime = tmpTime + "fffffff"
|
||
}
|
||
if len(wxID) > 0 {
|
||
wxIDMd5 := baseutils.Md5Value(wxID)
|
||
tmpTime = tmpTime + baseutils.StringCut(wxIDMd5, 0, 7)
|
||
}
|
||
|
||
misSecond := currentTime.UnixNano() / 1000000
|
||
var modValue = uint32(misSecond % 65535)
|
||
var modValue2 = int(misSecond%7 + 100)
|
||
modHexString := string(baseutils.UInt32To16Bytes(modValue))
|
||
mod2String := strconv.Itoa(modValue2)
|
||
tmpTime = tmpTime + modHexString + mod2String
|
||
|
||
return baseutils.HashCode(tmpTime)
|
||
}
|
||
|
||
// WithSeqidCalcCheckCode 根据seqid计算
|
||
func WithSeqidCalcCheckCode(wxID string, seqid int64) uint32 {
|
||
currentTime := time.Unix(0, seqid)
|
||
var tmpTime = currentTime.Format("051504010206")
|
||
if len(wxID) <= 0 {
|
||
tmpTime = tmpTime + "fffffff"
|
||
}
|
||
if len(wxID) > 0 {
|
||
wxIDMd5 := baseutils.Md5Value(wxID)
|
||
tmpTime = tmpTime + baseutils.StringCut(wxIDMd5, 0, 7)
|
||
}
|
||
|
||
misSecond := currentTime.UnixNano() / 1000000
|
||
var modValue = uint32(misSecond % 65535)
|
||
var modValue2 = int(misSecond%7 + 100)
|
||
modHexString := string(baseutils.UInt32To16Bytes(modValue))
|
||
mod2String := strconv.Itoa(modValue2)
|
||
tmpTime = tmpTime + modHexString + mod2String
|
||
|
||
return baseutils.HashCode(tmpTime)
|
||
}
|
||
|
||
// GetErrStrByErrCode GetErrStrByErrCode
|
||
func GetErrStrByErrCode(errCode int32) string {
|
||
if errCode == -2 {
|
||
return "error: args not whole or args type error"
|
||
}
|
||
if errCode == -13 {
|
||
return "error: session timeout"
|
||
}
|
||
if errCode == -102 {
|
||
return "error: cert expired"
|
||
}
|
||
if errCode == -306 {
|
||
return "error: ecdh failed rollback"
|
||
}
|
||
if errCode == -3001 || errCode == -3003 {
|
||
return "error: need get dns"
|
||
}
|
||
if errCode == -3002 {
|
||
return "error: MM_ERR_IDCDISASTER"
|
||
}
|
||
|
||
return "unknow"
|
||
}
|
||
|
||
// GetRespErrorCode 当response 小于32个字节时,调用这个接口获取响应的错误码
|
||
func GetRespErrorCode(data []byte) int32 {
|
||
tmpData := make([]byte, 0)
|
||
tmpData = append(tmpData, data[2:6]...)
|
||
|
||
tmpRet := binary.BigEndian.Uint32(tmpData)
|
||
return int32(tmpRet)
|
||
}
|
||
|
||
// RqtKey 计算RQT用到到Key
|
||
var RqtKey = []byte{0x6a, 0x66, 0x4d, 0x5d, 0x53, 0x7c, 0x25, 0x3f, 0x73, 0x6e, 0x48, 0x27, 0x3a, 0x29, 0x5e, 0x4f}
|
||
|
||
// SignRqtBufByAutoChosenKey 计算RQT值
|
||
func SignRqtBufByAutoChosenKey(md5Value string) uint32 {
|
||
// tmpRqtKeyOne
|
||
rqtLen := len(RqtKey)
|
||
totalLength := 48 + rqtLen
|
||
blockOne := make([]byte, totalLength)
|
||
for index := 0; index < totalLength; index++ {
|
||
blockOne[index] = 0
|
||
if index < rqtLen {
|
||
blockOne[index] = RqtKey[index]
|
||
}
|
||
blockOne[index] = blockOne[index] ^ 0x36
|
||
}
|
||
|
||
// tmpRqtKeyTwo
|
||
blockTwo := make([]byte, totalLength)
|
||
for index := 0; index < totalLength; index++ {
|
||
blockTwo[index] = 0
|
||
if index < rqtLen {
|
||
blockTwo[index] = RqtKey[index]
|
||
}
|
||
blockTwo[index] = blockTwo[index] ^ 0x5c
|
||
}
|
||
// 计算Hash值
|
||
tmpData := append(blockOne, []byte(md5Value)[0:]...)
|
||
shaValue := baseutils.Sha1(tmpData)
|
||
tmpData = append(blockTwo, shaValue[0:]...)
|
||
shaValue = baseutils.Sha1(tmpData)
|
||
|
||
// 计算key1,key2, key3
|
||
key1 := 0
|
||
key2 := 0
|
||
key3 := 0
|
||
tmpLen := len(shaValue) - 2
|
||
for index := 0; index < tmpLen; index++ {
|
||
tmpValue1 := shaValue[index] & 0xff
|
||
tmpValue2 := shaValue[index+1] & 0xff
|
||
tmpValue3 := shaValue[index+2] & 0xff
|
||
|
||
key1 = key1*0x83 + int(tmpValue1)
|
||
key2 = key2*0x83 + int(tmpValue2)
|
||
key3 = key3*0x83 + int(tmpValue3)
|
||
}
|
||
|
||
// 计算RQT值
|
||
key1 = key1 & 0x7f
|
||
key2 = (key2 << 8) & 0x7f00
|
||
key3 = (key3 << 16) & 0x7f0000
|
||
retValue := key1 | key3 | key2
|
||
retValue = retValue | 0x21000000
|
||
return uint32(retValue)
|
||
}
|
||
|
||
// CalcHeadCheckSum 计算HeadCheckSum值
|
||
func CalcHeadCheckSum(uin uint32, checkSumKey []byte, srcData []byte) uint32 {
|
||
uinBytes := baseutils.Int32ToBytes(uin)
|
||
tmpBytes := append(uinBytes, checkSumKey[0:]...)
|
||
md5Value := baseutils.Md5Value16(tmpBytes)
|
||
|
||
dataLen := uint32(len(srcData))
|
||
dataLenBytes := baseutils.Int32ToBytes(dataLen)
|
||
tmpBytes = append(dataLenBytes, checkSumKey[0:]...)
|
||
tmpBytes = append(tmpBytes, md5Value[0:]...)
|
||
md5Value = baseutils.Md5Value16(tmpBytes)
|
||
|
||
tmpBytes = append([]byte{}, md5Value[0:]...)
|
||
// 计算返回
|
||
/*tmpSum := baseutils.Adler32(1, tmpBytes)
|
||
return baseutils.Adler32(tmpSum, srcData)*/
|
||
return crc32.ChecksumIEEE(tmpBytes)
|
||
}
|
||
|
||
// TenPaySignDes3 支付相关的加密算法
|
||
func TenPaySignDes3(srcData string, encKey string) (string, error) {
|
||
srcMD5Bytes := []byte(baseutils.Md5ValueByte([]byte(srcData), true))
|
||
keyMD5Bytes := baseutils.Md5ValueByte([]byte(encKey), true)
|
||
desKey := baseutils.HexStringToBytes(keyMD5Bytes)
|
||
|
||
encBytes := make([]byte, 0)
|
||
for index := 0; index < 4; index++ {
|
||
currentOffset := index * 8
|
||
tmpSrcData := srcMD5Bytes[currentOffset : currentOffset+8]
|
||
encData, err := baseutils.Encrypt3DES(tmpSrcData, desKey)
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
encBytes = append(encBytes, encData...)
|
||
}
|
||
return baseutils.BytesToHexString(encBytes, true), nil
|
||
}
|