背景:接口方开发环境是Java,要求我使用私钥对数据进行加密,他使用公钥进行解密。
开发时遇到的问题:
1).Net平台默认是使用公钥进行加密,私钥进行解密。私钥加密需要自己实现或者使用第三方dll。
2)双方平台不一致,出现了我加密的数据对方不能解密,对方加密的数据我不能解密,但是自身是可以正常加密解密。
解决办法:
1)使用第三方dll,此处使用的是C#的BouncyCastle.Crypto进行加密及解密。在官网https://www.bouncycastle.org/csharp/ 下载最新dll。
2)设置Cipher为“RSA/ECB/PKCS1Padding”,与Java平台统一。
这是实现的方法,方法后面是解决过程,有兴趣可以看一看。如果这个代码不能解决你的问题,建议看下后面的解决过程,里面的链接也许对你有帮助。
/// <summary>用私钥给数据进行RSA加密
///
/// </summary>
/// <param name="xmlPrivateKey">私钥</param>
/// <param name="m_strEncryptString">待加密数据</param>
/// <returns>加密后的数据(Base64)</returns>
public static string RSAEncryptByPrivateKey(string xmlPrivateKey, string strEncryptString)
{
//加载私钥
RSACryptoServiceProvider privateRsa = new RSACryptoServiceProvider();
privateRsa.FromXmlString(xmlPrivateKey);
//转换密钥
AsymmetricCipherKeyPair keyPair = DotNetUtilities.GetKeyPair(privateRsa);
IBufferedCipher c = CipherUtilities.GetCipher("RSA/ECB/PKCS1Padding");// 参数与Java中加密解密的参数一致
//第一个参数为true表示加密,为false表示解密;第二个参数表示密钥
c.Init(true, keyPair.Private);
byte[] DataToEncrypt = Encoding.UTF8.GetBytes(strEncryptString);
byte[] outBytes = c.DoFinal(DataToEncrypt);//加密
string strBase64 = Convert.ToBase64String(outBytes);
return strBase64;
}
-------------------------------------解决过程-------------------------------------
1.确认是使用私钥进行加密后,发现.Net没有使用私钥进行加密的方法。搜索后得知需要自己实现。
2.搜索实现方式,但得到的方法里需要两个BigInteger,由于对私钥的xml并不了解,不清楚参数该用什么值。只好放弃这种方式。不过后来查资料找到私钥xml中各节点的含义以及加密时该用哪些节点的值。不过这是后话了。
微软对公钥私钥各节点的解释:RSAParameters 结构 https://msdn.microsoft.com/zh-cn/library/system.security.cryptography.rsaparameters%28v=vs.110%29.aspx
加密解密时该使用什么节点:
3.找到一个已经封装好的方法,只需要把密钥和加密数据传进去就可以实现的方法。但是加密出来的结果本身可以解密,但是对方无法解密。对方提供的加密数据使用此方法无法解密。
此处使用的代码:http://www.codeproject.com/Articles/38739/RSA-Private-Key-Encryption
4.在前两步搜索资料的时候,得知BouncyCastle。看到相关介绍,于是使用其提供的dll进行加密解密操作。但是此时网上找到的都是BouncyCastle自动生成密钥进行加密解密而不是读取.Net的密钥进行加密解密。
使用BouncyCastle进行加密解密的代码是:
5.查找密钥转换方式,找到以下资料:http://stackoverflow.com/questions/3240222/get-private-key-from-bouncycastle-x509-certificate-c-sharp
使用“CriGoT”或者“majkinetor”提供的代码都可以进行私钥的转换。
6.通过第四步和第五步可以获得完整的加密解密方法。在使用此方法进行私钥加密后对方解密时报错“javax.crypto.BadPaddingException: Blocktype mismatch: 0”,查找资料后得知,也许与Cipher.getInstance("RSA")中的参数有关,需要改为“RSA/ECB/PKCS1Padding”。但对方排查后应当默认就是“RSA/ECB/PKCS1Padding”。最终在 http://www.xuebuyuan.com/301023.html 找到另一种调用的方法可以传入“RSA/ECB/PKCS1Padding”。
至此.Net和Java之间RSA私钥加密公钥解密进行数据交互完成。