SecretWallet.decode constructor

SecretWallet.decode(
  1. String encoded,
  2. String password, {
  3. SecretWalletEncoding encoding = SecretWalletEncoding.json,
})

Factory method to decode and create a SecretWallet from an encoded string and a password.

  • encoded: The encoded string containing wallet data.
  • password: The password used to derive the encryption key.

Returns a SecretWallet instance decoded from the input data, or throws an error if decoding or password validation fails.

Implementation

factory SecretWallet.decode(String encoded, String password,
    {SecretWalletEncoding encoding = SecretWalletEncoding.json}) {
  if (encoding == SecretWalletEncoding.cbor) {
    return _decodeCbor(encoded, password);
  }
  final data = _toJsonEcoded(encoded, encoding: encoding);

  final version = data['version'];
  if (version != 3) {
    throw ArgumentException("Library only supports version 3");
  }

  final params = data['crypto'] ?? data['Crypto'];

  final String kdf = params['kdf'];
  _Derivator derivator;

  switch (kdf) {
    case 'pbkdf2':
      final derParams = params['kdfparams'] as Map<String, dynamic>;

      if (derParams['prf'] != 'hmac-sha256') {
        throw ArgumentException('Invalid prf only support hmac-sha256');
      }

      derivator = _PBDKDF2Derivator(
        derParams['c'] as int,
        BytesUtils.fromHexString(derParams['salt']),
        derParams['dklen'] as int,
      );

      break;
    case 'scrypt':
      final derParams = params['kdfparams'] as Map<String, dynamic>;
      derivator = _Scrypt(
        derParams['dklen'] as int,
        derParams['n'] as int,
        derParams['r'] as int,
        derParams['p'] as int,
        BytesUtils.fromHexString(derParams['salt']),
      );
      break;
    default:
      throw ArgumentException(
        '$kdf which is not supported.',
      );
  }

  final encodedPassword = List<int>.from(StringUtils.encode(password));
  final derivedKey = derivator.deriveKey(encodedPassword);
  final aesKey = List<int>.from(derivedKey.sublist(0, 16));
  final List<int> macBytes = derivedKey.sublist(16, 32);
  final encryptedPrivateKey = BytesUtils.fromHexString(params['ciphertext']);
  final derivedMac = _mac(macBytes, encryptedPrivateKey);
  if (derivedMac != params['mac']) {
    throw ArgumentException('wrong password or the file is corrupted');
  }

  if (params['cipher'] != 'aes-128-ctr') {
    throw ArgumentException("only cipher aes-128-ctr is supported.");
  }
  final iv = BytesUtils.fromHexString(params['cipherparams']['iv']);
  final encryptText = List<int>.from(encryptedPrivateKey);
  final CTR ctr = CTR(AES(aesKey), iv);
  final List<int> privateKey = List<int>.filled(encryptText.length, 0);
  ctr.streamXOR(encryptText, privateKey);
  ctr.clean();
  final id = UUID.toBuffer(data['id'] as String);
  return SecretWallet._(privateKey, derivator, encodedPassword, iv, id);
}