Exemplo n.º 1
0
 /**
  * Return the fingerprint of this key's parent as an int value, or zero if this key is the root
  * node of the key hierarchy. Raise an exception if the arguments are inconsistent. This method
  * exists to avoid code repetition in the constructors.
  */
 private int ascertainParentFingerprint(DeterministicKey parentKey, int parentFingerprint)
     throws IllegalArgumentException {
   if (parentFingerprint != 0) {
     if (parent != null)
       checkArgument(
           parent.getFingerprint() == parentFingerprint,
           "parent fingerprint mismatch",
           Integer.toHexString(parent.getFingerprint()),
           Integer.toHexString(parentFingerprint));
     return parentFingerprint;
   } else return 0;
 }
Exemplo n.º 2
0
 /**
  * Deserialize an HD Key.
  *
  * @param parent The parent node in the given key's deterministic hierarchy.
  */
 public static DeterministicKey deserialize(
     NetworkParameters params, byte[] serializedKey, @Nullable DeterministicKey parent) {
   ByteBuffer buffer = ByteBuffer.wrap(serializedKey);
   int header = buffer.getInt();
   if (header != params.getBip32HeaderPriv() && header != params.getBip32HeaderPub())
     throw new IllegalArgumentException(
         "Unknown header bytes: " + toBase58(serializedKey).substring(0, 4));
   boolean pub = header == params.getBip32HeaderPub();
   int depth =
       buffer.get() & 0xFF; // convert signed byte to positive int since depth cannot be negative
   final int parentFingerprint = buffer.getInt();
   final int i = buffer.getInt();
   final ChildNumber childNumber = new ChildNumber(i);
   ImmutableList<ChildNumber> path;
   if (parent != null) {
     if (parentFingerprint == 0)
       throw new IllegalArgumentException("Parent was provided but this key doesn't have one");
     if (parent.getFingerprint() != parentFingerprint)
       throw new IllegalArgumentException("Parent fingerprints don't match");
     path = HDUtils.append(parent.getPath(), childNumber);
     if (path.size() != depth) throw new IllegalArgumentException("Depth does not match");
   } else {
     if (depth >= 1)
       // We have been given a key that is not a root key, yet we lack the object representing the
       // parent.
       // This can happen when deserializing an account key for a watching wallet.  In this case,
       // we assume that
       // the client wants to conceal the key's position in the hierarchy.  The path is truncated
       // at the
       // parent's node.
       path = ImmutableList.of(childNumber);
     else path = ImmutableList.of();
   }
   byte[] chainCode = new byte[32];
   buffer.get(chainCode);
   byte[] data = new byte[33];
   buffer.get(data);
   checkArgument(!buffer.hasRemaining(), "Found unexpected data in key");
   if (pub) {
     return new DeterministicKey(
         path,
         chainCode,
         new LazyECPoint(ECKey.CURVE.getCurve(), data),
         parent,
         depth,
         parentFingerprint);
   } else {
     return new DeterministicKey(
         path, chainCode, new BigInteger(1, data), parent, depth, parentFingerprint);
   }
 }
Exemplo n.º 3
0
 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;
 }
Exemplo n.º 4
0
 @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;
 }
Exemplo n.º 5
0
  public static List<TransactionOutput> getMyOutputs(Transaction tx, DeterministicKey key) {
    List<TransactionOutput> mines = new ArrayList<>();
    for (TransactionOutput curr : tx.getOutputs()) {
      boolean isMine = false;

      String to = null;
      Address add = curr.getAddressFromP2PKHScript(BitcoinNetwork.getInstance().get().getParams());
      if (add != null) to = add.toString();
      else {
        add = curr.getAddressFromP2SH(BitcoinNetwork.getInstance().get().getParams());
        if (add != null) to = add.toString();
      }
      if (to != null) { // VERIFICATION BY ADDRESS
        isMine = to.equals(keyToStringAddress(key));
      } else { // VERIFICATION BY PUBKEY
        final byte[] pubKeyCurr = curr.getScriptPubKey().getPubKey();
        isMine = Arrays.equals(key.getPubKey(), pubKeyCurr);
      }

      if (isMine) {
        mines.add(curr);
        break;
      }
    }
    return mines;
  }
Exemplo n.º 6
0
 /**
  * Returns this keys {@link org.bitcoinj.crypto.KeyCrypter} <b>or</b> the keycrypter of its parent
  * key.
  */
 @Override
 @Nullable
 public KeyCrypter getKeyCrypter() {
   if (keyCrypter != null) return keyCrypter;
   else if (parent != null) return parent.getKeyCrypter();
   else return null;
 }
 private void checkEncryptedKeyChain(SimpleHDKeyChain encChain, DeterministicKey key1) {
   // Check we can look keys up and extend the chain without the AES key being provided.
   DeterministicKey encKey1 = encChain.findKeyFromPubKey(key1.getPubKey());
   DeterministicKey encKey2 = encChain.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
   assertFalse(key1.isEncrypted());
   assertTrue(encKey1.isEncrypted());
   assertEquals(encKey1.getPubKeyPoint(), key1.getPubKeyPoint());
   final KeyParameter aesKey = checkNotNull(encChain.getKeyCrypter()).deriveKey("open secret");
   encKey1.sign(Sha256Hash.ZERO_HASH, aesKey);
   encKey2.sign(Sha256Hash.ZERO_HASH, aesKey);
   assertTrue(encChain.checkAESKey(aesKey));
   assertFalse(encChain.checkPassword("access denied"));
   assertTrue(encChain.checkPassword("open secret"));
 }
