[英].NET RSACryptoServiceProvider encrypt with 4096 private key, how to decrypt it on Android
I am encrypting the message in .NET with RSACryptoServiceProvider with private key .我正在使用带有私钥的RSACryptoServiceProvider加密.NET 中的消息。 (PKCS#1 v1.5)
(PKCS#1 v1.5)
When I try to decrypt in .NET with the following code that uses public key everything works fine:当我尝试使用以下使用公钥的代码在 .NET 中解密时,一切正常:
private static string Decrypt(string key, string content)
{
byte[] rgb = Convert.FromBase64String(content);
var cryptoServiceProvider = new RSACryptoServiceProvider(new CspParameters()
{
ProviderType = 1
});
cryptoServiceProvider.ImportCspBlob(Convert.FromBase64String(key));
return Convert.ToBase64String(cryptoServiceProvider.Decrypt(rgb, false));
}
When on the other hand I try to find an algorithm to make the same decrypt method in Android, I am failing to decrypt it properly with public key.另一方面,当我尝试在 Android 中找到一种算法来制作相同的解密方法时,我无法使用公钥对其进行正确解密。 I exported the modulus and exponent from public key in .NET in order to load it properly on Android.
我从 .NET 中的公钥导出了模数和指数,以便在 Android 上正确加载它。
The method in Android is here: Android中的方法在这里:
public String Decrypt(String input) {
try {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
String modulusString = "mmGn1IXB+/NEm1ecLiUzgz7g2L6L5EE5DUcptppTNwZSqxeYKn0AuAccupL0iyX3LMPw6Dl9pjPXDjk93TQwYwyGgZaXOSRDQd/W2Y93g8erpGBRm/Olt7QN2GYhxP8Vn+cWUbNuikdD4yMfYX9NeD9UNt5WJGFf+jRkLk0zRK0A7ZIS+q0NvGJ/CgaRuoe3x4Mh1qYP9ZWNRw8rsDbZ6N2zyUa3Hk/WJkptRa6jrzc937r3QYF3eDTurVJZHwC7c3TJ474/8up3YNREnpK1p7hqwQ78fn35Tw4ZyTNxCevVJfYtc7pKHHiwfk36OxtOIesfKlMnHMs4vMWJm79ctixqAe3i9aFbbRj710dKAfZZ0FnwSnTpsoKO5g7N8mKY8nVpZej7tcLdTL44JqWEqnQkocRqgO/p3R8V/6To/OjQGf0r6ut9y/LnlM5qalnKJ1gFg1D7gCzZJ150TX4AO5kGSAFRyjkwGxnR0WLKf+BDZ8T/syOrFOrzg6b05OxiECwCvLWk0AaQiJkdu2uHbsFUj3J2BcwDYm/kZiD0Ri886xHqZMNExZshlIqiecqCskQhaMVC1+aCm+IFf16Qg/+eMYCd+3jm/deezT4rcMBOV/M+muownGYQ9WOdjEK53h9oVheahD3LqCW8MizABFimvXR3wAgkIUvhocVhSN0=";
String exponentString = "AQAB";
byte[] modulusBytes = Base64.decode(modulusString.getBytes("UTF-8"), Base64.DEFAULT);
byte[] dBytes = Base64.decode(exponentString.getBytes("UTF-8"), Base64.DEFAULT);
BigInteger modulus = new BigInteger(1, modulusBytes);
BigInteger d = new BigInteger(1, dBytes);
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(modulus, d);
PublicKey key = keyFactory.generatePublic(keySpec);
//at one point I read somewhere that .net reverses the byte array so that it needs to be reversed for java, but who knows any more
/*byte[] inputArrayReversed = Base64.decode(input.getBytes("UTF-8"), Base64.DEFAULT);
for (int i = 0; i < inputArrayReversed.length / 2; i++) {
byte temp = inputArrayReversed[i];
inputArrayReversed[i] = inputArrayReversed[inputArrayReversed.length - 1];
inputArrayReversed[inputArrayReversed.length - 1] = temp;
}*/
byte[] decryptedText = null;
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, key);
decryptedText = cipher.doFinal(Base64.decode(input.getBytes("UTF-8"), Base64.DEFAULT));
return Base64.encodeToString(decryptedText, Base64.NO_WRAP);
//return new String(decryptedText, "UTF-8");
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
Actually I tried also with different algorithms specified in Cypher class, also tried many other combinations, tried using SpongyCastle instead of built in Android RSA providers, but nothing worked.实际上,我还尝试了 Cypher 类中指定的不同算法,还尝试了许多其他组合,尝试使用 SpongyCastle 而不是内置的 Android RSA 提供程序,但没有任何效果。 If anybody has any clue to point me in right direction, I would be absolutely grateful.
如果有人有任何线索为我指明正确的方向,我将不胜感激。
First hint is that decrypted string from .NET comes as around 25 characters long, and when I get Android to return decrypted string without exceptions it is usually much longer, around 500 bytes.第一个提示是,来自 .NET 的解密字符串大约有 25 个字符长,当我让 Android 毫无例外地返回解密字符串时,它通常要长得多,大约 500 个字节。
Second hint deleted第二个提示已删除
Third hint I also tried spongycastle, but it didn't help that much第三个提示我也试过 spongycastle,但没有多大帮助
Anyways, thank you in advance for any help!!!无论如何,在此先感谢您的帮助!!!
UPDATE 1更新 1
Second hint is deleted because was wrong, disregard it.第二个提示被删除,因为是错误的,无视它。 Now I have one question if the following can prove that the public key is loaded correctly, just to rule that problem out.
现在我有一个问题,以下是否可以证明公钥已正确加载,只是为了排除该问题。
BigInteger modulus and exponent in the upper Android code and the following BigIntegers in .NET show equal integer values.上层 Android 代码中的 BigInteger 模数和指数以及 .NET 中的以下 BigInteger 显示相等的整数值。
var parameters = csp.ExportParameters(false);
var modulusInteger = new BigInteger(parameters.Modulus.Reverse().Concat(new byte[] { 0 }).ToArray());
var exponentInteger = new BigInteger(parameters.Exponent.Reverse().Concat(new byte[] { 0 }).ToArray());
UPDATE 2更新 2
This and This SO answers provide some interesting clues这个和这个SO 答案提供了一些有趣的线索
Heeh, the mistake was one of the basics, we had an architecture where we were doing encryption with public key and decryption with private key.嘿,错误是基础之一,我们有一个架构,我们用公钥加密,用私钥解密。 The problem was in the architecture itself because as we initially set it up, we were sending private keys to all our client apps, which is big security flaw.
问题在于架构本身,因为在我们最初设置它时,我们将私钥发送到我们所有的客户端应用程序,这是一个很大的安全漏洞。
My mistake was that I assumed that on the client we have public key and actually from private key all the time I was trying to load the public key and then do decrypt.我的错误是我假设在客户端上我们有公钥,实际上我一直在尝试加载公钥然后解密。
If I knew the PKI in depth and communicated a bit better with my colleague, I could have noticed few things:如果我深入了解 PKI 并与我的同事更好地沟通,我可能会注意到以下几点:
Few things that I already knew or learnt and want to share with others:我已经知道或学到的东西很少,想与他人分享:
.NET server code .NET 服务器代码
public string Sign(string privateKey, string data)
{
_rsaProvider.ImportCspBlob(Convert.FromBase64String(privateKey));
//// Write the message to a byte array using UTF8 as the encoding.
var encoder = new UTF8Encoding();
byte[] byteData = encoder.GetBytes(data);
//// Sign the data, using SHA512 as the hashing algorithm
byte[] encryptedBytes = _rsaProvider.SignData(byteData, new SHA1CryptoServiceProvider());
return Convert.ToBase64String(encryptedBytes);
}
.NET client code (Win Mobile) .NET 客户端代码 (Win Mobile)
private bool Verify(string key, string signature, string data)
{
CspParameters cspParams = new CspParameters { ProviderType = 1 };
RSACryptoServiceProvider rsaProvider = new RSACryptoServiceProvider(cspParams);
rsaProvider.ImportCspBlob(Convert.FromBase64String(key));
byte[] signatureBytes = Convert.FromBase64String(signature);
var encoder = new UTF8Encoding();
byte[] dataBytes = encoder.GetBytes(data);
return rsaProvider.VerifyData(dataBytes, new SHA1CryptoServiceProvider(), signatureBytes);
}
Android client code:安卓客户端代码:
public boolean Verify(RSAPublicKey key, String signature, String data)
{
try
{
Signature sign = Signature.getInstance("SHA1withRSA");
sign.initVerify(key);
sign.update(data.getBytes("UTF-8"));
return sign.verify(Base64.decode(signature.getBytes("UTF-8"), Base64.NO_WRAP));
}
catch (Exception e)
{
e.printStackTrace();
}
return false;
}
in .NET public key is exported in xml format with following code: .NET 中的公钥以 xml 格式导出,代码如下:
public string ExportPublicToXML(string publicKey)
{
RSACryptoServiceProvider csp = new RSACryptoServiceProvider(new CspParameters()
{
ProviderType = 1
});
csp.ImportCspBlob(Convert.FromBase64String(publicKey));
return csp.ToXmlString(false);
}
and then modulus and exponent are used in Android to load public key:然后在Android中使用模数和指数来加载公钥:
private RSAPublicKey GetPublicKey(String keyXmlString) throws InvalidKeySpecException, UnsupportedEncodingException, NoSuchAlgorithmException
{
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
String modulusString = keyXmlString.substring(keyXmlString.indexOf("<Modulus>"), keyXmlString.indexOf("</Modulus>")).replace("<Modulus>", "");
String exponentString = keyXmlString.substring(keyXmlString.indexOf("<Exponent>"), keyXmlString.indexOf("</Exponent>")).replace("<Exponent>", "");
byte[] modulusBytes = Base64.decode(modulusString.getBytes("UTF-8"), Base64.DEFAULT);
byte[] dBytes = Base64.decode(exponentString.getBytes("UTF-8"), Base64.DEFAULT);
BigInteger modulus = new BigInteger(1, modulusBytes);
BigInteger d = new BigInteger(1, dBytes);
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(modulus, d);
return (RSAPublicKey) keyFactory.generatePublic(keySpec);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.