Input data length must be a multiple of cipher's block size in AES CTR

359

I cannot reproduce the problem when decrypting with AES/CTR and the encrypt package.

The following code with an encryption and associated decryption runs fine on my machine:

final key = enc.Key.fromUtf8('H4WtkvK4qyehIe2kjQfH7we1xIHFK67e'); //32 length
final iv = enc.IV.fromUtf8('HgNRbGHbDSz9T0CC');

// Encryption
String kelime = 'The quick brown fox jumps over the lazy dog';
final encrypter = enc.Encrypter(enc.AES(key, mode: enc.AESMode.ctr, padding: null));
final encrypted = encrypter.encrypt(kelime, iv: iv);
final ciphertext = encrypted.base64;
print(ciphertext);

// Decryption
final decrypter = enc.Encrypter(enc.AES(key, mode: enc.AESMode.ctr, padding: null));
final decrypted = decrypter.decryptBytes(enc.Encrypted.fromBase64(ciphertext), iv: iv);
final decryptedData = utf8.decode(decrypted);
print(decryptedData);

CTR is a stream cipher mode that does not require padding. Unlike most libraries, the encrypt package does not implicitly disable padding for CTR mode, so this must happen explicitly (padding: null). Otherwise, when decrypting with other libraries (such as PointyCastle), the padding bytes will generally not be removed.

Note that in the posted code you are using CBC mode for encryption, not CTR mode. Maybe the modes you use for encryption and decryption just don't match.

By the way, a static IV is generally insecure, especially for CTR (but OK for testing purposes), s. here.


The decryption also works if the decryption block in the above code is replaced by a decryption with PointyCastle:

// Decryption
final encryptedText = enc.Encrypted.fromBase64(ciphertext);
final ctr = pc.CTRStreamCipher(pc.AESFastEngine())..init(false, pc.ParametersWithIV(pc.KeyParameter(key.bytes), iv.bytes));
final decrypted = ctr.process(encryptedText.bytes);
final decryptedData = utf8.decode(decrypted);
print(decryptedData);
Share:
359
Stick
Author by

Stick

Updated on December 29, 2022

Comments

  • Stick
    Stick over 1 year

    I encrypt a string using Dart's encrypt package. The code I encrypted is below.

    String encrypt(String kelime) {
        final key = Key.fromUtf8('H4WtkvK4qyehIe2kjQfH7we1xIHFK67e'); //32 length
        final iv = IV.fromUtf8('HgNRbGHbDSz9T0CC');
        final encrypter = Encrypter(AES(key, mode: AESMode.cbc));
        final encrypted = encrypter.encrypt(kelime, iv: iv);
        return encrypted.base64;
      }
    

    Then I decode the encrypted data with the same package and I get this error Input data length must be a multiple of cipher's block size. After some research, I learned that the encrypt package had trouble deciphering the AES encryption algorithm. I have learned that the encrypted word can be decrypted with the Pointycastle package. Code below

    String decryptt(String cipher) {
    
        final key = Key.fromUtf8('H4WtkvK4qyehIe2kjQfH7we1xIHFK67e');
    
        final iv = IV.fromUtf8('HgNRbGHbDSz9T0CC');
    
        final encryptedText = Encrypted.fromUtf8(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);
      }
    

    When I decrypt data encrypted with pointycastle I get an output like this.

    có¥ÄÐÒË.å$[~?q{.. 9

    The word I encrypt is

    Hello

    Packs of darts I use