diff --git a/drongo b/drongo index c675e395..242c8373 160000 --- a/drongo +++ b/drongo @@ -1 +1 @@ -Subproject commit c675e395dbbf386d2371ac3819b2a4539bf25e95 +Subproject commit 242c83735a24456a4bd23fd556a56122c9b259ab diff --git a/src/main/java/com/sparrowwallet/sparrow/control/FileKeystoreImportPane.java b/src/main/java/com/sparrowwallet/sparrow/control/FileKeystoreImportPane.java index de4fb658..2882d38c 100644 --- a/src/main/java/com/sparrowwallet/sparrow/control/FileKeystoreImportPane.java +++ b/src/main/java/com/sparrowwallet/sparrow/control/FileKeystoreImportPane.java @@ -1,7 +1,7 @@ package com.sparrowwallet.sparrow.control; import com.google.gson.JsonParseException; -import com.sparrowwallet.drongo.crypto.ECKey; +import com.sparrowwallet.drongo.crypto.ECIESKeyCrypter; import com.sparrowwallet.drongo.wallet.Keystore; import com.sparrowwallet.drongo.wallet.Wallet; import com.sparrowwallet.sparrow.EventManager; @@ -83,7 +83,7 @@ public class FileKeystoreImportPane extends KeystoreImportPane { if(e.getCause() != null && e.getCause().getMessage() != null && !e.getCause().getMessage().isEmpty()) { errorMessage = e.getCause().getMessage(); } - if(e instanceof ECKey.InvalidPasswordException || e.getCause() instanceof ECKey.InvalidPasswordException) { + if(e instanceof ECIESKeyCrypter.InvalidPasswordException || e.getCause() instanceof ECIESKeyCrypter.InvalidPasswordException) { errorMessage = "Invalid wallet password"; } if(e instanceof JsonParseException || e.getCause() instanceof JsonParseException) { diff --git a/src/main/java/com/sparrowwallet/sparrow/io/Bip39.java b/src/main/java/com/sparrowwallet/sparrow/io/Bip39.java index 85f9f944..ffbcae9c 100644 --- a/src/main/java/com/sparrowwallet/sparrow/io/Bip39.java +++ b/src/main/java/com/sparrowwallet/sparrow/io/Bip39.java @@ -2,6 +2,7 @@ package com.sparrowwallet.sparrow.io; import com.sparrowwallet.drongo.crypto.ChildNumber; import com.sparrowwallet.drongo.wallet.Bip39MnemonicCode; +import com.sparrowwallet.drongo.wallet.DeterministicSeed; import com.sparrowwallet.drongo.wallet.Keystore; import com.sparrowwallet.drongo.wallet.WalletModel; @@ -27,7 +28,7 @@ public class Bip39 implements KeystoreMnemonicImport { public Keystore getKeystore(List derivation, List mnemonicWords, String passphrase) throws ImportException { try { Bip39MnemonicCode.INSTANCE.check(mnemonicWords); - byte[] seed = Bip39MnemonicCode.toSeed(mnemonicWords, passphrase); + DeterministicSeed seed = new DeterministicSeed(mnemonicWords, null, passphrase, System.currentTimeMillis()); return Keystore.fromSeed(seed, derivation); } catch (Exception e) { throw new ImportException(e); diff --git a/src/main/java/com/sparrowwallet/sparrow/io/ECIESInputStream.java b/src/main/java/com/sparrowwallet/sparrow/io/ECIESInputStream.java index 377dfdad..0c08667f 100644 --- a/src/main/java/com/sparrowwallet/sparrow/io/ECIESInputStream.java +++ b/src/main/java/com/sparrowwallet/sparrow/io/ECIESInputStream.java @@ -1,7 +1,9 @@ package com.sparrowwallet.sparrow.io; import com.google.common.io.ByteStreams; +import com.sparrowwallet.drongo.crypto.ECIESKeyCrypter; import com.sparrowwallet.drongo.crypto.ECKey; +import com.sparrowwallet.drongo.crypto.EncryptedData; import java.io.*; import java.nio.charset.StandardCharsets; @@ -38,9 +40,11 @@ public class ECIESInputStream extends FilterInputStream { private synchronized void ensureDecrypted() throws IOException { if(!decrypted) { - byte[] encrypted = ByteStreams.toByteArray(in); + byte[] encryptedBytes = ByteStreams.toByteArray(in); in.close(); - in = new ByteArrayInputStream(decryptionKey.decryptEcies(encrypted, encryptionMagic)); + ECIESKeyCrypter keyCrypter = new ECIESKeyCrypter(); + byte[] decryptedBytes = keyCrypter.decrypt(new EncryptedData(encryptionMagic, encryptedBytes), decryptionKey); + in = new ByteArrayInputStream(decryptedBytes); decrypted = true; } } diff --git a/src/main/java/com/sparrowwallet/sparrow/io/ECIESOutputStream.java b/src/main/java/com/sparrowwallet/sparrow/io/ECIESOutputStream.java index 170c2c09..2c8ecfc5 100644 --- a/src/main/java/com/sparrowwallet/sparrow/io/ECIESOutputStream.java +++ b/src/main/java/com/sparrowwallet/sparrow/io/ECIESOutputStream.java @@ -1,7 +1,9 @@ package com.sparrowwallet.sparrow.io; import com.google.common.io.ByteStreams; +import com.sparrowwallet.drongo.crypto.ECIESKeyCrypter; import com.sparrowwallet.drongo.crypto.ECKey; +import com.sparrowwallet.drongo.crypto.EncryptedData; import java.io.*; import java.nio.charset.StandardCharsets; @@ -32,8 +34,9 @@ public class ECIESOutputStream extends FilterOutputStream { public void close() throws IOException { super.close(); byte[] unencrypted = ((ByteArrayOutputStream)out).toByteArray(); - byte[] encryptedWallet = encryptionKey.encryptEcies(unencrypted, encryptionMagic); - ByteStreams.copy(new ByteArrayInputStream(encryptedWallet), encryptedStream); + ECIESKeyCrypter keyCrypter = new ECIESKeyCrypter(); + EncryptedData encryptedData = keyCrypter.encrypt(unencrypted, encryptionMagic, encryptionKey); + ByteStreams.copy(new ByteArrayInputStream(encryptedData.getEncryptedBytes()), encryptedStream); encryptedStream.flush(); encryptedStream.close(); } diff --git a/src/main/java/com/sparrowwallet/sparrow/io/Electrum.java b/src/main/java/com/sparrowwallet/sparrow/io/Electrum.java index e00e428f..f8690795 100644 --- a/src/main/java/com/sparrowwallet/sparrow/io/Electrum.java +++ b/src/main/java/com/sparrowwallet/sparrow/io/Electrum.java @@ -5,6 +5,7 @@ import com.google.gson.reflect.TypeToken; import com.sparrowwallet.drongo.ExtendedKey; import com.sparrowwallet.drongo.KeyDerivation; import com.sparrowwallet.drongo.Utils; +import com.sparrowwallet.drongo.crypto.ECIESKeyCrypter; import com.sparrowwallet.drongo.crypto.ECKey; import com.sparrowwallet.drongo.policy.Policy; import com.sparrowwallet.drongo.policy.PolicyType; @@ -57,7 +58,7 @@ public class Electrum implements KeystoreFileImport, SinglesigWalletImport, Mult public Wallet importWallet(InputStream inputStream, String password) throws ImportException { Reader reader; if(password != null) { - ECKey decryptionKey = ECKey.createKeyPbkdf2HmacSha512(password); + ECKey decryptionKey = ECIESKeyCrypter.deriveECKey(password); reader = new InputStreamReader(new InflaterInputStream(new ECIESInputStream(inputStream, decryptionKey))); } else { reader = new InputStreamReader(inputStream); diff --git a/src/main/java/com/sparrowwallet/sparrow/io/Storage.java b/src/main/java/com/sparrowwallet/sparrow/io/Storage.java index cee50e94..9b348c40 100644 --- a/src/main/java/com/sparrowwallet/sparrow/io/Storage.java +++ b/src/main/java/com/sparrowwallet/sparrow/io/Storage.java @@ -79,7 +79,7 @@ public class Storage { } private static byte[] getEncryptionMagic() { - return "SPRW1".getBytes(StandardCharsets.UTF_8); + return "BIE1".getBytes(StandardCharsets.UTF_8); } public File getWalletFile(String walletName) { diff --git a/src/main/java/com/sparrowwallet/sparrow/wallet/SettingsController.java b/src/main/java/com/sparrowwallet/sparrow/wallet/SettingsController.java index 4b28a019..b8d051cb 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.crypto.ECIESKeyCrypter; import com.sparrowwallet.drongo.crypto.ECKey; import com.sparrowwallet.drongo.policy.Policy; import com.sparrowwallet.drongo.policy.PolicyType; @@ -279,7 +280,7 @@ public class SettingsController extends WalletFormController implements Initiali return Optional.of(WalletForm.NO_PASSWORD_KEY); } - ECKey encryptionFullKey = ECKey.createKeyPbkdf2HmacSha512(password.get()); + ECKey encryptionFullKey = ECIESKeyCrypter.deriveECKey(password.get()); ECKey encryptionPubKey = ECKey.fromPublicOnly(encryptionFullKey); if(existingPubKey != null) { if(WalletForm.NO_PASSWORD_KEY.equals(existingPubKey) || existingPubKey.equals(encryptionPubKey)) { diff --git a/src/main/java/com/sparrowwallet/sparrow/wallet/WalletForm.java b/src/main/java/com/sparrowwallet/sparrow/wallet/WalletForm.java index c9f90f50..caf94770 100644 --- a/src/main/java/com/sparrowwallet/sparrow/wallet/WalletForm.java +++ b/src/main/java/com/sparrowwallet/sparrow/wallet/WalletForm.java @@ -1,5 +1,6 @@ package com.sparrowwallet.sparrow.wallet; +import com.sparrowwallet.drongo.crypto.ECIESKeyCrypter; import com.sparrowwallet.drongo.crypto.ECKey; import com.sparrowwallet.drongo.wallet.Wallet; import com.sparrowwallet.sparrow.io.Storage; @@ -8,7 +9,7 @@ import java.io.File; import java.io.IOException; public class WalletForm { - public static final ECKey NO_PASSWORD_KEY = ECKey.fromPublicOnly(ECKey.createKeyPbkdf2HmacSha512("")); + public static final ECKey NO_PASSWORD_KEY = ECKey.fromPublicOnly(ECIESKeyCrypter.deriveECKey("")); private File walletFile; private ECKey encryptionPubKey; diff --git a/src/test/java/com/sparrowwallet/sparrow/io/ECIESInputStreamTest.java b/src/test/java/com/sparrowwallet/sparrow/io/ECIESInputStreamTest.java index d3de15e9..30b9c323 100644 --- a/src/test/java/com/sparrowwallet/sparrow/io/ECIESInputStreamTest.java +++ b/src/test/java/com/sparrowwallet/sparrow/io/ECIESInputStreamTest.java @@ -1,5 +1,6 @@ package com.sparrowwallet.sparrow.io; +import com.sparrowwallet.drongo.crypto.ECIESKeyCrypter; import com.sparrowwallet.drongo.crypto.ECKey; import com.sparrowwallet.drongo.policy.PolicyType; import com.sparrowwallet.drongo.protocol.ScriptType; @@ -13,7 +14,7 @@ public class ECIESInputStreamTest extends IoTest { @Test public void decrypt() throws ImportException { Electrum electrum = new Electrum(); - ECKey decryptionKey = ECKey.createKeyPbkdf2HmacSha512("pass"); + ECKey decryptionKey = ECIESKeyCrypter.deriveECKey("pass"); Wallet wallet = electrum.importWallet(new InflaterInputStream(new ECIESInputStream(getInputStream("electrum-encrypted"), decryptionKey)), null); Assert.assertEquals(PolicyType.SINGLE, wallet.getPolicyType()); diff --git a/src/test/java/com/sparrowwallet/sparrow/io/ECIESOutputStreamTest.java b/src/test/java/com/sparrowwallet/sparrow/io/ECIESOutputStreamTest.java index 105be2b6..f446ddaf 100644 --- a/src/test/java/com/sparrowwallet/sparrow/io/ECIESOutputStreamTest.java +++ b/src/test/java/com/sparrowwallet/sparrow/io/ECIESOutputStreamTest.java @@ -1,5 +1,6 @@ package com.sparrowwallet.sparrow.io; +import com.sparrowwallet.drongo.crypto.ECIESKeyCrypter; import com.sparrowwallet.drongo.crypto.ECKey; import com.sparrowwallet.drongo.policy.PolicyType; import com.sparrowwallet.drongo.protocol.ScriptType; @@ -16,7 +17,7 @@ public class ECIESOutputStreamTest extends IoTest { @Test public void encrypt() throws ImportException, ExportException { Electrum electrum = new Electrum(); - ECKey decryptionKey = ECKey.createKeyPbkdf2HmacSha512("pass"); + ECKey decryptionKey = ECIESKeyCrypter.deriveECKey("pass"); Wallet wallet = electrum.importWallet(new InflaterInputStream(new ECIESInputStream(getInputStream("electrum-encrypted"), decryptionKey)), null); ECKey encyptionKey = ECKey.fromPublicOnly(decryptionKey); diff --git a/src/test/java/com/sparrowwallet/sparrow/io/ElectrumTest.java b/src/test/java/com/sparrowwallet/sparrow/io/ElectrumTest.java index a9e38e61..4404d974 100644 --- a/src/test/java/com/sparrowwallet/sparrow/io/ElectrumTest.java +++ b/src/test/java/com/sparrowwallet/sparrow/io/ElectrumTest.java @@ -83,4 +83,20 @@ public class ElectrumTest extends IoTest { Assert.assertEquals("7bb026be", wallet.getKeystores().get(2).getKeyDerivation().getMasterFingerprint()); Assert.assertEquals("m/48'/1'/0'/1'", wallet.getKeystores().get(2).getKeyDerivation().getDerivationPath()); } + + @Test + public void testEncryptedImport() throws ImportException, IOException { + Electrum electrum = new Electrum(); + byte[] walletBytes = ByteStreams.toByteArray(getInputStream("electrum-encrypted")); + Wallet wallet = electrum.importWallet(new ByteArrayInputStream(walletBytes), "pass"); + + Assert.assertTrue(wallet.isValid()); + Assert.assertEquals(PolicyType.SINGLE, wallet.getPolicyType()); + Assert.assertEquals(ScriptType.P2WPKH, wallet.getScriptType()); + Assert.assertEquals(1, wallet.getDefaultPolicy().getNumSignaturesRequired()); + Assert.assertEquals("pkh(electrum05aba071)", wallet.getDefaultPolicy().getMiniscript().getScript()); + Assert.assertEquals("05aba071", wallet.getKeystores().get(0).getKeyDerivation().getMasterFingerprint()); + Assert.assertEquals("m/0'", wallet.getKeystores().get(0).getKeyDerivation().getDerivationPath()); + Assert.assertEquals("xpub67vv394epQsLhdjNGx7dfgURicP7XwBMuHPTVAMdXcXhDuC9VP8SqVvh2cYqKWm9xoUd6YynWK8JzRcXpmeuZFRH7i1kt8fR9GXoJSiHk1E", wallet.getKeystores().get(0).getExtendedPublicKey().toString()); + } } diff --git a/src/test/java/com/sparrowwallet/sparrow/io/StorageTest.java b/src/test/java/com/sparrowwallet/sparrow/io/StorageTest.java index 760c9c43..8ee7a2d6 100644 --- a/src/test/java/com/sparrowwallet/sparrow/io/StorageTest.java +++ b/src/test/java/com/sparrowwallet/sparrow/io/StorageTest.java @@ -1,5 +1,6 @@ package com.sparrowwallet.sparrow.io; +import com.sparrowwallet.drongo.crypto.ECIESKeyCrypter; import com.sparrowwallet.drongo.crypto.ECKey; import com.sparrowwallet.drongo.wallet.Wallet; import org.junit.Assert; @@ -12,14 +13,14 @@ import java.io.IOException; public class StorageTest extends IoTest { @Test public void loadWallet() throws IOException { - ECKey decryptionKey = ECKey.createKeyPbkdf2HmacSha512("pass"); + ECKey decryptionKey = ECIESKeyCrypter.deriveECKey("pass"); Wallet wallet = Storage.getStorage().loadWallet(getFile("sparrow-single-wallet"), decryptionKey); Assert.assertTrue(wallet.isValid()); } @Test public void saveWallet() throws IOException { - ECKey decryptionKey = ECKey.createKeyPbkdf2HmacSha512("pass"); + ECKey decryptionKey = ECIESKeyCrypter.deriveECKey("pass"); Wallet wallet = Storage.getStorage().loadWallet(getFile("sparrow-single-wallet"), decryptionKey); Assert.assertTrue(wallet.isValid());