摘要:至于RSA是什么,基本概念去园子里面搜索,讲的详细的大神大有人在。今天在此记录,对接第三方支付中的MD5WithRSA签名问题。
我这边是用C#开发接口需要使用rsa私钥进行签名,对方使用的Java,出现签名问题在所难免。
签名与加密解释:用A的私钥签名,B用A给的公钥验证签名,可以保证该信息是由A发送的。B用A的公钥加密,A用私钥解密,可以保证该信息只能由A接收到。
废话少说现给出代码
1、私钥签名字符串
//私钥是java生成的一串字符串,并不是pfx文件
/// <summary>
/// RSA私钥格式转换,java->.net
/// </summary>
/// <param name="privateKey">java生成的RSA私钥</param>
/// <returns></returns>
public static string RSAPrivateKeyJava2DotNet(string privateKey)
{
RsaPrivateCrtKeyParameters privateKeyParam = (RsaPrivateCrtKeyParameters)PrivateKeyFactory.CreateKey(Convert.FromBase64String(privateKey));
return string.Format("<RSAKeyValue><Modulus>{0}</Modulus><Exponent>{1}</Exponent><P>{2}</P><Q>{3}</Q><DP>{4}</DP><DQ>{5}</DQ><InverseQ>{6}</InverseQ><D>{7}</D></RSAKeyValue>",
Convert.ToBase64String(privateKeyParam.Modulus.ToByteArrayUnsigned()),
Convert.ToBase64String(privateKeyParam.PublicExponent.ToByteArrayUnsigned()),
Convert.ToBase64String(privateKeyParam.P.ToByteArrayUnsigned()),
Convert.ToBase64String(privateKeyParam.Q.ToByteArrayUnsigned()),
Convert.ToBase64String(privateKeyParam.DP.ToByteArrayUnsigned()),
Convert.ToBase64String(privateKeyParam.DQ.ToByteArrayUnsigned()),
Convert.ToBase64String(privateKeyParam.QInv.ToByteArrayUnsigned()),
Convert.ToBase64String(privateKeyParam.Exponent.ToByteArrayUnsigned()));
}
/// <summary>
/// PrivateKey为java生成的一串字符串rsa密钥
/// </summary>
/// <param name="signdata">需要签名的字符串</param>
/// <returns></returns>
public static string DataSign(string signdata)
{
string xmlPrivateKey = RSAPrivateKeyJava2DotNet(PrivateKey);
//加载私钥
RSACryptoServiceProvider privateRsa = new RSACryptoServiceProvider();
privateRsa.FromXmlString(xmlPrivateKey);
byte[] buffer = Encoding.UTF8.GetBytes(signdata);
var MSG_SIGN = Convert.ToBase64String(privateRsa.SignData(buffer, "md5"));
return MSG_SIGN;
}
2、私钥加密字符串
RSA私钥长度为1024则可加密的字符串为127(1024/8-11
),依次类推。所以当需要加密的字符串过大的时候,必须要进行分段加密,直接给出代码
/// <summary>
/// 用私钥给数据进行RSA加密
/// </summary>
/// <param name="xmlPrivateKey">私钥</param>
/// <param name="m_strEncryptString">待加密数据</param>
/// <returns>加密后的数据(Base64)</returns>
public static string RSAEncryptByPrivateKey(string PrivateKey, string strEncryptString)
{
string xmlPrivateKey = RSAPrivateKeyJava2DotNet(PrivateKey);
//加载私钥
RSACryptoServiceProvider privateRsa = new RSACryptoServiceProvider();
privateRsa.FromXmlString(xmlPrivateKey);
//转换密钥
AsymmetricCipherKeyPair keyPair = DotNetUtilities.GetKeyPair(privateRsa);
// 参数与Java中加密解密的参数一致
IBufferedCipher c = CipherUtilities.GetCipher("RSA/ECB/PKCS1Padding");
//第一个参数为true表示加密,为false表示解密;第二个参数表示密钥
c.Init(true, keyPair.Private);
byte[] DataToEncrypt = Encoding.UTF8.GetBytes(strEncryptString);
//对超过数据进行分段加密
byte[] bytes = Encoding.UTF8.GetBytes(strEncryptString);
int inputlen = bytes.Length;
byte[] cache;
MemoryStream ms = new MemoryStream();
int offset = 0;
int i = 0;
while (inputlen - offset > 0)
{
if (inputlen - offset > 117)
{
cache = c.DoFinal(DataToEncrypt, offset, 117);
}
else
{
cache = c.DoFinal(DataToEncrypt, offset, inputlen - offset);
}
ms.Write(cache, 0, cache.Length);
i++;
offset = i * 117;
}
byte[] resultbytes = ms.ToArray();
//byte[] outBytes = c.DoFinal(DataToEncrypt);//加密
string strBase64 = Convert.ToBase64String(resultbytes);
return strBase64;
}