decrypt static method
Дешифрует 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,
);
}