decrypt method

  1. @override
Future<List<int>> decrypt(
  1. SecretBox secretBox, {
  2. required SecretKey secretKey,
  3. List<int> aad = const <int>[],
  4. int keyStreamIndex = 0,
  5. Uint8List? possibleBuffer,
})

Decrypts SecretBox and returns the bytes.

Subclasses of Cipher do the following: 1.Authenticates SecretBox.mac with macAlgorithm. 2.Decrypts SecretBox.cipherText. 3.Returns the cleartext.

The SecretBox is authenticated with [SecretBox.checkMac()), which will throw SecretBoxAuthenticationError if the MAC is incorrect.

You must give a SecretKey that has the correct length and type.

Optional parameter nonce (also known as "initialization vector", "IV", or "salt") is some non-secret unique sequence of bytes. If you don't define it, the cipher will generate nonce for you.

Parameter aad can be used to pass Associated Authenticated Data (AAD). If you pass a non-empty list and the underlying cipher doesn't support AAD, the method will throw ArgumentError.

If possibleBuffer is non-null, the method is allowed (but not required) to write the output to it. Otherwise the method will allocate memory for the output.

Implementation

@override
Future<List<int>> decrypt(
  SecretBox secretBox, {
  required SecretKey secretKey,
  List<int> aad = const <int>[],
  int keyStreamIndex = 0,
  Uint8List? possibleBuffer,
}) async {
  if (kIsWeb || !channelPolicy.matches(length: secretBox.cipherText.length)) {
    return await fallback.decrypt(
      secretBox,
      secretKey: secretKey,
      aad: aad,
    );
  }
  final cipherText = secretBox.cipherText;
  final nonce = secretBox.nonce;
  final mac = secretBox.mac.bytes;
  if (nonce.length != nonceLength) {
    throw ArgumentError.value(
      nonce,
      'nonce',
      'Nonce should be $nonceLength bytes long, not ${nonce.length} bytes.',
    );
  }
  if (mac.length != macAlgorithm.macLength) {
    throw SecretBoxAuthenticationError();
  }
  final secretKeyBytes = await secretKey.extractBytes();
  if (secretKeyBytes.length != secretKeyLength) {
    throw ArgumentError.value(
      secretKey,
      'secretKey',
      'Secret key should be $secretKeyLength bytes long, not ${secretKeyBytes.length} bytes.',
    );
  }
  final args = [
    asUint8List(cipherText),
    asUint8List(secretKeyBytes),
    asUint8List(nonce),
    asUint8List(mac),
    asUint8List(aad),
  ];
  final size = CryptographyChannelQueue.estimateSize(args);
  final queue = CryptographyChannelQueue.defaultInstance;
  final lock = queue.newLock(size: size);
  await lock.lock();
  List result;
  try {
    result = await dispatchBackgroundDecrypt(args);
  } finally {
    lock.unlock();
  }
  final errorMessage = result[0] as String?;
  if (errorMessage != null) {
    switch (errorMessage) {
      case 'AUTHENTICATION_ERROR':
        throw SecretBoxAuthenticationError();
      case 'PADDING_ERROR':
        throw SecretBoxPaddingError();
      default:
        throw StateError('$runtimeType.decrypt failed: $errorMessage');
    }
  }
  final clearText = result[1] as Uint8List;

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

  return clearText;
}