/** * Creates a wallet that tracks payments to and from the HD key hierarchy rooted by the given watching key. A * watching key corresponds to account zero in the recommended BIP32 key hierarchy. The key is specified in base58 * notation and the creation time of the key. If you don't know the creation time, you can pass * {@link DeterministicHierarchy#BIP32_STANDARDISATION_TIME_SECS}. */ public static Wallet fromWatchingKeyB58(NetworkParameters params, String watchKeyB58, long creationTimeSeconds) { final DeterministicKey watchKey = DeterministicKey.deserializeB58(null, watchKeyB58, params); watchKey.setCreationTimeSeconds(creationTimeSeconds); return fromWatchingKey(params, watchKey); }
@Override public void formatKeyWithAddress(boolean includePrivateKeys, StringBuilder builder, NetworkParameters params) { final Address address = toAddress(params); builder.append(" addr:").append(address); builder.append(" hash160:").append(Utils.HEX.encode(getPubKeyHash())); builder.append(" (").append(getPathAsString()).append(")\n"); if (includePrivateKeys) { builder.append(" ").append(toStringWithPrivate(params)).append("\n"); } } }
public DeterministicKey encrypt(KeyCrypter keyCrypter, KeyParameter aesKey, @Nullable DeterministicKey newParent) throws KeyCrypterException { // Same as the parent code, except we construct a DeterministicKey instead of an ECKey. checkNotNull(keyCrypter); if (newParent != null) checkArgument(newParent.isEncrypted()); final byte[] privKeyBytes = getPrivKeyBytes(); checkState(privKeyBytes != null, "Private key is not available"); EncryptedData encryptedPrivateKey = keyCrypter.encrypt(privKeyBytes, aesKey); DeterministicKey key = new DeterministicKey(childNumberPath, chainCode, keyCrypter, pub, encryptedPrivateKey, newParent); if (newParent == null) key.setCreationTimeSeconds(getCreationTimeSeconds()); return key; }
public NxtFamilyKey(DeterministicKey entropy, @Nullable KeyCrypter keyCrypter, @Nullable KeyParameter key) { checkArgument(!entropy.isEncrypted(), "Entropy must not be encrypted"); this.publicKey = Crypto.getPublicKey(entropy.getPrivKeyBytes()); // Encrypt entropy if needed if (keyCrypter != null && key != null) { this.entropy = entropy.encrypt(keyCrypter, key, entropy.getParent()); } else { this.entropy = entropy; } }
private byte[] serialize(NetworkParameters params, boolean pub) { ByteBuffer ser = ByteBuffer.allocate(78); ser.putInt(pub ? params.getBip32HeaderPub() : params.getBip32HeaderPriv()); ser.put((byte) getDepth()); ser.putInt(getParentFingerprint()); ser.putInt(getChildNumber().i()); ser.put(getChainCode()); ser.put(pub ? getPubKey() : getPrivKeyBytes33()); checkState(ser.position() == 78); return ser.array(); }
public static RawKeyBytes deriveChildKeyBytesFromPrivate(DeterministicKey parent, ChildNumber childNumber) throws HDDerivationException { checkArgument(parent.hasPrivKey(), "Parent key must have private key bytes for this method."); byte[] parentPublicKey = parent.getPubKeyPoint().getEncoded(true); checkState(parentPublicKey.length == 33, "Parent pubkey must be 33 bytes, but is " + parentPublicKey.length); ByteBuffer data = ByteBuffer.allocate(37); if (childNumber.isHardened()) { data.put(parent.getPrivKeyBytes33()); } else { data.put(parentPublicKey); } data.putInt(childNumber.i()); byte[] i = HDUtils.hmacSha512(parent.getChainCode(), data.array()); checkState(i.length == 64, i.length); byte[] il = Arrays.copyOfRange(i, 0, 32); byte[] chainCode = Arrays.copyOfRange(i, 32, 64); BigInteger ilInt = new BigInteger(1, il); assertLessThanN(ilInt, "Illegal derived key: I_L >= n"); final BigInteger priv = parent.getPrivKey(); BigInteger ki = priv.add(ilInt).mod(ECKey.CURVE.getN()); assertNonZero(ki, "Illegal derived key: derived private key equals 0."); return new RawKeyBytes(ki.toByteArray(), chainCode); }
@Override public DeterministicKey decrypt(KeyCrypter keyCrypter, KeyParameter aesKey) throws KeyCrypterException { checkNotNull(keyCrypter); // Check that the keyCrypter matches the one used to encrypt the keys, if set. if (this.keyCrypter != null && !this.keyCrypter.equals(keyCrypter)) throw new KeyCrypterException("The keyCrypter being used to decrypt the key is different to the one that was used to encrypt it"); BigInteger privKey = findOrDeriveEncryptedPrivateKey(keyCrypter, aesKey); DeterministicKey key = new DeterministicKey(childNumberPath, chainCode, privKey, parent); if (!Arrays.equals(key.getPubKey(), getPubKey())) throw new KeyCrypterException("Provided AES key is wrong"); if (parent == null) key.setCreationTimeSeconds(getCreationTimeSeconds()); return key; }
/** * Pre-generate enough keys to reach the lookahead size, but only if there are more than the lookaheadThreshold to * be generated, so that the Bloom filter does not have to be regenerated that often. * * The returned mutable list of keys must be inserted into the basic key chain. */ private List<DeterministicKey> maybeLookAhead(DeterministicKey parent, int issued, int lookaheadSize, int lookaheadThreshold) { checkState(lock.isHeldByCurrentThread()); final int numChildren = hierarchy.getNumChildren(parent.getPath()); final int needed = issued + lookaheadSize + lookaheadThreshold - numChildren; if (needed <= lookaheadThreshold) return new ArrayList<DeterministicKey>(); log.info("{} keys needed for {} = {} issued + {} lookahead size + {} lookahead threshold - {} num children", needed, parent.getPathAsString(), issued, lookaheadSize, lookaheadThreshold, numChildren); List<DeterministicKey> result = new ArrayList<DeterministicKey>(needed); final Stopwatch watch = Stopwatch.createStarted(); int nextChild = numChildren; for (int i = 0; i < needed; i++) { DeterministicKey key = HDKeyDerivation.deriveThisOrNextChildKey(parent, nextChild); key = key.dropPrivateBytes(); hierarchy.putKey(key); result.add(key); nextChild = key.getChildNumber().num() + 1; } watch.stop(); log.info("Took {}", watch); return result; }
@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; }
@Override public String toString() { final MoreObjects.ToStringHelper helper = MoreObjects.toStringHelper(this).omitNullValues(); helper.add("pub", Utils.HEX.encode(pub.getEncoded())); helper.add("chainCode", HEX.encode(chainCode)); helper.add("path", getPathAsString()); if (creationTimeSeconds > 0) helper.add("creationTimeSeconds", creationTimeSeconds); helper.add("isEncrypted", isEncrypted()); helper.add("isPubKeyOnly", isPubKeyOnly()); return helper.toString(); }
/** * Constructor an HD address. * * @param params NetworkParameters * @param cKey deterministic key for this address * @param child index of this address in its chain */ public HDAddress(NetworkParameters params, DeterministicKey cKey, int child) { this.params = params; childNum = child; DeterministicKey dk = HDKeyDerivation.deriveChildKey(cKey, new ChildNumber(childNum, false)); // compressed WIF private key format if (dk.hasPrivKey()) { byte[] prepended0Byte = ArrayUtils.addAll(new byte[1], dk.getPrivKeyBytes()); ecKey = ECKey.fromPrivate(new BigInteger(prepended0Byte), true); } else { ecKey = ECKey.fromPublicOnly(dk.getPubKey()); } long now = Utils.now().getTime() / 1000; // use Unix time (in seconds) ecKey.setCreationTimeSeconds(now); pubKey = ecKey.getPubKey(); pubKeyHash = ecKey.getPubKeyHash(); strPath = dk.getPathAsString(); }
@Override public boolean checkAESKey(KeyParameter aesKey) { checkNotNull(aesKey, "Cannot check null KeyParameter"); checkState(getKeyCrypter() != null, "Key chain not encrypted"); try { return rootKey.decrypt(aesKey).getPubKeyPoint().equals(rootKey.getPubKeyPoint()); } catch (KeyCrypterException e) { return false; } }
private void checkForBitFlip(DeterministicKey k) { DeterministicKey parent = checkNotNull(k.getParent()); byte[] rederived = HDKeyDerivation.deriveChildKeyBytesFromPublic(parent, k.getChildNumber(), HDKeyDerivation.PublicDeriveMode.WITH_INVERSION).keyBytes; byte[] actual = k.getPubKey(); if (!Arrays.equals(rederived, actual)) throw new IllegalStateException(String.format(Locale.US, "Bit-flip check failed: %s vs %s", Arrays.toString(rederived), Arrays.toString(actual))); }
aesKey = crypter.deriveKey(password); seed = wallet.getSeed().decrypt(crypter, password.toString(), aesKey); masterKey = wallet.getMasterKey().decrypt(crypter, aesKey); } else { masterKey = wallet.getMasterKey(); checkState(!masterKey.isEncrypted()); seedInfo.seedString = Wallet.mnemonicToString(seed.getMnemonicCode()); DeterministicKey testMasterKey = HDKeyDerivation.createMasterPrivateKey(seed.getSeedBytes()); seedInfo.isSeedPasswordProtected = !masterKey.getPrivKey().equals(testMasterKey.getPrivKey());
public boolean isEncrypted() { lock.lock(); try { return masterKey.isEncrypted(); } finally { lock.unlock(); } }
/** * Returns private key bytes, padded with zeros to 33 bytes. * @throws java.lang.IllegalStateException if the private key bytes are missing. */ public byte[] getPrivKeyBytes33() { byte[] bytes33 = new byte[33]; byte[] priv = getPrivKeyBytes(); System.arraycopy(priv, 0, bytes33, 33 - priv.length, priv.length); return bytes33; }
@Override public boolean checkAESKey(KeyParameter aesKey) { checkNotNull(aesKey, "Cannot check null KeyParameter"); checkNotNull(getKeyCrypter(), "Key not encrypted"); try { return Arrays.equals(publicKey, Crypto.getPublicKey(entropy.decrypt(aesKey).getPrivKeyBytes())); } catch (KeyCrypterException e) { return false; } }
@Test public void pubOnlyDerivation() throws Exception { DeterministicKey key1 = HDKeyDerivation.createMasterPrivateKey("satoshi lives!".getBytes()); assertFalse(key1.isPubKeyOnly()); DeterministicKey key2 = HDKeyDerivation.deriveChildKey(key1, ChildNumber.ZERO_HARDENED); assertFalse(key2.isPubKeyOnly()); DeterministicKey key3 = HDKeyDerivation.deriveChildKey(key2, ChildNumber.ZERO); assertFalse(key3.isPubKeyOnly()); key2 = key2.dropPrivateBytes(); assertFalse(key2.isPubKeyOnly()); // still got private key bytes from the parents! // pubkey2 got its cached private key bytes (if any) dropped, and now it'll lose its parent too, so now it // becomes a true pubkey-only object. DeterministicKey pubkey2 = key2.dropParent(); DeterministicKey pubkey3 = HDKeyDerivation.deriveChildKey(pubkey2, ChildNumber.ZERO); assertTrue(pubkey3.isPubKeyOnly()); assertEquals(key3.getPubKeyPoint(), pubkey3.getPubKeyPoint()); }
public String encryptFor(String xpub, String payload) throws UnsupportedEncodingException, InvalidCipherTextException { ECKey myKey = getNode(); DeterministicKey otherKey = DeterministicKey.deserializeB58(null, xpub, PersistentUrls.getInstance().getCurrentNetworkParams()); byte[] sharedSecret = otherKey.getPubKeyPoint().multiply(myKey.getPrivKey()).getEncoded(); byte[] sharedKey = Sha256Hash.hash(sharedSecret); return new String(AESUtil.encryptWithKey(sharedKey, payload)); }
/** Deserialize a base-58-encoded HD Key with no parent */ public static DeterministicKey deserializeB58(String base58, NetworkParameters params) { return deserializeB58(null, base58, params); }