【发布时间】:2015-09-15 10:06:58
【问题描述】:
我正在使用 RSACryptoServiceProvider 和 私钥 在 .NET 中加密消息。 (PKCS#1 v1.5)
当我尝试在 .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));
}
另一方面,当我尝试在 Android 中找到一种算法来制作相同的解密方法时,我无法使用公钥正确解密它。我从 .NET 中的 public key 导出了 modulus 和 exponent,以便在 Android 上正确加载。
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 "";
}
实际上,我也尝试了在 Cypher 类中指定的不同算法,还尝试了许多其他组合,尝试使用 SpongyCastle 而不是内置的 Android RSA 提供程序,但没有任何效果。如果有人有任何线索可以为我指明正确的方向,我将不胜感激。
第一个提示是来自 .NET 的解密字符串大约有 25 个字符长,当我让 Android 毫无例外地返回解密字符串时,它通常更长,大约 500 个字节。
第二个提示已删除
第三个提示我也试过 spongycastle,但没有太大帮助
无论如何,提前感谢您的帮助!!!
更新 1
第二个提示因错误而被删除,忽略它。现在我有一个问题,如果以下可以证明公钥加载正确,只是为了排除这个问题。
上方 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());
更新 2
【问题讨论】:
-
您可以尝试反转模数而不是密文吗? RSA 的输出定义为八位字节串,而模数是数字。八位字节字符串没有小/大字节序问题,但数字有。公共指数也是如此,但由于它的值是
010001,所以它是一个二进制回文。尽管如此,如果它 not010001而是一个小的随机素数,您的算法仍然可能失败。如果这解决了问题,您最好发表评论,以便我可以将此评论转换为答案。 -
这种假设不会与我的第二个提示相反,但当然,到最后,我会尝试这样做,并让你知道。
-
这是远程调试。在我现在相当丰富的经验中,它总是归结为程序员用手掌拍他们的头,而我们只是为程序员提供了足够的熵来继续调试:)
-
@MaartenBodewes 当我尝试在模数中反转字节时,我得到 java.lang.RuntimeException: error:0306E06C:bignumroutines:BN_mod_inverse:no inverse
-
请注意,如果您根本不使用正确的键(但使用正确的键大小),也可能出现填充异常。
标签: c# android .net cryptography rsacryptoserviceprovider