gitee.com/h79/goutils@v1.22.10/common/algorithm/crypt.go (about) 1 package algorithm 2 3 import ( 4 "encoding/base64" 5 "fmt" 6 "gitee.com/h79/goutils/common/stringutil" 7 ) 8 9 // Crypt 10 /** 11 * 1.第三方回复加密消息给公众平台; 12 * 2.第三方收到公众平台发送的消息,验证消息的安全性,并对消息进行解密。 13 */ 14 type Crypt struct { 15 Token string 16 AesKey []byte 17 } 18 19 // NewCrypt 20 /** 21 * 构造函数 22 * @param $token string 公众平台上,开发者设置的token 23 * @param $encodingAesKey string 公众平台上,开发者设置的EncodingAESKey 24 * @param $appId string 公众平台的appId 25 */ 26 func NewCrypt(token, aesKey string) *Crypt { 27 28 ak, _ := base64.StdEncoding.DecodeString(aesKey + "=") 29 30 return &Crypt{ 31 Token: token, 32 AesKey: ak, 33 } 34 } 35 36 // Encrypt 37 /** 38 * 将公众平台回复用户的消息加密打包. 39 * <ol> 40 * <li>对要发送的消息进行AES-CBC加密</li> 41 * <li>生成安全签名</li> 42 * <li>将消息密文和安全签名打包成xml格式</li> 43 * </ol> 44 * 45 * @param msg string 公众平台待回复用户的消息,xml格式的字符串 46 * @param timeStamp string 时间戳,可以自己生成,也可以用URL参数的timestamp 47 * @param nonce string 随机串,可以自己生成,也可以用URL参数的nonce 48 * 49 */ 50 func (ct *Crypt) Encrypt(msg, timestamp, nonce string) (string, string, error) { 51 52 pc := NewPKCS7() 53 54 en, err := pc.Encrypt([]byte(msg), ct.AesKey) 55 if err != nil { 56 return "", "", err 57 } 58 59 sign := "" 60 if sign, err = SignWithSha1("", ct.Token, timestamp, nonce, en); err != nil { 61 return "", "", err 62 } 63 64 return sign, en, nil 65 } 66 67 // Decrypt 68 /** 69 * 检验消息的真实性,并且获取解密后的明文. 70 * <ol> 71 * <li>利用收到的密文生成安全签名,进行签名验证</li> 72 * <li>若验证通过,则提取xml中的加密消息</li> 73 * <li>对消息进行解密</li> 74 * </ol> 75 * 76 * @param signature string 签名串,对应URL参数的msg_signature 77 * @param timestamp string 时间戳 对应URL参数的timestamp 78 * @param nonce string 随机串,对应URL参数的nonce 79 * @param encrypt string 密文 80 * 81 */ 82 func (ct *Crypt) Decrypt(signature, timestamp, nonce, encrypt string) ([]byte, error) { 83 sign, err := SignWithSha1("", ct.Token, timestamp, nonce, encrypt) 84 if err != nil { 85 return nil, err 86 } 87 if signature != sign { 88 return nil, fmt.Errorf("sign no match") 89 } 90 pc := NewPKCS7() 91 buff, err := pc.Decrypt(encrypt, ct.AesKey) 92 if err != nil { 93 return nil, err 94 } 95 return buff, nil 96 } 97 98 // DecryptMsg 99 /** 100 * @return @string 正文 @string appid @error 101 */ 102 func (ct *Crypt) DecryptMsg(signature, timestamp, nonce, encrypt string) ([]byte, string, error) { 103 104 buff, err := ct.Decrypt(signature, timestamp, nonce, encrypt) 105 if err != nil { 106 return nil, "", err 107 } 108 l := stringutil.BytesToUInt32(buff[0:4]) 109 return buff[4 : l+4], string(buff[l+4:]), nil 110 } 111 112 // GenerateXmlMsg 113 /** 114 * 生成xml消息 115 * @param string $encrypt 加密后的消息密文 116 * @param string $signature 安全签名 117 * @param string $timestamp 时间戳 118 * @param string $nonce 随机字符串 119 */ 120 func (ct *Crypt) GenerateXmlMsg(msg, timestamp, nonce string) string { 121 signature, encrypt, er := ct.Encrypt(msg, timestamp, nonce) 122 if er != nil { 123 return "" 124 } 125 format := "<xml>" + 126 "<Encrypt><![CDATA[%s]]></Encrypt>" + 127 "<MsgSignature><![CDATA[%s]]></MsgSignature>" + 128 "<TimeStamp>%s</TimeStamp>" + 129 "<Nonce><![CDATA[%s]]></Nonce>" + 130 "</xml>" 131 return fmt.Sprintf(format, encrypt, signature, timestamp, nonce) 132 }