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 }