Exemplo n.º 8
0
 /** Constructs a key from its components. This is not normally something you should use. */
 public DeterministicKey(
     ImmutableList<ChildNumber> childNumberPath,
     byte[] chainCode,
     BigInteger priv,
     @Nullable DeterministicKey parent) {
   super(priv, compressPoint(ECKey.publicPointFromPrivate(priv)));
   checkArgument(chainCode.length == 32);
   this.parent = parent;
   this.childNumberPath = checkNotNull(childNumberPath);
   this.chainCode = Arrays.copyOf(chainCode, chainCode.length);
   this.depth = this.childNumberPath.size();
   this.parentFingerprint = (parent != null) ? parent.getFingerprint() : 0;
 }
Exemplo n.º 9
0
 private BigInteger derivePrivateKeyDownwards(
     DeterministicKey cursor, byte[] parentalPrivateKeyBytes) {
   DeterministicKey downCursor =
       new DeterministicKey(
           cursor.childNumberPath,
           cursor.chainCode,
           cursor.pub,
           new BigInteger(1, parentalPrivateKeyBytes),
           cursor.parent);
   // Now we have to rederive the keys along the path back to ourselves. That path can be found by
   // just truncating
   // our path with the length of the parents path.
   ImmutableList<ChildNumber> path =
       childNumberPath.subList(cursor.getPath().size(), childNumberPath.size());
   for (ChildNumber num : path) {
     downCursor = HDKeyDerivation.deriveChildKey(downCursor, num);
   }
   // downCursor is now the same key as us, but with private key bytes.
   checkState(downCursor.pub.equals(pub));
   return checkNotNull(downCursor.priv);
 }
  @Test
  public void testRoundTripMarriedWallet() throws Exception {
    // create 2-of-2 married wallet
    myWallet = new Wallet(params);
    final DeterministicKeyChain partnerChain = new DeterministicKeyChain(new SecureRandom());
    DeterministicKey partnerKey =
        DeterministicKey.deserializeB58(
            null, partnerChain.getWatchingKey().serializePubB58(params), params);
    MarriedKeyChain chain =
        MarriedKeyChain.builder()
            .random(new SecureRandom())
            .followingKeys(partnerKey)
            .threshold(2)
            .build();
    myWallet.addAndActivateHDChain(chain);

    myAddress = myWallet.currentAddress(KeyChain.KeyPurpose.RECEIVE_FUNDS);

    Wallet wallet1 = roundTrip(myWallet);
    assertEquals(0, wallet1.getTransactions(true).size());
    assertEquals(Coin.ZERO, wallet1.getBalance());
    assertEquals(2, wallet1.getActiveKeyChain().getSigsRequiredToSpend());
    assertEquals(myAddress, wallet1.currentAddress(KeyChain.KeyPurpose.RECEIVE_FUNDS));
  }
  public void serializeUnencrypted(SimpleHDKeyChain keyChain, String expectedSerialization)
      throws UnreadableWalletException {
    keyChain.setLookaheadSize(10);

    keyChain.maybeLookAhead();
    DeterministicKey key1 = keyChain.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
    DeterministicKey key2 = keyChain.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
    DeterministicKey key3 = keyChain.getKey(KeyChain.KeyPurpose.CHANGE);
    List<Protos.Key> keys = keyChain.toProtobuf();
    // 1 master key, 1 account key, 2 internal keys, 3 derived, 20 lookahead and 5 lookahead
    // threshold.
    int numItems =
        1 // master key/account key
            + 2 // ext/int parent keys
            + (keyChain.getLookaheadSize() + keyChain.getLookaheadThreshold())
                * 2 // lookahead zone on each chain
        ;
    assertEquals(numItems, keys.size());

    // Get another key that will be lost during round-tripping, to ensure we can derive it again.
    DeterministicKey key4 = keyChain.getKey(KeyChain.KeyPurpose.CHANGE);

    String sb = protoToString(keys);
    assertEquals(expectedSerialization, sb);

    // Round trip the data back and forth to check it is preserved.
    int oldLookaheadSize = keyChain.getLookaheadSize();
    keyChain = SimpleHDKeyChain.fromProtobuf(keys, null);
    assertEquals(expectedSerialization, protoToString(keyChain.toProtobuf()));
    assertEquals(key1, keyChain.findKeyFromPubHash(key1.getPubKeyHash()));
    assertEquals(key2, keyChain.findKeyFromPubHash(key2.getPubKeyHash()));
    assertEquals(key3, keyChain.findKeyFromPubHash(key3.getPubKeyHash()));
    assertEquals(key4, keyChain.getKey(KeyChain.KeyPurpose.CHANGE));
    key1.sign(Sha256Hash.ZERO_HASH);
    key2.sign(Sha256Hash.ZERO_HASH);
    key3.sign(Sha256Hash.ZERO_HASH);
    key4.sign(Sha256Hash.ZERO_HASH);
    assertEquals(oldLookaheadSize, keyChain.getLookaheadSize());
  }
