Skip to content

Commit

Permalink
#445 reworked tests etc to use BIP32 wallets
Browse files Browse the repository at this point in the history
  • Loading branch information
jim618 committed Mar 9, 2015
1 parent 46d0e9e commit 3f539f5
Show file tree
Hide file tree
Showing 13 changed files with 127 additions and 70 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -83,5 +83,4 @@ public boolean isValid(List<String> seedPhrase) {
return false;

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@
import java.util.regex.Pattern;

import static org.multibit.hd.core.dto.WalletId.*;
import static org.multibit.hd.core.utils.Collators.*;

/**
* <p>Manager to provide the following to core users:</p>
Expand Down Expand Up @@ -324,6 +323,8 @@ public WalletSummary badlyGetOrCreateMBHDSoftWalletSummaryFromSeed(
log.debug("Creating new wallet file...");

// Create a wallet using the seed (no salt passphrase)
// THIS METHOD CALL PRODUCES NON BIP32 COMPLIANT WALLETS !
// The entropy should be passed in - not the seed bytes
DeterministicSeed deterministicSeed = new DeterministicSeed(seed, "", creationTimeInSeconds);
Wallet walletToReturn = Wallet.fromSeed(networkParameters, deterministicSeed);
walletToReturn.setKeychainLookaheadSize(LOOK_AHEAD_SIZE);
Expand Down Expand Up @@ -376,9 +377,10 @@ public WalletSummary badlyGetOrCreateMBHDSoftWalletSummaryFromSeed(
* <p>Synchronization is begun if required</p>
*
* @param applicationDataDirectory The application data directory containing the wallet
* @param entropy The entropy equivalent to the mnenomic seed phrase
* This is the byte array equivalent to the random number you are using
* This is NOT the seed bytes, which have undergone Scrypt processing
* @param entropy The entropy equivalent to the wallet words (seed phrase)
* This is the byte array equivalent to the random number you are using
* This is NOT the seed bytes, which have undergone Scrypt processing
* @param seed The seed byte array (the seed phrase after Scrypt processing)
* @param creationTimeInSeconds The creation time of the wallet, in seconds since epoch
* @param password The credentials to use to encrypt the wallet - if null then the wallet is not loaded
* @param name The wallet name
Expand All @@ -394,18 +396,18 @@ public WalletSummary badlyGetOrCreateMBHDSoftWalletSummaryFromSeed(
public WalletSummary getOrCreateMBHDSoftWalletSummaryFromEntropy(
File applicationDataDirectory,
byte[] entropy,
byte[] seed,
long creationTimeInSeconds,
String password,
String name,
String notes,
boolean performSynch) throws WalletLoadException, WalletVersionException, IOException {
log.debug("badlyGetOrCreateMBHDSoftWalletSummaryFromSeed called");
log.debug("getOrCreateMBHDSoftWalletSummaryFromEntropy called");
final WalletSummary walletSummary;

// Create a wallet id from the entropy to work out the wallet root directory
// TODO should the WalletId be created from the entropy or the seed ?
// TODO other walletIds are created from the seed bytes
final WalletId walletId = new WalletId(entropy);
// Create a wallet id from the seed to work out the wallet root directory
// The seed bytes are used for backwards compatibility
final WalletId walletId = new WalletId(seed);
String walletRoot = createWalletRoot(walletId);

final File walletDirectory = WalletManager.getOrCreateWalletDirectory(applicationDataDirectory, walletRoot);
Expand All @@ -428,6 +430,7 @@ public WalletSummary getOrCreateMBHDSoftWalletSummaryFromEntropy(
log.debug("Creating new wallet file...");

// Create a wallet using the entropy
// DeterministicSeed constructor expects ENTROPY here
DeterministicSeed deterministicSeed = new DeterministicSeed(entropy, "", creationTimeInSeconds);
Wallet walletToReturn = Wallet.fromSeed(networkParameters, deterministicSeed);
walletToReturn.setKeychainLookaheadSize(LOOK_AHEAD_SIZE);
Expand All @@ -444,22 +447,23 @@ public WalletSummary getOrCreateMBHDSoftWalletSummaryFromEntropy(
walletSummary.setNotes(notes);
walletSummary.setWalletPassword(new WalletPassword(password, walletId));
walletSummary.setWalletFile(walletFile);
walletSummary.setWalletType(WalletType.MBHD_SOFT_WALLET);
walletSummary.setWalletType(WalletType.MBHD_SOFT_WALLET_BIP32);
setCurrentWalletSummary(walletSummary);

// Save the wallet YAML
saveWalletYaml = true;
createdNew = true;

try {
WalletManager.writeEncryptedPasswordAndBackupKey(walletSummary, entropy, password);
// The seed bytes are used as the secret to encrypt the password (mainly for backwards compatibility)
WalletManager.writeEncryptedPasswordAndBackupKey(walletSummary, seed, password);
} catch (NoSuchAlgorithmException e) {
throw new WalletLoadException("Could not store encrypted credentials and backup AES key", e);
}
}

// Set wallet type
walletSummary.getWallet().addOrUpdateExtension(new WalletTypeExtension(WalletType.MBHD_SOFT_WALLET));
walletSummary.getWallet().addOrUpdateExtension(new WalletTypeExtension(WalletType.MBHD_SOFT_WALLET_BIP32));

if (createdNew) {
CoreEvents.fireWalletLoadEvent(new WalletLoadEvent(Optional.of(walletId), true, CoreMessageKey.WALLET_LOADED_OK, null, Optional.<File>absent()));
Expand Down Expand Up @@ -1200,7 +1204,7 @@ public static List<WalletSummary> getWalletSummaries() {
/**
*
* <p>This list contains MBHD soft wallets and Trezor soft wallets</p>
* @param Locale the locale to sort results by
* @param localeOptional the locale to sort results by
* @return A list of soft wallet summaries based on the current application directory contents (never null), ordered by wallet name
*
*/
Expand Down Expand Up @@ -1498,24 +1502,27 @@ public static WalletSummary getOrCreateWalletSummary(File walletDirectory, Walle
/**
* Write the encrypted wallet credentials and backup AES key to the wallet configuration.
* You probably want to save it afterwards with an updateSummary
* @param walletSummary The wallet summary to write the encrypted details for
* @param secret The secret used to derive the AES encryption key. This is typically created deterministically from the wallet words
* @param password The password you want to store encrypted
*/
public static void writeEncryptedPasswordAndBackupKey(WalletSummary walletSummary, byte[] entropy, String password) throws NoSuchAlgorithmException {
public static void writeEncryptedPasswordAndBackupKey(WalletSummary walletSummary, byte[] secret, String password) throws NoSuchAlgorithmException {

Preconditions.checkNotNull(walletSummary, "'walletSummary' must be present");
Preconditions.checkNotNull(entropy, "'entropy' must be present");
Preconditions.checkNotNull(secret, "'secret' must be present");
Preconditions.checkNotNull(password, "'password' must be present");

// Save the wallet credentials, AES encrypted with a key derived from the wallet entropy
KeyParameter entropyDerivedAESKey = org.multibit.hd.core.crypto.AESUtils.createAESKey(entropy, SCRYPT_SALT);
// Save the wallet credentials, AES encrypted with a key derived from the wallet secret
KeyParameter secretDerivedAESKey = org.multibit.hd.core.crypto.AESUtils.createAESKey(secret, SCRYPT_SALT);
byte[] passwordBytes = password.getBytes(Charsets.UTF_8);

byte[] paddedPasswordBytes = padPasswordBytes(passwordBytes);
byte[] encryptedPaddedPassword = org.multibit.hd.brit.crypto.AESUtils.encrypt(paddedPasswordBytes, entropyDerivedAESKey, AES_INITIALISATION_VECTOR);
byte[] encryptedPaddedPassword = org.multibit.hd.brit.crypto.AESUtils.encrypt(paddedPasswordBytes, secretDerivedAESKey, AES_INITIALISATION_VECTOR);
walletSummary.setEncryptedPassword(encryptedPaddedPassword);

// Save the backupAESKey, AES encrypted with a key generated from the wallet password
KeyParameter walletPasswordDerivedAESKey = org.multibit.hd.core.crypto.AESUtils.createAESKey(passwordBytes, SCRYPT_SALT);
byte[] encryptedBackupAESKey = org.multibit.hd.brit.crypto.AESUtils.encrypt(entropyDerivedAESKey.getKey(), walletPasswordDerivedAESKey, AES_INITIALISATION_VECTOR);
byte[] encryptedBackupAESKey = org.multibit.hd.brit.crypto.AESUtils.encrypt(secretDerivedAESKey.getKey(), walletPasswordDerivedAESKey, AES_INITIALISATION_VECTOR);
walletSummary.setEncryptedBackupKey(encryptedBackupAESKey);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import com.google.common.base.Optional;
import com.google.common.util.concurrent.Uninterruptibles;
import org.bitcoinj.core.Wallet;
import org.bitcoinj.crypto.MnemonicCode;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
Expand All @@ -34,7 +35,6 @@
import org.multibit.hd.core.utils.Dates;

import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.TimeUnit;

Expand Down Expand Up @@ -66,7 +66,7 @@ public void tearDown() throws Exception {
}

@Test
public void testBackupWallet() throws IOException {
public void testBackupWallet() throws Exception {

// Get the application directory
File applicationDirectory = InstallationManager.getOrCreateApplicationDataDirectory();
Expand All @@ -81,15 +81,18 @@ public void testBackupWallet() throws IOException {

// Create a temporary seed phrase
SeedPhraseGenerator seedGenerator = new Bip39SeedPhraseGenerator();
byte[] seed = seedGenerator.convertToSeed(Bip39SeedPhraseGenerator.split(WalletIdTest.SEED_PHRASE_1));
List<String> seedPhraseList = Bip39SeedPhraseGenerator.split(WalletIdTest.SEED_PHRASE_1);
byte[] entropy = MnemonicCode.INSTANCE.toEntropy(seedPhraseList);
byte[] seed = seedGenerator.convertToSeed(seedPhraseList);
long nowInSeconds = Dates.nowInSeconds();
String password = "credentials";

// Create a wallet summary (requires a backup manager to be in place)
WalletSummary walletSummary = WalletManager
.INSTANCE
.badlyGetOrCreateMBHDSoftWalletSummaryFromSeed(
.getOrCreateMBHDSoftWalletSummaryFromEntropy(
applicationDirectory,
entropy,
seed,
nowInSeconds,
password,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,13 +136,15 @@ public void testCreateWallet() throws Exception {
WalletManager walletManager = WalletManager.INSTANCE;
BackupManager.INSTANCE.initialise(applicationDirectory, Optional.<File>absent());

byte[] entropy = MnemonicCode.INSTANCE.toEntropy(Bip39SeedPhraseGenerator.split(WalletIdTest.SEED_PHRASE_1));
SeedPhraseGenerator seedGenerator = new Bip39SeedPhraseGenerator();
byte[] seed = seedGenerator.convertToSeed(Bip39SeedPhraseGenerator.split(WalletIdTest.SEED_PHRASE_1));
long nowInSeconds = Dates.nowInSeconds();

WalletSummary walletSummary1 = walletManager
.badlyGetOrCreateMBHDSoftWalletSummaryFromSeed(
.getOrCreateMBHDSoftWalletSummaryFromEntropy(
applicationDirectory,
entropy,
seed,
nowInSeconds,
"credentials",
Expand All @@ -160,8 +162,9 @@ public void testCreateWallet() throws Exception {
BackupManager.INSTANCE.initialise(applicationDirectory2, Optional.<File>absent());

WalletSummary walletSummary2 = walletManager
.badlyGetOrCreateMBHDSoftWalletSummaryFromSeed(
.getOrCreateMBHDSoftWalletSummaryFromEntropy(
applicationDirectory2,
entropy,
seed,
nowInSeconds,
"credentials",
Expand All @@ -187,8 +190,8 @@ public void testCreateWallet() throws Exception {
);

assertThat(expectedFile.exists()).isTrue();
assertThat(WalletType.MBHD_SOFT_WALLET.equals(walletSummary1.getWalletType()));
assertThat(WalletType.MBHD_SOFT_WALLET.equals(walletSummary2.getWalletType()));
assertThat(WalletType.MBHD_SOFT_WALLET_BIP32.equals(walletSummary1.getWalletType()));
assertThat(WalletType.MBHD_SOFT_WALLET_BIP32.equals(walletSummary2.getWalletType()));
}

@Test
Expand Down Expand Up @@ -302,6 +305,7 @@ public void testCreateSkinSeedPhraseWalletInABadWay() throws Exception {

SeedPhraseGenerator seedGenerator = new Bip39SeedPhraseGenerator();
byte[] seed = seedGenerator.convertToSeed(Bip39SeedPhraseGenerator.split(SKIN_SEED_PHRASE));

long nowInSeconds = Dates.nowInSeconds();

WalletSummary walletSummary = walletManager.badlyGetOrCreateMBHDSoftWalletSummaryFromSeed(
Expand Down Expand Up @@ -359,18 +363,22 @@ public void testCreateSkinSeedPhraseWalletInAGoodWay() throws Exception {
BackupManager.INSTANCE.initialise(applicationDirectory, Optional.<File>absent());

byte[] entropy = MnemonicCode.INSTANCE.toEntropy(Bip39SeedPhraseGenerator.split(SKIN_SEED_PHRASE));
SeedPhraseGenerator seedGenerator = new Bip39SeedPhraseGenerator();
byte[] seed = seedGenerator.convertToSeed(Bip39SeedPhraseGenerator.split(SKIN_SEED_PHRASE));

long nowInSeconds = Dates.nowInSeconds();

WalletSummary walletSummary = walletManager.getOrCreateMBHDSoftWalletSummaryFromEntropy(
applicationDirectory,
entropy,
seed,
nowInSeconds,
"aPassword",
"Skin",
"Skin", true);

assertThat(walletSummary).isNotNull();
assertThat(WalletType.MBHD_SOFT_WALLET.equals(walletSummary.getWalletType()));
assertThat(WalletType.MBHD_SOFT_WALLET_BIP32.equals(walletSummary.getWalletType()));

// Check that the generated addresses match the expected

Expand Down Expand Up @@ -517,13 +525,16 @@ public void testSignAndVerifyMessage() throws Exception {
WalletManager walletManager = WalletManager.INSTANCE;
BackupManager.INSTANCE.initialise(applicationDirectory, Optional.<File>absent());

byte[] entropy = MnemonicCode.INSTANCE.toEntropy(Bip39SeedPhraseGenerator.split(WalletIdTest.SEED_PHRASE_1));
SeedPhraseGenerator seedGenerator = new Bip39SeedPhraseGenerator();
byte[] seed = seedGenerator.convertToSeed(Bip39SeedPhraseGenerator.split(WalletIdTest.SEED_PHRASE_1));

long nowInSeconds = Dates.nowInSeconds();

log.debug("");
WalletSummary walletSummary = walletManager.badlyGetOrCreateMBHDSoftWalletSummaryFromSeed(
WalletSummary walletSummary = walletManager.getOrCreateMBHDSoftWalletSummaryFromEntropy(
applicationDirectory,
entropy,
seed,
nowInSeconds,
SIGNING_PASSWORD,
Expand Down Expand Up @@ -597,7 +608,6 @@ public void testSignAndVerifyMessage() throws Exception {

@Test
public void testWriteOfEncryptedPasswordAndSeed() throws Exception {

List<String> passwordList = Lists.newArrayList();
passwordList.add(SHORT_PASSWORD);
passwordList.add(MEDIUM_PASSWORD);
Expand All @@ -606,6 +616,8 @@ public void testWriteOfEncryptedPasswordAndSeed() throws Exception {
passwordList.add(LONGEST_PASSWORD);

SeedPhraseGenerator seedGenerator = new Bip39SeedPhraseGenerator();
byte[] entropy = MnemonicCode.INSTANCE.toEntropy(Bip39SeedPhraseGenerator.split(WalletIdTest.SEED_PHRASE_1));
byte[] seed = seedGenerator.convertToSeed(Bip39SeedPhraseGenerator.split(WalletIdTest.SEED_PHRASE_1));

for (String passwordToCheck : passwordList) {

Expand All @@ -616,12 +628,13 @@ public void testWriteOfEncryptedPasswordAndSeed() throws Exception {

WalletManager walletManager = WalletManager.INSTANCE;

byte[] seed = seedGenerator.convertToSeed(Bip39SeedPhraseGenerator.split(WalletIdTest.SEED_PHRASE_1));

long nowInSeconds = Dates.nowInSeconds();

WalletSummary walletSummary = walletManager
.badlyGetOrCreateMBHDSoftWalletSummaryFromSeed(
.getOrCreateMBHDSoftWalletSummaryFromEntropy(
applicationDirectory,
entropy,
seed,
nowInSeconds,
passwordToCheck,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.google.common.eventbus.Subscribe;
import com.google.common.util.concurrent.Uninterruptibles;
import org.bitcoinj.core.*;
import org.bitcoinj.crypto.MnemonicCode;
import org.bitcoinj.store.BlockStoreException;
import org.joda.time.DateTime;
import org.junit.Before;
Expand Down Expand Up @@ -107,8 +108,10 @@ public void testSyncSingleWallet() throws Exception {

// Create a wallet from the WALLET_SEED_1_PROPERTY_NAME
SeedPhraseGenerator seedGenerator = new Bip39SeedPhraseGenerator();
byte[] entropy = MnemonicCode.INSTANCE.toEntropy(Bip39SeedPhraseGenerator.split(seedProperties.getProperty(WALLET_SEED_1_PROPERTY_NAME)));

byte[] seed = seedGenerator.convertToSeed(Bip39SeedPhraseGenerator.split(seedProperties.getProperty(WALLET_SEED_1_PROPERTY_NAME)));
WalletSummary walletSummary = createWallet(temporaryDirectory, seed, "Example", "Example");
WalletSummary walletSummary = createWallet(temporaryDirectory, entropy, seed, "Example", "Example");

DateTime timestamp1 = Dates.parseSeedTimestamp(seedProperties.getProperty(WALLET_TIMESTAMP_1_PROPERTY_NAME));

Expand Down Expand Up @@ -144,14 +147,16 @@ public void testSendBetweenTwoRealWallets() throws Exception {

// Create two wallets from the two seeds
SeedPhraseGenerator seedGenerator = new Bip39SeedPhraseGenerator();
byte[] entropy1 = MnemonicCode.INSTANCE.toEntropy(Bip39SeedPhraseGenerator.split(seedProperties.getProperty(WALLET_SEED_1_PROPERTY_NAME)));
byte[] seed1 = seedGenerator.convertToSeed(Bip39SeedPhraseGenerator.split(seedProperties.getProperty(WALLET_SEED_1_PROPERTY_NAME)));
WalletSummary walletSummary1 = createWallet(temporaryDirectory, seed1, "Example", "Example");
WalletSummary walletSummary1 = createWallet(temporaryDirectory, entropy1, seed1, "Example", "Example");
String walletRoot1 = WalletManager.createWalletRoot(walletSummary1.getWalletId());

DateTime timestamp1 = Dates.parseSeedTimestamp(seedProperties.getProperty(WALLET_TIMESTAMP_1_PROPERTY_NAME));

byte[] entropy2 = MnemonicCode.INSTANCE.toEntropy(Bip39SeedPhraseGenerator.split(seedProperties.getProperty(WALLET_SEED_2_PROPERTY_NAME)));
byte[] seed2 = seedGenerator.convertToSeed(Bip39SeedPhraseGenerator.split(seedProperties.getProperty(WALLET_SEED_2_PROPERTY_NAME)));
WalletSummary walletSummary2 = createWallet(temporaryDirectory, seed2, "Example", "Example");
WalletSummary walletSummary2 = createWallet(temporaryDirectory, entropy2, seed2, "Example", "Example");
String walletRoot2 = WalletManager.createWalletRoot(walletSummary2.getWalletId());

DateTime timestamp2 = Dates.parseSeedTimestamp(seedProperties.getProperty(WALLET_TIMESTAMP_2_PROPERTY_NAME));
Expand Down Expand Up @@ -257,12 +262,13 @@ public void onBitcoinNetworkChangedEvent(BitcoinNetworkChangedEvent bitcoinNetwo
}
}

private WalletSummary createWallet(File walletDirectory, byte[] seed, String name, String notes) throws IOException {
private WalletSummary createWallet(File walletDirectory, byte[] entropy, byte[] seed, String name, String notes) throws IOException {

long nowInSeconds = Dates.nowInSeconds();

WalletSummary walletSummary = walletManager.badlyGetOrCreateMBHDSoftWalletSummaryFromSeed(
WalletSummary walletSummary = walletManager.getOrCreateMBHDSoftWalletSummaryFromEntropy(
walletDirectory,
entropy,
seed,
nowInSeconds,
WALLET_PASSWORD,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.google.common.base.Optional;
import org.bitcoinj.core.Wallet;
import org.bitcoinj.crypto.MnemonicCode;
import org.junit.Before;
import org.junit.Ignore;
import org.multibit.hd.brit.dto.FeeState;
Expand Down Expand Up @@ -52,15 +53,17 @@ public void testCreateFeeService() throws Exception {

// Create a wallet from a seed
SeedPhraseGenerator seedGenerator = new Bip39SeedPhraseGenerator();
byte[] entropy = MnemonicCode.INSTANCE.toEntropy(Bip39SeedPhraseGenerator.split(WalletIdTest.SEED_PHRASE_1));
byte[] seed = seedGenerator.convertToSeed(Bip39SeedPhraseGenerator.split(WalletIdTest.SEED_PHRASE_1));

BackupManager.INSTANCE.initialise(temporaryDirectory, Optional.<File>absent());

long nowInSeconds = Dates.nowInSeconds();
WalletSummary walletSummary = WalletManager
.INSTANCE
.badlyGetOrCreateMBHDSoftWalletSummaryFromSeed(
.getOrCreateMBHDSoftWalletSummaryFromEntropy(
temporaryDirectory,
entropy,
seed,
nowInSeconds,
PASSWORD,
Expand Down
Loading

0 comments on commit 3f539f5

Please sign in to comment.