first commit
This commit is contained in:
@@ -0,0 +1,266 @@
|
||||
package clientsdk
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/zlib"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"golang.org/x/crypto/hkdf"
|
||||
"io"
|
||||
"log"
|
||||
rnd "math/rand"
|
||||
"time"
|
||||
"xiawan/wx/clientsdk/cecdh"
|
||||
"xiawan/wx/protobuf/wechat"
|
||||
)
|
||||
|
||||
const (
|
||||
//145 新疆号可以登录
|
||||
WeChatPubKey_145 = "0493b4723be07a56d81e6f1994a55597ade831b78c60b8c8a9a5ad656bc10534a6ecfcd6b2504ccbc9682dc9c6f5d213bc3cc3e98a5d759747d4f9c7c46f0aa6fa"
|
||||
//146
|
||||
//iPad_WeChatPubKey_146 = "047ebe7604acf072b0ab0177ea551a7b72588f9b5d3801dfd7bb1bca8e33d1c3b8fa6e4e4026eb38d5bb365088a3d3167c83bdd0bbb46255f88a16ede6f7ab43b5\n"
|
||||
WeChatPubKey_146 = "0495bc6e5c1331ad172d0f35b1792c3ce63f91572abd2dd6df6dac2d70195c3f6627cca60307305d8495a8c38b4416c75021e823b6c97dffe79c14cb7c3af8a586"
|
||||
)
|
||||
|
||||
type EcdhKeyPair struct {
|
||||
PriKey []byte
|
||||
PubKey []byte
|
||||
}
|
||||
|
||||
func HybridEcdhDecrypt(data, priKey, pubKey, FinalShaData []byte) ([]byte, error) {
|
||||
hybridEcdhDecryptResp := &wechat.HybridDecryptResponse{}
|
||||
if err := proto.Unmarshal(data, hybridEcdhDecryptResp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
//进行ecdh
|
||||
secretKey, err := ECDH(priKey, hybridEcdhDecryptResp.Key.Buffer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
/*logger.Debugln(hex.EncodeToString(priKey))
|
||||
logger.Debugln(hex.EncodeToString(hybridEcdhDecryptResp.Key.Buffer))
|
||||
logger.Debugln("HybridEcdhDecrypt -> secretKey: ", hex.EncodeToString(secretKey))*/
|
||||
|
||||
//pubKey,_ = hex.DecodeString(WeChatPubKey)
|
||||
h1 := sha256.New()
|
||||
h1.Write(FinalShaData)
|
||||
h1.Write([]byte{0x34, 0x31, 0x35})
|
||||
h1.Write(hybridEcdhDecryptResp.Key.Buffer)
|
||||
h1.Write([]byte{0x31})
|
||||
h1Sha256RetData := h1.Sum(nil)
|
||||
|
||||
deProtoBuf, err := AesGcmDecryptWithUnCompress(secretKey[:24], h1Sha256RetData, hybridEcdhDecryptResp.ProtobufData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return deProtoBuf, nil
|
||||
}
|
||||
|
||||
func HybridEncrypt(data []byte, WeChatPubKey string) (protoEnData []byte, epKey []byte, token []byte, ecdhpairkey *EcdhKeyPair, err error) {
|
||||
//pubKey2,_ := hex.DecodeString("046ECE0D01D24E9360397CDB0B44B07FC94312E0DDCEB0C671C410A475BEF4C115844C8C98C78C6C17AA8A547B5EDBCA62DD40B3ABBDFC1A7B4AE5C17B144C6D31")
|
||||
//priKey2,_ := hex.DecodeString("30770201010420F8D96C0C7DD8474D5CA4A5CC374825DBC9D5BC144D90DA6A90F07509AD05ADDBA00A06082A8648CE3D030107A144034200046ECE0D01D24E9360397CDB0B44B07FC94312E0DDCEB0C671C410A475BEF4C115844C8C98C78C6C17AA8A547B5EDBCA62DD40B3ABBDFC1A7B4AE5C17B144C6D31")
|
||||
//生成公私密钥
|
||||
ecdhKeyPair, err := GenEcdhKeyPair()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
/* logger.Debugln("GenEcdhKeyPair -> PriKey: ", ecdhKeyPair.PriKey)
|
||||
logger.Debugln("GenEcdhKeyPair -> PubKey: ", ecdhKeyPair.PubKey)
|
||||
*/
|
||||
//进行ECDH
|
||||
pubKey, _ := hex.DecodeString(WeChatPubKey)
|
||||
secretKey, err := ECDH(ecdhKeyPair.PriKey, pubKey)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
//ecdh成功后取前24 为作为AesKey
|
||||
//logger.Debugln("SecretKey -> ", hex.EncodeToString(secretKey), len(secretKey))
|
||||
h1 := sha256.New()
|
||||
// 31343135 进行sha256
|
||||
h1.Write([]byte{0x31, 0x34, 0x31, 0x35})
|
||||
// 对生成的pubKey 进行sha256
|
||||
h1.Write(ecdhKeyPair.PubKey)
|
||||
h1SHA256RetData := h1.Sum(nil)
|
||||
//生成32个字节的随机数
|
||||
randomBytes := GenRandomBytes(32)
|
||||
//对随机生成32个字节进行加密
|
||||
enData, err := AesGcmEncryptWithCompress(secretKey[:24], h1SHA256RetData, randomBytes)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
//logger.Debugln(enData)
|
||||
// 对随机生成的 32 个字节和 sha256 的结果进行密钥扩展HKDF
|
||||
epKey = hkdfEP(randomBytes, h1SHA256RetData, []byte("security hdkf expand"))
|
||||
//log.Println("securityHdkfExpand -> ", hex.EncodeToString(epKey))
|
||||
//再次进行Sha256
|
||||
|
||||
/*h2 := sha256.New()
|
||||
//1 + 415 字符串进行sha256
|
||||
h2.Write([]byte{0x31,0x34,0x31,0x35})
|
||||
//再次对生成PubKey 进行Sha256
|
||||
h2.Write(pubKey2)
|
||||
//对上次AEsGCm加密后结果进行sha256
|
||||
h2.Write(enData)*/
|
||||
//生成32个字节的随机数 ToKen 进行sha256
|
||||
/*token = GenRandomBytes(32)
|
||||
h2.Write(token)*/
|
||||
h1.Write(enData)
|
||||
h2SHA256RetData := h1.Sum(nil)
|
||||
|
||||
//对ProtoBuf进行加密
|
||||
//取HKDF 后的数据取前24个字节
|
||||
protoEnData, err = AesGcmEncryptWithCompress(epKey[:24], h2SHA256RetData, data)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
/*ecdhKeyPair.PubKey = pubKey2
|
||||
ecdhKeyPair.PriKey = priKey2*/
|
||||
|
||||
//需要返回的数据 epKey ecdhKeyPair token protoEnData
|
||||
//最后还需要对 原data 和 epKey 进行最后的 hash256
|
||||
return protoEnData, epKey, enData, ecdhKeyPair, nil
|
||||
}
|
||||
|
||||
func GenEcdhKeyPair() (*EcdhKeyPair, error) {
|
||||
ecdh := cecdh.NewEllipticECDH(elliptic.P256())
|
||||
priKey, pubKey, err := ecdh.GenerateKey(rand.Reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &EcdhKeyPair{
|
||||
PriKey: priKey,
|
||||
PubKey: pubKey,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func ECDH(priKey, pubKey []byte) (SecretKey []byte, err error) {
|
||||
ecdh := cecdh.NewEllipticECDH(elliptic.P256())
|
||||
publicKey, ok := ecdh.Unmarshal(pubKey)
|
||||
if !ok {
|
||||
return nil, errors.New("序列化失败!")
|
||||
}
|
||||
SecretKey, err = ecdh.GenerateSharedSecret(priKey, publicKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
h := sha256.New()
|
||||
h.Write(SecretKey)
|
||||
SecretKey = h.Sum(nil)
|
||||
return
|
||||
}
|
||||
|
||||
// Aes-Gcm 压缩加密
|
||||
func AesGcmEncryptWithCompress(key, aad, data []byte) ([]byte, error) {
|
||||
compressData := DoZlibCompress(data)
|
||||
//生成12个字节的nonce
|
||||
nonce := GenRandomBytes(12)
|
||||
//logger.Debugln("nonce -> ",hex.EncodeToString(nonce))
|
||||
//logger.Debugln("aad -> ",hex.EncodeToString(aad))
|
||||
enData, err := AesGcmEncrypt(key, nonce, aad, compressData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
newData := append([]byte{}, enData[:len(enData)-16]...)
|
||||
newData = append(newData, nonce...)
|
||||
newData = append(newData, enData[len(enData)-16:]...)
|
||||
//logger.Debugln("enData -> ", hex.EncodeToString(enData))
|
||||
//logger.Debugln("newData -> ", hex.EncodeToString(newData))
|
||||
return newData, nil
|
||||
}
|
||||
|
||||
func AesGcmDecryptWithUnCompress(key, aad, data []byte) ([]byte, error) {
|
||||
newData := append([]byte{}, data[:len(data)-28]...)
|
||||
newData = append(newData, data[len(data)-16:]...)
|
||||
//logger.Debugln("Data -> ", hex.EncodeToString(data))
|
||||
//logger.Debugln("newData -> ", hex.EncodeToString(newData))
|
||||
nonce := data[len(data)-(12+16) : len(data)-16]
|
||||
//logger.Debugln("nonce -> ",hex.EncodeToString(nonce))
|
||||
deData, err := AesGCMDecrypt(key, nonce, aad, newData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return DoZlibUnCompress(deData)
|
||||
}
|
||||
|
||||
// 进行zlib压缩
|
||||
func DoZlibCompress(src []byte) []byte {
|
||||
var in bytes.Buffer
|
||||
w := zlib.NewWriter(&in)
|
||||
_, _ = w.Write(src)
|
||||
_ = w.Close()
|
||||
return in.Bytes()
|
||||
}
|
||||
|
||||
func GenRandomBytes(length int) []byte {
|
||||
randomStr := []byte("0123456789abcdefghijklmnopqrstuvwxyz")
|
||||
var result []byte
|
||||
r := rnd.New(rnd.NewSource(time.Now().UnixNano()))
|
||||
for i := 0; i < length; i++ {
|
||||
result = append(result, randomStr[r.Intn(len(randomStr))])
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func hkdfEP(randData, sha256Data, info []byte) []byte {
|
||||
ex := hkdf.Extract(sha256.New, randData, []byte("security hdkf expand"))
|
||||
expand := hkdf.Expand(sha256.New, ex, sha256Data)
|
||||
expandBytes := make([]byte, 56)
|
||||
_, _ = expand.Read(expandBytes)
|
||||
return expandBytes
|
||||
}
|
||||
|
||||
/*func hkdfEP(secret, salt, info []byte) []byte {
|
||||
reader := hkdf.New(sha256.New, secret, salt,info)
|
||||
ex := make([]byte, 56)
|
||||
reader.Read(ex)
|
||||
return ex
|
||||
}*/
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
return aesgcm.Open(nil, nonce, data, aad)
|
||||
}
|
||||
|
||||
func AesGcmEncrypt(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
|
||||
}
|
||||
|
||||
return aesgcm.Seal(nil, nonce, data, aad), nil
|
||||
}
|
||||
|
||||
// 进行zlib解压缩
|
||||
func DoZlibUnCompress(compressSrc []byte) ([]byte, error) {
|
||||
b := bytes.NewReader(compressSrc)
|
||||
var out bytes.Buffer
|
||||
r, err := zlib.NewReader(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err := io.Copy(&out, r); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out.Bytes(), nil
|
||||
}
|
||||
Reference in New Issue
Block a user