Search code examples
flutterencryptiondartaes

Input data must be multiple of cipher block size in AES CTR mode


I get this exception when I use Dart's encrypt package to decrypt something using AES CTR mode:

E/flutter (19095): Invalid argument(s): Input data length must be a multiple of cipher's block size
E/flutter (19095): #0      PaddedBlockCipherImpl.process (package:pointycastle/padded_block_cipher/padded_block_cipher_impl.dart:55:9)
E/flutter (19095): #1      AES.decrypt (package:encrypt/src/algorithms/aes.dart:38:20)

Here is my code:

final encrypter = encrypt.Encrypter(encrypt.AES(key, mode: encrypt.AESMode.ctr));
final decrypted = encrypter.decrypt(encrypt.Encrypted.fromBase16(cipher), iv: iv);

cipher is hexadecimal string of length 10. I thought AES CTR mode did not require any padding. If it does require padding, what do I pad with? I tried this:

final decrypted = encrypter.decrypt(encrypt.Encrypted.fromBase16(cipher.padRight(16, null)), iv: iv);

But I get the following exception:

E/flutter (19095): FormatException: Invalid radix-16 number (at character 1)
E/flutter (19095): nu
E/flutter (19095): ^

Using '0' as the padding results in the first exception I describe.


Solution

  • This is a problem in Dart's encrypt package. It cannot handle something encrypted using AES CTR mode if it isn't a multiple of the block size. This package is wrapper for Pointy Castle, which I was able to use successfully to decrypt a string encrypted using AES CTR mode. Here's the code:

    import 'package:encrypt/encrypt.dart' as encrypt;
    import 'package:pointycastle/export.dart' as pc;
    
    String decrypt(String cipher, Uint8List key, Uint8List iv) {
      final encryptedText = encrypt.Encrypted.fromBase16(cipher);
      final ctr = pc.CTRStreamCipher(pc.AESFastEngine())
        ..init(false, pc.ParametersWithIV(pc.KeyParameter(key.bytes), iv.bytes));
      Uint8List decrypted = ctr.process(encryptedText.bytes);
    
      print(String.fromCharCodes(decrypted));
    
      return String.fromCharCodes(decrypted);
    }
    

    cipher is a hexadecimal string. encrypt's package is still useful because it provides utilities for converting a hexadecimal string to a Uint8List