Skip to content

Commit c7b048c

Browse files
committed
Better keyring interface for Convex Desktop GUI
1 parent d5d7c8b commit c7b048c

File tree

13 files changed

+276
-291
lines changed

13 files changed

+276
-291
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,20 @@
11
package convex.core.crypto.wallet;
22

3+
import convex.core.data.AArrayBlob;
4+
35
public abstract class AWalletEntry implements IWalletEntry {
46

7+
@Override
8+
public void unlock(char[] password) {
9+
if (tryUnlock(password)) return;
10+
11+
throw new IllegalStateException("Invalid password");
12+
}
13+
14+
/**
15+
* Returns the data to be used for a wallet identicon. Should be the public account key
16+
* @return
17+
*/
18+
public abstract AArrayBlob getIdenticonData();
19+
520
}

convex-core/src/main/java/convex/core/crypto/wallet/BasicWalletEntry.java

Lines changed: 0 additions & 105 deletions
This file was deleted.
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
package convex.core.crypto.wallet;
2+
3+
import convex.core.crypto.AKeyPair;
4+
import convex.core.data.AArrayBlob;
5+
import convex.core.data.ACell;
6+
import convex.core.data.AccountKey;
7+
import convex.core.data.Hash;
8+
import convex.core.data.SignedData;
9+
import convex.core.data.Strings;
10+
11+
/**
12+
* Class implementing a Hot Wallet Entry. Hot keys are stored in memory, and are accessible to
13+
* attackers able to gain full control of the machine.
14+
*
15+
* May be in a locked locked or unlocked state. Unlocking requires passphrase.
16+
*/
17+
public class HotWalletEntry extends AWalletEntry {
18+
private final AKeyPair keyPair;
19+
private Hash passHash=null;
20+
boolean locked=false;
21+
22+
private HotWalletEntry(AKeyPair kp) {
23+
this.keyPair = kp;
24+
}
25+
26+
public static HotWalletEntry create(AKeyPair kp) {
27+
return new HotWalletEntry(kp);
28+
}
29+
30+
@Override
31+
public AccountKey getPublicKey() {
32+
if (keyPair==null) return null;
33+
return keyPair.getAccountKey();
34+
}
35+
36+
@Override
37+
public AKeyPair getKeyPair() {
38+
if (keyPair == null) throw new IllegalStateException("Wallet not unlocked!");
39+
return keyPair;
40+
}
41+
42+
43+
@Override
44+
public boolean isLocked() {
45+
return locked;
46+
}
47+
48+
@Override
49+
public String toString() {
50+
AccountKey pubKey=getPublicKey();
51+
String ks="0x"+pubKey.toChecksumHex();
52+
return "Wallet Entry for: "+ks;
53+
}
54+
55+
public <R extends ACell> SignedData<R> sign(R message) {
56+
return keyPair.signData(message);
57+
}
58+
59+
@Override
60+
public AArrayBlob getIdenticonData() {
61+
return keyPair.getAccountKey();
62+
}
63+
64+
@Override
65+
public synchronized boolean tryUnlock(char[] password) {
66+
if (!isLocked()) return true;
67+
Hash h=getPasswordHash(password);
68+
if (h.equals(passHash)) {
69+
locked=false;
70+
return true;
71+
} else {
72+
return false;
73+
}
74+
}
75+
76+
@Override
77+
public synchronized void lock(char[] password) {
78+
Hash h=getPasswordHash(password);
79+
if (locked) {
80+
throw new IllegalStateException("Wallet already locked)");
81+
} else {
82+
passHash=h;
83+
locked=true;
84+
}
85+
}
86+
87+
protected Hash getPasswordHash(char[] password) {
88+
String s=new String(password);
89+
Hash h=Strings.create(s).getHash();
90+
return h;
91+
}
92+
93+
}

convex-core/src/main/java/convex/core/crypto/wallet/IWalletEntry.java

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,16 @@ public interface IWalletEntry {
1212
public boolean isLocked();
1313

1414
/**
15-
* Gets the key pair associated with this wallet entry
16-
* @return
15+
* Gets the key pair associated with this wallet entry, if unlocked
16+
* @return Key pair instance, or null if not available (locked)
1717
*/
1818
AKeyPair getKeyPair();
1919

2020
/**
2121
* Get the public key associated with this wallet entry
2222
* @return
2323
*/
24-
AccountKey getPublicKey();
24+
AccountKey getPublicKey();
2525

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

33+
/**
34+
* Unlock the wallet entry. Unlocking makes the entry usable for signing
35+
* @param passPhrase
36+
* @return
37+
*/
38+
public void unlock(char[] passPhrase);
39+
40+
/**
41+
* Lock the wallet entry. Locking makes the wallet entry unusable until unlocked.
42+
* @param password
43+
*/
44+
public void lock(char[] password);
45+
3346
}

