unwrapConfigLink static method
Implementation
static String unwrapConfigLink({
required String sbmmLink,
required String passphrase,
}) {
final String normalized = sbmmLink.trim();
if (!isSbmmLink(normalized)) {
throw const FormatException('Input is not an sbmm:// link.');
}
final String normalizedPassphrase = passphrase.trim();
if (normalizedPassphrase.isEmpty) {
throw const FormatException('sbmm passphrase cannot be empty.');
}
final String token = _extractEnvelopeToken(normalized);
final Uint8List envelopeBytes = _decodeBase64UrlNoPadding(token);
final Object? envelopeRaw = _tryJsonDecode(utf8.decode(envelopeBytes));
if (envelopeRaw is! Map<Object?, Object?>) {
throw const FormatException('Invalid sbmm envelope JSON.');
}
final Map<String, Object?> envelope = <String, Object?>{};
envelopeRaw.forEach((Object? key, Object? value) {
if (key != null) {
envelope[key.toString()] = value;
}
});
final int version = _readInt(envelope['v']);
if (version != currentVersion) {
throw FormatException('Unsupported sbmm envelope version: $version.');
}
final int iterations = _readInt(envelope['iter']);
if (iterations < 100000) {
throw const FormatException('Invalid sbmm PBKDF2 iteration count.');
}
final Uint8List salt = _decodeBase64UrlNoPadding(
_readString(envelope['salt'], field: 'salt'),
);
final Uint8List nonce = _decodeBase64UrlNoPadding(
_readString(envelope['nonce'], field: 'nonce'),
);
final Uint8List cipherText = _decodeBase64UrlNoPadding(
_readString(envelope['ct'], field: 'ct'),
);
if (salt.length != _saltLengthBytes) {
throw const FormatException('Invalid sbmm salt length.');
}
if (nonce.length != _nonceLengthBytes) {
throw const FormatException('Invalid sbmm nonce length.');
}
final Uint8List key = _deriveKey(
passphrase: normalizedPassphrase,
salt: salt,
iterations: iterations,
);
final Uint8List plainBytes = _decryptAesGcm(
cipherText: cipherText,
key: key,
nonce: nonce,
aad: Uint8List.fromList(utf8.encode(_aad)),
);
final String plain = utf8.decode(plainBytes).trim();
if (plain.isEmpty) {
throw const FormatException('sbmm payload decrypted to empty config.');
}
return plain;
}