decryptSync method

List<int> decryptSync(
  1. SecretBox secretBox, {
  2. required SecretKeyData secretKeyData,
  3. List<int> aad = const <int>[],
  4. int keyStreamIndex = 0,
})

Implementation

List<int> decryptSync(
  SecretBox secretBox, {
  required SecretKeyData secretKeyData,
  List<int> aad = const <int>[],
  int keyStreamIndex = 0,
}) {
  final actualSecretKeyLength = secretKeyData.bytes.length;
  final expectedSecretKeyLength = secretKeyLength;
  if (actualSecretKeyLength != expectedSecretKeyLength) {
    throw ArgumentError.value(
      secretKeyData,
      'secretKeyData',
      'Expected $secretKeyLength bytes, got $actualSecretKeyLength bytes',
    );
  }
  if (keyStreamIndex < 0 || keyStreamIndex >= 0x10000000) {
    throw ArgumentError.value(keyStreamIndex, 'keyStreamIndex');
  }
  final nonce = secretBox.nonce;

  final expandedKey = aesExpandKeyForEncrypting(secretKeyData);

  final h = Uint32List(4);
  aesEncryptBlock(h, 0, h, 0, expandedKey);
  h[0] = _uint32ChangeEndian(h[0]);
  h[1] = _uint32ChangeEndian(h[1]);
  h[2] = _uint32ChangeEndian(h[2]);
  h[3] = _uint32ChangeEndian(h[3]);

  // Calculate initial nonce
  var stateBytes = _nonceToBlock(h: h, nonce: nonce);
  var state = Uint32List.view(stateBytes.buffer);

  // Calculate MAC
  final cipherText = secretBox.cipherText;
  final mac = secretBox.mac;
  final calculatedMac = const DartGcm()._calculateMacSync(
    cipherText,
    aad: aad,
    expandedKey: expandedKey,
    h: h,
    precounterBlock: state,
  );

  // Check MAC is correct
  if (calculatedMac != mac) {
    throw SecretBoxAuthenticationError(secretBox: secretBox);
  }

  // Increment nonce
  bytesIncrementBigEndian(stateBytes, 1 + (keyStreamIndex ~/ 16));

  // Allocate output bytes
  final blockCount = (cipherText.length + 31) ~/ 16;
  final keyStream = Uint32List(blockCount * 4);

  // For each keystream block
  for (var i = 0; i < keyStream.length; i += 4) {
    // Encrypt state.
    aesEncryptBlock(keyStream, i, state, 0, expandedKey);

    // Increment state.
    bytesIncrementBigEndian(stateBytes, 1);
  }

  // clearText = keyStream[start, end] ^ ciphertext
  final clearText = Uint8List.view(
    keyStream.buffer,
    keyStream.offsetInBytes + keyStreamIndex % 16,
    cipherText.length,
  );
  for (var i = 0; i < cipherText.length; i++) {
    clearText[i] ^= cipherText[i];
  }
  return clearText;
}