reprompt for the bip38 passphrase rather than clearing the encrypted key
What changed, and why it matters
This commit changes how Sparrow Wallet handles a wrong BIP38 passphrase when sweeping an encrypted private key. Previously, entering the wrong passphrase cleared the entire encrypted key text, forcing the user to retype it. Now, the app simply shows an 'Incorrect passphrase' error and asks again, leaving the encrypted key in place. It is a usability improvement, not a security fix, and does not appear to prevent or introduce any exploit.
No security action required. Treat as a normal usability improvement. If reviewing the drongo submodule bump, verify that InvalidPasswordException is introduced only for wrong-passphrase detection and does not alter BIP38 decryption behavior.
Security signals we found
No security-relevant signal: change is purely UX around passphrase retry
No memory-safety, cryptographic, or authorization change visible in diff
Evidence from the diff
PrivateKeySweepDialog.decryptKey() was refactored from a single-pass prompt into a while(true) loop. If the user cancels the dialog, the key field is cleared and the method returns. If decryption succeeds, the field is updated with the decrypted key and the method returns. If InvalidPasswordException is thrown, an error dialog is shown and the loop continues, preserving the encrypted key text. Any other exception still clears the field and returns. The drongo submodule was also bumped, likely to add InvalidPasswordException.
Changed components
src/main/java/com/sparrowwallet/sparrow/control/PrivateKeySweepDialog.javadrongo submoduleInspect captured patch +16 / −7
### drongo
@@ -1 +1 @@
-Subproject commit b8a9ff19000124d259b7172d9de80a6461baf721
+Subproject commit cee00202dc8e8b09d223d694781459a6da9e05e3
### src/main/java/com/sparrowwallet/sparrow/control/PrivateKeySweepDialog.java
@@ -9,6 +9,7 @@
import com.sparrowwallet.drongo.crypto.BIP38;
import com.sparrowwallet.drongo.crypto.DumpedPrivateKey;
import com.sparrowwallet.drongo.crypto.ECKey;
+import com.sparrowwallet.drongo.crypto.InvalidPasswordException;
import com.sparrowwallet.drongo.policy.PolicyType;
import com.sparrowwallet.drongo.protocol.*;
import com.sparrowwallet.drongo.psbt.PSBT;
@@ -272,20 +273,28 @@ private boolean isEncryptedKey() {
}
private void decryptKey() {
- PassphraseDialog passphraseDialog = new PassphraseDialog();
- passphraseDialog.initOwner(getDialogPane().getScene().getWindow());
- Optional<String> optPassphrase = passphraseDialog.showAndWait();
- if(optPassphrase.isPresent()) {
+ while(true) {
+ PassphraseDialog passphraseDialog = new PassphraseDialog();
+ passphraseDialog.initOwner(getDialogPane().getScene().getWindow());
+ Optional<String> optPassphrase = passphraseDialog.showAndWait();
+ if(optPassphrase.isEmpty()) {
+ Platform.runLater(() -> key.setText(""));
+ return;
+ }
+
try {
DumpedPrivateKey decryptedKey = BIP38.decrypt(optPassphrase.get(), key.getText());
Platform.runLater(() -> key.setText(decryptedKey.toString()));
+ return;
+ } catch(InvalidPasswordException e) {
+ //The encrypted key is still valid, so prompt again rather than making the user re-enter it
+ AppServices.showErrorDialog("Incorrect passphrase", e.getMessage());
} catch(Exception e) {
log.error("Failed to decrypt BIP38 key", e);
AppServices.showErrorDialog("Failed to decrypt BIP38 key", e.getMessage());
Platform.runLater(() -> key.setText(""));
+ return;
}
- } else {
- Platform.runLater(() -> key.setText(""));
}
}
Why this scored 22/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.