diff --git a/drongo b/drongo index aa60e6b9..9f5f5689 160000 --- a/drongo +++ b/drongo @@ -1 +1 @@ -Subproject commit aa60e6b92e0401a27c3760cc9cb7e726a2caa845 +Subproject commit 9f5f5689bbbe85dad51be84d4a5a2e5d31562564 diff --git a/src/main/java/com/sparrowwallet/sparrow/AppController.java b/src/main/java/com/sparrowwallet/sparrow/AppController.java index a0d5f618..2aeccd40 100644 --- a/src/main/java/com/sparrowwallet/sparrow/AppController.java +++ b/src/main/java/com/sparrowwallet/sparrow/AppController.java @@ -3,6 +3,7 @@ package com.sparrowwallet.sparrow; import com.google.common.base.Charsets; import com.google.common.eventbus.Subscribe; import com.google.common.io.ByteSource; +import com.sparrowwallet.drongo.SecureString; import com.sparrowwallet.drongo.Utils; import com.sparrowwallet.drongo.crypto.*; import com.sparrowwallet.drongo.policy.PolicyType; @@ -10,7 +11,6 @@ import com.sparrowwallet.drongo.protocol.ScriptType; import com.sparrowwallet.drongo.protocol.Transaction; import com.sparrowwallet.drongo.psbt.PSBT; import com.sparrowwallet.drongo.psbt.PSBTParseException; -import com.sparrowwallet.drongo.wallet.Keystore; import com.sparrowwallet.drongo.wallet.Wallet; import com.sparrowwallet.sparrow.control.*; import com.sparrowwallet.sparrow.event.*; @@ -235,14 +235,14 @@ public class AppController implements Initializable { if(file != null) { try { Wallet wallet; - String password = null; + CharSequence password = null; Storage storage = new Storage(file); FileType fileType = IOUtils.getFileType(file); if(FileType.JSON.equals(fileType)) { wallet = storage.loadWallet(); } else if(FileType.BINARY.equals(fileType)) { WalletPasswordDialog dlg = new WalletPasswordDialog(WalletPasswordDialog.PasswordRequirement.LOAD); - Optional optionalPassword = dlg.showAndWait(); + Optional optionalPassword = dlg.showAndWait(); if(!optionalPassword.isPresent()) { return; } diff --git a/src/main/java/com/sparrowwallet/sparrow/control/FileWalletExportPane.java b/src/main/java/com/sparrowwallet/sparrow/control/FileWalletExportPane.java index c5371dec..221a2cfc 100644 --- a/src/main/java/com/sparrowwallet/sparrow/control/FileWalletExportPane.java +++ b/src/main/java/com/sparrowwallet/sparrow/control/FileWalletExportPane.java @@ -1,6 +1,6 @@ package com.sparrowwallet.sparrow.control; -import com.sparrowwallet.drongo.wallet.Keystore; +import com.sparrowwallet.drongo.SecureString; import com.sparrowwallet.drongo.wallet.Wallet; import com.sparrowwallet.sparrow.EventManager; import com.sparrowwallet.sparrow.event.WalletExportEvent; @@ -53,7 +53,7 @@ public class FileWalletExportPane extends TitledDescriptionPane { if(copy.isEncrypted()) { WalletPasswordDialog dlg = new WalletPasswordDialog(WalletPasswordDialog.PasswordRequirement.LOAD); - Optional password = dlg.showAndWait(); + Optional password = dlg.showAndWait(); if(password.isPresent()) { copy.decrypt(password.get()); } else { diff --git a/src/main/java/com/sparrowwallet/sparrow/control/WalletPasswordDialog.java b/src/main/java/com/sparrowwallet/sparrow/control/WalletPasswordDialog.java index 0d5ff1db..574c4014 100644 --- a/src/main/java/com/sparrowwallet/sparrow/control/WalletPasswordDialog.java +++ b/src/main/java/com/sparrowwallet/sparrow/control/WalletPasswordDialog.java @@ -1,5 +1,6 @@ package com.sparrowwallet.sparrow.control; +import com.sparrowwallet.drongo.SecureString; import com.sparrowwallet.sparrow.AppController; import javafx.application.Platform; import javafx.beans.binding.Bindings; @@ -14,7 +15,7 @@ import org.controlsfx.validation.ValidationResult; import org.controlsfx.validation.ValidationSupport; import org.controlsfx.validation.decoration.StyleClassValidationDecoration; -public class WalletPasswordDialog extends Dialog { +public class WalletPasswordDialog extends Dialog { private final ButtonType okButtonType; private final PasswordRequirement requirement; private final CustomPasswordField password; @@ -80,7 +81,7 @@ public class WalletPasswordDialog extends Dialog { password.requestFocus(); passwordConfirm.setPromptText("Password Confirmation"); - setResultConverter(dialogButton -> dialogButton == okButtonType ? password.getText() : null); + setResultConverter(dialogButton -> dialogButton == okButtonType ? new SecureString(password.getText()) : null); } public enum PasswordRequirement { diff --git a/src/main/java/com/sparrowwallet/sparrow/io/Storage.java b/src/main/java/com/sparrowwallet/sparrow/io/Storage.java index addc6ed3..031165a5 100644 --- a/src/main/java/com/sparrowwallet/sparrow/io/Storage.java +++ b/src/main/java/com/sparrowwallet/sparrow/io/Storage.java @@ -8,6 +8,8 @@ import com.sparrowwallet.drongo.wallet.Keystore; import com.sparrowwallet.drongo.wallet.MnemonicException; import com.sparrowwallet.drongo.wallet.Wallet; import com.sparrowwallet.sparrow.control.KeystorePassphraseDialog; +import javafx.concurrent.Service; +import javafx.concurrent.Task; import java.io.*; import java.lang.reflect.Type; @@ -71,7 +73,7 @@ public class Storage { return wallet; } - public Wallet loadWallet(String password) throws IOException, MnemonicException, StorageException { + public Wallet loadWallet(CharSequence password) throws IOException, MnemonicException, StorageException { InputStream fileStream = new FileInputStream(walletFile); ECKey encryptionKey = getEncryptionKey(password, fileStream); @@ -198,11 +200,11 @@ public class Storage { this.encryptionPubKey = encryptionPubKey; } - public ECKey getEncryptionKey(String password) throws IOException, StorageException { + public ECKey getEncryptionKey(CharSequence password) throws IOException, StorageException { return getEncryptionKey(password, null); } - private ECKey getEncryptionKey(String password, InputStream inputStream) throws IOException, StorageException { + private ECKey getEncryptionKey(CharSequence password, InputStream inputStream) throws IOException, StorageException { if(password.equals("")) { return NO_PASSWORD_KEY; } @@ -312,4 +314,23 @@ public class Storage { return jsonObject; } } + + public static class KeyDerivationService extends Service { + private final Storage storage; + private final String password; + + public KeyDerivationService(Storage storage, String password) { + this.storage = storage; + this.password = password; + } + + @Override + protected Task createTask() { + return new Task<>() { + protected ECKey call() throws IOException, StorageException { + return storage.getEncryptionKey(password); + } + }; + } + } } diff --git a/src/main/java/com/sparrowwallet/sparrow/wallet/SettingsController.java b/src/main/java/com/sparrowwallet/sparrow/wallet/SettingsController.java index 0241c775..533dd6f4 100644 --- a/src/main/java/com/sparrowwallet/sparrow/wallet/SettingsController.java +++ b/src/main/java/com/sparrowwallet/sparrow/wallet/SettingsController.java @@ -1,6 +1,7 @@ package com.sparrowwallet.sparrow.wallet; import com.google.common.eventbus.Subscribe; +import com.sparrowwallet.drongo.SecureString; import com.sparrowwallet.drongo.crypto.*; import com.sparrowwallet.drongo.policy.Policy; import com.sparrowwallet.drongo.policy.PolicyType; @@ -266,9 +267,9 @@ public class SettingsController extends WalletFormController implements Initiali } WalletPasswordDialog dlg = new WalletPasswordDialog(requirement); - Optional password = dlg.showAndWait(); + Optional password = dlg.showAndWait(); if(password.isPresent()) { - if(password.get().isEmpty()) { + if(password.get().length() == 0) { return Optional.of(Storage.NO_PASSWORD_KEY); }