Skip to content

Commit

Permalink
Better keyring interface for Convex Desktop GUI
Browse files Browse the repository at this point in the history
  • Loading branch information
mikera committed Apr 23, 2024
1 parent d5d7c8b commit c7b048c
Show file tree
Hide file tree
Showing 13 changed files with 276 additions and 291 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
package convex.core.crypto.wallet;

import convex.core.data.AArrayBlob;

public abstract class AWalletEntry implements IWalletEntry {

@Override
public void unlock(char[] password) {
if (tryUnlock(password)) return;

throw new IllegalStateException("Invalid password");
}

/**
* Returns the data to be used for a wallet identicon. Should be the public account key
* @return
*/
public abstract AArrayBlob getIdenticonData();

}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package convex.core.crypto.wallet;

import convex.core.crypto.AKeyPair;
import convex.core.data.AArrayBlob;
import convex.core.data.ACell;
import convex.core.data.AccountKey;
import convex.core.data.Hash;
import convex.core.data.SignedData;
import convex.core.data.Strings;

/**
* Class implementing a Hot Wallet Entry. Hot keys are stored in memory, and are accessible to
* attackers able to gain full control of the machine.
*
* May be in a locked locked or unlocked state. Unlocking requires passphrase.
*/
public class HotWalletEntry extends AWalletEntry {
private final AKeyPair keyPair;
private Hash passHash=null;
boolean locked=false;

private HotWalletEntry(AKeyPair kp) {
this.keyPair = kp;
}

public static HotWalletEntry create(AKeyPair kp) {
return new HotWalletEntry(kp);
}

@Override
public AccountKey getPublicKey() {
if (keyPair==null) return null;
return keyPair.getAccountKey();
}

@Override
public AKeyPair getKeyPair() {
if (keyPair == null) throw new IllegalStateException("Wallet not unlocked!");
return keyPair;
}


@Override
public boolean isLocked() {
return locked;
}

@Override
public String toString() {
AccountKey pubKey=getPublicKey();
String ks="0x"+pubKey.toChecksumHex();
return "Wallet Entry for: "+ks;
}

public <R extends ACell> SignedData<R> sign(R message) {
return keyPair.signData(message);
}

@Override
public AArrayBlob getIdenticonData() {
return keyPair.getAccountKey();
}

@Override
public synchronized boolean tryUnlock(char[] password) {
if (!isLocked()) return true;
Hash h=getPasswordHash(password);
if (h.equals(passHash)) {
locked=false;
return true;
} else {
return false;
}
}

@Override
public synchronized void lock(char[] password) {
Hash h=getPasswordHash(password);
if (locked) {
throw new IllegalStateException("Wallet already locked)");
} else {
passHash=h;
locked=true;
}
}

protected Hash getPasswordHash(char[] password) {
String s=new String(password);
Hash h=Strings.create(s).getHash();
return h;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,16 @@ public interface IWalletEntry {
public boolean isLocked();

/**
* Gets the key pair associated with this wallet entry
* @return
* Gets the key pair associated with this wallet entry, if unlocked
* @return Key pair instance, or null if not available (locked)
*/
AKeyPair getKeyPair();

/**
* Get the public key associated with this wallet entry
* @return
*/
AccountKey getPublicKey();
AccountKey getPublicKey();

/**
* Try to unlock a wallet with the given password
Expand All @@ -30,4 +30,17 @@ public interface IWalletEntry {
*/
public boolean tryUnlock(char[] password);

/**
* Unlock the wallet entry. Unlocking makes the entry usable for signing
* @param passPhrase
* @return
*/
public void unlock(char[] passPhrase);

/**
* Lock the wallet entry. Locking makes the wallet entry unusable until unlocked.
* @param password
*/
public void lock(char[] password);

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,17 @@ public class PKCS12Wallet extends AWallet {

private static final Logger log = LoggerFactory.getLogger(PKCS12Wallet.class.getName());

private HashMap<Address, BasicWalletEntry> data;
private HashMap<Address, HotWalletEntry> data;

private PKCS12Wallet(HashMap<Address, BasicWalletEntry> data) {
private PKCS12Wallet(HashMap<Address, HotWalletEntry> data) {
this.data = data;
}

public static PKCS12Wallet create() {
return new PKCS12Wallet(new HashMap<Address, BasicWalletEntry>());
return new PKCS12Wallet(new HashMap<Address, HotWalletEntry>());
}

public BasicWalletEntry get(Address a) {
public HotWalletEntry get(Address a) {
return data.get(a);
}

Expand Down
82 changes: 42 additions & 40 deletions convex-gui/src/main/java/convex/gui/keys/KeyGenPanel.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import convex.core.crypto.AKeyPair;
import convex.core.crypto.BIP39;
import convex.core.crypto.SLIP10;
import convex.core.crypto.wallet.BasicWalletEntry;
import convex.core.crypto.wallet.HotWalletEntry;
import convex.core.data.AccountKey;
import convex.core.data.Blob;
import convex.core.data.Blobs;
Expand All @@ -47,7 +47,7 @@ public class KeyGenPanel extends JPanel {

JSpinner numSpinner;

JButton addWalletButton = new JButton("Add to wallet");
JButton addWalletButton = new JButton("Add to keyring");

JPanel formPanel;

Expand Down Expand Up @@ -198,45 +198,7 @@ private void generatePublicKey() {
public KeyGenPanel(PeerGUI manager) {
setLayout(new BorderLayout());

// Action panel with buttons

JPanel actionPanel = new ActionPanel();
add(actionPanel, BorderLayout.SOUTH);

JButton btnRecreate = new JButton("Generate");
actionPanel.add(btnRecreate);
btnRecreate.addActionListener(e -> {
Integer wc=(Integer) numSpinner.getValue();
mnemonicArea.setText(BIP39.createSecureMnemonic(wc));
updateMnemonic();
});

numSpinner = new JSpinner();
numSpinner.setModel(new SpinnerNumberModel(12, 3, 30, 1));
actionPanel.add(numSpinner);

JButton btnNewButton = new JButton("Export...");
actionPanel.add(btnNewButton);

{ // Button to Normalise Mnemonic string
JButton btnNormalise = new JButton("Normalise Mnemonic");
actionPanel.add(btnNormalise);
btnNormalise.addActionListener(e -> {
String s=mnemonicArea.getText();
mnemonicArea.setText(BIP39.normalise(s));
updateMnemonic();
});
}

actionPanel.add(addWalletButton);
addWalletButton.addActionListener(e -> {
String pks = privateKeyArea.getText();
pks = Utils.stripWhiteSpace(pks);
BasicWalletEntry we = BasicWalletEntry.create(null,AKeyPair.create(Utils.hexToBytes(pks)));
manager.addWalletEntry(we);
manager.switchPanel("Wallet");

});

// Main Key generation form

Expand Down Expand Up @@ -366,6 +328,46 @@ public KeyGenPanel(PeerGUI manager) {
addLabel("Identicon:");
formPanel.add(identicon,"grow 0");

////////////////////////////////////////////////////////////////
// Action panel with buttons

JPanel actionPanel = new ActionPanel();
add(actionPanel, BorderLayout.SOUTH);

JButton btnRecreate = new JButton("Generate");
actionPanel.add(btnRecreate);
btnRecreate.addActionListener(e -> {
Integer wc=(Integer) numSpinner.getValue();
mnemonicArea.setText(BIP39.createSecureMnemonic(wc));
updateMnemonic();
});

numSpinner = new JSpinner();
numSpinner.setModel(new SpinnerNumberModel(12, 3, 30, 1));
actionPanel.add(numSpinner);

JButton btnNewButton = new JButton("Export...");
actionPanel.add(btnNewButton);

{ // Button to Normalise Mnemonic string
JButton btnNormalise = new JButton("Normalise Mnemonic");
actionPanel.add(btnNormalise);
btnNormalise.addActionListener(e -> {
String s=mnemonicArea.getText();
mnemonicArea.setText(BIP39.normalise(s));
updateMnemonic();
});
}

actionPanel.add(addWalletButton);
addWalletButton.setEnabled(false);
addWalletButton.addActionListener(e -> {
String pks = privateKeyArea.getText();
pks = Utils.stripWhiteSpace(pks);
HotWalletEntry we = HotWalletEntry.create(AKeyPair.create(Utils.hexToBytes(pks)));
KeyRingPanel.addWalletEntry(we);
manager.switchPanel("Keyring");
});
}

private void addNote(String s) {
Expand Down
Loading

0 comments on commit c7b048c

Please sign in to comment.