Skip to content

bug: browser AES key generation exposes raw JavaScript errors for out-of-range lengths #403

Description

@harrshita123

Description

AesCbcSecretKey.generateKey, AesCtrSecretKey.generateKey, and AesGcmSecretKey.generateKey handle out-of-range key lengths differently between the native and browser backends.

On the native backend, values outside the supported AES key lengths are rejected with a Dart FormatException. On Chrome, values outside the Web IDL unsigned short range reach AesKeyGenParams.length. Its [EnforceRange]
conversion throws a JavaScript TypeError, which escapes the package as a raw JSObject.

This makes error handling backend-dependent and exposes a JavaScript interop implementation detail through the public Dart API.

Reproduction

import 'package:webcrypto/webcrypto.dart';

Future<void> main() async {
  final generators = <String, Future<Object> Function(int)>{
    'AES-CBC': AesCbcSecretKey.generateKey,
    'AES-CTR': AesCtrSecretKey.generateKey,
    'AES-GCM': AesGcmSecretKey.generateKey,
  };

  for (final length in [-1, 65536]) {
    for (final entry in generators.entries) {
      try {
        await entry.value(length);
      } catch (error) {
        print('${entry.key} $length: ${error.runtimeType}: $error');
      }
    }
  }
}

Actual behavior

On the native VM, every call completes with a FormatException. On Chrome with Dart2JS, every call completes with an error similar to:

JSObject: TypeError: Failed to execute 'generateKey' on 'SubtleCrypto':
AesKeyGenParams: length: Outside of numeric range

Expected behavior

All backends should reject invalid AES key lengths with the same public Dart exception behavior. Raw JavaScript objects should not escape from these APIs.

Suggested fix

Validate AES key lengths at the shared Dart API boundary before dispatching to the backend:

  • retain support for 128-bit and 256-bit keys;
  • preserve the existing UnsupportedError behavior for 192-bit AES;
  • return FormatException for other lengths;
  • add shared regression coverage for AES-CBC, AES-CTR, and AES-GCM on the VM, Chrome Dart2JS, and Chrome Dart2Wasm.

Environment

  • Dart SDK: 3.11.0
  • Chrome: 153.0.8010.36
  • macOS arm64: 26.6.2

Related work

Issue #387 addressed the same class of Web IDL boundary leak for RSA modulusLength. The AES key-generation paths use different parameters and remain affected.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions