KeyStore.fromV1Json constructor

KeyStore.fromV1Json(
  1. String encoded,
  2. String password
)

Reads and unlocks the key store denoted in the json string given with the specified password. encoded must be the String contents of a valid v1 Topl key store.

Implementation

factory KeyStore.fromV1Json(String encoded, String password) {
  /*
    In order to read the keystore and obtain the secret key stored in it, we
    need to do the following:
    1: Key Derivation: Based on the key derivator specified (either pbdkdf2 or
       scryt), we need to use the password to obtain the aes key used to
       decrypt the private key.
    2: Using the obtained aes key and the iv parameter, decrypt the private
       key stored in the keystore.
  */

  final data = json.decode(encoded);

  // Ensure version is 1, only version that we support at the moment
  final version = data['version'];
  if (version != 1) {
    throw ArgumentError.value(
        version,
        'version',
        'Library only supports '
            'version 1 of key store files at the moment. However, the following value'
            ' has been given:');
  }

  final crypto = data['crypto'] ?? data['Crypto'];
  _KeyDerivator derivator;

  final kdf = crypto['kdf'] as String;

  switch (kdf) {
    case 'scrypt':
      final derParams = crypto['kdfparams'] as Map<String, dynamic>;
      derivator = _ScryptKeyDerivator(
          derParams['dkLen'] as int,
          derParams['n'] as int,
          derParams['r'] as int,
          derParams['p'] as int,
          Uint8List.fromList(str2ByteArray(derParams['salt'] as String)));
      break;
    default:
      throw ArgumentError(
          'Wallet file uses $kdf as key derivation function which is currently not supported');
  }

  // Now that we have the derivator, let's obtain the aes key:
  final encodedPassword =
      Uint8List.fromList(str2ByteArray(password, enc: 'latin1'));
  final derivedKey = derivator.deriveKey(encodedPassword);
  final encryptedPrivateKey = str2ByteArray(crypto['cipherText'] as String);

  //Validate the derived key with the mac provided
  final derivedMac = _getMac(derivedKey, encryptedPrivateKey);
  if (derivedMac != crypto['mac']) {
    throw ArgumentError(
        'Invalid MAC: Could not unlock key store file. You either supplied the wrong password or the file is corrupted');
  }

  // We only support this mode at the moment
  if (crypto['cipher'] != 'aes-256-ctr') {
    throw ArgumentError(
        'Invalid Cipher: key store file uses ${crypto["cipher"]} as cipher, but only aes-256-ctr is supported.');
  }

  final iv = str2ByteArray(crypto['cipherParams']['iv'] as String);

  final aes = _initCipher(false, derivedKey, iv);

  final privateKey =
      Base58Encoder.instance.encode(aes.process(encryptedPrivateKey));

  final id = parseUuid(data['id'] as String);

  return KeyStore._(privateKey, derivator, encodedPassword, iv, id);
}