123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716 |
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.IO;
- using Org.BouncyCastle.X509;
- using PaySharp.Alipay.Util.Asymmetric;
- namespace PaySharp.Alipay.Util
- {
- /// <summary>
- /// 支付宝签名工具类
- /// </summary>
- public static class AlipaySignature
- {
- /** 默认编码字符集 */
- private static readonly string DEFAULT_CHARSET = "GBK";
- /// <summary>
- /// 从支付宝公钥证书中提取支付宝公钥
- /// </summary>
- /// <param name="certPath">证书路径</param>
- /// <returns>公钥字符串</returns>
- public static string ExtractPemPublicKeyFromCert(string certPath)
- {
- ArgumentValidator.CheckArgument(!String.IsNullOrEmpty(certPath), "证书文件路径不可为空。");
- X509Certificate alipayPublicKeyCert = AntCertificationUtil.ParseCert(File.ReadAllText(certPath));
- return AntCertificationUtil.ExtractPemPublicKeyFromCert(alipayPublicKeyCert);
- }
- /// <summary>
- /// 异步通知参数验签,支持RSA、RSA2、SM2三种算法
- /// V1版本方法将删除sign_type参数再进行验签,V2版本方法则不会
- /// </summary>
- /// <param name="parameters">待验签的参数集合</param>
- /// <param name="alipayPublicCertPath">支付宝公钥证书路径</param>
- /// <param name="charset">参数编码字符集</param>
- /// <param name="signType">签名类型,RSA2或RSA、SM2</param>
- /// <returns>true:验证成功;false:验证失败</returns>
- public static bool CertVerifyV1(IDictionary<string, string> parameters, string alipayPublicCertPath, string charset, string signType)
- {
- return RSACertCheckV1(parameters, alipayPublicCertPath, charset, signType);
- }
- /// <summary>
- /// 异步通知参数验签,支持RSA、RSA2、SM2三种算法,推荐替换为相同功能的方法CertVerifyV1
- /// V1版本方法将删除sign_type参数再进行验签,V2版本方法则不会
- /// </summary>
- /// <param name="parameters">待验签的参数集合</param>
- /// <param name="alipayPublicCertPath">支付宝公钥证书路径</param>
- /// <param name="charset">参数编码字符集</param>
- /// <param name="signType">签名类型,RSA2或RSA、SM2</param>
- /// <returns>true:验证成功;false:验证失败</returns>
- public static bool RSACertCheckV1(IDictionary<string, string> parameters, string alipayPublicCertPath, string charset, string signType)
- {
- ArgumentValidator.CheckNotNull(parameters, "parameters参数不可为Null");
- ArgumentValidator.CheckArgument(!String.IsNullOrEmpty(alipayPublicCertPath), "证书文件路径不可为空。");
- string alipayPublicKey = ExtractPemPublicKeyFromCert(alipayPublicCertPath);
- return RSACheckV1(parameters, alipayPublicKey, charset, signType, false);
- }
- /// <summary>
- /// 异步通知参数验签,支持RSA、RSA2、SM2三种算法
- /// V1版本方法将删除sign_type参数再进行验签,V2版本方法则不会
- /// </summary>
- /// <param name="parameters">待验签字符串</param>
- /// <param name="publicKey">支付宝公钥</param>
- /// <param name="charset">参数编码字符集</param>
- /// <param name="signType">签名类型,RSA2或RSA、SM2</param>
- /// <param name="keyFromFile">是否从文件加载支付宝公钥内容。
- /// 如果该参数为true,则publicKey为公钥文件路径;
- /// 如果该参数为false,则publicKey为公钥内容
- /// </param>
- /// <returns>true:验证成功;false:验证失败</returns>
- public static bool VerifyV1(IDictionary<string, string> parameters, string publicKey, string charset, string signType, bool keyFromFile)
- {
- return RSACheckV1(parameters, publicKey, charset, signType, keyFromFile);
- }
- /// <summary>
- /// 异步通知参数验签,支持RSA、RSA2、SM2三种算法,推荐替换为相同功能的方法VerifyV1
- /// V1版本方法将删除sign_type参数再进行验签,V2版本方法则不会
- /// </summary>
- /// <param name="parameters">待验签字符串</param>
- /// <param name="publicKey">支付宝公钥</param>
- /// <param name="charset">参数编码字符集</param>
- /// <param name="signType">签名类型,RSA2或RSA、SM2</param>
- /// <param name="keyFromFile">是否从文件加载支付宝公钥内容。
- /// 如果该参数为true,则publicKey为公钥文件路径;
- /// 如果该参数为false,则publicKey为公钥内容
- /// </param>
- /// <returns>true:验证成功;false:验证失败</returns>
- public static bool RSACheckV1(IDictionary<string, string> parameters, string publicKey, string charset, string signType, bool keyFromFile)
- {
- ArgumentValidator.CheckNotNull(parameters, "parameters参数不可为Null");
- string sign = parameters["sign"];
- parameters.Remove("sign");
- parameters.Remove("sign_type");
- string signContent = GetSignContent(parameters);
- return RSACheckContent(signContent, sign, publicKey, charset, signType, keyFromFile);
- }
- /// <summary>
- /// 异步通知参数验签,支持RSA、RSA2、SM2三种算法
- /// V1版本方法将删除sign_type参数再进行验签,V2版本方法则不会
- /// </summary>
- /// <param name="parameters">待验签的参数集合</param>
- /// <param name="alipayPublicCertPath">支付宝公钥证书路径</param>
- /// <param name="charset">参数编码字符集</param>
- /// <param name="signType">签名类型,RSA2或RSA、SM2</param>
- /// <returns>true:验证成功;false:验证失败</returns>
- public static bool CertVerifyV2(IDictionary<string, string> parameters, string alipayPublicCertPath, string charset, string signType)
- {
- return RSACertCheckV2(parameters, alipayPublicCertPath, charset, signType);
- }
- /// <summary>
- /// 异步通知参数验签,支持RSA、RSA2、SM2三种算法,推荐替换为相同功能的方法CertVerifyV2
- /// V1版本方法将删除sign_type参数再进行验签,V2版本方法则不会
- /// </summary>
- /// <param name="parameters">待验签的参数集合</param>
- /// <param name="alipayPublicCertPath">支付宝公钥证书路径</param>
- /// <param name="charset">参数编码字符集</param>
- /// <param name="signType">签名类型,RSA2或RSA、SM2</param>
- /// <returns>true:验证成功;false:验证失败</returns>
- public static bool RSACertCheckV2(IDictionary<string, string> parameters, string alipayPublicCertPath, string charset, string signType)
- {
- ArgumentValidator.CheckNotNull(parameters, "parameters参数不可为Null");
- string alipayPublicKey = ExtractPemPublicKeyFromCert(alipayPublicCertPath);
- return RSACheckV2(parameters, alipayPublicKey, charset, signType, false);
- }
- /// <summary>
- /// 异步通知参数验签,支持RSA、RSA2、SM2三种算法
- /// V1版本方法将删除sign_type参数再进行验签,V2版本方法则不会
- /// </summary>
- /// <param name="parameters">待验签字符串</param>
- /// <param name="publicKey">支付宝公钥</param>
- /// <param name="charset">参数编码字符集</param>
- /// <param name="signType">签名类型,RSA2或RSA、SM2</param>
- /// <param name="keyFromFile">是否从文件加载支付宝公钥内容。
- /// 如果该参数为true,则publicKey为公钥文件路径;
- /// 如果该参数为false,则publicKey为公钥内容
- /// </param>
- /// <returns>true:验证成功;false:验证失败</returns>
- public static bool VerifyV2(IDictionary<string, string> parameters, string publicKey, string charset, string signType, bool keyFromFile)
- {
- return RSACheckV2(parameters, publicKey, charset, signType, keyFromFile);
- }
- /// <summary>
- /// 异步通知参数验签,支持RSA、RSA2、SM2三种算法,推荐替换为相同功能的方法VerifyV2
- /// V1版本方法将删除sign_type参数再进行验签,V2版本方法则不会
- /// </summary>
- /// <param name="parameters">待验签字符串</param>
- /// <param name="publicKey">支付宝公钥</param>
- /// <param name="charset">参数编码字符集</param>
- /// <param name="signType">签名类型,RSA2或RSA、SM2</param>
- /// <param name="keyFromFile">是否从文件加载支付宝公钥内容。
- /// 如果该参数为true,则publicKey为公钥文件路径;
- /// 如果该参数为false,则publicKey为公钥内容
- /// </param>
- /// <returns>true:验证成功;false:验证失败</returns>
- public static bool RSACheckV2(IDictionary<string, string> parameters, string publicKey, string charset, string signType, bool keyFromFile)
- {
- ArgumentValidator.CheckNotNull(parameters, "parameters参数不可为Null");
- string sign = parameters["sign"];
- parameters.Remove("sign");
- string signContent = GetSignContent(parameters);
- return RSACheckContent(signContent, sign, publicKey, charset, signType, keyFromFile);
- }
- /// <summary>
- /// 验证指定内容的签名,支持RSA、RSA2、SM2三种算法
- /// </summary>
- /// <param name="content">待验签的内容</param>
- /// <param name="sign">签名字符串</param>
- /// <param name="publicKey">支付宝公钥</param>
- /// <param name="charset">字符集编码</param>
- /// <param name="signType">签名算法类型,RSA2或RSA、SM2</param>
- /// <param name="keyFromFile">是否从文件加载支付宝公钥内容。
- /// 如果该参数为true,则publicKey为公钥文件路径;
- /// 如果该参数为false,则publicKey为公钥内容
- /// </param>
- /// <returns>true:验证成功;false:验证失败</returns>
- public static bool VerifyContent(string content, string sign, string publicKey, string charset, string signType, bool keyFromFile)
- {
- return RSACheckContent(content, sign, publicKey, charset, signType, keyFromFile);
- }
- /// <summary>
- /// 验证指定内容的签名,支持RSA、RSA2、SM2三种算法,推荐替换为相同功能的方法VerifyContent
- /// </summary>
- /// <param name="content">待验签的内容</param>
- /// <param name="sign">签名字符串</param>
- /// <param name="publicKey">支付宝公钥</param>
- /// <param name="charset">字符集编码</param>
- /// <param name="signType">签名算法类型,RSA2或RSA、SM2</param>
- /// <param name="keyFromFile">是否从文件加载支付宝公钥内容。
- /// 如果该参数为true,则publicKey为公钥文件路径;
- /// 如果该参数为false,则publicKey为公钥内容
- /// </param>
- /// <returns>true:验证成功;false:验证失败</returns>
- public static bool RSACheckContent(string content, string sign, string publicKey, string charset, string signType, bool keyFromFile)
- {
- if (keyFromFile)
- {
- ArgumentValidator.CheckArgument(!String.IsNullOrEmpty(publicKey), "公钥文件路径不可为空。");
- publicKey = File.ReadAllText(publicKey);
- }
- return AsymmetricManager.GetByName(signType).Verify(content, charset, publicKey, sign);
- }
- /// <summary>
- /// 对指定参数进行签名,支持RSA、RSA2、SM2三种算法
- /// </summary>
- /// <param name="parameters">参数集合</param>
- /// <param name="privateKey">商户私钥</param>
- /// <param name="charset">字符集编码</param>
- /// <param name="signType">签名算法类型,RSA2或RSA、SM2</param>
- /// <param name="keyFromFile">是否从私钥证书文件中加载私钥
- /// 如果该参数为true,privateKey为私钥证书文件路径;
- /// 如果该参数为false,privateKey为私钥内容字符串
- /// </param>
- /// <returns>签名字符串</returns>
- public static string Sign(IDictionary<string, string> parameters, string privateKey, string charset, string signType, bool keyFromFile)
- {
- return RSASign(parameters, privateKey, charset, signType, keyFromFile);
- }
- /// <summary>
- /// 对指定参数进行签名,支持RSA、RSA2、SM2三种算法,推荐替换为相同功能的方法Sign
- /// </summary>
- /// <param name="parameters">参数集合</param>
- /// <param name="privateKey">商户私钥</param>
- /// <param name="charset">字符集编码</param>
- /// <param name="signType">签名算法类型,RSA2或RSA、SM2</param>
- /// <param name="keyFromFile">是否从私钥证书文件中加载私钥
- /// 如果该参数为true,privateKey为私钥证书文件路径;
- /// 如果该参数为false,privateKey为私钥内容字符串
- /// </param>
- /// <returns>签名字符串</returns>
- public static string RSASign(IDictionary<string, string> parameters, string privateKey, string charset, string signType, bool keyFromFile)
- {
- ArgumentValidator.CheckNotNull(parameters, "parameters参数不可为Null");
- string signContent = GetSignContent(parameters);
- return RSASignCharSet(signContent, privateKey, charset, signType, keyFromFile);
- }
- /// <summary>
- /// 对指定内容进行签名,支持RSA、RSA2、SM2三种算法
- /// </summary>
- /// <param name="data">内容字符串</param>
- /// <param name="privateKey">商户私钥</param>
- /// <param name="charset">字符集编码</param>
- /// <param name="signType">签名算法类型,RSA2或RSA、SM2</param>
- /// <param name="keyFromFile">是否从私钥证书文件中加载私钥
- /// 如果该参数为true,privateKey为私钥证书文件路径;
- /// 如果该参数为false,privateKey为私钥内容字符串
- /// </param>
- /// <returns>签名字符串</returns>
- public static string Sign(string data, string privateKey, string charset, string signType, bool keyFromFile)
- {
- return RSASign(data, privateKey, charset, signType, keyFromFile);
- }
- /// <summary>
- /// 对指定内容进行签名,支持RSA、RSA2、SM2三种算法,推荐替换为相同功能的方法Sign
- /// </summary>
- /// <param name="data">内容字符串</param>
- /// <param name="privateKey">商户私钥</param>
- /// <param name="charset">字符集编码</param>
- /// <param name="signType">签名算法类型,RSA2或RSA、SM2</param>
- /// <param name="keyFromFile">是否从私钥证书文件中加载私钥
- /// 如果该参数为true,privateKey为私钥证书文件路径;
- /// 如果该参数为false,privateKey为私钥内容字符串
- /// </param>
- /// <returns>签名字符串</returns>
- public static string RSASign(string data, string privateKey, string charset, string signType, bool keyFromFile)
- {
- return RSASignCharSet(data, privateKey, charset, signType, keyFromFile);
- }
- /// <summary>
- /// 验签并解密,目前仅适用于生活号
- /// </summary>
- /// <param name="parameters">待验签并解密的参数</param>
- /// <param name="alipayPublicKey">支付宝公钥字符串,用于验签</param>
- /// <param name="cusPrivateKey">商户私钥字符串,用于解密</param>
- /// <param name="isCheckSign">是否检查签名</param>
- /// <param name="isDecrypt">是否解密</param>
- /// <param name="signType">非对称加密算法类型,RSA2或RSA、SM2</param>
- /// <param name="keyFromFile">是否从文件加载支付宝公钥和商户私钥
- /// 如果该参数为true,alipayPublicKey为公钥文件路径,cusPrivateKey为私钥证书文件路径;
- /// 如果该参数为false,则publicKeyPem为公钥内容字符串,cusPrivateKey为私钥内容字符串
- /// </param>
- /// <returns>验签解密后的内容</returns>
- public static string CheckSignAndDecrypt(IDictionary<string, string> parameters, string alipayPublicKey, string cusPrivateKey,
- bool isCheckSign, bool isDecrypt, string signType, bool keyFromFile)
- {
- ArgumentValidator.CheckNotNull(parameters, "parameters参数不可为Null");
- string charset = parameters["charset"];
- string bizContent = parameters["biz_content"];
- if (isCheckSign)
- {
- if (!RSACheckV2(parameters, alipayPublicKey, charset, signType, keyFromFile))
- {
- throw new Exception("rsaCheck failure:rsaParams=" + parameters);
- }
- }
- if (isDecrypt)
- {
- return RSADecrypt(bizContent, cusPrivateKey, charset, signType, keyFromFile);
- }
- return bizContent;
- }
- /// <summary>
- /// 加密并加签,目前仅适用于生活号
- /// </summary>
- /// <param name="bizContent">待加密和加签的原文</param>
- /// <param name="alipayPublicKey">支付宝公钥字符串,用于加密</param>
- /// <param name="cusPrivateKey">商户私钥字符串,用于加签</param>
- /// <param name="charset">字符集编码</param>
- /// <param name="isEncrypt">是否需要加密</param>
- /// <param name="isSign">是否需要加签</param>
- /// <param name="signType">非对称加密算法类型,RSA或RSA2、SM2</param>
- /// <param name="keyFromFile">是否从文件加载支付宝公钥和商户私钥
- /// 如果该参数为true,alipayPublicKey为公钥文件路径,cusPrivateKey为私钥证书文件路径;
- /// 如果该参数为false,则publicKeyPem为公钥内容字符串,cusPrivateKey为私钥内容字符串
- /// </param>
- /// <returns>加密加签后的内容</returns>
- public static string EncryptAndSign(string bizContent, string alipayPublicKey, string cusPrivateKey, string charset,
- bool isEncrypt, bool isSign, string signType, bool keyFromFile)
- {
- StringBuilder sb = new StringBuilder();
- if (string.IsNullOrEmpty(charset))
- {
- charset = DEFAULT_CHARSET;
- }
- sb.Append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>");
- if (isEncrypt)
- {
- // 加密
- sb.Append("<alipay>");
- String encrypted = RSAEncrypt(bizContent, alipayPublicKey, charset, keyFromFile);
- sb.Append("<response>" + encrypted + "</response>");
- sb.Append("<encryption_type>" + signType + "</encryption_type>");
- if (isSign)
- {
- String sign = RSASign(encrypted, cusPrivateKey, charset, signType, keyFromFile);
- sb.Append("<sign>" + sign + "</sign>");
- sb.Append("<sign_type>" + signType + "</sign_type>");
- }
- sb.Append("</alipay>");
- }
- else if (isSign)
- {
- // 不加密,但需要签名
- sb.Append("<alipay>");
- sb.Append("<response>" + bizContent + "</response>");
- String sign = RSASign(bizContent, cusPrivateKey, charset, signType, keyFromFile);
- sb.Append("<sign>" + sign + "</sign>");
- sb.Append("<sign_type>" + signType + "</sign_type>");
- sb.Append("</alipay>");
- }
- else
- {
- // 不加密,不加签
- sb.Append(bizContent);
- }
- return sb.ToString();
- }
- public static string GetSignContent(IDictionary<string, string> parameters)
- {
- // 第一步:把字典按Key的字母顺序排序
- IDictionary<string, string> sortedParams = new SortedDictionary<string, string>(parameters, StringComparer.Ordinal);
- IEnumerator<KeyValuePair<string, string>> dem = sortedParams.GetEnumerator();
- // 第二步:把所有参数名和参数值串在一起
- StringBuilder query = new StringBuilder("");
- while (dem.MoveNext())
- {
- string key = dem.Current.Key;
- string value = dem.Current.Value;
- if (!string.IsNullOrEmpty(key) && !string.IsNullOrEmpty(value))
- {
- query.Append(key).Append("=").Append(value).Append("&");
- }
- }
- string content = query.ToString().Substring(0, query.Length - 1);
- return content;
- }
- public static string RSASignCharSet(string data, string privateKeyPem, string charset, string signType, bool keyFromFile)
- {
- if (keyFromFile)
- {
- ArgumentValidator.CheckArgument(!String.IsNullOrEmpty(privateKeyPem), "私钥文件路径不可为空。");
- privateKeyPem = LoadPrivateKeyFromRSACertFile(privateKeyPem);
- }
- return AsymmetricManager.GetByName(signType).Sign(data, charset, privateKeyPem);
- }
- public static string RSAEncrypt(string content, string publicKeyPem, string charset, bool keyFromFile)
- {
- if (keyFromFile)
- {
- ArgumentValidator.CheckArgument(!String.IsNullOrEmpty(publicKeyPem), "公钥文件路径不可为空。");
- publicKeyPem = File.ReadAllText(publicKeyPem);
- }
- return AsymmetricManager.GetByName("RSA").Encrypt(content, charset, publicKeyPem);
- }
- public static string RSADecrypt(string content, string privateKeyPem, string charset, string signType, bool keyFromFile)
- {
- if (keyFromFile)
- {
- ArgumentValidator.CheckArgument(!String.IsNullOrEmpty(privateKeyPem), "私钥文件路径不可为空。");
- privateKeyPem = LoadPrivateKeyFromRSACertFile(privateKeyPem);
- }
- return AsymmetricManager.GetByName(signType).Decrypt(content, charset, privateKeyPem);
- }
- private static string LoadPrivateKeyFromRSACertFile(string filename)
- {
- using (FileStream fs = File.OpenRead(filename))
- {
- byte[] data = new byte[fs.Length];
- fs.Read(data, 0, data.Length);
- if (data[0] != 0x30)
- {
- return GetPem("RSA PRIVATE KEY", data);
- }
- throw new Exception("证书文件格式不符合预期,无法提取私钥。");
- }
- }
- private static string GetPem(string type, byte[] data)
- {
- string pem = Encoding.UTF8.GetString(data);
- string header = String.Format("-----BEGIN {0}-----\\n", type);
- string footer = String.Format("-----END {0}-----", type);
- int start = pem.IndexOf(header, StringComparison.Ordinal) + header.Length;
- int end = pem.IndexOf(footer, start, StringComparison.Ordinal);
- return pem.Substring(start, (end - start));
- }
- public static SignSourceData ExtractSignContent(String str, int begin)
- {
- if (str == null)
- {
- return null;
- }
- int beginIndex = ExtractBeginPosition(str, begin);
- if (beginIndex >= str.Length)
- {
- return null;
- }
- int endIndex = ExtractEndPosition(str, beginIndex);
- return new SignSourceData()
- {
- SourceData = str.Substring(beginIndex, endIndex - beginIndex),
- BeginIndex = beginIndex,
- EndIndex = endIndex
- };
- }
- private static int ExtractBeginPosition(String responseString, int begin)
- {
- int beginPosition = begin;
- //找到第一个左大括号(对应响应的是JSON对象的情况:普通调用OpenAPI响应明文)
- //或者双引号(对应响应的是JSON字符串的情况:加密调用OpenAPI响应Base64串),作为待验签内容的起点
- while (beginPosition < responseString.Length
- && responseString[beginPosition] != '{'
- && responseString[beginPosition] != '"')
- {
- ++beginPosition;
- }
- return beginPosition;
- }
- private static int ExtractEndPosition(String responseString, int beginPosition)
- {
- //提取明文验签内容终点
- if (responseString[beginPosition] == '{')
- {
- return ExtractJsonObjectEndPosition(responseString, beginPosition);
- }
- //提取密文验签内容终点
- else
- {
- return ExtractJsonBase64ValueEndPosition(responseString, beginPosition);
- }
- }
- private static int ExtractJsonBase64ValueEndPosition(String responseString, int beginPosition)
- {
- for (int index = beginPosition; index < responseString.Length; ++index)
- {
- //找到第2个双引号作为终点,由于中间全部是Base64编码的密文,所以不会有干扰的特殊字符
- if (responseString[index] == '"' && index != beginPosition)
- {
- return index + 1;
- }
- }
- //如果没有找到第2个双引号,说明验签内容片段提取失败,直接尝试选取剩余整个响应字符串进行验签
- return responseString.Length;
- }
- private static int ExtractJsonObjectEndPosition(String responseString, int beginPosition)
- {
- //记录当前尚未发现配对闭合的大括号
- LinkedList<String> braces = new LinkedList<String>();
- //记录当前字符是否在双引号中
- bool inQuotes = false;
- //记录当前字符前面连续的转义字符个数
- int consecutiveEscapeCount = 0;
- //从待验签字符的起点开始遍历后续字符串,找出待验签字符串的终止点,终点即是与起点{配对的}
- for (int index = beginPosition; index < responseString.Length; ++index)
- {
- //提取当前字符
- char currentChar = responseString[index];
- //如果当前字符是"且前面有偶数个转义标记(0也是偶数)
- if (currentChar == '"' && consecutiveEscapeCount % 2 == 0)
- {
- //是否在引号中的状态取反
- inQuotes = !inQuotes;
- }
- //如果当前字符是{且不在引号中
- else if (currentChar == '{' && !inQuotes)
- {
- //将该{加入未闭合括号中
- braces.AddLast("{");
- }
- //如果当前字符是}且不在引号中
- else if (currentChar == '}' && !inQuotes)
- {
- //弹出一个未闭合括号
- braces.RemoveLast();
- //如果弹出后,未闭合括号为空,说明已经找到终点
- if (braces.Count == 0)
- {
- return index + 1;
- }
- }
- //如果当前字符是转义字符
- if (currentChar == '\\')
- {
- //连续转义字符个数+1
- ++consecutiveEscapeCount;
- }
- else
- {
- //连续转义字符个数置0
- consecutiveEscapeCount = 0;
- }
- }
- //如果没有找到配对的闭合括号,说明验签内容片段提取失败,直接尝试选取剩余整个响应字符串进行验签
- return responseString.Length;
- }
- /// <summary>
- /// 获取公钥证书序列号
- /// </summary>
- /// <param name="certPath">公钥证书路径</param>
- /// <returns>公钥证书序列号</returns>
- public static String GetCertSN(String certPath)
- {
- X509Certificate cert = AntCertificationUtil.ParseCert(File.ReadAllText(certPath));
- return AntCertificationUtil.GetCertSN(cert);
- }
- [Obsolete("因之前方法命名不符合C#规范而废弃的方法,请替换为EncryptAndSign方法")]
- public static string encryptAndSign(string bizContent, string alipayPublicKey, string cusPrivateKey, string charset,
- bool isEncrypt, bool isSign, string signType, bool keyFromFile)
- {
- return EncryptAndSign(bizContent, alipayPublicKey, cusPrivateKey, charset, isEncrypt, isSign, signType, keyFromFile);
- }
- [Obsolete("请替换为EncryptAndSign方法,显式设置参数:signTyp=RSA,keyFromFile=true")]
- public static string encryptAndSign(string bizContent, string alipayPublicKey, string cusPrivateKey, string charset,
- bool isEncrypt, bool isSign)
- {
- return EncryptAndSign(bizContent, alipayPublicKey, cusPrivateKey, charset, isEncrypt, isSign, "RSA", true);
- }
- [Obsolete("请替换为未废弃的有完整参数列表的重载版本,明确指定各参数的值")]
- public static string CheckSignAndDecrypt(IDictionary<string, string> parameters, string alipayPublicKey,
- string cusPrivateKey, bool isCheckSign, bool isDecrypt)
- {
- return CheckSignAndDecrypt(parameters, alipayPublicKey, cusPrivateKey, isCheckSign, isDecrypt, "RSA", true);
- }
- [Obsolete("请替换为未废弃的有完整参数列表的重载版本,明确指定各参数的值")]
- public static string RSASign(IDictionary<string, string> parameters, string privateKeyPem, string charset, string signType)
- {
- string signContent = GetSignContent(parameters);
- return RSASignCharSet(signContent, privateKeyPem, charset, signType);
- }
- [Obsolete("请替换为未废弃的有完整参数列表的重载版本,明确指定各参数的值")]
- public static string RSASign(string data, string privateKeyPem, string charset, string signType)
- {
- return RSASignCharSet(data, privateKeyPem, charset, signType);
- }
- [Obsolete("请替换为未废弃的有完整参数列表的重载版本,按照惯例将keyFromFile参数列在最后")]
- public static string RSASign(IDictionary<string, string> parameters, string privateKey, string charset, bool keyFromFile, string signType)
- {
- string signContent = GetSignContent(parameters);
- return RSASignCharSet(signContent, privateKey, charset, signType, keyFromFile);
- }
- [Obsolete("请替换为未废弃的有完整参数列表的重载版本,明确指定各参数的值")]
- public static string RSASignCharSet(string data, string privateKeyPem, string charset, string signType)
- {
- return RSASignCharSet(data, privateKeyPem, charset, signType, true);
- }
- [Obsolete("请替换为未废弃的有完整参数列表的重载版本,明确指定各参数的值")]
- public static bool RSACheckV1(IDictionary<string, string> parameters, string publicKeyPem, string charset)
- {
- string sign = parameters["sign"];
- parameters.Remove("sign");
- parameters.Remove("sign_type");
- string signContent = GetSignContent(parameters);
- return RSACheckContent(signContent, sign, publicKeyPem, charset, "RSA");
- }
- [Obsolete("请替换为未废弃的有完整参数列表的重载版本,明确指定各参数的值")]
- public static bool RSACheckV1(IDictionary<string, string> parameters, string publicKeyPem)
- {
- string sign = parameters["sign"];
- parameters.Remove("sign");
- parameters.Remove("sign_type");
- string signContent = GetSignContent(parameters);
- return RSACheckContent(signContent, sign, publicKeyPem, DEFAULT_CHARSET, "RSA");
- }
- [Obsolete("请替换为未废弃的有完整参数列表的重载版本,明确指定各参数的值")]
- public static bool RSACheckV2(IDictionary<string, string> parameters, string publicKeyPem)
- {
- string sign = parameters["sign"];
- parameters.Remove("sign");
- string signContent = GetSignContent(parameters);
- return RSACheckContent(signContent, sign, publicKeyPem, DEFAULT_CHARSET, "RSA");
- }
- [Obsolete("请替换为未废弃的有完整参数列表的重载版本,明确指定各参数的值")]
- public static bool RSACheckV2(IDictionary<string, string> parameters, string publicKeyPem, string charset)
- {
- string sign = parameters["sign"];
- parameters.Remove("sign");
- string signContent = GetSignContent(parameters);
- return RSACheckContent(signContent, sign, publicKeyPem, charset, "RSA");
- }
- [Obsolete("请替换为未废弃的有完整参数列表的重载版本,明确指定各参数的值")]
- public static bool RSACheckContent(string signContent, string sign, string publicKeyPem, string charset, string signType)
- {
- return RSACheckContent(signContent, sign, publicKeyPem, charset, signType, true);
- }
- [Obsolete("请替换为未废弃的有完整参数列表的重载版本,明确指定各参数的值")]
- public static bool RSACheckContent(string signContent, string sign, string publicKeyPem, string charset, bool keyFromFile)
- {
- return RSACheckContent(signContent, sign, publicKeyPem, charset, "RSA", keyFromFile);
- }
- [Obsolete("请替换为未废弃的有完整参数列表的重载版本,明确指定各参数的值")]
- public static string RSAEncrypt(string content, string publicKeyPem, string charset)
- {
- return RSAEncrypt(content, publicKeyPem, charset, true);
- }
- [Obsolete("请替换为未废弃的有完整参数列表的重载版本,明确指定各参数的值")]
- public static string RSADecrypt(string content, string privateKeyPem, string charset, string signType)
- {
- return RSADecrypt(content, privateKeyPem, charset, signType, true);
- }
- }
- }
|