mirror of
https://gitee.com/durcframework/SOP.git
synced 2025-08-11 21:57:56 +08:00
C#SDK提交,在window上验证
This commit is contained in:
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
- 安装并启动zookeeper,[安装教程](http://zookeeper.apache.org/doc/r3.4.13/zookeeperStarted.html)
|
- 安装并启动zookeeper,[安装教程](http://zookeeper.apache.org/doc/r3.4.13/zookeeperStarted.html)
|
||||||
- 执行Mysql脚本`sop.sql`
|
- 执行Mysql脚本`sop.sql`
|
||||||
- IDE打开项目(IDEA下可以打开根pom.xml,然后open as project)
|
- IDE安装lombok插件,然后打开项目(IDEA下可以打开根pom.xml,然后open as project)
|
||||||
- 启动注册中心,sop-registry(运行SopRegistryApplication.java)
|
- 启动注册中心,sop-registry(运行SopRegistryApplication.java)
|
||||||
- 启动微服务:sop-story-web(运行SopStoryApplication.java)
|
- 启动微服务:sop-story-web(运行SopStoryApplication.java)
|
||||||
- 启动网关:打开sop-gateway下的`application.yml`,修改数据库`username/password`,SopGatewayApplication.java
|
- 启动网关:打开sop-gateway下的`application.yml`,修改数据库`username/password`,SopGatewayApplication.java
|
||||||
|
@@ -78,7 +78,7 @@ namespace SDKCSharp.Client
|
|||||||
}
|
}
|
||||||
form[this.openConfig.AppKeyName] = this.appId;
|
form[this.openConfig.AppKeyName] = this.appId;
|
||||||
string content = SopSignature.getSignContent(form);
|
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;
|
form[this.openConfig.SignName] = sign;
|
||||||
|
|
||||||
string resp = this.doExecute(url, requestForm, header);
|
string resp = this.doExecute(url, requestForm, header);
|
||||||
|
@@ -16,7 +16,7 @@ namespace SDKCSharp.Common
|
|||||||
|
|
||||||
public static String TIMESTAMP_PATTERN = "yyyy-MM-dd HH:mm:ss";
|
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";
|
public static String SIGN_TYPE = "RSA2";
|
||||||
}
|
}
|
||||||
|
51
sop-sdk/sdk-csharp/SDKCSharp/Common/SopException.cs
Executable file
51
sop-sdk/sdk-csharp/SDKCSharp/Common/SopException.cs
Executable file
@@ -0,0 +1,51 @@
|
|||||||
|
using System;
|
||||||
|
using System.Runtime.Serialization;
|
||||||
|
|
||||||
|
namespace SDKCSharp.Common
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// AOP客户端异常。
|
||||||
|
/// </summary>
|
||||||
|
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; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -30,6 +30,8 @@ namespace SDKCSharp.Request
|
|||||||
public string BizContent { set => bizContent = value; }
|
public string BizContent { set => bizContent = value; }
|
||||||
public object BizModel { set => bizModel = value; }
|
public object BizModel { set => bizModel = value; }
|
||||||
public string Version { get => version; set => version = 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; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 返回接口名
|
/// 返回接口名
|
||||||
|
@@ -67,12 +67,15 @@
|
|||||||
<Compile Include="Utility\JsonUtil.cs" />
|
<Compile Include="Utility\JsonUtil.cs" />
|
||||||
<Compile Include="Utility\MD5Util.cs" />
|
<Compile Include="Utility\MD5Util.cs" />
|
||||||
<Compile Include="Utility\RSA.cs" />
|
<Compile Include="Utility\RSA.cs" />
|
||||||
<Compile Include="Utility\RSAUtil.cs" />
|
|
||||||
<Compile Include="Utility\SignUtil.cs" />
|
<Compile Include="Utility\SignUtil.cs" />
|
||||||
<Compile Include="Common\SopSignature.cs" />
|
<Compile Include="Common\SopSignature.cs" />
|
||||||
<Compile Include="Model\GetStoryModel.cs" />
|
<Compile Include="Model\GetStoryModel.cs" />
|
||||||
<Compile Include="Request\GetStoryRequest.cs" />
|
<Compile Include="Request\GetStoryRequest.cs" />
|
||||||
<Compile Include="Response\GetStoryResponse.cs" />
|
<Compile Include="Response\GetStoryResponse.cs" />
|
||||||
|
<Compile Include="Utility\AlipaySignature.cs" />
|
||||||
|
<Compile Include="Common\SopException.cs" />
|
||||||
|
<Compile Include="Utility\RSACryptoServiceProviderExtension.cs" />
|
||||||
|
<Compile Include="Utility\SopUtils.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Include="Dll\BouncyCastle.Crypto.dll" />
|
<Content Include="Dll\BouncyCastle.Crypto.dll" />
|
||||||
|
797
sop-sdk/sdk-csharp/SDKCSharp/Utility/AlipaySignature.cs
Executable file
797
sop-sdk/sdk-csharp/SDKCSharp/Utility/AlipaySignature.cs
Executable file
@@ -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<string, string> parameters)
|
||||||
|
{
|
||||||
|
// 第一步:把字典按Key的字母顺序排序
|
||||||
|
IDictionary<string, string> sortedParams = new SortedDictionary<string, string>(parameters);
|
||||||
|
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 RSASign(IDictionary<string, string> 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<string, string> 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<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");
|
||||||
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool RSACheckV1(IDictionary<string, string> 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<string, string> 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<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");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool RSACheckV2(IDictionary<string, string> 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<string, string> 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<string, string> 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("<?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 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("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>");
|
||||||
|
if (isEncrypt)
|
||||||
|
{// 加密
|
||||||
|
sb.Append("<alipay>");
|
||||||
|
String encrypted = RSAEncrypt(bizContent, alipayPublicKey, charset);
|
||||||
|
sb.Append("<response>" + encrypted + "</response>");
|
||||||
|
sb.Append("<encryption_type>RSA</encryption_type>");
|
||||||
|
if (isSign)
|
||||||
|
{
|
||||||
|
String sign = RSASign(encrypted, cusPrivateKey, charset, "RSA");
|
||||||
|
sb.Append("<sign>" + sign + "</sign>");
|
||||||
|
sb.Append("<sign_type>RSA</sign_type>");
|
||||||
|
}
|
||||||
|
sb.Append("</alipay>");
|
||||||
|
}
|
||||||
|
else if (isSign)
|
||||||
|
{// 不加密,但需要签名
|
||||||
|
sb.Append("<alipay>");
|
||||||
|
sb.Append("<response>" + bizContent + "</response>");
|
||||||
|
String sign = RSASign(bizContent, cusPrivateKey, charset, "RSA");
|
||||||
|
sb.Append("<sign>" + sign + "</sign>");
|
||||||
|
sb.Append("<sign_type>RSA</sign_type>");
|
||||||
|
sb.Append("</alipay>");
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
245
sop-sdk/sdk-csharp/SDKCSharp/Utility/RSACryptoServiceProviderExtension.cs
Executable file
245
sop-sdk/sdk-csharp/SDKCSharp/Utility/RSACryptoServiceProviderExtension.cs
Executable file
@@ -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
|
||||||
|
|
||||||
|
/// <summary>Extension method which initializes an RSACryptoServiceProvider from a DER public key blob.</summary>
|
||||||
|
public static void LoadPublicKeyDER( RSACryptoServiceProvider provider, byte[] DERData )
|
||||||
|
{
|
||||||
|
byte[] RSAData = RSACryptoServiceProviderExtension.GetRSAFromDER( DERData );
|
||||||
|
byte[] publicKeyBlob = RSACryptoServiceProviderExtension.GetPublicKeyBlobFromRSA( RSAData );
|
||||||
|
provider.ImportCspBlob( publicKeyBlob );
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Extension method which initializes an RSACryptoServiceProvider from a PEM public key string.</summary>
|
||||||
|
public static void LoadPublicKeyPEM( RSACryptoServiceProvider provider, string sPEM )
|
||||||
|
{
|
||||||
|
byte[] DERData = RSACryptoServiceProviderExtension.GetDERFromPEM( sPEM );
|
||||||
|
RSACryptoServiceProviderExtension.LoadPublicKeyDER( provider, DERData );
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Returns a public key blob from an RSA public key.</summary>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Converts DER binary format to a CAPI CERT_PUBLIC_KEY_INFO structure containing an RSA key.</summary>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Extracts the binary data from a PEM file.</summary>
|
||||||
|
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
|
||||||
|
|
||||||
|
/// <summary>Enumeration derived from Crypto API.</summary>
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Enumeration derived from Crypto API.</summary>
|
||||||
|
internal enum CRYPT_PROVIDER_TYPE : uint
|
||||||
|
{
|
||||||
|
PROV_RSA_FULL = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Enumeration derived from Crypto API.</summary>
|
||||||
|
internal enum CRYPT_DECODE_FLAGS : uint
|
||||||
|
{
|
||||||
|
NONE = 0,
|
||||||
|
CRYPT_DECODE_ALLOC_FLAG = 0x8000
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Enumeration derived from Crypto API.</summary>
|
||||||
|
internal enum CRYPT_ENCODING_FLAGS : uint
|
||||||
|
{
|
||||||
|
PKCS_7_ASN_ENCODING = 0x00010000,
|
||||||
|
X509_ASN_ENCODING = 0x00000001,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Enumeration derived from Crypto API.</summary>
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Enumeration derived from Crypto API.</summary>
|
||||||
|
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
|
||||||
|
|
||||||
|
/// <summary>Structure from Crypto API.</summary>
|
||||||
|
[StructLayout( LayoutKind.Sequential )]
|
||||||
|
internal struct CRYPT_OBJID_BLOB
|
||||||
|
{
|
||||||
|
internal UInt32 cbData;
|
||||||
|
internal IntPtr pbData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Structure from Crypto API.</summary>
|
||||||
|
[StructLayout( LayoutKind.Sequential )]
|
||||||
|
internal struct CRYPT_ALGORITHM_IDENTIFIER
|
||||||
|
{
|
||||||
|
internal IntPtr pszObjId;
|
||||||
|
internal CRYPT_OBJID_BLOB Parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Structure from Crypto API.</summary>
|
||||||
|
[StructLayout( LayoutKind.Sequential )]
|
||||||
|
struct CRYPT_BIT_BLOB
|
||||||
|
{
|
||||||
|
internal UInt32 cbData;
|
||||||
|
internal IntPtr pbData;
|
||||||
|
internal UInt32 cUnusedBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Structure from Crypto API.</summary>
|
||||||
|
[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
|
||||||
|
|
||||||
|
/// <summary>Function for Crypto API.</summary>
|
||||||
|
[DllImport( "advapi32.dll", SetLastError = true )]
|
||||||
|
[return: MarshalAs( UnmanagedType.Bool )]
|
||||||
|
internal static extern bool CryptDestroyKey( IntPtr hKey );
|
||||||
|
|
||||||
|
/// <summary>Function for Crypto API.</summary>
|
||||||
|
[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 );
|
||||||
|
|
||||||
|
/// <summary>Function for Crypto API.</summary>
|
||||||
|
[DllImport( "advapi32.dll", SetLastError = true )]
|
||||||
|
[return: MarshalAs( UnmanagedType.Bool )]
|
||||||
|
internal static extern bool CryptReleaseContext( IntPtr hProv, Int32 dwFlags );
|
||||||
|
|
||||||
|
/// <summary>Function for Crypto API.</summary>
|
||||||
|
[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 );
|
||||||
|
|
||||||
|
/// <summary>Function from Crypto API.</summary>
|
||||||
|
[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 );
|
||||||
|
|
||||||
|
/// <summary>Function from Crypto API.</summary>
|
||||||
|
[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 );
|
||||||
|
|
||||||
|
/// <summary>Function from Crypto API.</summary>
|
||||||
|
[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
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -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();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 私钥加密
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>The by private key.</returns>
|
|
||||||
/// <param name="data">内容.</param>
|
|
||||||
/// <param name="privateKey">私钥.</param>
|
|
||||||
public static string EncryptByPrivateKey(string data, string privateKey)
|
|
||||||
{
|
|
||||||
return rsa.EncryptByPrivateKey(data, privateKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
@@ -14,30 +14,17 @@ namespace SDKCSharp.Utility
|
|||||||
{
|
{
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 参数签名
|
/// 构建签名。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="paramsMap">参数</param>
|
/// <param name="parameters">参数.</param>
|
||||||
/// <param name="secret">秘钥</param>
|
/// <param name="privateKeyPem">私钥.</param>
|
||||||
/// <returns>返回sign</returns>
|
/// <param name="charset">字符集.</param>
|
||||||
public static String CreateSign(Dictionary<string, object> paramsMap, string secret)
|
/// <param name="signType">签名类型.</param>
|
||||||
|
/// <returns>返回签名.</returns>
|
||||||
|
public static string CreateSign(IDictionary<string, string> parameters, string privateKeyPem, string charset, string signType)
|
||||||
{
|
{
|
||||||
StringBuilder sb = new StringBuilder();
|
return AlipaySignature.RSASign(parameters, privateKeyPem, charset, false, signType);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -12,9 +12,9 @@ namespace SDKTest
|
|||||||
class MainClass
|
class MainClass
|
||||||
{
|
{
|
||||||
static string url = "http://localhost:8081/api"; // zuul
|
static string url = "http://localhost:8081/api"; // zuul
|
||||||
static string appId = "2019032617262200001";
|
static string appId = "201904035630907729292csharp";
|
||||||
// 支付宝私钥
|
// 私钥, PKCS1 1024
|
||||||
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 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";
|
||||||
|
|
||||||
|
|
||||||
// 声明一个就行
|
// 声明一个就行
|
||||||
|
Reference in New Issue
Block a user