unwrap static method
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);
}