unwrap static method

Future<K4LocalKey> unwrap(
  1. String serialized,
  2. String password
)

Implementation

static Future<K4LocalKey> unwrap(
  String serialized,
  String password,
) async {
  if (!serialized.startsWith(PaserkKey.k4LocalPwPrefix)) {
    throw ArgumentError('Invalid k4.local-pw format');
  }

  final data = Uint8List.fromList(
    SafeBase64.decode(serialized.substring(PaserkKey.k4LocalPwPrefix.length)),
  );

  if (data.length <
      saltLength +
          8 +
          4 +
          4 +
          nonceLength +
          K4LocalKey.keyLength +
          tagLength) {
    throw ArgumentError('Invalid wrapped key length');
  }

  var offset = 0;
  final salt = data.sublist(offset, offset + saltLength);
  offset += saltLength;
  final memoryCost = _bytesToUint64(data.sublist(offset, offset + 8));
  offset += 8;
  final timeCost = _bytesToUint32(data.sublist(offset, offset + 4));
  offset += 4;
  final parallelism = _bytesToUint32(data.sublist(offset, offset + 4));
  offset += 4;
  final nonce = data.sublist(offset, offset + nonceLength);
  offset += nonceLength;
  final encrypted = data.sublist(offset, data.length - tagLength);
  final tag = data.sublist(data.length - tagLength);

  if (memoryCost <= 0 || memoryCost % 1024 != 0) {
    throw ArgumentError('Invalid memoryCost value');
  }
  if (timeCost <= 0 || parallelism <= 0) {
    throw ArgumentError('Invalid PBKW parameters');
  }

  final preKey = await _derivePreKey(
    password,
    salt,
    memoryCost,
    timeCost,
    parallelism,
  );

  final encKey = _deriveKeyMaterial(preKey, 0xff);
  final authKey = _deriveKeyMaterial(preKey, 0xfe);

  final expectedTag = _calculateTag(
    PaserkKey.k4LocalPwPrefix,
    salt,
    memoryCost,
    timeCost,
    parallelism,
    nonce,
    encrypted,
    authKey,
  );

  if (!_constantTimeEquals(tag, expectedTag)) {
    throw ArgumentError('Invalid authentication tag');
  }

  final decrypted = _decrypt(encKey, nonce, encrypted);
  if (decrypted.length != K4LocalKey.keyLength) {
    throw ArgumentError('Decrypted key has invalid length');
  }

  return K4LocalKey(decrypted);
}