decrypt static method
Decrypts a Keystore V3 JSON object.
Implementation
static Uint8List decrypt(Map<String, dynamic> json, String password) {
if (json['version'] != 3) {
throw ArgumentError('Only Keystore V3 is supported');
}
final crypto = (json['crypto'] ?? json['Crypto']) as Map<String, dynamic>?;
if (crypto == null) {
throw ArgumentError('Invalid keystore: missing crypto section');
}
final ciphertext = _fromHex(crypto['ciphertext'] as String);
final cipherparams = crypto['cipherparams'] as Map<String, dynamic>;
final iv = _fromHex(cipherparams['iv'] as String);
final mac = _fromHex(crypto['mac'] as String);
final kdf = crypto['kdf'] as String;
final kdfParams = crypto['kdfparams'] as Map<String, dynamic>;
final passwordBytes = Uint8List.fromList(utf8.encode(password));
Uint8List derivedKey;
if (kdf == 'scrypt') {
final n = kdfParams['n'] as int;
final r = kdfParams['r'] as int;
final p = kdfParams['p'] as int;
final salt = _fromHex(kdfParams['salt'] as String);
derivedKey = Scrypt.derive(passwordBytes, salt, n, r, p, 32);
} else if (kdf == 'pbkdf2') {
final iterations = kdfParams['c'] as int;
final salt = _fromHex(kdfParams['salt'] as String);
derivedKey = Pbkdf2.deriveSha256(
password: passwordBytes,
salt: salt,
iterations: iterations,
keyLength: 32);
} else {
throw ArgumentError('Unsupported KDF: $kdf');
}
// Verify MAC
final macData = Uint8List.fromList(derivedKey.sublist(16, 32) + ciphertext);
final calculatedMac = Keccak256.hash(macData);
if (!_uint8ListEquals(calculatedMac, mac)) {
throw StateError('Invalid password or corrupted keystore (MAC mismatch)');
}
final encryptionKey = derivedKey.sublist(0, 16);
final aes = AES(encryptionKey);
return aes.ctr(ciphertext, iv);
}