diff --git a/lib/src/impl_ffi/impl_ffi.aesctr.dart b/lib/src/impl_ffi/impl_ffi.aesctr.dart index d68044e3..8b21b19b 100644 --- a/lib/src/impl_ffi/impl_ffi.aesctr.dart +++ b/lib/src/impl_ffi/impl_ffi.aesctr.dart @@ -140,7 +140,7 @@ Stream _aesCtrEncryptOrDecrypt( // Consume the first M bytes from data. var i = 0; // Number of bytes consumed, after offset while (i < M) { - final N = math.min(M, bufSize); + final N = math.min(M - i, bufSize); inData.setAll(0, data.skip(offset + i).take(N)); _checkOpIsOne(ssl.EVP_CipherUpdate(ctx, outBuf, outLen, inBuf, N)); diff --git a/test/aes_ctr_counter_wrap_test.dart b/test/aes_ctr_counter_wrap_test.dart index 207c1493..a6fb316e 100644 --- a/test/aes_ctr_counter_wrap_test.dart +++ b/test/aes_ctr_counter_wrap_test.dart @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +import 'dart:async'; import 'dart:typed_data'; import 'package:test/test.dart'; @@ -37,4 +38,21 @@ void main() { expect(ciphertextA.sublist(16, 32), isNot(equals(ciphertextB))); }); + + test('AES-CTR handles input larger than the internal buffer', () async { + final key = await AesCtrSecretKey.importRawKey(Uint8List(16)); + final plaintext = Uint8List(4097); + final counter = Uint8List(16); + + final ciphertext = await key.encryptBytes(plaintext, counter, 128); + final decrypted = await key.decryptBytes(ciphertext, counter, 128); + final streamedCiphertext = await key + .encryptStream(Stream.value(plaintext), counter, 128) + .expand((chunk) => chunk) + .toList(); + + expect(ciphertext, hasLength(plaintext.length)); + expect(decrypted, equals(plaintext)); + expect(streamedCiphertext, equals(ciphertext)); + }); }