tnblog
首页
视频
资源
登录

.NET接入微信支付(三)加解密验签

1748人阅读 2023/2/23 17:01 总访问:16509 评论:0 收藏:0 手机
分类: 微信支付
  • 签名等所需要的加解密

    •     /// <summary>
          /// 解密类
          /// </summary>
          public class WxPayDecrypt
          {
              /// <summary>
              /// 解析密文
              /// </summary>
              /// <param name="associated_data"></param>
              /// <param name="nonce"></param>
              /// <param name="ciphertext"></param>
              /// <returns></returns>
              public static string GetAesGcmDecrypt(string associated_data, string nonce, string ciphertext)
              {
                  return Encoding.UTF8.GetString(AesGcmDecrypt(associated_data, nonce, ciphertext,WxPayConfig.KEY));
              }
      
              /// <summary>
              /// AesGcm256解密
              /// </summary>
              /// <see cref="https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay4_2.shtml"/>
              /// <param name="associatedData"></param>
              /// <param name="nonce"></param>
              /// <param name="ciphertext"></param>
              /// <param name="aesKey"></param>
              /// <returns></returns>
              public static byte[] AesGcmDecrypt(string associatedData, string nonce, string ciphertext, string aesKey)
              {
                  GcmBlockCipher gcmBlockCipher = new GcmBlockCipher(new AesEngine());
                  AeadParameters aeadParameters = new AeadParameters(
                      new KeyParameter(Encoding.UTF8.GetBytes(aesKey)),
                      128,
                      Encoding.UTF8.GetBytes(nonce),
                      Encoding.UTF8.GetBytes(associatedData));
                  gcmBlockCipher.Init(false, aeadParameters);
      
                  byte[] data = Convert.FromBase64String(ciphertext);
                  byte[] plaintext = new byte[gcmBlockCipher.GetOutputSize(data.Length)];
                  int length = gcmBlockCipher.ProcessBytes(data, 0, data.Length, plaintext, 0);
                  gcmBlockCipher.DoFinal(plaintext, length);
                  return plaintext;
              }
      
              /// <summary>
              /// AEAD_AES_256_GCM
              /// https://tools.ietf.org/html/rfc5116#page-15
              /// GCM加密后附加128位TAG形成密文
              /// </summary>
              /// <param name="key"></param>
              /// <returns></returns>
              public static byte[] Decrypt(string key, EncryptInfo encryptInfo)
              {
                  var data = Convert.FromBase64String(encryptInfo.ciphertext);
                  var cipher = data.AsEnumerable().Take(data.Length - 16).ToArray();
                  var tag = data.AsEnumerable().Skip(data.Length - 16).ToArray();
      
                  return AesGcmDecrypt(encryptInfo.associated_data, encryptInfo.nonce, encryptInfo.ciphertext, key);
              }
          }
    •     /// <summary>
          /// 加密类
          /// </summary>
          public static class WxPayEncrypt
          {
              /// <summary>
              /// 构造签名头
              /// </summary>
              /// <param name="url"></param>
              /// <param name="method"></param>
              /// <param name="body"></param>
              /// <param name="options"></param>
              /// <returns></returns>
              public static string BuildToken(string url, string method, string body, X509Certificate2 certificate, string merchantId)
              {
                  string uri = string.Empty, nonce = string.Empty, message = string.Empty, signature = string.Empty, SerialNumber = string.Empty;
      
                  try
                  {
                      uri = new Uri(url).PathAndQuery;
      
                      long timestamp = WxPayUitls.GenerateTimeStamp();
      
                      nonce = Guid.NewGuid().ToString("N");
      
                      message = $"{method}\n{uri}\n{timestamp}\n{nonce}\n{body}\n";
      
                      signature = message.ToRSAPrivateString(certificate);
      
                      SerialNumber = certificate.SerialNumber;
      
                      return $"mchid=\"{merchantId}\",nonce_str=\"{nonce}\",timestamp=\"{timestamp}\",serial_no=\"{SerialNumber}\",signature=\"{signature}\"";
                  }
                  catch (Exception ex)
                  {
                      Logger loger = LogManager.GetCurrentClassLogger();
                      loger.Info("生成TOKEN失败 :" + DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss")
                          + "\n message --> " + message + "--- SerialNumber --> " + SerialNumber
                          + "\n" + ex.Message + "\n" + ex.StackTrace);
                      throw;
                  }
              }
      
              /// <summary>
              /// 调起支付生成签名
              /// </summary>
              /// <param name="request"></param>
              /// <returns></returns>
              public static string MakePaySign(string message)
              {
                  try
                  {
                      X509Certificate2 Certificate = null;
                      Certificate = new X509Certificate2(WxPayConfig.SSLCERT_PATH, WxPayConfig.SSLCERT_PASSWORD, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);
                      if (Certificate == null)
                      {
                          throw new WxPayException("证书获取失败");
                      }
                      return message.ToRSAPrivateString(Certificate);
                  }
                  catch (Exception e)
                  {
                      Logger loger = LogManager.GetCurrentClassLogger();
                      loger.Error("调起支付生成签名异常:" + DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss") + "\r Message-->" + e.Message + "\r StackTrace--> " + e.StackTrace);
                      throw;
                  }
      
              }
      
              /// <summary>
              /// RSA 加密
              /// </summary>
              /// <param name="message">消息</param>
              /// <param name="certificate">证书</param>
              /// <returns></returns>
              private static string ToRSAPrivateString(this string message, X509Certificate2 certificate)
              {
                  string signature = string.Empty;
      
                  using (RSA rsa = certificate.GetRSAPrivateKey())
                  {
                      signature = Convert.ToBase64String(rsa.SignData(Encoding.UTF8.GetBytes(message), HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1));
                  }
                  return signature;
              }
      
              /// <summary>
              /// 平台证书验签
              /// </summary>
              /// <param name="responseContent">响应原文</param>
              /// <param name="payHeader">请求头</param>
              /// <returns></returns>
              public static bool VerifySign(string responseContent, WechatPayHeader payHeader)
              {
                  try
                  {
                      X509Certificate2 certificate = null;
                      string pemPath = WxPayConfig.PLATEFORMSSLCERT_PATH + payHeader.SerialNo + ".pem";
                      if (File.Exists(pemPath))
                      {
                          certificate = new X509Certificate2(pemPath, WxPayConfig.SSLCERT_APIV3KEY, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);
                      }
                      if (certificate == null)
                      {
                          certificate = WxPayApi.GetPlatformCertificate(payHeader.SerialNo);
                      }
                      string message = $"{payHeader.TimeStamp}\n{payHeader.Nonce}\n{responseContent}\n";
      
                      using (var rsa = certificate.GetRSAPublicKey())
                      {
                          var res = rsa.VerifyData(Encoding.UTF8.GetBytes(message), Convert.FromBase64String(payHeader.Signature), HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
      
                          return res;
                      }
                  }
                  catch (Exception e)
                  {
                      Logger loger = LogManager.GetCurrentClassLogger();
                      loger.Error("平台证书验签异常:" + DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss") + "\r Message-->" + e.Message + "\r StackTrace--> " + e.StackTrace);
                      throw;
                  }
              }
      
          }
评价
一木浮沉,吾与之。
排名
6
文章
6
粉丝
16
评论
8
{{item.articleTitle}}
{{item.blogName}} : {{item.content}}
ICP备案 :渝ICP备18016597号-1
网站信息:2018-2024TNBLOG.NET
技术交流:群号656732739
联系我们:contact@tnblog.net
欢迎加群交流技术