I have an example of AES decryption written in C#. By copying this method and converting codes to Dart equivalent, I'm trying to apply decryption but it did not work so far.

I'm using "encrypt" library.

Here is the C# code:


public static string DecryptString(string cipherText) 
        {
            try
            {
            string key = "b14ca5898a4e4133bbce2ea2315a1916";
            byte[] iv = new byte[16];
                cipherText = cipherText.Trim();
                cipherText = cipherText.Replace(' ', '+');
                cipherText = cipherText.Replace('_', '/');
                cipherText = cipherText.Replace('=', '/');
                cipherText = cipherText.Replace(':', '/');
                byte[] buffer = Convert.FromBase64String(cipherText);

            using (Aes aes = Aes.Create())
            {
                aes.Key = Encoding.UTF8.GetBytes(key);
                aes.IV = iv;
                ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);

                using (MemoryStream memoryStream = new MemoryStream(buffer))
                {
                    using (CryptoStream cryptoStream = new CryptoStream((Stream)memoryStream, decryptor, CryptoStreamMode.Read))
                    {
                        using (StreamReader streamReader = new StreamReader((Stream)cryptoStream))
                        {
                            return streamReader.ReadToEnd();
                        }
                    }
                }
                }
            }
            catch (Exception ex)
            {
                return "";
            }
        }

And here is the Dart code I wrote in Flutter.

  _decryptHash(String cipherText) {
    String key = "b14ca5898a4e4133bbce2ea2315a1916";
    cipherText = cipherText.trim();
    cipherText = cipherText.replaceAll(' ', '+');
    cipherText = cipherText.replaceAll('_', '/');
    cipherText = cipherText.replaceAll('=', '/');
    cipherText = cipherText.replaceAll(':', '/');

    // Uint8List buffer = base64Decode(cipherText);

    final base64Key = Key.fromUtf8(key);
    final iv = IV.fromLength(16);

    final encrypter =
        Encrypter(AES(base64Key, mode: AESMode.sic, padding: null));
    final decrypted = encrypter.decrypt(Encrypted.from64(cipherText), iv: iv);

    print(decrypted);

    return decrypted;
  }

It returns this error when trying to decrypt.

[VERBOSE-2:ui_dart_state.cc(209)] Unhandled Exception: Invalid argument(s): Input data length must be a multiple of cipher's block size
#0      PaddedBlockCipherImpl.process (package:pointycastle/padded_block_cipher/padded_block_cipher_impl.dart:60:9)

Can anyone know how to solve this error?


Solution 1: julemand101

The problem is you are not specifying any padding and are therefore limited to only be able to decrypt messages with block sizes compatible with the algorithm you are using.

In the C# code we have this property which defines how we are doing padding:

One of the enumeration values that specifies the type of padding to apply. The default is PKCS7.

https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.aesmanaged.padding?view=net-6.0#System_Security_Cryptography_AesManaged_Padding

So your C# solution uses PKCS7 for padding but in your Dart example you are explicit telling your program to not use any padding (padding: null):

    final encrypter =
        Encrypter(AES(base64Key, mode: AESMode.sic, padding: null));

If we look at the documentation for Encrypter we can actually see that the default value for padding is PKCS7:

AES(
    Key key,
    {AESMode mode = AESMode.sic,
    String? padding = 'PKCS7'}
) 

https://pub.dev/documentation/encrypt/latest/encrypt/AES/AES.html

So you can solve your problem by just skip the padding argument:

    final encrypter =
        Encrypter(AES(base64Key, mode: AESMode.sic));