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  }