unseal static method
Implementation
static Future<K4LocalKey> unseal(
String serialized,
K4SecretKey secretKey,
) async {
if (!serialized.startsWith(PaserkKey.k4SealPrefix)) {
throw ArgumentError('Invalid k4.seal format');
}
final data = Uint8List.fromList(
SafeBase64.decode(serialized.substring(PaserkKey.k4SealPrefix.length)),
);
if (data.length !=
tagLength + ephemeralPublicKeyLength + K4LocalKey.keyLength) {
throw ArgumentError('Invalid sealed key length');
}
final tag = data.sublist(0, tagLength);
final epk = data.sublist(tagLength, tagLength + ephemeralPublicKeyLength);
final encrypted = data.sublist(tagLength + ephemeralPublicKeyLength);
final xsk = await _ed25519SecretToX25519(secretKey.rawBytes);
final xpk = _ed25519PublicToX25519(secretKey.publicKeyBytes);
final headerBytes = utf8.encode(PaserkKey.k4SealPrefix);
final x25519 = X25519();
final x25519KeyPair = SimpleKeyPairData(
xsk,
publicKey: SimplePublicKey(xpk, type: KeyPairType.x25519),
type: KeyPairType.x25519,
);
final sharedSecret = await x25519.sharedSecretKey(
keyPair: x25519KeyPair,
remotePublicKey: SimplePublicKey(epk, type: KeyPairType.x25519),
);
final xk = Uint8List.fromList(await sharedSecret.extractBytes());
final authKey = _derivePkeKey(0x02, headerBytes, xk, epk, xpk);
final expectedTag = _computeSealTag(headerBytes, epk, encrypted, authKey);
if (!_constantTimeEquals(tag, expectedTag)) {
throw ArgumentError('Invalid authentication tag');
}
final encKey = _derivePkeKey(0x01, headerBytes, xk, epk, xpk);
final nonce = _deriveNonce(epk, xpk);
final decrypted = _decrypt(encKey, nonce, encrypted);
if (decrypted.length != K4LocalKey.keyLength) {
throw ArgumentError('Decrypted key has invalid length');
}
return K4LocalKey(decrypted);
}