decrypt static method

Future<Package> decrypt(
  1. Token token, {
  2. required SecretKey secretKey,
  3. List<int>? implicit,
})

Дешифрует PASETO v4.local токен.

Implementation

static Future<Package> decrypt(
  Token token, {
  required SecretKey secretKey,
  List<int>? implicit,
}) async {
  // Получаем ключ для дешифрования
  final keyBytes = await secretKey.extractBytes();

  // Проверяем размер ключа
  if (keyBytes.length != keyLength) {
    throw ArgumentError(
        'Ключ должен быть $keyLength байт, получено: ${keyBytes.length}');
  }

  // Проверяем, что токен соответствует v4.local
  if (token.header != header) {
    throw FormatException('Неверный заголовок токена для v4.local');
  }

  // Получаем payload и разбираем его составляющие
  final payload = token.payloadLocal;
  if (payload == null) {
    throw FormatException('Неверный формат токена для v4.local');
  }

  // Извлекаем nonce, cipherText и MAC
  final nonce = payload.nonce;
  if (nonce == null || nonce.bytes.length != nonceLength) {
    throw FormatException('Неверный формат nonce в токене v4.local');
  }

  final secretBox = payload.secretBox;
  if (secretBox == null) {
    throw FormatException('Шифротекст отсутствует в токене v4.local');
  }

  final mac = payload.mac;
  if (mac == null || mac.bytes.length != macLength) {
    throw FormatException('Неверный формат MAC в токене v4.local');
  }

  // 1. Генерируем ключи шифрования (Ek) и аутентификации (Ak)
  final encKeys = await _deriveKeys(keyBytes, nonce.bytes);
  final encryptionKey = encKeys.encryptionKey;
  final counterNonce = encKeys.counterNonce;
  final authKey = encKeys.authKey;

  // 2. Подготавливаем данные для проверки аутентификации
  final headerBytes = utf8.encode(header.toTokenString);
  final implicitBytes = implicit ?? <int>[];
  final footer = token.footer ?? <int>[];

  // 3. PAE(h, n, c, f, i)
  final preAuth = _pae([
    headerBytes, // h - заголовок
    nonce.bytes, // n - nonce
    secretBox.cipherText, // c - шифротекст
    footer, // f - футер (опциональный)
    implicitBytes, // i - implicit assertion (опциональный)
  ]);

  // 4. Вычисляем BLAKE2b-MAC и проверяем совпадение с MAC из токена
  final calculatedMacBytes = _computeMac(preAuth, authKey);
  final calculatedMac = Mac(calculatedMacBytes);

  // Сравниваем MAC с постоянным временем
  if (!_constantTimeEquals(calculatedMac.bytes, mac.bytes)) {
    throw SecretBoxAuthenticationError(
      message: 'Сбой аутентификации токена v4.local: MAC недействителен',
    );
  }

  // 5. Дешифруем сообщение с помощью собственной реализации XChaCha20
  // Поскольку мы уже проверили MAC, мы знаем, что сообщение целостно
  // Используем нашу собственную реализацию XChaCha20 для дешифрования
  final decryptedBytes = await _decryptCipherText(
    secretBox.cipherText,
    encryptionKey,
    counterNonce,
  );

  // 6. Возвращаем дешифрованный пакет
  return Package(
    content: decryptedBytes,
    footer: token.footer,
  );
}