support bip 137 for message signing, but handle electrum approach as well when verifying

This commit is contained in:
Craig Raw 2020-09-03 19:26:54 +02:00
parent ec9534f8ae
commit 885efd7985
3 changed files with 47 additions and 20 deletions

View file

@ -71,7 +71,7 @@ class EntryCell extends TreeTableCell<Entry, Entry> {
NodeEntry nodeEntry = (NodeEntry)entry; NodeEntry nodeEntry = (NodeEntry)entry;
Address address = nodeEntry.getAddress(); Address address = nodeEntry.getAddress();
setText(address.toString()); setText(address.toString());
setContextMenu(new AddressContextMenu(address, nodeEntry.getOutputDescriptor(), nodeEntry)); setContextMenu(new AddressContextMenu(address, nodeEntry.getOutputDescriptor(), null));
Tooltip tooltip = new Tooltip(); Tooltip tooltip = new Tooltip();
tooltip.setText(nodeEntry.getNode().getDerivationPath()); tooltip.setText(nodeEntry.getNode().getDerivationPath());
setTooltip(tooltip); setTooltip(tooltip);
@ -98,6 +98,7 @@ class EntryCell extends TreeTableCell<Entry, Entry> {
messageSignDialog.showAndWait(); messageSignDialog.showAndWait();
}); });
actionBox.getChildren().add(signMessageButton); actionBox.getChildren().add(signMessageButton);
setContextMenu(new AddressContextMenu(address, nodeEntry.getOutputDescriptor(), nodeEntry));
} }
setGraphic(actionBox); setGraphic(actionBox);

View file

@ -5,6 +5,8 @@ import com.sparrowwallet.drongo.SecureString;
import com.sparrowwallet.drongo.address.Address; import com.sparrowwallet.drongo.address.Address;
import com.sparrowwallet.drongo.address.InvalidAddressException; import com.sparrowwallet.drongo.address.InvalidAddressException;
import com.sparrowwallet.drongo.crypto.ECKey; import com.sparrowwallet.drongo.crypto.ECKey;
import com.sparrowwallet.drongo.policy.PolicyType;
import com.sparrowwallet.drongo.protocol.ScriptType;
import com.sparrowwallet.drongo.wallet.Keystore; import com.sparrowwallet.drongo.wallet.Keystore;
import com.sparrowwallet.drongo.wallet.Wallet; import com.sparrowwallet.drongo.wallet.Wallet;
import com.sparrowwallet.drongo.wallet.WalletNode; import com.sparrowwallet.drongo.wallet.WalletNode;
@ -221,7 +223,7 @@ public class MessageSignDialog extends Dialog<ButtonBar.ButtonData> {
//Note we can expect a single keystore due to the check above //Note we can expect a single keystore due to the check above
Keystore keystore = decryptedWallet.getKeystores().get(0); Keystore keystore = decryptedWallet.getKeystores().get(0);
ECKey privKey = keystore.getKey(walletNode); ECKey privKey = keystore.getKey(walletNode);
String signatureText = privKey.signMessage(message.getText(), null); String signatureText = privKey.signMessage(message.getText().trim(), decryptedWallet.getScriptType(), null);
signature.clear(); signature.clear();
signature.appendText(signatureText); signature.appendText(signatureText);
} catch(Exception e) { } catch(Exception e) {
@ -234,31 +236,55 @@ public class MessageSignDialog extends Dialog<ButtonBar.ButtonData> {
try { try {
//Find ECKey from message and signature //Find ECKey from message and signature
//http://www.secg.org/download/aid-780/sec1-v2.pdf section 4.1.6 //http://www.secg.org/download/aid-780/sec1-v2.pdf section 4.1.6
boolean verified = false;
ECKey signedMessageKey = ECKey.signedMessageToKey(message.getText(), signature.getText()); try {
Address address = getAddress(); ECKey signedMessageKey = ECKey.signedMessageToKey(message.getText().trim(), signature.getText().trim(), false);
verified = verifyMessage(signedMessageKey);
byte[] pubKeyHash = address.getOutputScriptData(); } catch(SignatureException e) {
byte[] signedKeyHash = signedMessageKey.getPubKeyHash(); //ignore
if(!Arrays.equals(pubKeyHash, signedKeyHash)) {
throw new SignatureException("Address pubkey hash did not match signed pubkey hash");
} }
if(!verified) {
try {
ECKey electrumSignedMessageKey = ECKey.signedMessageToKey(message.getText(), signature.getText(), true);
verified = verifyMessage(electrumSignedMessageKey);
} catch(SignatureException e) {
//ignore
}
}
if(verified) {
Alert alert = new Alert(Alert.AlertType.INFORMATION); Alert alert = new Alert(Alert.AlertType.INFORMATION);
setStageIcon(alert.getDialogPane().getScene().getWindow()); setStageIcon(alert.getDialogPane().getScene().getWindow());
alert.setTitle("Verification Succeeded"); alert.setTitle("Verification Succeeded");
alert.setHeaderText("Verification Succeeded"); alert.setHeaderText("Verification Succeeded");
alert.setContentText("The signature verified against the message."); alert.setContentText("The signature verified against the message.");
alert.showAndWait(); alert.showAndWait();
} catch(SignatureException e) { } else {
AppController.showErrorDialog("Verification failed", "The provided signature did not match the message for this address."); AppController.showErrorDialog("Verification failed", "The provided signature did not match the message for this address.");
}
} catch(IllegalArgumentException e) {
AppController.showErrorDialog("Could not verify message", e.getMessage());
} catch(Exception e) { } catch(Exception e) {
log.error("Could not verify message", e); log.error("Could not verify message", e);
AppController.showErrorDialog("Could not verify message", e.getMessage()); AppController.showErrorDialog("Could not verify message", e.getMessage());
} }
} }
private boolean verifyMessage(ECKey signedMessageKey) throws InvalidAddressException, SignatureException {
Address providedAddress = getAddress();
ScriptType scriptType = providedAddress.getScriptType();
if(scriptType == ScriptType.P2SH) {
scriptType = ScriptType.P2SH_P2WPKH;
}
if(!ScriptType.getScriptTypesForPolicyType(PolicyType.SINGLE).contains(scriptType)) {
throw new IllegalArgumentException("Only single signature P2PKH, P2SH-P2WPKH or P2WPKH addresses can verify messages.");
}
Address signedMessageAddress = scriptType.getAddress(signedMessageKey);
return providedAddress.equals(signedMessageAddress);
}
@Subscribe @Subscribe
public void openWallets(OpenWalletsEvent event) { public void openWallets(OpenWalletsEvent event) {
Storage storage = event.getStorage(wallet); Storage storage = event.getStorage(wallet);

View file

@ -269,7 +269,7 @@ public class MnemonicKeystoreImportPane extends TitledDescriptionPane {
} }
private void displayMnemonicCode() { private void displayMnemonicCode() {
setDescription("Write down word list to confirm backup"); setDescription("Write down words before confirming");
showHideLink.setVisible(false); showHideLink.setVisible(false);
calculateButton.setVisible(false); calculateButton.setVisible(false);