convex-core/src/main/java/convex/core/crypto/wallet/PKCS12Wallet.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,17 @@ public class PKCS12Wallet extends AWallet {
1818

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

21-
private HashMap<Address, BasicWalletEntry> data;
21+
private HashMap<Address, HotWalletEntry> data;
2222

23-
private PKCS12Wallet(HashMap<Address, BasicWalletEntry> data) {
23+
private PKCS12Wallet(HashMap<Address, HotWalletEntry> data) {
2424
this.data = data;
2525
}
2626

2727
public static PKCS12Wallet create() {
28-
return new PKCS12Wallet(new HashMap<Address, BasicWalletEntry>());
28+
return new PKCS12Wallet(new HashMap<Address, HotWalletEntry>());
2929
}
3030

31-
public BasicWalletEntry get(Address a) {
31+
public HotWalletEntry get(Address a) {
3232
return data.get(a);
3333
}
3434

convex-gui/src/main/java/convex/gui/keys/KeyGenPanel.java

Lines changed: 42 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
import convex.core.crypto.AKeyPair;
2121
import convex.core.crypto.BIP39;
2222
import convex.core.crypto.SLIP10;
23-
import convex.core.crypto.wallet.BasicWalletEntry;
23+
import convex.core.crypto.wallet.HotWalletEntry;
2424
import convex.core.data.AccountKey;
2525
import convex.core.data.Blob;
2626
import convex.core.data.Blobs;
@@ -47,7 +47,7 @@ public class KeyGenPanel extends JPanel {
4747

4848
JSpinner numSpinner;
4949

50-
JButton addWalletButton = new JButton("Add to wallet");
50+
JButton addWalletButton = new JButton("Add to keyring");
5151

5252
JPanel formPanel;
5353

@@ -198,45 +198,7 @@ private void generatePublicKey() {
198198
public KeyGenPanel(PeerGUI manager) {
199199
setLayout(new BorderLayout());
200200

201-
// Action panel with buttons
202-
203-
JPanel actionPanel = new ActionPanel();
204-
add(actionPanel, BorderLayout.SOUTH);
205-
206-
JButton btnRecreate = new JButton("Generate");
207-
actionPanel.add(btnRecreate);
208-
btnRecreate.addActionListener(e -> {
209-
Integer wc=(Integer) numSpinner.getValue();
210-
mnemonicArea.setText(BIP39.createSecureMnemonic(wc));
211-
updateMnemonic();
212-
});
213-
214-
numSpinner = new JSpinner();
215-
numSpinner.setModel(new SpinnerNumberModel(12, 3, 30, 1));
216-
actionPanel.add(numSpinner);
217201

218-
JButton btnNewButton = new JButton("Export...");
219-
actionPanel.add(btnNewButton);
220-
221-
{ // Button to Normalise Mnemonic string
222-
JButton btnNormalise = new JButton("Normalise Mnemonic");
223-
actionPanel.add(btnNormalise);
224-
btnNormalise.addActionListener(e -> {
225-
String s=mnemonicArea.getText();
226-
mnemonicArea.setText(BIP39.normalise(s));
227-
updateMnemonic();
228-
});
229-
}
230-
231-
actionPanel.add(addWalletButton);
232-
addWalletButton.addActionListener(e -> {
233-
String pks = privateKeyArea.getText();
234-
pks = Utils.stripWhiteSpace(pks);
235-
BasicWalletEntry we = BasicWalletEntry.create(null,AKeyPair.create(Utils.hexToBytes(pks)));
236-
manager.addWalletEntry(we);
237-
manager.switchPanel("Wallet");
238-
239-
});
240202

241203
// Main Key generation form
242204

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

331+
////////////////////////////////////////////////////////////////
332+
// Action panel with buttons
333+
334+
JPanel actionPanel = new ActionPanel();
335+
add(actionPanel, BorderLayout.SOUTH);
336+
337+
JButton btnRecreate = new JButton("Generate");
338+
actionPanel.add(btnRecreate);
339+
btnRecreate.addActionListener(e -> {
340+
Integer wc=(Integer) numSpinner.getValue();
341+
mnemonicArea.setText(BIP39.createSecureMnemonic(wc));
342+
updateMnemonic();
343+
});
344+
345+
numSpinner = new JSpinner();
346+
numSpinner.setModel(new SpinnerNumberModel(12, 3, 30, 1));
347+
actionPanel.add(numSpinner);
348+
349+
JButton btnNewButton = new JButton("Export...");
350+
actionPanel.add(btnNewButton);
351+
352+
{ // Button to Normalise Mnemonic string
353+
JButton btnNormalise = new JButton("Normalise Mnemonic");
354+
actionPanel.add(btnNormalise);
355+
btnNormalise.addActionListener(e -> {
356+
String s=mnemonicArea.getText();
357+
mnemonicArea.setText(BIP39.normalise(s));
358+
updateMnemonic();
359+
});
360+
}
361+
362+
actionPanel.add(addWalletButton);
363+
addWalletButton.setEnabled(false);
364+
addWalletButton.addActionListener(e -> {
365+
String pks = privateKeyArea.getText();
366+
pks = Utils.stripWhiteSpace(pks);
367+
HotWalletEntry we = HotWalletEntry.create(AKeyPair.create(Utils.hexToBytes(pks)));
368+
KeyRingPanel.addWalletEntry(we);
369+
manager.switchPanel("Keyring");
370+
});
369371
}
370372

371373
private void addNote(String s) {

0 commit comments

Comments
 (0)