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.
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