public static void estimateKeyDerivationTime() {
   // This is run in the background after startup. If we haven't recorded it before, do a key
   // derivation to see
   // how long it takes. This helps us produce better progress feedback, as on Windows we don't
   // currently have a
   // native Scrypt impl and the Java version is ~3 times slower, plus it depends a lot on CPU
   // speed.
   checkGuiThread();
   estimatedKeyDerivationTime = Main.instance.prefs.getExpectedKeyDerivationTime();
   if (estimatedKeyDerivationTime == null) {
     new Thread(
             () -> {
               log.info("Doing background test key derivation");
               KeyCrypterScrypt scrypt = new KeyCrypterScrypt(SCRYPT_PARAMETERS);
               long start = System.currentTimeMillis();
               scrypt.deriveKey("test password");
               long msec = System.currentTimeMillis() - start;
               log.info("Background test key derivation took {}msec", msec);
               Platform.runLater(
                   () -> {
                     estimatedKeyDerivationTime = Duration.ofMillis(msec);
                     Main.instance.prefs.setExpectedKeyDerivationTime(estimatedKeyDerivationTime);
                   });
             })
         .start();
   }
 }
    protected Wallet doInBackground(Bundle... params) {
      ArrayList<String> seedWords = new ArrayList<String>();
      for (String word : seed.trim().split(" ")) {
        if (word.isEmpty()) continue;
        seedWords.add(word);
      }

      Wallet wallet = null;
      try {
        if (seedProtect) {
          wallet = new Wallet(seedWords, password);
        } else {
          wallet = new Wallet(seedWords);
        }

        KeyParameter aesKey = null;
        if (password != null && !password.isEmpty()) {
          KeyCrypterScrypt crypter = new KeyCrypterScrypt();
          aesKey = crypter.deriveKey(password);
          wallet.encrypt(crypter, aesKey);
        }

        wallet.createAccounts(coinsToCreate, true, aesKey);
        getWalletApplication().setWallet(wallet);
        getWalletApplication().saveWalletNow();
        getWalletApplication().startBlockchainService(CoinService.ServiceMode.RESET_WALLET);
      } catch (Exception e) {
        log.error("Error creating a wallet", e);
        errorMessage = e.getMessage();
      }
      return wallet;
    }
 @Test(expected = KeyCrypterException.class)
 public void cannotMixParams() throws Exception {
   chain = chain.toEncrypted("foobar");
   KeyCrypterScrypt scrypter = new KeyCrypterScrypt(2); // Some bogus params.
   ECKey key1 = new ECKey().encrypt(scrypter, scrypter.deriveKey("other stuff"));
   chain.importKeys(key1);
 }
public class WalletSetPasswordController {
  private static final Logger log = LoggerFactory.getLogger(WalletSetPasswordController.class);
  public PasswordField pass1, pass2;

  public ProgressIndicator progressMeter;
  public GridPane widgetGrid;
  public HBox buttonHBox;
  public Label explanationLabel;

  public Main.OverlayUI overlayUI;
  // These params were determined empirically on a top-range (as of 2014) MacBook Pro with native
  // scrypt support,
  // using the scryptenc command line tool from the original scrypt distribution, given a memory
  // limit of 40mb.
  public static final Protos.ScryptParameters SCRYPT_PARAMETERS =
      Protos.ScryptParameters.newBuilder()
          .setP(6)
          .setR(8)
          .setN(32768)
          .setSalt(ByteString.copyFrom(KeyCrypterScrypt.randomSalt()))
          .build();

  public void initialize() {
    progressMeter.setOpacity(0);
  }

  public static Duration estimatedKeyDerivationTime = null;

  public static void estimateKeyDerivationTime() {
    // This is run in the background after startup. If we haven't recorded it before, do a key
    // derivation to see
    // how long it takes. This helps us produce better progress feedback, as on Windows we don't
    // currently have a
    // native Scrypt impl and the Java version is ~3 times slower, plus it depends a lot on CPU
    // speed.
    checkGuiThread();
    estimatedKeyDerivationTime = Main.instance.prefs.getExpectedKeyDerivationTime();
    if (estimatedKeyDerivationTime == null) {
      new Thread(
              () -> {
                log.info("Doing background test key derivation");
                KeyCrypterScrypt scrypt = new KeyCrypterScrypt(SCRYPT_PARAMETERS);
                long start = System.currentTimeMillis();
                scrypt.deriveKey("test password");
                long msec = System.currentTimeMillis() - start;
                log.info("Background test key derivation took {}msec", msec);
                Platform.runLater(
                    () -> {
                      estimatedKeyDerivationTime = Duration.ofMillis(msec);
                      Main.instance.prefs.setExpectedKeyDerivationTime(estimatedKeyDerivationTime);
                    });
              })
          .start();
    }
  }

