decryptWithPlugin static method

  1. @protected
Future<List<int>> decryptWithPlugin({
  1. required String name,
  2. required FlutterCipher cipher,
  3. Cipher? fallback,
  4. PaddingAlgorithm? paddingAlgorithm,
  5. required SecretBox secretBox,
  6. required SecretKey secretKey,
  7. required List<int> aad,
})

Implementation

@protected
static Future<List<int>> decryptWithPlugin({
  required String name,
  required FlutterCipher cipher,
  Cipher? fallback,
  PaddingAlgorithm? paddingAlgorithm,
  required SecretBox secretBox,
  required SecretKey secretKey,
  required List<int> aad,
}) async {
  final secretKeyData = await secretKey.extractBytes();
  final secretKeyUint8List = asUint8List(secretKeyData);
  final nonceUint8List = asUint8List(secretBox.nonce);
  final macUint8List = asUint8List(secretBox.mac.bytes);
  final aadUint8List = asUint8List(aad);

  if (secretKeyUint8List.length != cipher.secretKeyLength) {
    throw ArgumentError.value(
      secretKey,
      'secretKey',
      'Expected a secret key with ${cipher.secretKeyLength} bytes, got ${secretKeyUint8List.length} bytes.',
    );
  }
  if (nonceUint8List.length != cipher.nonceLength) {
    throw ArgumentError.value(
      secretBox,
      'secretBox',
      'Expected a nonce with ${cipher.nonceLength} bytes, got ${nonceUint8List.length} bytes.',
    );
  }
  final macAlgorithm = cipher.macAlgorithm;
  if (macUint8List.length != macAlgorithm.macLength) {
    throw SecretBoxAuthenticationError();
  }
  if (aadUint8List.isNotEmpty && !macAlgorithm.supportsAad) {
    throw ArgumentError(
      'AAD is not supported by $macAlgorithm, but parameter `aad` is non-empty.',
    );
  }

  final cipherText = secretBox.cipherText;
  final cipherTextSize = cipherText.length;
  final lock = CryptographyChannelQueue.defaultInstance.newLock(
    size: cipherTextSize,
  );
  await lock.lock();
  late Map result;
  try {
    final cipherTextUint8List = asUint8List(secretBox.cipherText);
    result = await invokeMethod(
      'decrypt',
      {
        'algo': name,
        'data': cipherTextUint8List,
        'key': secretKeyUint8List,
        'nonce': nonceUint8List,
        'mac': macUint8List,
        'aad': aadUint8List,
      },
      useQueue: false, // We do queueing ourselves
    );
  } on UnsupportedError {
    if (fallback == null) {
      rethrow;
    }
    return fallback.decrypt(
      secretBox,
      secretKey: secretKey,
      aad: aad,
    );
  } on PlatformException catch (error) {
    switch (error.code) {
      case 'INCORRECT_MAC':
        throw SecretBoxAuthenticationError();

      case 'INCORRECT_PADDING':
        throw SecretBoxPaddingError(
          message: error.message,
        );

      default:
        rethrow;
    }
  } finally {
    lock.unlock();
  }

  final clearText = result['clearText'] as Uint8List;

  // Sanity check
  if (cipherTextSize != cipher.cipherTextLength(clearText.length)) {
    throw StateError(
      '${cipher.runtimeType}.decrypt sanity check failed: '
      'clearText.length (${clearText.length}) != '
      'cipherText.length ($cipherTextSize)',
    );
  }

  return clearText;
}