public Wallet(List<String> mnemonic, @Nullable String password) throws MnemonicException { MnemonicCode.INSTANCE.check(mnemonic); password = password == null ? "" : password; seed = new DeterministicSeed(mnemonic, null, password, 0); masterKey = HDKeyDerivation.createMasterPrivateKey(seed.getSeedBytes()); accountsByType = new LinkedHashMap<CoinType, ArrayList<WalletAccount>>(); accounts = new LinkedHashMap<String, WalletAccount>(); }
/** Returns a list of words that represent the seed or null if this chain is a watching chain. */ @Nullable public List<String> getMnemonicCode() { if (seed == null) return null; lock.lock(); try { return seed.getMnemonicCode(); } finally { lock.unlock(); } }
public DeterministicSeed decrypt(KeyCrypter crypter, String passphrase, KeyParameter aesKey) { checkState(isEncrypted()); checkNotNull(encryptedMnemonicCode); List<String> mnemonic = decodeMnemonicCode(crypter.decrypt(encryptedMnemonicCode, aesKey)); byte[] seed = encryptedSeed == null ? null : crypter.decrypt(encryptedSeed, aesKey); return new DeterministicSeed(mnemonic, seed, passphrase, creationTimeSeconds); }
@Override public String toString() { return isEncrypted() ? "DeterministicSeed [encrypted]" : "DeterministicSeed " + toHexString() + " " + Utils.SPACE_JOINER.join(mnemonicCode); }
public String toString(boolean includePrivateKeys, @Nullable KeyParameter aesKey, NetworkParameters params) { final DeterministicKey watchingKey = getWatchingKey(); final StringBuilder builder = new StringBuilder(); if (seed != null) { if (includePrivateKeys) { DeterministicSeed decryptedSeed = seed.isEncrypted() ? seed.decrypt(getKeyCrypter(), DEFAULT_PASSPHRASE_FOR_MNEMONIC, aesKey) : seed; final List<String> words = decryptedSeed.getMnemonicCode(); builder.append("Seed as words: ").append(Utils.SPACE_JOINER.join(words)).append('\n'); builder.append("Seed as hex: ").append(decryptedSeed.toHexString()).append('\n'); } else { if (seed.isEncrypted()) builder.append("Seed is encrypted\n"); } builder.append("Seed birthday: ").append(seed.getCreationTimeSeconds()).append(" [") .append(Utils.dateTimeFormat(seed.getCreationTimeSeconds() * 1000)).append("]\n"); } else { builder.append("Key birthday: ").append(watchingKey.getCreationTimeSeconds()).append(" [") .append(Utils.dateTimeFormat(watchingKey.getCreationTimeSeconds() * 1000)).append("]\n"); } builder.append("Key to watch: ").append(watchingKey.serializePubB58(params)).append('\n'); formatAddresses(includePrivateKeys, aesKey, params, builder); return builder.toString(); }
KeyCrypter crypter = wallet.getKeyCrypter(); aesKey = crypter.deriveKey(password); seed = wallet.getSeed().decrypt(crypter, password.toString(), aesKey); masterKey = wallet.getMasterKey().decrypt(crypter, aesKey); } else { masterKey = wallet.getMasterKey(); checkState(!seed.isEncrypted()); checkState(!masterKey.isEncrypted()); seed = new DeterministicSeed(seed.getMnemonicCode(), null, "", 0); } catch (Exception e) { log.warn("Failed recovering seed."); seedInfo.seedString = Wallet.mnemonicToString(seed.getMnemonicCode()); DeterministicKey testMasterKey = HDKeyDerivation.createMasterPrivateKey(seed.getSeedBytes()); seedInfo.isSeedPasswordProtected = !masterKey.getPrivKey().equals(testMasterKey.getPrivKey());
/** * Generates a new key chain with entropy selected randomly from the given {@link java.security.SecureRandom} * object and of the requested size in bits. The derived seed is further protected with a user selected passphrase * (see BIP 39). */ public DeterministicKeyChain(SecureRandom random, int bits, String passphrase, long seedCreationTimeSecs, boolean useSegwit) { this(new DeterministicSeed(random, bits, passphrase, seedCreationTimeSecs), useSegwit); }
/*package*/ static void serializeSeedEncryptableItem(DeterministicSeed seed, Protos.Key.Builder proto) { // The seed can be missing if we have not derived it yet from the mnemonic. // This will not normally happen once all the wallets are on the latest code that caches // the seed. if (seed.isEncrypted() && seed.getEncryptedSeedData() != null) { EncryptedData data = seed.getEncryptedSeedData(); proto.getEncryptedDeterministicSeedBuilder() .setEncryptedPrivateKey(ByteString.copyFrom(data.encryptedBytes)) .setInitialisationVector(ByteString.copyFrom(data.initialisationVector)); // We don't allow mixing of encryption types at the moment. checkState(seed.getEncryptionType() == Protos.Wallet.EncryptionType.ENCRYPTED_SCRYPT_AES); } else { final byte[] secret = seed.getSeedBytes(); if (secret != null) proto.setDeterministicSeed(ByteString.copyFrom(secret)); } }
/** * For use in {@link KeyChainFactory} during deserialization. */ protected DeterministicKeyChain(DeterministicSeed seed, @Nullable KeyCrypter crypter) { this.seed = seed; basicKeyChain = new BasicKeyChain(crypter); if (!seed.isEncrypted()) { rootKey = HDKeyDerivation.createMasterPrivateKey(checkNotNull(seed.getSeedBytes())); rootKey.setCreationTimeSeconds(seed.getCreationTimeSeconds()); addToBasicChain(rootKey); hierarchy = new DeterministicHierarchy(rootKey); for (int i = 1; i <= getAccountPath().size(); i++) { addToBasicChain(hierarchy.get(getAccountPath().subList(0, i), false, true)); } initializeHierarchyUnencrypted(rootKey); } // Else... // We can't initialize ourselves with just an encrypted seed, so we expected deserialization code to do the // rest of the setup (loading the root key). }
public DeterministicSeed encrypt(KeyCrypter keyCrypter, KeyParameter aesKey) { checkState(encryptedMnemonicCode == null, "Trying to encrypt seed twice"); checkState(mnemonicCode != null, "Mnemonic missing so cannot encrypt"); EncryptedData encryptedMnemonic = keyCrypter.encrypt(getMnemonicAsBytes(), aesKey); EncryptedData encryptedSeed = keyCrypter.encrypt(seed, aesKey); return new DeterministicSeed(encryptedMnemonic, encryptedSeed, creationTimeSeconds); }
/* package */ void decrypt(KeyParameter aesKey) { checkNotNull(aesKey, "Attemting to decrypt with a null KeyParameter"); lock.lock(); try { checkState(isEncrypted(), "Wallet is already decrypted"); if (seed != null) { checkState(seed.isEncrypted(), "Seed is already decrypted"); List<String> mnemonic = null; try { mnemonic = decodeMnemonicCode(getKeyCrypter().decrypt(seed.getEncryptedData(), aesKey)); } catch (UnreadableWalletException e) { throw new RuntimeException(e); } seed = new DeterministicSeed(new byte[16], mnemonic, 0); } masterKey = masterKey.decrypt(getKeyCrypter(), aesKey); for (WalletAccount account : accounts.values()) { if (account.isEncryptable()) { account.decrypt(aesKey); } } } finally { lock.unlock(); } }
@Override public DeterministicKeyChain toDecrypted(KeyParameter aesKey) { checkState(getKeyCrypter() != null, "Key chain not encrypted"); checkState(seed != null, "Can't decrypt a watching chain"); checkState(seed.isEncrypted()); String passphrase = DEFAULT_PASSPHRASE_FOR_MNEMONIC; // FIXME allow non-empty passphrase DeterministicSeed decSeed = seed.decrypt(getKeyCrypter(), passphrase, aesKey); DeterministicKeyChain chain = makeKeyChainFromSeed(decSeed); // Now double check that the keys match to catch the case where the key is wrong but padding didn't catch it. if (!chain.getWatchingKey().getPubKeyPoint().equals(getWatchingKey().getPubKeyPoint())) throw new KeyCrypterException("Provided AES key is wrong"); chain.lookaheadSize = lookaheadSize; // Now copy the (pubkey only) leaf keys across to avoid rederiving them. The private key bytes are missing // anyway so there's nothing to decrypt. for (ECKey eckey : basicKeyChain.getKeys()) { DeterministicKey key = (DeterministicKey) eckey; if (key.getPath().size() != getAccountPath().size() + 2) continue; // Not a leaf key. checkState(key.isEncrypted()); DeterministicKey parent = chain.hierarchy.get(checkNotNull(key.getParent()).getPath(), false, false); // Clone the key to the new decrypted hierarchy. key = new DeterministicKey(key.dropPrivateBytes(), parent); chain.hierarchy.putKey(key); chain.basicKeyChain.importKey(key); } chain.issuedExternalKeys = issuedExternalKeys; chain.issuedInternalKeys = issuedInternalKeys; return chain; }
public static void main(String[] args) { NetworkParameters params = TestNet3Params.get(); Wallet wallet = new Wallet(params); DeterministicSeed seed = wallet.getKeyChainSeed(); System.out.println("seed: " + seed.toString()); System.out.println("creation time: " + seed.getCreationTimeSeconds()); System.out.println("mnemonicCode: " + Utils.join(seed.getMnemonicCode())); } }
private static EthHDWallet createEthWallet(DeterministicSeed ds, String[] pathArray, String password) { byte[] seedBytes = ds.getSeedBytes(); System.out.println("根私钥 " + Arrays.toString(seedBytes)); List<String> mnemonic = ds.getMnemonicCode(); System.out.println("助记词 " + Arrays.toString(mnemonic.toArray()));
@Override public long getEarliestKeyCreationTime() { if (seed != null) return seed.getCreationTimeSeconds(); else return getWatchingKey().getCreationTimeSeconds(); }
@Override public DeterministicKeyChain toEncrypted(CharSequence password) { checkNotNull(password); checkArgument(password.length() > 0); checkState(seed != null, "Attempt to encrypt a watching chain."); checkState(!seed.isEncrypted()); KeyCrypter scrypt = new KeyCrypterScrypt(); KeyParameter derivedKey = scrypt.deriveKey(password); return toEncrypted(scrypt, derivedKey); }
private static void setCreationTime() { DeterministicSeed seed = wallet.getActiveKeyChain().getSeed(); if (seed == null) { System.err.println("Active chain does not have a seed."); return; } long creationTime = getCreationTimeSeconds(); if (creationTime > 0) System.out.println("Setting creation time to: " + Utils.dateTimeFormat(creationTime * 1000)); else System.out.println("Clearing creation time."); seed.setCreationTimeSeconds(creationTime); }
public DeterministicSeed(String mnemonicCode, byte[] seed, String passphrase, long creationTimeSeconds) throws UnreadableWalletException { this(decodeMnemonicCode(mnemonicCode), seed, passphrase, creationTimeSeconds); }
@Test public void deterministicUpgradeEncrypted() throws Exception { group = new KeyChainGroup(PARAMS); final ECKey key = new ECKey(); group.importKeys(key); final KeyCrypterScrypt crypter = new KeyCrypterScrypt(); final KeyParameter aesKey = crypter.deriveKey("abc"); assertTrue(group.isDeterministicUpgradeRequired()); group.encrypt(crypter, aesKey); assertTrue(group.isDeterministicUpgradeRequired()); try { group.upgradeToDeterministic(0, null); fail(); } catch (DeterministicUpgradeRequiresPassword e) { // Expected. } group.upgradeToDeterministic(0, aesKey); assertFalse(group.isDeterministicUpgradeRequired()); final DeterministicSeed deterministicSeed = group.getActiveKeyChain().getSeed(); assertNotNull(deterministicSeed); assertTrue(deterministicSeed.isEncrypted()); byte[] entropy = checkNotNull(group.getActiveKeyChain().toDecrypted(aesKey).getSeed()).getEntropyBytes(); // Check we used the right key: oldest non rotating. byte[] truncatedBytes = Arrays.copyOfRange(key.getSecretBytes(), 0, 16); assertArrayEquals(entropy, truncatedBytes); }
@Test public void fromKeys() { ECKey key = ECKey.fromPrivate(Utils.HEX.decode("00905b93f990267f4104f316261fc10f9f983551f9ef160854f40102eb71cffdcc")); Wallet wallet = Wallet.fromKeys(PARAMS, Arrays.asList(key)); assertEquals(1, wallet.getImportedKeys().size()); assertEquals(key, wallet.getImportedKeys().get(0)); wallet.upgradeToDeterministic(null); String seed = wallet.getKeyChainSeed().toHexString(); assertEquals("5ca8cd6c01aa004d3c5396c628b78a4a89462f412f460a845b594ac42eceaa264b0e14dcd4fe73d4ed08ce06f4c28facfa85042d26d784ab2798a870bb7af556", seed); }