  @FXML
  public void setPasswordClicked(ActionEvent event) {
    if (!pass1.getText().equals(pass2.getText())) {
      informationalAlert(tr("Passwords do not match"), tr("Try re-typing your chosen passwords."));
      return;
    }
    String password = pass1.getText();
    // This is kind of arbitrary and we could do much more to help people pick strong passwords.
    if (password.length() < 4) {
      informationalAlert(
          tr("Password too short"),
          tr("You need to pick a password at least five characters or longer."));
      return;
    }

    fadeIn(progressMeter);
    fadeOut(widgetGrid);
    fadeOut(explanationLabel);
    fadeOut(buttonHBox);

    KeyCrypterScrypt scrypt = new KeyCrypterScrypt(SCRYPT_PARAMETERS);

    // Deriving the actual key runs on a background thread. 500msec is empirical on my laptop
    // (actual val is more like 333 but we give padding time).
    KeyDerivationTasks tasks =
        new KeyDerivationTasks(scrypt, password, estimatedKeyDerivationTime) {
          @Override
          protected void onFinish(KeyParameter aesKey, int timeTakenMsec) {
            // Write the target time to the wallet so we can make the progress bar work when
            // entering the password.
            WalletPasswordController.setTargetTime(Duration.ofMillis(timeTakenMsec));
            // The actual encryption part doesn't take very long as most private keys are derived on
            // demand.
            log.info("Key derived, now encrypting");
            Main.bitcoin.wallet().encrypt(scrypt, aesKey);
            log.info("Encryption done");
            informationalAlert(
                tr("Wallet encrypted"),
                tr("You can remove the password at any time from the settings screen."));
            overlayUI.done();
          }
        };
    progressMeter.progressProperty().bind(tasks.progress);
    tasks.start();
  }

  @FXML
  public void closeClicked(ActionEvent event) {
    overlayUI.done();
  }
}
  /**
   * Converts the given wallet to the object representation of the protocol buffers. This can be
   * modified, or additional data fields set, before serialization takes place.
   */
  public Protos.Wallet walletToProto(Wallet wallet) {
    Protos.Wallet.Builder walletBuilder = Protos.Wallet.newBuilder();
    walletBuilder.setNetworkIdentifier(wallet.getNetworkParameters().getId());
    if (wallet.getDescription() != null) {
      walletBuilder.setDescription(wallet.getDescription());
    }

    for (WalletTransaction wtx : wallet.getWalletTransactions()) {
      Protos.Transaction txProto = makeTxProto(wtx);
      walletBuilder.addTransaction(txProto);
    }

    walletBuilder.addAllKey(wallet.serializeKeychainToProtobuf());

    for (Script script : wallet.getWatchedScripts()) {
      Protos.Script protoScript =
          Protos.Script.newBuilder()
              .setProgram(ByteString.copyFrom(script.getProgram()))
              .setCreationTimestamp(script.getCreationTimeSeconds() * 1000)
              .build();

      walletBuilder.addWatchedScript(protoScript);
    }

    // Populate the lastSeenBlockHash field.
    Sha256Hash lastSeenBlockHash = wallet.getLastBlockSeenHash();
    if (lastSeenBlockHash != null) {
      walletBuilder.setLastSeenBlockHash(hashToByteString(lastSeenBlockHash));
      walletBuilder.setLastSeenBlockHeight(wallet.getLastBlockSeenHeight());
    }
    if (wallet.getLastBlockSeenTimeSecs() > 0)
      walletBuilder.setLastSeenBlockTimeSecs(wallet.getLastBlockSeenTimeSecs());

    // Populate the scrypt parameters.
    KeyCrypter keyCrypter = wallet.getKeyCrypter();
    if (keyCrypter == null) {
      // The wallet is unencrypted.
      walletBuilder.setEncryptionType(EncryptionType.UNENCRYPTED);
    } else {
      // The wallet is encrypted.
      walletBuilder.setEncryptionType(keyCrypter.getUnderstoodEncryptionType());
      if (keyCrypter instanceof KeyCrypterScrypt) {
        KeyCrypterScrypt keyCrypterScrypt = (KeyCrypterScrypt) keyCrypter;
        walletBuilder.setEncryptionParameters(keyCrypterScrypt.getScryptParameters());
      } else {
        // Some other form of encryption has been specified that we do not know how to persist.
        throw new RuntimeException(
            "The wallet has encryption of type '"
                + keyCrypter.getUnderstoodEncryptionType()
                + "' but this WalletProtobufSerializer does not know how to persist this.");
      }
    }

    if (wallet.getKeyRotationTime() != null) {
      long timeSecs = wallet.getKeyRotationTime().getTime() / 1000;
      walletBuilder.setKeyRotationTime(timeSecs);
    }

    populateExtensions(wallet, walletBuilder);

    for (Map.Entry<String, ByteString> entry : wallet.getTags().entrySet()) {
      Protos.Tag.Builder tag =
          Protos.Tag.newBuilder().setTag(entry.getKey()).setData(entry.getValue());
      walletBuilder.addTags(tag);
    }

    for (TransactionSigner signer : wallet.getTransactionSigners()) {
      // do not serialize LocalTransactionSigner as it's being added implicitly
      if (signer instanceof LocalTransactionSigner) continue;
      Protos.TransactionSigner.Builder protoSigner = Protos.TransactionSigner.newBuilder();
      protoSigner.setClassName(signer.getClass().getName());
      protoSigner.setData(ByteString.copyFrom(signer.serialize()));
      walletBuilder.addTransactionSigners(protoSigner);
    }

    walletBuilder.setSigsRequiredToSpend(wallet.getSigsRequiredToSpend());

    // Populate the wallet version.
    walletBuilder.setVersion(wallet.getVersion());

    return walletBuilder.build();
  }