在C#中加密然后用Android解密它(AES | IllegalBlockSizeException)

时间:2021-06-11 18:26:33

I have an application in C# that encrypt my files with AES algorithm with this method:

我在C#中有一个应用程序,使用此方法使用AES算法加密我的文件:

// strKey = "sample-16chr-key"
private static void encryptFile(string inputFile, string outputFile, string strKey)
{
  try
  {
    using (RijndaelManaged aes = new RijndaelManaged())
    {
      byte[] key = Encoding.UTF8.GetBytes(strKey);
      byte[] IV = Encoding.UTF8.GetBytes(strKey);

      using (FileStream fsCrypt = new FileStream(outputFile, FileMode.Create))
      {
        using (ICryptoTransform encryptor = aes.CreateEncryptor(key, IV))
        {
          using (CryptoStream cs = new CryptoStream(fsCrypt, encryptor, CryptoStreamMode.Write))
          {
            using (FileStream fsIn = new FileStream(inputFile, FileMode.Open))
            {
              int data;
              while ((data = fsIn.ReadByte()) != -1)
              {
                cs.WriteByte((byte)data);
              }
            }
          }
        }
      }
    }
  }
  catch (Exception ex)
  {
    Debug.WriteLine(ex.Message);
  }
}

The file is encrypted without an issue.

该文件已加密,没有问题。

Then I want to decrypt the encrypted file with my Android (2.2) application. So I do this:

然后我想用我的Android(2.2)应用程序解密加密文件。所以我这样做:

// myDoc is my Document object;
byte[] docBytes = serialize(myDoc);
byte[] key = ("sample-16chr-key").getBytes("UTF-8");
IvParameterSpec iv = new IvParameterSpec(key);

Cipher c = Cipher.getInstance("AES");
SecretKeySpec k = new SecretKeySpec(key, "AES");
c.init(Cipher.DECRYPT_MODE, k, iv);

// IllegalBlockSizeException Occurred
byte[] decryptedDocBytes = c.doFinal(docBytes);

Document decryptedDoc = (Document)deserialize(decryptedDocBytes);

And my serialize/deserialize methods:

我的序列化/反序列化方法:

private static byte[] serialize(Document obj) throws IOException {
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    ObjectOutputStream os = new ObjectOutputStream(out);
    os.writeObject(obj);
    return out.toByteArray();
}

private static Object deserialize(byte[] data) throws IOException, ClassNotFoundException {
    ByteArrayInputStream in = new ByteArrayInputStream(data);
    ObjectInputStream is = new ObjectInputStream(in);
    return is.readObject();
}

What is the problem here? Both encodings are UTF-8 and the key bytes are the same.
Am I missing something?

这里有什么问题?两种编码都是UTF-8,密钥字节是相同的。我错过了什么吗?

If this is not the solution for my application, what am I supposed to do?

如果这不是我的应用程序的解决方案,我该怎么办?

1 个解决方案

#1


2  

The javadoc for IllegalBlockSizeException is pretty clear:

IllegalBlockSizeException的javadoc非常清楚:

This exception is thrown when the length of data provided to a block cipher is incorrect, i.e., does not match the block size of the cipher.

当提供给分组密码的数据长度不正确时,即与密码的块大小不匹配时,抛出此异常。

The problem is that the C# code uses AES in CBC mode with PKCS#7 padding while the Java code uses AES in CBC mode with no padding. You should always spell out your intentions explicitly as opposed to relying on implementation dependent defaults to avoid confusion.

问题是C#代码在CBC模式下使用AES和PKCS#7填充,而Java代码在CBC模式下使用AES而没有填充。您应该始终明确说明您的意图,而不是依赖于依赖于实现的默认值来避免混淆。

As the Java code uses no padding, the cipher expects a ciphertext with a length that is a multiple of the block size.

由于Java代码不使用填充,因此密码需要一个长度为块大小倍数的密文。

The fix would be to change the relevant line to

修复方法是将相关行更改为

Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");

And similarly for the C# code for clarity.

同样,为了清晰起见,C#代码也是如此。

Note that using a static IV defeats several important security aspects of CBC mode. The IV should be unpredictable and unique, preferably from a secure random number generator, and it should be different every time the encryption method is called.

请注意,使用静态IV会破坏CBC模式的几个重要安全方面。 IV应该是不可预测且唯一的,优选地来自安全的随机数生成器,并且每次调用加密方法时它应该是不同的。

There's also no reason to limit the key to ASCII characters. Doing so makes brute forcing a lot easier.

也没有理由将密钥限制为ASCII字符。这样做会使暴力行为变得更容易。

#1


2  

The javadoc for IllegalBlockSizeException is pretty clear:

IllegalBlockSizeException的javadoc非常清楚:

This exception is thrown when the length of data provided to a block cipher is incorrect, i.e., does not match the block size of the cipher.

当提供给分组密码的数据长度不正确时,即与密码的块大小不匹配时,抛出此异常。

The problem is that the C# code uses AES in CBC mode with PKCS#7 padding while the Java code uses AES in CBC mode with no padding. You should always spell out your intentions explicitly as opposed to relying on implementation dependent defaults to avoid confusion.

问题是C#代码在CBC模式下使用AES和PKCS#7填充,而Java代码在CBC模式下使用AES而没有填充。您应该始终明确说明您的意图,而不是依赖于依赖于实现的默认值来避免混淆。

As the Java code uses no padding, the cipher expects a ciphertext with a length that is a multiple of the block size.

由于Java代码不使用填充,因此密码需要一个长度为块大小倍数的密文。

The fix would be to change the relevant line to

修复方法是将相关行更改为

Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");

And similarly for the C# code for clarity.

同样,为了清晰起见,C#代码也是如此。

Note that using a static IV defeats several important security aspects of CBC mode. The IV should be unpredictable and unique, preferably from a secure random number generator, and it should be different every time the encryption method is called.

请注意,使用静态IV会破坏CBC模式的几个重要安全方面。 IV应该是不可预测且唯一的,优选地来自安全的随机数生成器,并且每次调用加密方法时它应该是不同的。

There's also no reason to limit the key to ASCII characters. Doing so makes brute forcing a lot easier.

也没有理由将密钥限制为ASCII字符。这样做会使暴力行为变得更容易。