2

我一直有一些加密问题,看不到我做错了什么。我正在尝试在 Android 上使用 RSA 加密 AESkey 并使用 C# 在服务器端解密它,但不断收到“错误数据”异常。

我使用 Base64encoding 将加密密钥从客户端移动到服务器,并注意到在使用 JSON POST 请求将其从客户端(Android 应用程序)移动后,密钥中有许多“\u000a”,使得加密数据长度为 941,导致删除时将“用于解密的数据变大”使长度达到 920,这允许进行 80 次 8 字节迭代,并使我到达了现在遇到错误数据问题的位置。

我检查了密钥长度和算法是否正确,并且都设置为 2048 位密钥并使用 PKCS1Padding。

“Bad Data”异常 在以下场景中会抛出此异常。

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[]);
    }
4

1 回答 1

0

一次向 RSA 操作提供几个字节是不可能的。

此外,代码似乎不太可能执行正确数量的 base 64 迭代(正如您NO_PADDING在 android 中为 base 64 定义的那样,使用1而不是常量)。通常 RSA 加密的输出不会是 3 个字节的倍数,所以你至少离标记有一个块。

您可能想仔细查看您正在使用的 API 函数,并花一些时间研究 .NET 上的 RSA 示例。通常 RSA 仅用于加密少量数据(例如对称数据加密密钥),因此您应该能够一次解码所有 base64 数据。

请在调试器中测试您的输入和输出。加密/解密问题通常需要比较加密/解密算法的准确输入和输出。

于 2013-07-15T15:40:21.780 回答