【发布时间】:2013-07-15 13:53:23
【问题描述】:
我遇到了一些加密问题,看不到我做错了什么。我正在尝试在 Android 上使用 RSA 加密 AESkey 并使用 C# 在服务器端解密它,但不断收到“错误数据”异常。
我使用 Base64encoding 将加密密钥从客户端移动到服务器,并注意到在使用 JSON POST 请求将其从客户端(Android 应用程序)移动后,密钥中有许多“\u000a”使得加密数据长度941 在删除时导致“用于解密的数据很大”,使长度达到 920,允许 80 次 8 字节迭代,并让我遇到了错误数据问题。
我检查了密钥长度和算法是否正确,并且都设置为 2048 位密钥并使用 PKCS1Padding。
“错误数据”异常 以下场景会抛出此异常。
a) 用于解密的 RSA 私钥与用于加密的 RSA 公钥不匹配。
b) 传递给 Decrypt() 方法的二进制数据不正确。如果应用程序代码对加密数据的长度做出假设,或者传入的数据与 Encrypt() 方法返回的确切字节不匹配,则可能会发生这种情况。
我通过使用返回 RSACryptoServiceProvider.ToXMLString(false); 的 GET 从服务器拉取它来获取 android 上的公钥。并为私钥使用相同的密钥库,因此看不到它是 1。
据我所知,c# 解密器并未对加密数据的大小做出任何假设。可能我将块大小设置为 8,但那是在我知道加密的 AESkey 的大小之后。
我一直在寻找解决方案,但找不到解决方案,因此将不胜感激。如果我愚蠢并错过了一些简单的事情,我深表歉意,但如果我是愚蠢的,我会戴上眼罩,只是看不到它。
Java 加密
private byte[] encryptRSA(byte [] data) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException{
//instance of singleton PublicKey
AppPublicKey currKey = AppPublicKey.getInstance();
Log.d("ENCRYPT.MOD: ", currKey.getModBytes().toString());
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(new BigInteger(1,currKey.getModBytes()), new BigInteger(1,currKey.getExpBytes()));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey pubKey = keyFactory.generatePublic(keySpec);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] cipherData = cipher.doFinal(data);
Log.d("RSAENCRYPTION: ",Base64.encodeToString(cipherData, 1));
return cipherData;
}
C#解密
public string DecryptString(string inputString, int dwKeySize)
{
// TODO: Add Proper Exception Handlers
CspParameters cp = new CspParameters();
cp.KeyContainerName = "real_Keystore";
RSACryptoServiceProvider rsaCryptoServiceProvider
= new RSACryptoServiceProvider(dwKeySize,cp);
int base64BlockSize = 8;
int iterations = inputString.Length / base64BlockSize;
ArrayList arrayList = new ArrayList();
for (int i = 0; i < iterations; i++)
{
byte[] encryptedBytes = Convert.FromBase64String(
inputString.Substring(base64BlockSize * i, base64BlockSize));
//Array.Reverse(encryptedBytes);
arrayList.AddRange(rsaCryptoServiceProvider.Decrypt(
encryptedBytes, false));
}
return Encoding.UTF32.GetString(arrayList.ToArray(
Type.GetType("System.Byte")) as byte[]);
}
【问题讨论】:
-
"我通过 GET 从服务器拉取它来获取 android 上的公钥。" 你为此使用 TLS (https),对吗?在这种情况下,您已经有了一个安全的通信渠道,根本不需要这种额外的加密技术。
-
不,我没有使用 htts,尽管它可能更容易,但最终的实现可能会很好地使用 Https。但是,我真的很想让这个加密/解密工作,它已经困扰了我一段时间并且讨厌无法修复它。
-
如果您不使用 TLS 来获取公钥,那么所有这些加密都是无用的,因为它容易受到中间人攻击。 TLS 通过签名证书解决了这个问题。这里有一些关于这个问题的讨论:blogs.msdn.com/b/ericlippert/archive/2011/09/27/… 如果您不关心 MITM 漏洞,您可以使用 Diffie–Hellman,它比 RSA 简单得多。
-
哇...我不敢相信我错过了。我正在运行公钥是公共的,所以它的良好心态 -_- ..... MITM 甚至没有出现在我的脑海中。看起来 TLS 是肯定要走的路,而这正是现在用于实际实施的方法。感谢您的输入。我仍然很想弄清楚为什么我的解决方案不起作用,以备将来使用,这样我就不会拔头发了。
标签: c# android encryption cryptography