Exemplo n.º 12
0
 /**
  * The creation time of a deterministic key is equal to that of its parent, unless this key is the
  * root of a tree in which case the time is stored alongside the key as per normal, see {@link
  * org.bitcoinj.core.ECKey#getCreationTimeSeconds()}.
  */
 @Override
 public long getCreationTimeSeconds() {
   if (parent != null) return parent.getCreationTimeSeconds();
   else return super.getCreationTimeSeconds();
 }
 @Override
 public ListenableFuture<ECKey.ECDSASignature> signHash(final Sha256Hash hash) {
   return Futures.immediateFuture(ECKey.fromPrivate(hdWallet.getPrivKey()).sign(hash));
 }
Exemplo n.º 14
0
 /**
  * A deterministic key is considered to be encrypted if it has access to encrypted private key
  * bytes, OR if its parent does. The reason is because the parent would be encrypted under the
  * same key and this key knows how to rederive its own private key bytes from the parent, if
  * needed.
  */
 @Override
 public boolean isEncrypted() {
   return priv == null && (super.isEncrypted() || (parent != null && parent.isEncrypted()));
 }
Exemplo n.º 15
0
 /**
  * A deterministic key is considered to be 'public key only' if it hasn't got a private key part
  * and it cannot be rederived. If the hierarchy is encrypted this returns true.
  */
 @Override
 public boolean isPubKeyOnly() {
   return super.isPubKeyOnly() && (parent == null || parent.isPubKeyOnly());
 }
Exemplo n.º 16
0
 /**
  * Returns the same key with the parent pointer removed (it still knows its own path and the
  * parent fingerprint).
  *
  * <p>If this key doesn't have private key bytes stored/cached itself, but could rederive them
  * from the parent, then the new key returned by this method won't be able to do that. Thus, using
  * dropPrivateBytes().dropParent() on a regular DeterministicKey will yield a new DeterministicKey
  * that cannot sign or do other things involving the private key at all.
  */
 public DeterministicKey dropParent() {
   DeterministicKey key = new DeterministicKey(getPath(), getChainCode(), pub, priv, null);
   key.parentFingerprint = parentFingerprint;
   return key;
 }
  public void encryption(SimpleHDKeyChain unencChain) throws UnreadableWalletException {
    DeterministicKey key1 = unencChain.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
    SimpleHDKeyChain encChain = unencChain.toEncrypted("open secret");
    DeterministicKey encKey1 = encChain.findKeyFromPubKey(key1.getPubKey());
    checkEncryptedKeyChain(encChain, key1);

    // Round-trip to ensure de/serialization works and that we can store two chains and they both
    // deserialize.
    List<Protos.Key> serialized = encChain.toProtobuf();
    System.out.println(protoToString(serialized));
    encChain = SimpleHDKeyChain.fromProtobuf(serialized, encChain.getKeyCrypter());
    checkEncryptedKeyChain(encChain, unencChain.findKeyFromPubKey(key1.getPubKey()));

    DeterministicKey encKey2 = encChain.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
    // Decrypt and check the keys match.
    SimpleHDKeyChain decChain = encChain.toDecrypted("open secret");
    DeterministicKey decKey1 = decChain.findKeyFromPubHash(encKey1.getPubKeyHash());
    DeterministicKey decKey2 = decChain.findKeyFromPubHash(encKey2.getPubKeyHash());
    assertEquals(decKey1.getPubKeyPoint(), encKey1.getPubKeyPoint());
    assertEquals(decKey2.getPubKeyPoint(), encKey2.getPubKeyPoint());
    assertFalse(decKey1.isEncrypted());
    assertFalse(decKey2.isEncrypted());
    assertNotEquals(encKey1.getParent(), decKey1.getParent()); // parts of a different hierarchy
    // Check we can once again derive keys from the decrypted chain.
    decChain.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS).sign(Sha256Hash.ZERO_HASH);
    decChain.getKey(KeyChain.KeyPurpose.CHANGE).sign(Sha256Hash.ZERO_HASH);
  }
 @Override
 public ListenableFuture<byte[]> getIdentifier() {
   return Futures.immediateFuture(hdWallet.getIdentifier());
 }