From e09539bf72542cf8b4ed5a5a6759c6734eeba28d Mon Sep 17 00:00:00 2001 From: tanghc Date: Wed, 3 Apr 2019 20:35:33 +0800 Subject: [PATCH] =?UTF-8?q?C#SDK=E6=8F=90=E4=BA=A4=EF=BC=8C=E5=9C=A8window?= =?UTF-8?q?=E4=B8=8A=E9=AA=8C=E8=AF=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/docs/files/10010_快速体验.md | 2 +- .../sdk-csharp/SDKCSharp/Client/OpenClient.cs | 2 +- .../sdk-csharp/SDKCSharp/Common/SdkConfig.cs | 2 +- .../SDKCSharp/Common/SopException.cs | 51 ++ .../SDKCSharp/Request/BaseRequest.cs | 2 + sop-sdk/sdk-csharp/SDKCSharp/SDKCSharp.csproj | 5 +- .../SDKCSharp/Utility/AlipaySignature.cs | 797 ++++++++++++++++++ .../RSACryptoServiceProviderExtension.cs | 245 ++++++ .../sdk-csharp/SDKCSharp/Utility/RSAUtil.cs | 47 -- .../sdk-csharp/SDKCSharp/Utility/SignUtil.cs | 29 +- sop-sdk/sdk-csharp/SDKTest/Program.cs | 6 +- 11 files changed, 1113 insertions(+), 75 deletions(-) create mode 100755 sop-sdk/sdk-csharp/SDKCSharp/Common/SopException.cs create mode 100755 sop-sdk/sdk-csharp/SDKCSharp/Utility/AlipaySignature.cs create mode 100755 sop-sdk/sdk-csharp/SDKCSharp/Utility/RSACryptoServiceProviderExtension.cs delete mode 100644 sop-sdk/sdk-csharp/SDKCSharp/Utility/RSAUtil.cs diff --git a/doc/docs/files/10010_快速体验.md b/doc/docs/files/10010_快速体验.md index cafae7e3..6e2742fd 100644 --- a/doc/docs/files/10010_快速体验.md +++ b/doc/docs/files/10010_快速体验.md @@ -4,7 +4,7 @@ - 安装并启动zookeeper,[安装教程](http://zookeeper.apache.org/doc/r3.4.13/zookeeperStarted.html) - 执行Mysql脚本`sop.sql` -- IDE打开项目(IDEA下可以打开根pom.xml,然后open as project) +- IDE安装lombok插件,然后打开项目(IDEA下可以打开根pom.xml,然后open as project) - 启动注册中心,sop-registry(运行SopRegistryApplication.java) - 启动微服务:sop-story-web(运行SopStoryApplication.java) - 启动网关:打开sop-gateway下的`application.yml`,修改数据库`username/password`,SopGatewayApplication.java diff --git a/sop-sdk/sdk-csharp/SDKCSharp/Client/OpenClient.cs b/sop-sdk/sdk-csharp/SDKCSharp/Client/OpenClient.cs index 7c4ff321..373f3300 100644 --- a/sop-sdk/sdk-csharp/SDKCSharp/Client/OpenClient.cs +++ b/sop-sdk/sdk-csharp/SDKCSharp/Client/OpenClient.cs @@ -78,7 +78,7 @@ namespace SDKCSharp.Client } form[this.openConfig.AppKeyName] = this.appId; string content = SopSignature.getSignContent(form); - string sign = RSAUtil.EncryptByPrivateKey(content, this.privateKey); + string sign = SignUtil.CreateSign(form, privateKey, request.Charset, request.SignType); form[this.openConfig.SignName] = sign; string resp = this.doExecute(url, requestForm, header); diff --git a/sop-sdk/sdk-csharp/SDKCSharp/Common/SdkConfig.cs b/sop-sdk/sdk-csharp/SDKCSharp/Common/SdkConfig.cs index c7843ce9..8f83ddb6 100644 --- a/sop-sdk/sdk-csharp/SDKCSharp/Common/SdkConfig.cs +++ b/sop-sdk/sdk-csharp/SDKCSharp/Common/SdkConfig.cs @@ -16,7 +16,7 @@ namespace SDKCSharp.Common public static String TIMESTAMP_PATTERN = "yyyy-MM-dd HH:mm:ss"; - public static String CHARSET = "UTF-8"; + public static String CHARSET = "GBK"; public static String SIGN_TYPE = "RSA2"; } diff --git a/sop-sdk/sdk-csharp/SDKCSharp/Common/SopException.cs b/sop-sdk/sdk-csharp/SDKCSharp/Common/SopException.cs new file mode 100755 index 00000000..c7f2dc70 --- /dev/null +++ b/sop-sdk/sdk-csharp/SDKCSharp/Common/SopException.cs @@ -0,0 +1,51 @@ +using System; +using System.Runtime.Serialization; + +namespace SDKCSharp.Common +{ + /// + /// AOP客户端异常。 + /// + public class SopException : Exception + { + private string errorCode; + private string errorMsg; + + public SopException() + : base() + { + } + + public SopException(string message) + : base(message) + { + } + + protected SopException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + public SopException(string message, Exception innerException) + : base(message, innerException) + { + } + + public SopException(string errorCode, string errorMsg) + : base(errorCode + ":" + errorMsg) + { + this.errorCode = errorCode; + this.errorMsg = errorMsg; + } + + public string ErrorCode + { + get { return this.errorCode; } + } + + public string ErrorMsg + { + get { return this.errorMsg; } + } + } +} diff --git a/sop-sdk/sdk-csharp/SDKCSharp/Request/BaseRequest.cs b/sop-sdk/sdk-csharp/SDKCSharp/Request/BaseRequest.cs index 6fbbff99..d98d0630 100644 --- a/sop-sdk/sdk-csharp/SDKCSharp/Request/BaseRequest.cs +++ b/sop-sdk/sdk-csharp/SDKCSharp/Request/BaseRequest.cs @@ -30,6 +30,8 @@ namespace SDKCSharp.Request public string BizContent { set => bizContent = value; } public object BizModel { set => bizModel = value; } public string Version { get => version; set => version = value; } + public string Charset { get => charset; set => charset = value; } + public string SignType { get => signType; set => signType = value; } /// /// 返回接口名 diff --git a/sop-sdk/sdk-csharp/SDKCSharp/SDKCSharp.csproj b/sop-sdk/sdk-csharp/SDKCSharp/SDKCSharp.csproj index f6b3cbe9..b96b9174 100644 --- a/sop-sdk/sdk-csharp/SDKCSharp/SDKCSharp.csproj +++ b/sop-sdk/sdk-csharp/SDKCSharp/SDKCSharp.csproj @@ -67,12 +67,15 @@ - + + + + diff --git a/sop-sdk/sdk-csharp/SDKCSharp/Utility/AlipaySignature.cs b/sop-sdk/sdk-csharp/SDKCSharp/Utility/AlipaySignature.cs new file mode 100755 index 00000000..d401ecdc --- /dev/null +++ b/sop-sdk/sdk-csharp/SDKCSharp/Utility/AlipaySignature.cs @@ -0,0 +1,797 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Security.Cryptography; +using System.IO; +using SDKCSharp.Common; + +namespace SDKCSharp.Utility +{ + public class AlipaySignature + { + /** 默认编码字符集 */ + private static string DEFAULT_CHARSET = SdkConfig.CHARSET; + + public static string GetSignContent(IDictionary parameters) + { + // 第一步:把字典按Key的字母顺序排序 + IDictionary sortedParams = new SortedDictionary(parameters); + IEnumerator> 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 RSASign(IDictionary parameters, string privateKeyPem, string charset, string signType) + { + string signContent = GetSignContent(parameters); + + return RSASignCharSet(signContent, privateKeyPem, charset, signType); + } + + public static string RSASign(string data, string privateKeyPem, string charset, string signType) + { + return RSASignCharSet(data, privateKeyPem, charset, signType); + } + ///* + public static string RSASign(IDictionary parameters, string privateKeyPem, string charset, bool keyFromFile, string signType) + { + string signContent = GetSignContent(parameters); + + return RSASignCharSet(signContent, privateKeyPem, charset, keyFromFile, signType); + } + + public static string RSASign(string data, string privateKeyPem, string charset, string signType, bool keyFromFile) + { + return RSASignCharSet(data, privateKeyPem, charset, keyFromFile, signType); + } + //*/ + public static string RSASignCharSet(string data, string privateKeyPem, string charset, string signType) + { + RSACryptoServiceProvider rsaCsp = LoadCertificateFile(privateKeyPem, signType); + byte[] dataBytes = null; + if (string.IsNullOrEmpty(charset)) + { + dataBytes = Encoding.UTF8.GetBytes(data); + } + else + { + dataBytes = Encoding.GetEncoding(charset).GetBytes(data); + } + + + if ("RSA2".Equals(signType)) + { + + byte[] signatureBytes = rsaCsp.SignData(dataBytes, "SHA256"); + + return Convert.ToBase64String(signatureBytes); + + } + else + { + byte[] signatureBytes = rsaCsp.SignData(dataBytes, "SHA1"); + + return Convert.ToBase64String(signatureBytes); + } + } + + + public static string RSASignCharSet(string data, string privateKeyPem, string charset, bool keyFromFile, string signType) + { + + byte[] signatureBytes = null; + try + { + RSACryptoServiceProvider rsaCsp = null; + if (keyFromFile) + {//文件读取 + rsaCsp = LoadCertificateFile(privateKeyPem, signType); + } + else + { + //字符串获取 + rsaCsp = LoadCertificateString(privateKeyPem, signType); + } + + byte[] dataBytes = null; + if (string.IsNullOrEmpty(charset)) + { + dataBytes = Encoding.UTF8.GetBytes(data); + } + else + { + dataBytes = Encoding.GetEncoding(charset).GetBytes(data); + } + if (null == rsaCsp) + { + throw new SopException("您使用的私钥格式错误,请检查RSA私钥配置" + ",charset = " + charset); + } + if ("RSA2".Equals(signType)) + { + + signatureBytes = rsaCsp.SignData(dataBytes, "SHA256"); + + } + else + { + signatureBytes = rsaCsp.SignData(dataBytes, "SHA1"); + } + + } + catch (Exception ex) + { + throw new SopException("您使用的私钥格式错误,请检查RSA私钥配置" + ",charset = " + charset, ex); + } + return Convert.ToBase64String(signatureBytes); + } + + + public static bool RSACheckV1(IDictionary 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"); + } + + public static bool RSACheckV1(IDictionary 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"); + } + + public static bool RSACheckV1(IDictionary parameters, string publicKeyPem, string charset, string signType, bool keyFromFile) + { + string sign = parameters["sign"]; + + parameters.Remove("sign"); + parameters.Remove("sign_type"); + string signContent = GetSignContent(parameters); + return RSACheckContent(signContent, sign, publicKeyPem, charset, signType, keyFromFile); + } + + public static bool RSACheckV2(IDictionary parameters, string publicKeyPem) + { + string sign = parameters["sign"]; + + parameters.Remove("sign"); + string signContent = GetSignContent(parameters); + + return RSACheckContent(signContent, sign, publicKeyPem, DEFAULT_CHARSET, "RSA"); + } + + public static bool RSACheckV2(IDictionary parameters, string publicKeyPem, string charset) + { + string sign = parameters["sign"]; + + parameters.Remove("sign"); + string signContent = GetSignContent(parameters); + + return RSACheckContent(signContent, sign, publicKeyPem, charset, "RSA"); + } + + public static bool RSACheckV2(IDictionary parameters, string publicKeyPem, string charset, string signType, bool keyFromFile) + { + string sign = parameters["sign"]; + + parameters.Remove("sign"); + string signContent = GetSignContent(parameters); + + return RSACheckContent(signContent, sign, publicKeyPem, charset, signType, keyFromFile); + } + + public static bool RSACheckContent(string signContent, string sign, string publicKeyPem, string charset, string signType) + { + + try + { + if (string.IsNullOrEmpty(charset)) + { + charset = DEFAULT_CHARSET; + } + + + if ("RSA2".Equals(signType)) + { + string sPublicKeyPEM = File.ReadAllText(publicKeyPem); + + RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); + rsa.PersistKeyInCsp = false; + RSACryptoServiceProviderExtension.LoadPublicKeyPEM(rsa, sPublicKeyPEM); + + bool bVerifyResultOriginal = rsa.VerifyData(Encoding.GetEncoding(charset).GetBytes(signContent), "SHA256", Convert.FromBase64String(sign)); + return bVerifyResultOriginal; + + } + else + { + string sPublicKeyPEM = File.ReadAllText(publicKeyPem); + RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); + rsa.PersistKeyInCsp = false; + RSACryptoServiceProviderExtension.LoadPublicKeyPEM(rsa, sPublicKeyPEM); + + SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider(); + bool bVerifyResultOriginal = rsa.VerifyData(Encoding.GetEncoding(charset).GetBytes(signContent), sha1, Convert.FromBase64String(sign)); + return bVerifyResultOriginal; + } + } + catch + { + return false; + } + + } + public static bool RSACheckContent(string signContent, string sign, string publicKeyPem, string charset, string signType, bool keyFromFile) + { + + try + { + if (string.IsNullOrEmpty(charset)) + { + charset = DEFAULT_CHARSET; + } + + string sPublicKeyPEM; + + if (keyFromFile) + { + sPublicKeyPEM = File.ReadAllText(publicKeyPem); + } + else + { + sPublicKeyPEM = "-----BEGIN PUBLIC KEY-----\r\n"; + sPublicKeyPEM += publicKeyPem; + sPublicKeyPEM += "-----END PUBLIC KEY-----\r\n\r\n"; + } + + + if ("RSA2".Equals(signType)) + { + RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); + rsa.PersistKeyInCsp = false; + RSACryptoServiceProviderExtension.LoadPublicKeyPEM(rsa, sPublicKeyPEM); + + bool bVerifyResultOriginal = rsa.VerifyData(Encoding.GetEncoding(charset).GetBytes(signContent), "SHA256", Convert.FromBase64String(sign)); + return bVerifyResultOriginal; + } + else + { + RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); + rsa.PersistKeyInCsp = false; + RSACryptoServiceProviderExtension.LoadPublicKeyPEM(rsa, sPublicKeyPEM); + + SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider(); + bool bVerifyResultOriginal = rsa.VerifyData(Encoding.GetEncoding(charset).GetBytes(signContent), sha1, Convert.FromBase64String(sign)); + return bVerifyResultOriginal; + } + } + catch + { + return false; + } + + } + public static bool RSACheckContent(string signContent, string sign, string publicKeyPem, string charset, bool keyFromFile) + { + try + { + string sPublicKeyPEM; + if (keyFromFile) + { + sPublicKeyPEM = File.ReadAllText(publicKeyPem); + } + else + { + sPublicKeyPEM = "-----BEGIN PUBLIC KEY-----\r\n"; + sPublicKeyPEM = sPublicKeyPEM + publicKeyPem; + sPublicKeyPEM = sPublicKeyPEM + "-----END PUBLIC KEY-----\r\n\r\n"; + } + RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); + rsa.PersistKeyInCsp = false; + RSACryptoServiceProviderExtension.LoadPublicKeyPEM(rsa, sPublicKeyPEM); + SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider(); + if (string.IsNullOrEmpty(charset)) + { + charset = DEFAULT_CHARSET; + } + bool bVerifyResultOriginal = rsa.VerifyData(Encoding.GetEncoding(charset).GetBytes(signContent), sha1, Convert.FromBase64String(sign)); + return bVerifyResultOriginal; + } + catch (Exception ex) + { + string s = ex.Message.ToString(); + return false; + } + + } + + public static string CheckSignAndDecrypt(IDictionary parameters, string alipayPublicKey, + string cusPrivateKey, bool isCheckSign, + bool isDecrypt) + { + string charset = parameters["charset"]; + string bizContent = parameters["biz_content"]; + if (isCheckSign) + { + if (!RSACheckV2(parameters, alipayPublicKey, charset)) + { + throw new SopException("rsaCheck failure:rsaParams=" + parameters); + } + } + + if (isDecrypt) + { + return RSADecrypt(bizContent, cusPrivateKey, charset, "RSA"); + } + + return bizContent; + } + + public static string CheckSignAndDecrypt(IDictionary parameters, string alipayPublicKey, + string cusPrivateKey, bool isCheckSign, + bool isDecrypt, string signType, bool keyFromFile) + { + string charset = parameters["charset"]; + string bizContent = parameters["biz_content"]; + if (isCheckSign) + { + if (!RSACheckV2(parameters, alipayPublicKey, charset, signType, keyFromFile)) + { + throw new SopException("rsaCheck failure:rsaParams=" + parameters); + } + } + + if (isDecrypt) + { + return RSADecrypt(bizContent, cusPrivateKey, charset, signType ,keyFromFile); + } + + return bizContent; + } + + 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(""); + if (isEncrypt) + {// 加密 + sb.Append(""); + String encrypted = RSAEncrypt(bizContent, alipayPublicKey, charset, keyFromFile); + sb.Append("" + encrypted + ""); + sb.Append(""+signType+""); + if (isSign) + { + String sign = RSASign(encrypted, cusPrivateKey, charset, signType, keyFromFile); + sb.Append("" + sign + ""); + sb.Append(""+signType+""); + } + sb.Append(""); + } + else if (isSign) + {// 不加密,但需要签名 + sb.Append(""); + sb.Append("" + bizContent + ""); + String sign = RSASign(bizContent, cusPrivateKey, charset, signType, keyFromFile); + sb.Append("" + sign + ""); + sb.Append(""+signType+""); + sb.Append(""); + } + else + {// 不加密,不加签 + sb.Append(bizContent); + } + return sb.ToString(); + } + + public static string encryptAndSign(string bizContent, string alipayPublicKey, + string cusPrivateKey, string charset, bool isEncrypt, + bool isSign) + { + StringBuilder sb = new StringBuilder(); + if (string.IsNullOrEmpty(charset)) + { + charset = DEFAULT_CHARSET; + } + sb.Append(""); + if (isEncrypt) + {// 加密 + sb.Append(""); + String encrypted = RSAEncrypt(bizContent, alipayPublicKey, charset); + sb.Append("" + encrypted + ""); + sb.Append("RSA"); + if (isSign) + { + String sign = RSASign(encrypted, cusPrivateKey, charset, "RSA"); + sb.Append("" + sign + ""); + sb.Append("RSA"); + } + sb.Append(""); + } + else if (isSign) + {// 不加密,但需要签名 + sb.Append(""); + sb.Append("" + bizContent + ""); + String sign = RSASign(bizContent, cusPrivateKey, charset, "RSA"); + sb.Append("" + sign + ""); + sb.Append("RSA"); + sb.Append(""); + } + else + {// 不加密,不加签 + sb.Append(bizContent); + } + return sb.ToString(); + } + + public static string RSAEncrypt(string content, string publicKeyPem, string charset) + { + try + { + string sPublicKeyPEM = File.ReadAllText(publicKeyPem); + RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); + rsa.PersistKeyInCsp = false; + RSACryptoServiceProviderExtension.LoadPublicKeyPEM(rsa, sPublicKeyPEM); + if (string.IsNullOrEmpty(charset)) + { + charset = DEFAULT_CHARSET; + } + byte[] data = Encoding.GetEncoding(charset).GetBytes(content); + int maxBlockSize = rsa.KeySize / 8 - 11; //加密块最大长度限制 + if (data.Length <= maxBlockSize) + { + byte[] cipherbytes = rsa.Encrypt(data, false); + return Convert.ToBase64String(cipherbytes); + } + MemoryStream plaiStream = new MemoryStream(data); + MemoryStream crypStream = new MemoryStream(); + Byte[] buffer = new Byte[maxBlockSize]; + int blockSize = plaiStream.Read(buffer, 0, maxBlockSize); + while (blockSize > 0) + { + Byte[] toEncrypt = new Byte[blockSize]; + Array.Copy(buffer, 0, toEncrypt, 0, blockSize); + Byte[] cryptograph = rsa.Encrypt(toEncrypt, false); + crypStream.Write(cryptograph, 0, cryptograph.Length); + blockSize = plaiStream.Read(buffer, 0, maxBlockSize); + } + + return Convert.ToBase64String(crypStream.ToArray(), Base64FormattingOptions.None); + } + catch (Exception ex) + { + throw new SopException("EncryptContent = " + content + ",charset = " + charset, ex); + } + } + public static string RSAEncrypt(string content, string publicKeyPem, string charset, bool keyFromFile) + { + try + { + string sPublicKeyPEM; + if (keyFromFile) { + sPublicKeyPEM = File.ReadAllText(publicKeyPem); + }else{ + sPublicKeyPEM = "-----BEGIN PUBLIC KEY-----\r\n"; + sPublicKeyPEM += publicKeyPem; + sPublicKeyPEM += "-----END PUBLIC KEY-----\r\n\r\n"; + } + RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); + rsa.PersistKeyInCsp = false; + RSACryptoServiceProviderExtension.LoadPublicKeyPEM(rsa, sPublicKeyPEM); + if (string.IsNullOrEmpty(charset)) + { + charset = DEFAULT_CHARSET; + } + byte[] data = Encoding.GetEncoding(charset).GetBytes(content); + int maxBlockSize = rsa.KeySize / 8 - 11; //加密块最大长度限制 + if (data.Length <= maxBlockSize) + { + byte[] cipherbytes = rsa.Encrypt(data, false); + return Convert.ToBase64String(cipherbytes); + } + MemoryStream plaiStream = new MemoryStream(data); + MemoryStream crypStream = new MemoryStream(); + Byte[] buffer = new Byte[maxBlockSize]; + int blockSize = plaiStream.Read(buffer, 0, maxBlockSize); + while (blockSize > 0) + { + Byte[] toEncrypt = new Byte[blockSize]; + Array.Copy(buffer, 0, toEncrypt, 0, blockSize); + Byte[] cryptograph = rsa.Encrypt(toEncrypt, false); + crypStream.Write(cryptograph, 0, cryptograph.Length); + blockSize = plaiStream.Read(buffer, 0, maxBlockSize); + } + + return Convert.ToBase64String(crypStream.ToArray(), Base64FormattingOptions.None); + } + catch (Exception ex) + { + throw new SopException("EncryptContent = " + content + ",charset = " + charset, ex); + } + } + + public static string RSADecrypt(string content, string privateKeyPem, string charset, string signType) + { + try + { + RSACryptoServiceProvider rsaCsp = LoadCertificateFile(privateKeyPem, signType); + if (string.IsNullOrEmpty(charset)) + { + charset = DEFAULT_CHARSET; + } + byte[] data = Convert.FromBase64String(content); + int maxBlockSize = rsaCsp.KeySize / 8; //解密块最大长度限制 + if (data.Length <= maxBlockSize) + { + byte[] cipherbytes = rsaCsp.Decrypt(data, false); + return Encoding.GetEncoding(charset).GetString(cipherbytes); + } + MemoryStream crypStream = new MemoryStream(data); + MemoryStream plaiStream = new MemoryStream(); + Byte[] buffer = new Byte[maxBlockSize]; + int blockSize = crypStream.Read(buffer, 0, maxBlockSize); + while (blockSize > 0) + { + Byte[] toDecrypt = new Byte[blockSize]; + Array.Copy(buffer, 0, toDecrypt, 0, blockSize); + Byte[] cryptograph = rsaCsp.Decrypt(toDecrypt, false); + plaiStream.Write(cryptograph, 0, cryptograph.Length); + blockSize = crypStream.Read(buffer, 0, maxBlockSize); + } + + return Encoding.GetEncoding(charset).GetString(plaiStream.ToArray()); + } + catch (Exception ex) + { + throw new SopException("DecryptContent = " + content + ",charset = " + charset, ex); + } + } + + public static string RSADecrypt(string content, string privateKeyPem, string charset, string signType, bool keyFromFile) + { + try + { + RSACryptoServiceProvider rsaCsp = null; + if (keyFromFile) + { + //文件读取 + rsaCsp = LoadCertificateFile(privateKeyPem, signType); + } + else + { + //字符串获取 + rsaCsp = LoadCertificateString(privateKeyPem, signType); + } + if (string.IsNullOrEmpty(charset)) + { + charset = DEFAULT_CHARSET; + } + byte[] data = Convert.FromBase64String(content); + int maxBlockSize = rsaCsp.KeySize / 8; //解密块最大长度限制 + if (data.Length <= maxBlockSize) + { + byte[] cipherbytes = rsaCsp.Decrypt(data, false); + return Encoding.GetEncoding(charset).GetString(cipherbytes); + } + MemoryStream crypStream = new MemoryStream(data); + MemoryStream plaiStream = new MemoryStream(); + Byte[] buffer = new Byte[maxBlockSize]; + int blockSize = crypStream.Read(buffer, 0, maxBlockSize); + while (blockSize > 0) + { + Byte[] toDecrypt = new Byte[blockSize]; + Array.Copy(buffer, 0, toDecrypt, 0, blockSize); + Byte[] cryptograph = rsaCsp.Decrypt(toDecrypt, false); + plaiStream.Write(cryptograph, 0, cryptograph.Length); + blockSize = crypStream.Read(buffer, 0, maxBlockSize); + } + + return Encoding.GetEncoding(charset).GetString(plaiStream.ToArray()); + } + catch (Exception ex) + { + throw new SopException("DecryptContent = " + content + ",charset = " + charset, ex); + } + } + + private static byte[] 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) + header.Length; + int end = pem.IndexOf(footer, start); + string base64 = pem.Substring(start, (end - start)); + + return Convert.FromBase64String(base64); + } + + // 加载秘钥文件 + private static RSACryptoServiceProvider LoadCertificateFile(string filename, string signType) + { + using (System.IO.FileStream fs = System.IO.File.OpenRead(filename)) + { + byte[] data = new byte[fs.Length]; + byte[] res = null; + fs.Read(data, 0, data.Length); + if (data[0] != 0x30) + { + res = GetPem("RSA PRIVATE KEY", data); + } + try + { + RSACryptoServiceProvider rsa = DecodeRSAPrivateKey(res, signType); + return rsa; + } + catch (Exception ex) + { + throw new SopException("LoadCertificateFile fail", ex); + } + } + } + private static RSACryptoServiceProvider LoadCertificateString(string strKey, string signType) + { + byte[] data = null; + //读取带 + //ata = Encoding.Default.GetBytes(strKey); + data = Convert.FromBase64String(strKey); + //data = GetPem("RSA PRIVATE KEY", data); + try + { + RSACryptoServiceProvider rsa = DecodeRSAPrivateKey(data, signType); + return rsa; + } + catch (Exception ex) + { + throw new SopException("DecodeRSAPrivateKey fail", ex); + } + } + + private static RSACryptoServiceProvider DecodeRSAPrivateKey(byte[] privkey, string signType) + { + byte[] MODULUS, E, D, P, Q, DP, DQ, IQ; + + // --------- Set up stream to decode the asn.1 encoded RSA private key ------ + MemoryStream mem = new MemoryStream(privkey); + BinaryReader binr = new BinaryReader(mem); //wrap Memory Stream with BinaryReader for easy reading + byte bt = 0; + ushort twobytes = 0; + int elems = 0; + try + { + twobytes = binr.ReadUInt16(); + if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81) + binr.ReadByte(); //advance 1 byte + else if (twobytes == 0x8230) + binr.ReadInt16(); //advance 2 bytes + else + return null; + + twobytes = binr.ReadUInt16(); + if (twobytes != 0x0102) //version number + return null; + bt = binr.ReadByte(); + if (bt != 0x00) + return null; + + + //------ all private key components are Integer sequences ---- + elems = GetIntegerSize(binr); + MODULUS = binr.ReadBytes(elems); + + elems = GetIntegerSize(binr); + E = binr.ReadBytes(elems); + + elems = GetIntegerSize(binr); + D = binr.ReadBytes(elems); + + elems = GetIntegerSize(binr); + P = binr.ReadBytes(elems); + + elems = GetIntegerSize(binr); + Q = binr.ReadBytes(elems); + + elems = GetIntegerSize(binr); + DP = binr.ReadBytes(elems); + + elems = GetIntegerSize(binr); + DQ = binr.ReadBytes(elems); + + elems = GetIntegerSize(binr); + IQ = binr.ReadBytes(elems); + + + // ------- create RSACryptoServiceProvider instance and initialize with public key ----- + CspParameters CspParameters = new CspParameters(); + CspParameters.Flags = CspProviderFlags.UseMachineKeyStore; + + int bitLen = 1024; + if ("RSA2".Equals(signType)) + { + bitLen = 2048; + } + + RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(bitLen, CspParameters); + RSAParameters RSAparams = new RSAParameters(); + RSAparams.Modulus = MODULUS; + RSAparams.Exponent = E; + RSAparams.D = D; + RSAparams.P = P; + RSAparams.Q = Q; + RSAparams.DP = DP; + RSAparams.DQ = DQ; + RSAparams.InverseQ = IQ; + RSA.ImportParameters(RSAparams); + return RSA; + } + catch (Exception ex) + { + throw new SopException("DecodeRSAPrivateKey fail" + ex.Message, ex); + } + finally + { + binr.Close(); + } + } + + private static int GetIntegerSize(BinaryReader binr) + { + byte bt = 0; + byte lowbyte = 0x00; + byte highbyte = 0x00; + int count = 0; + bt = binr.ReadByte(); + if (bt != 0x02) //expect integer + return 0; + bt = binr.ReadByte(); + + if (bt == 0x81) + count = binr.ReadByte(); // data size in next byte + else + if (bt == 0x82) + { + highbyte = binr.ReadByte(); // data size in next 2 bytes + lowbyte = binr.ReadByte(); + byte[] modint = { lowbyte, highbyte, 0x00, 0x00 }; + count = BitConverter.ToInt32(modint, 0); + } + else + { + count = bt; // we already have the data size + } + + while (binr.ReadByte() == 0x00) + { //remove high order zeros in data + count -= 1; + } + binr.BaseStream.Seek(-1, SeekOrigin.Current); //last ReadByte wasn't a removed zero, so back up a byte + return count; + } + } +} + diff --git a/sop-sdk/sdk-csharp/SDKCSharp/Utility/RSACryptoServiceProviderExtension.cs b/sop-sdk/sdk-csharp/SDKCSharp/Utility/RSACryptoServiceProviderExtension.cs new file mode 100755 index 00000000..ca940dff --- /dev/null +++ b/sop-sdk/sdk-csharp/SDKCSharp/Utility/RSACryptoServiceProviderExtension.cs @@ -0,0 +1,245 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Security.Cryptography; +using System.ComponentModel; +using System.Runtime.InteropServices; +using System.IO; + +namespace SDKCSharp.Utility +{ + public static class RSACryptoServiceProviderExtension + { + + #region Methods + + /// Extension method which initializes an RSACryptoServiceProvider from a DER public key blob. + public static void LoadPublicKeyDER( RSACryptoServiceProvider provider, byte[] DERData ) + { + byte[] RSAData = RSACryptoServiceProviderExtension.GetRSAFromDER( DERData ); + byte[] publicKeyBlob = RSACryptoServiceProviderExtension.GetPublicKeyBlobFromRSA( RSAData ); + provider.ImportCspBlob( publicKeyBlob ); + } + + /// Extension method which initializes an RSACryptoServiceProvider from a PEM public key string. + public static void LoadPublicKeyPEM( RSACryptoServiceProvider provider, string sPEM ) + { + byte[] DERData = RSACryptoServiceProviderExtension.GetDERFromPEM( sPEM ); + RSACryptoServiceProviderExtension.LoadPublicKeyDER( provider, DERData ); + } + + /// Returns a public key blob from an RSA public key. + internal static byte[] GetPublicKeyBlobFromRSA( byte[] RSAData ) + { + byte[] data = null; + UInt32 dwCertPublicKeyBlobSize = 0; + if ( RSACryptoServiceProviderExtension.CryptDecodeObject( CRYPT_ENCODING_FLAGS.X509_ASN_ENCODING | CRYPT_ENCODING_FLAGS.PKCS_7_ASN_ENCODING, + new IntPtr( (int)CRYPT_OUTPUT_TYPES.RSA_CSP_PUBLICKEYBLOB ), RSAData, (UInt32)RSAData.Length, CRYPT_DECODE_FLAGS.NONE, + data, ref dwCertPublicKeyBlobSize ) ) + { + data = new byte[ dwCertPublicKeyBlobSize ]; + if ( !RSACryptoServiceProviderExtension.CryptDecodeObject( CRYPT_ENCODING_FLAGS.X509_ASN_ENCODING | CRYPT_ENCODING_FLAGS.PKCS_7_ASN_ENCODING, + new IntPtr( (int)CRYPT_OUTPUT_TYPES.RSA_CSP_PUBLICKEYBLOB ), RSAData, (UInt32)RSAData.Length, CRYPT_DECODE_FLAGS.NONE, + data, ref dwCertPublicKeyBlobSize ) ) + throw new Win32Exception( Marshal.GetLastWin32Error() ); + } + else + throw new Win32Exception( Marshal.GetLastWin32Error() ); + return data; + } + + /// Converts DER binary format to a CAPI CERT_PUBLIC_KEY_INFO structure containing an RSA key. + internal static byte[] GetRSAFromDER( byte[] DERData ) + { + byte[] data = null; + byte[] publicKey = null; + CERT_PUBLIC_KEY_INFO info; + UInt32 dwCertPublicKeyInfoSize = 0; + IntPtr pCertPublicKeyInfo = IntPtr.Zero; + if ( RSACryptoServiceProviderExtension.CryptDecodeObject( CRYPT_ENCODING_FLAGS.X509_ASN_ENCODING | CRYPT_ENCODING_FLAGS.PKCS_7_ASN_ENCODING, new IntPtr( (int)CRYPT_OUTPUT_TYPES.X509_PUBLIC_KEY_INFO ), + DERData, (UInt32)DERData.Length, CRYPT_DECODE_FLAGS.NONE, data, ref dwCertPublicKeyInfoSize ) ) + { + data = new byte[ dwCertPublicKeyInfoSize ]; + if ( RSACryptoServiceProviderExtension.CryptDecodeObject( CRYPT_ENCODING_FLAGS.X509_ASN_ENCODING | CRYPT_ENCODING_FLAGS.PKCS_7_ASN_ENCODING, new IntPtr( (int)CRYPT_OUTPUT_TYPES.X509_PUBLIC_KEY_INFO ), + DERData, (UInt32)DERData.Length, CRYPT_DECODE_FLAGS.NONE, data, ref dwCertPublicKeyInfoSize ) ) + { + GCHandle handle = GCHandle.Alloc( data, GCHandleType.Pinned ); + try + { + info = (CERT_PUBLIC_KEY_INFO)Marshal.PtrToStructure( handle.AddrOfPinnedObject(), typeof( CERT_PUBLIC_KEY_INFO ) ); + publicKey = new byte[ info.PublicKey.cbData ]; + Marshal.Copy( info.PublicKey.pbData, publicKey, 0, publicKey.Length ); + } + finally + { + handle.Free(); + } + } + else + throw new Win32Exception( Marshal.GetLastWin32Error() ); + } + else + throw new Win32Exception( Marshal.GetLastWin32Error() ); + return publicKey; + } + + /// Extracts the binary data from a PEM file. + internal static byte[] GetDERFromPEM( string sPEM ) + { + UInt32 dwSkip, dwFlags; + UInt32 dwBinarySize = 0; + + if ( !RSACryptoServiceProviderExtension.CryptStringToBinary( sPEM, (UInt32)sPEM.Length, CRYPT_STRING_FLAGS.CRYPT_STRING_BASE64HEADER, null, ref dwBinarySize, out dwSkip, out dwFlags ) ) + throw new Win32Exception( Marshal.GetLastWin32Error() ); + + byte[] decodedData = new byte[ dwBinarySize ]; + if ( !RSACryptoServiceProviderExtension.CryptStringToBinary( sPEM, (UInt32)sPEM.Length, CRYPT_STRING_FLAGS.CRYPT_STRING_BASE64HEADER, decodedData, ref dwBinarySize, out dwSkip, out dwFlags ) ) + throw new Win32Exception( Marshal.GetLastWin32Error() ); + return decodedData; + } + + #endregion Methods + + #region P/Invoke Constants + + /// Enumeration derived from Crypto API. + internal enum CRYPT_ACQUIRE_CONTEXT_FLAGS : uint + { + CRYPT_NEWKEYSET = 0x8, + CRYPT_DELETEKEYSET = 0x10, + CRYPT_MACHINE_KEYSET = 0x20, + CRYPT_SILENT = 0x40, + CRYPT_DEFAULT_CONTAINER_OPTIONAL = 0x80, + CRYPT_VERIFYCONTEXT = 0xF0000000 + } + + /// Enumeration derived from Crypto API. + internal enum CRYPT_PROVIDER_TYPE : uint + { + PROV_RSA_FULL = 1 + } + + /// Enumeration derived from Crypto API. + internal enum CRYPT_DECODE_FLAGS : uint + { + NONE = 0, + CRYPT_DECODE_ALLOC_FLAG = 0x8000 + } + + /// Enumeration derived from Crypto API. + internal enum CRYPT_ENCODING_FLAGS : uint + { + PKCS_7_ASN_ENCODING = 0x00010000, + X509_ASN_ENCODING = 0x00000001, + } + + /// Enumeration derived from Crypto API. + internal enum CRYPT_OUTPUT_TYPES : int + { + X509_PUBLIC_KEY_INFO = 8, + RSA_CSP_PUBLICKEYBLOB = 19, + PKCS_RSA_PRIVATE_KEY = 43, + PKCS_PRIVATE_KEY_INFO = 44 + } + + /// Enumeration derived from Crypto API. + internal enum CRYPT_STRING_FLAGS : uint + { + CRYPT_STRING_BASE64HEADER = 0, + CRYPT_STRING_BASE64 = 1, + CRYPT_STRING_BINARY = 2, + CRYPT_STRING_BASE64REQUESTHEADER = 3, + CRYPT_STRING_HEX = 4, + CRYPT_STRING_HEXASCII = 5, + CRYPT_STRING_BASE64_ANY = 6, + CRYPT_STRING_ANY = 7, + CRYPT_STRING_HEX_ANY = 8, + CRYPT_STRING_BASE64X509CRLHEADER = 9, + CRYPT_STRING_HEXADDR = 10, + CRYPT_STRING_HEXASCIIADDR = 11, + CRYPT_STRING_HEXRAW = 12, + CRYPT_STRING_NOCRLF = 0x40000000, + CRYPT_STRING_NOCR = 0x80000000 + } + + #endregion P/Invoke Constants + + #region P/Invoke Structures + + /// Structure from Crypto API. + [StructLayout( LayoutKind.Sequential )] + internal struct CRYPT_OBJID_BLOB + { + internal UInt32 cbData; + internal IntPtr pbData; + } + + /// Structure from Crypto API. + [StructLayout( LayoutKind.Sequential )] + internal struct CRYPT_ALGORITHM_IDENTIFIER + { + internal IntPtr pszObjId; + internal CRYPT_OBJID_BLOB Parameters; + } + + /// Structure from Crypto API. + [StructLayout( LayoutKind.Sequential )] + struct CRYPT_BIT_BLOB + { + internal UInt32 cbData; + internal IntPtr pbData; + internal UInt32 cUnusedBits; + } + + /// Structure from Crypto API. + [StructLayout( LayoutKind.Sequential )] + struct CERT_PUBLIC_KEY_INFO + { + internal CRYPT_ALGORITHM_IDENTIFIER Algorithm; + internal CRYPT_BIT_BLOB PublicKey; + } + + #endregion P/Invoke Structures + + #region P/Invoke Functions + + /// Function for Crypto API. + [DllImport( "advapi32.dll", SetLastError = true )] + [return: MarshalAs( UnmanagedType.Bool )] + internal static extern bool CryptDestroyKey( IntPtr hKey ); + + /// Function for Crypto API. + [DllImport( "advapi32.dll", SetLastError = true )] + [return: MarshalAs( UnmanagedType.Bool )] + internal static extern bool CryptImportKey( IntPtr hProv, byte[] pbKeyData, UInt32 dwDataLen, IntPtr hPubKey, UInt32 dwFlags, ref IntPtr hKey ); + + /// Function for Crypto API. + [DllImport( "advapi32.dll", SetLastError = true )] + [return: MarshalAs( UnmanagedType.Bool )] + internal static extern bool CryptReleaseContext( IntPtr hProv, Int32 dwFlags ); + + /// Function for Crypto API. + [DllImport( "advapi32.dll", CharSet = CharSet.Auto, SetLastError = true )] + [return: MarshalAs( UnmanagedType.Bool )] + internal static extern bool CryptAcquireContext( ref IntPtr hProv, string pszContainer, string pszProvider, CRYPT_PROVIDER_TYPE dwProvType, CRYPT_ACQUIRE_CONTEXT_FLAGS dwFlags ); + + /// Function from Crypto API. + [DllImport( "crypt32.dll", SetLastError = true, CharSet = CharSet.Auto )] + [return: MarshalAs( UnmanagedType.Bool )] + internal static extern bool CryptStringToBinary( string sPEM, UInt32 sPEMLength, CRYPT_STRING_FLAGS dwFlags, [Out] byte[] pbBinary, ref UInt32 pcbBinary, out UInt32 pdwSkip, out UInt32 pdwFlags ); + + /// Function from Crypto API. + [DllImport( "crypt32.dll", SetLastError = true )] + [return: MarshalAs( UnmanagedType.Bool )] + internal static extern bool CryptDecodeObjectEx( CRYPT_ENCODING_FLAGS dwCertEncodingType, IntPtr lpszStructType, byte[] pbEncoded, UInt32 cbEncoded, CRYPT_DECODE_FLAGS dwFlags, IntPtr pDecodePara, ref byte[] pvStructInfo, ref UInt32 pcbStructInfo ); + + /// Function from Crypto API. + [DllImport( "crypt32.dll", SetLastError = true )] + [return: MarshalAs( UnmanagedType.Bool )] + internal static extern bool CryptDecodeObject( CRYPT_ENCODING_FLAGS dwCertEncodingType, IntPtr lpszStructType, byte[] pbEncoded, UInt32 cbEncoded, CRYPT_DECODE_FLAGS flags, [In, Out] byte[] pvStructInfo, ref UInt32 cbStructInfo ); + + #endregion P/Invoke Functions + + } + +} diff --git a/sop-sdk/sdk-csharp/SDKCSharp/Utility/RSAUtil.cs b/sop-sdk/sdk-csharp/SDKCSharp/Utility/RSAUtil.cs deleted file mode 100644 index 753ffd93..00000000 --- a/sop-sdk/sdk-csharp/SDKCSharp/Utility/RSAUtil.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using System.Xml; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Security.Cryptography; -using System.Text; - -using Org.BouncyCastle.Asn1.Pkcs; -using Org.BouncyCastle.Asn1.X509; -using Org.BouncyCastle.Crypto.Generators; -using Org.BouncyCastle.Crypto.Parameters; -using Org.BouncyCastle.Math; -using Org.BouncyCastle.Pkcs; -using Org.BouncyCastle.Security; -using Org.BouncyCastle.Crypto.Engines; -using Org.BouncyCastle.X509; -using Org.BouncyCastle.Crypto; -using Org.BouncyCastle.Asn1; -using Org.BouncyCastle.Crypto.Encodings; - -namespace SDKCSharp.Utility -{ - public class RSAUtil - { - - static Encoding UTF8 = Encoding.UTF8; - static RSA rsa = new RSA(); - - /// - /// 私钥加密 - /// - /// The by private key. - /// 内容. - /// 私钥. - public static string EncryptByPrivateKey(string data, string privateKey) - { - return rsa.EncryptByPrivateKey(data, privateKey); - } - - - } - - - - -} diff --git a/sop-sdk/sdk-csharp/SDKCSharp/Utility/SignUtil.cs b/sop-sdk/sdk-csharp/SDKCSharp/Utility/SignUtil.cs index 0da83e5b..12c42b42 100644 --- a/sop-sdk/sdk-csharp/SDKCSharp/Utility/SignUtil.cs +++ b/sop-sdk/sdk-csharp/SDKCSharp/Utility/SignUtil.cs @@ -14,30 +14,17 @@ namespace SDKCSharp.Utility { /// - /// 参数签名 + /// 构建签名。 /// - /// 参数 - /// 秘钥 - /// 返回sign - public static String CreateSign(Dictionary paramsMap, string secret) + /// 参数. + /// 私钥. + /// 字符集. + /// 签名类型. + /// 返回签名. + public static string CreateSign(IDictionary parameters, string privateKeyPem, string charset, string signType) { - StringBuilder sb = new StringBuilder(); - ArrayList paramNames = new ArrayList(paramsMap.Keys); - - paramNames.Sort(); - - sb.Append(secret); - foreach (string paramName in paramNames) - { - sb.Append(paramName).Append(paramsMap[paramName]); - } - sb.Append(secret); - - string source = sb.ToString(); - - return MD5Util.EncryptToUpper(source); + return AlipaySignature.RSASign(parameters, privateKeyPem, charset, false, signType); } - } } diff --git a/sop-sdk/sdk-csharp/SDKTest/Program.cs b/sop-sdk/sdk-csharp/SDKTest/Program.cs index f187f9b3..6baeb653 100644 --- a/sop-sdk/sdk-csharp/SDKTest/Program.cs +++ b/sop-sdk/sdk-csharp/SDKTest/Program.cs @@ -12,9 +12,9 @@ namespace SDKTest class MainClass { static string url = "http://localhost:8081/api"; // zuul - static string appId = "2019032617262200001"; - // 支付宝私钥 - static string privateKey = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCXJv1pQFqWNA/++OYEV7WYXwexZK/J8LY1OWlP9X0T6wHFOvxNKRvMkJ5544SbgsJpVcvRDPrcxmhPbi/sAhdO4x2PiPKIz9Yni2OtYCCeaiE056B+e1O2jXoLeXbfi9fPivJZkxH/tb4xfLkH3bA8ZAQnQsoXA0SguykMRZntF0TndUfvDrLqwhlR8r5iRdZLB6F8o8qXH6UPDfNEnf/K8wX5T4EB1b8x8QJ7Ua4GcIUqeUxGHdQpzNbJdaQvoi06lgccmL+PHzminkFYON7alj1CjDN833j7QMHdPtS9l7B67fOU/p2LAAkPMtoVBfxQt9aFj7B8rEhGCz02iJIBAgMBAAECggEARqOuIpY0v6WtJBfmR3lGIOOokLrhfJrGTLF8CiZMQha+SRJ7/wOLPlsH9SbjPlopyViTXCuYwbzn2tdABigkBHYXxpDV6CJZjzmRZ+FY3S/0POlTFElGojYUJ3CooWiVfyUMhdg5vSuOq0oCny53woFrf32zPHYGiKdvU5Djku1onbDU0Lw8w+5tguuEZ76kZ/lUcccGy5978FFmYpzY/65RHCpvLiLqYyWTtaNT1aQ/9pw4jX9HO9NfdJ9gYFK8r/2f36ZE4hxluAfeOXQfRC/WhPmiw/ReUhxPznG/WgKaa/OaRtAx3inbQ+JuCND7uuKeRe4osP2jLPHPP6AUwQKBgQDUNu3BkLoKaimjGOjCTAwtp71g1oo+k5/uEInAo7lyEwpV0EuUMwLA/HCqUgR4K9pyYV+Oyb8d6f0+Hz0BMD92I2pqlXrD7xV2WzDvyXM3s63NvorRooKcyfd9i6ccMjAyTR2qfLkxv0hlbBbsPHz4BbU63xhTJp3Ghi0/ey/1HQKBgQC2VsgqC6ykfSidZUNLmQZe3J0p/Qf9VLkfrQ+xaHapOs6AzDU2H2osuysqXTLJHsGfrwVaTs00ER2z8ljTJPBUtNtOLrwNRlvgdnzyVAKHfOgDBGwJgiwpeE9voB1oAV/mXqSaUWNnuwlOIhvQEBwekqNyWvhLqC7nCAIhj3yvNQKBgQCqYbeec56LAhWP903Zwcj9VvG7sESqXUhIkUqoOkuIBTWFFIm54QLTA1tJxDQGb98heoCIWf5x/A3xNI98RsqNBX5JON6qNWjb7/dobitti3t99v/ptDp9u8JTMC7penoryLKK0Ty3bkan95Kn9SC42YxaSghzqkt+uvfVQgiNGQKBgGxU6P2aDAt6VNwWosHSe+d2WWXt8IZBhO9d6dn0f7ORvcjmCqNKTNGgrkewMZEuVcliueJquR47IROdY8qmwqcBAN7Vg2K7r7CPlTKAWTRYMJxCT1Hi5gwJb+CZF3+IeYqsJk2NF2s0w5WJTE70k1BSvQsfIzAIDz2yE1oPHvwVAoGAA6e+xQkVH4fMEph55RJIZ5goI4Y76BSvt2N5OKZKd4HtaV+eIhM3SDsVYRLIm9ZquJHMiZQGyUGnsvrKL6AAVNK7eQZCRDk9KQz+0GKOGqku0nOZjUbAu6A2/vtXAaAuFSFx1rUQVVjFulLexkXR3KcztL1Qu2k5pB6Si0K/uwQ="; + static string appId = "201904035630907729292csharp"; + // 私钥, PKCS1 1024 + static string privateKey = "MIIEowIBAAKCAQEA5+OvJxeSzf44NxQ/cl7Ii+BzPg2k6sRcvH4ffOtU5Dzq1/oEvg02nxIhmwOHBZmjbmuUu0aLsfglUTAwqfXftfAKZidshsgj9NNh0/kxk0avRZ1UoljWGz/FxVZA0ogbxxhohPZ9jWcD+eBQcIwF2DtHfAJqWWZrYFnCMeHD8mPzxo2kwXSvDzi0vf9I2tKiYvNG26a9FqeYtPOoi81sdS3+70HOMdxP8ejXtyfnKpKz7Dx506LCIRS5moWS3Q5eTLV3NGX/1CSJ8wpQA2DAQTjVhX5eVu7Yqz12t8W+sjWM/tHUR6cgwYYR10p7tSCeCPzkigjGxKm4cYXWtATQJQIDAQABAoIBAHFDsgrrJca+NKEan77ycwx3jnKx4WrWjOF4zVKL9AQjiSYDNgvKknJyPb3kpC/lEoHdxGERHSzJoxib7DkoIqRQYhPxj73pxj5QfYk3P7LLJNNg/LTrpXDb3nL8JV9wIflGf87qQvstZTDJEyFWE4jBs7Hr0BxovWvri8InnzkmERJ1cbGJgNHe1Y3Zo2tw0yaHxQCxLuajP+notRZhD9bEp7uKeI0w9AvlW6k8m/7y10F0BK/TlyW8rQiEC391yOiRYoMcUh4hd2Q9bMx3jngZgX8PXIvZZcup4/pvWlv1alwhB2tsnLdazP62r1MO80vLyLunzGO+7WwCjEYlVaECgYEA+lQRFmbhKaPuAuXMtY31Fbga8nedka5TjnEV7+/kX+yowE2OlNujF+ZG8UTddTxAGv56yVNi/mjRlgD74j8z0eOsgvOq9mwbCrgLhLo51H9O/wAxtb+hBKtC5l50pBr4gER6d8W6EQNTSGojnMIaLXTkAZ5Qf6Z8e2HFVdOn0X0CgYEA7SSrTokwzukt5KldNu5ukyyd+C3D1i6orbg6qD73EP9CfNMfGSBn7dDv9wMSJH01+Ty+RgTROgtjGRDbMJWnfbdt/61NePr9ar5sb6Nbsf7/I0w7cZF5dsaFYgzaOfQYquzXPbLQHkpMT64bqpv/Mwy4F2lFvaYWY5fA4pC2uckCgYEAg75Ym9ybJaoTqky8ttQ2Jy8UZ4VSVQhVC0My02sCWwWXLlXi8y7An+Rec73Ve0yxREOn5WrQT6pkmzh7V/ABWrYi5WxODpCIjtSbo0fLBa3Wqle00b0/hdCITetqIa/cFs1zUrOqICgK3bKWeXqiAkhhcwSZwwSgwOKM04Wn7ZUCgYBvhHX2mbdVJfyJ8kc+hMOE/E9RHRxiBVEXWHJlGi8PVCqNDq8qHr4g7Mdbzprig+s0yKblwHAvrpkseWvKHiZEjVTyDipHgShY4TGXEigVvUd37uppTrLi8xpYcJjS9gH/px7VCdiq1d+q/MJP6coJ1KphgATm2UrgDMYNBWaYWQKBgEHRxrmER7btUF60/YgcqPHFc8RpYQB2ZZE0kyKGDqk2Data1XYUY6vsPAU28yRLAaWr/D2H17iyLkxP80VLm6QhifxCadv90Q/Wl1DFfOJQMW6avyQ0so6G0wFq/LJxaFK4iLXQn1RJnmTp6BYiJMmK2BhFbRzw8ssMoF6ad2rr"; // 声明一个就行