Summary
The browser implementation of AesCtrSecretKey.encryptBytes and decryptBytes forwards length to SubtleCrypto without validating the AES-CTR counter length range first.
The native backend validates that length is between 1 and 128 and throws ArgumentError. In browsers, invalid values are instead handled at the Web IDL or Web Crypto boundary. Values outside the Web IDL octet range can expose a raw JavaScript TypeError, while other invalid AES-CTR lengths produce OperationError.
This makes the public API behavior dependent on the selected backend.
Reproduction
import 'package:webcrypto/webcrypto.dart';
Future<void> main() async {
final key = await AesCtrSecretKey.importRawKey(List.filled(16, 0));
final counter = List.filled(16, 0);
await key.encryptBytes([1, 2, 3], counter, -1);
}
Native result
Invalid argument (length): must be between 1 and 128: -1
Chrome result
TypeError: Failed to execute 'encrypt' on 'SubtleCrypto':
AesCtrParams: length: Outside of numeric range
The browser result occurs under both dart2js and dart2wasm.
Expected behavior
AES-CTR length values outside 1..128 should be rejected consistently with ArgumentError before entering browser interop, matching the native backend.
Both encryption and decryption should have the same behavior.
Cause
Web Crypto defines AesCtrParams.length as an [EnforceRange] octet. The browser backend currently passes the Dart integer directly to SubtleCrypto, while the native backend performs an explicit 1..128 validation.
Suggested fix
- Validate
1 <= length <= 128 in the browser AES-CTR implementation before calling SubtleCrypto.
- Apply the validation to encryption and decryption.
- Add shared regression coverage for
-1, 0, 129, and 256.
- Run the regression on native, Chrome/dart2js, and Chrome/dart2wasm.
Summary
The browser implementation of
AesCtrSecretKey.encryptBytesanddecryptBytesforwardslengthtoSubtleCryptowithout validating the AES-CTR counter length range first.The native backend validates that
lengthis between 1 and 128 and throwsArgumentError. In browsers, invalid values are instead handled at the Web IDL or Web Crypto boundary. Values outside the Web IDLoctetrange can expose a raw JavaScriptTypeError, while other invalid AES-CTR lengths produceOperationError.This makes the public API behavior dependent on the selected backend.
Reproduction
Native result
Chrome result
The browser result occurs under both dart2js and dart2wasm.
Expected behavior
AES-CTR
lengthvalues outside1..128should be rejected consistently withArgumentErrorbefore entering browser interop, matching the native backend.Both encryption and decryption should have the same behavior.
Cause
Web Crypto defines
AesCtrParams.lengthas an[EnforceRange] octet. The browser backend currently passes the Dart integer directly toSubtleCrypto, while the native backend performs an explicit1..128validation.Suggested fix
1 <= length <= 128in the browser AES-CTR implementation before callingSubtleCrypto.-1,0,129, and256.