first commit
This commit is contained in:
@@ -0,0 +1,806 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user