分享RSA的一点东西

时间:2021-12-01 04:04:03

摘要:至于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;
}