Beispiel #1
0
 @Test
 public void bloom() throws Exception {
   ECKey key1 = group.freshKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
   ECKey key2 = new ECKey();
   BloomFilter filter =
       group.getBloomFilter(
           group.getBloomFilterElementCount(), 0.001, (long) (Math.random() * Long.MAX_VALUE));
   assertTrue(filter.contains(key1.getPubKeyHash()));
   assertTrue(filter.contains(key1.getPubKey()));
   assertFalse(filter.contains(key2.getPubKey()));
   // Check that the filter contains the lookahead buffer and threshold zone.
   for (int i = 0; i < LOOKAHEAD_SIZE + group.getLookaheadThreshold(); i++) {
     ECKey k = group.freshKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
     assertTrue(filter.contains(k.getPubKeyHash()));
   }
   // We ran ahead of the lookahead buffer.
   assertFalse(filter.contains(group.freshKey(KeyChain.KeyPurpose.RECEIVE_FUNDS).getPubKey()));
   group.importKeys(key2);
   filter =
       group.getBloomFilter(
           group.getBloomFilterElementCount(), 0.001, (long) (Math.random() * Long.MAX_VALUE));
   assertTrue(filter.contains(key1.getPubKeyHash()));
   assertTrue(filter.contains(key1.getPubKey()));
   assertTrue(filter.contains(key2.getPubKey()));
 }
Beispiel #2
0
  @Test
  public void deterministicUpgradeUnencrypted() throws Exception {
    // Check that a group that contains only random keys has its HD chain created using the private
    // key bytes of
    // the oldest random key, so upgrading the same wallet twice gives the same outcome.
    group = new KeyChainGroup(params);
    group.setLookaheadSize(LOOKAHEAD_SIZE); // Don't want slow tests.
    ECKey key1 = new ECKey();
    Utils.rollMockClock(86400);
    ECKey key2 = new ECKey();
    group.importKeys(key2, key1);

    List<Protos.Key> protobufs = group.serializeToProtobuf();
    group.upgradeToDeterministic(0, null);
    assertFalse(group.isDeterministicUpgradeRequired());
    DeterministicKey dkey1 = group.freshKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
    DeterministicSeed seed1 = group.getActiveKeyChain().getSeed();
    assertNotNull(seed1);

    group = KeyChainGroup.fromProtobufUnencrypted(params, protobufs);
    group.upgradeToDeterministic(0, null); // Should give same result as last time.
    DeterministicKey dkey2 = group.freshKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
    DeterministicSeed seed2 = group.getActiveKeyChain().getSeed();
    assertEquals(seed1, seed2);
    assertEquals(dkey1, dkey2);

    // Check we used the right (oldest) key despite backwards import order.
    byte[] truncatedBytes = Arrays.copyOfRange(key1.getSecretBytes(), 0, 16);
    assertArrayEquals(seed1.getEntropyBytes(), truncatedBytes);
  }
Beispiel #3
0
 @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);
 }
Beispiel #4
0
  private void loadWalletFromProtobuf() {
    if (walletFile.exists()) {
      final long start = System.currentTimeMillis();

      FileInputStream walletStream = null;

      try {
        walletStream = new FileInputStream(walletFile);

        wallet = new WalletProtobufSerializer().readWallet(walletStream);

        log.info(
            "wallet loaded from: '"
                + walletFile
                + "', took "
                + (System.currentTimeMillis() - start)
                + "ms");
      } catch (final FileNotFoundException x) {
        log.error("problem loading wallet", x);

        Toast.makeText(WalletApplication.this, x.getClass().getName(), Toast.LENGTH_LONG).show();

        wallet = restoreWalletFromBackup();
      } catch (final UnreadableWalletException x) {
        log.error("problem loading wallet", x);

        Toast.makeText(WalletApplication.this, x.getClass().getName(), Toast.LENGTH_LONG).show();

        wallet = restoreWalletFromBackup();
      } finally {
        if (walletStream != null) {
          try {
            walletStream.close();
          } catch (final IOException x) {
            // swallow
          }
        }
      }

      if (!wallet.isConsistent()) {
        Toast.makeText(this, "inconsistent wallet: " + walletFile, Toast.LENGTH_LONG).show();

        wallet = restoreWalletFromBackup();
      }

      if (!wallet.getParams().equals(Constants.NETWORK_PARAMETERS))
        throw new Error("bad wallet network parameters: " + wallet.getParams().getId());
    } else {
      wallet = new Wallet(Constants.NETWORK_PARAMETERS);

      log.info("new wallet created");
    }

    // this check is needed so encrypted wallets won't get their private keys removed accidently
    for (final ECKey key : wallet.getKeys())
      if (key.getPrivKeyBytes() == null)
        throw new Error(
            "found read-only key, but wallet is likely an encrypted wallet from the future");
  }
Beispiel #5
0
  @Test
  public void testCreateMultiSigInputScript() throws AddressFormatException {
    // Setup transaction and signatures
    ECKey key1 =
        new DumpedPrivateKey(params, "cVLwRLTvz3BxDAWkvS3yzT9pUcTCup7kQnfT2smRjvmmm1wAP6QT")
            .getKey();
    ECKey key2 =
        new DumpedPrivateKey(params, "cTine92s8GLpVqvebi8rYce3FrUYq78ZGQffBYCS1HmDPJdSTxUo")
            .getKey();
    ECKey key3 =
        new DumpedPrivateKey(params, "cVHwXSPRZmL9adctwBwmn4oTZdZMbaCsR5XF6VznqMgcvt1FDDxg")
            .getKey();
    Script multisigScript =
        ScriptBuilder.createMultiSigOutputScript(2, Arrays.asList(key1, key2, key3));
    byte[] bytes =
        Hex.decode(
            "01000000013df681ff83b43b6585fa32dd0e12b0b502e6481e04ee52ff0fdaf55a16a4ef61000000006b483045022100a84acca7906c13c5895a1314c165d33621cdcf8696145080895cbf301119b7cf0220730ff511106aa0e0a8570ff00ee57d7a6f24e30f592a10cae1deffac9e13b990012102b8d567bcd6328fd48a429f9cf4b315b859a58fd28c5088ef3cb1d98125fc4e8dffffffff02364f1c00000000001976a91439a02793b418de8ec748dd75382656453dc99bcb88ac40420f000000000017a9145780b80be32e117f675d6e0ada13ba799bf248e98700000000");
    Transaction transaction = new Transaction(params, bytes);
    TransactionOutput output = transaction.getOutput(1);
    Transaction spendTx = new Transaction(params);
    Address address = new Address(params, "n3CFiCmBXVt5d3HXKQ15EFZyhPz4yj5F3H");
    Script outputScript = ScriptBuilder.createOutputScript(address);
    spendTx.addOutput(output.getValue(), outputScript);
    spendTx.addInput(output);
    Sha256Hash sighash = spendTx.hashForSignature(0, multisigScript, SigHash.ALL, false);
    ECKey.ECDSASignature party1Signature = key1.sign(sighash);
    ECKey.ECDSASignature party2Signature = key2.sign(sighash);
    TransactionSignature party1TransactionSignature =
        new TransactionSignature(party1Signature, SigHash.ALL, false);
    TransactionSignature party2TransactionSignature =
        new TransactionSignature(party2Signature, SigHash.ALL, false);

    // Create p2sh multisig input script
    Script inputScript =
        ScriptBuilder.createP2SHMultiSigInputScript(
            ImmutableList.of(party1TransactionSignature, party2TransactionSignature),
            multisigScript.getProgram());

    // Assert that the input script contains 4 chunks
    assertTrue(inputScript.getChunks().size() == 4);

    // Assert that the input script created contains the original multisig
    // script as the last chunk
    ScriptChunk scriptChunk = inputScript.getChunks().get(inputScript.getChunks().size() - 1);
    Assert.assertArrayEquals(scriptChunk.data, multisigScript.getProgram());

    // Create regular multisig input script
    inputScript =
        ScriptBuilder.createMultiSigInputScript(
            ImmutableList.of(party1TransactionSignature, party2TransactionSignature));

    // Assert that the input script only contains 3 chunks
    assertTrue(inputScript.getChunks().size() == 3);

    // Assert that the input script created does not end with the original
    // multisig script
    scriptChunk = inputScript.getChunks().get(inputScript.getChunks().size() - 1);
    Assert.assertThat(scriptChunk.data, IsNot.not(IsEqual.equalTo(multisigScript.getProgram())));
  }
 /**
  * Creates the initial multisig contract and incomplete refund transaction which can be requested
  * at the appropriate time using {@link PaymentChannelClientState#getIncompleteRefundTransaction}
  * and {@link PaymentChannelClientState#getMultisigContract()}. The way the contract is crafted
  * can be adjusted by overriding {@link
  * PaymentChannelClientState#editContractSendRequest(com.google.bitcoin.core.Wallet.SendRequest)}.
  * By default unconfirmed coins are allowed to be used, as for micropayments the risk should be
  * relatively low.
  *
  * @throws ValueOutOfRangeException if the value being used is too small to be accepted by the
  *     network
  * @throws InsufficientMoneyException if the wallet doesn't contain enough balance to initiate
  */
 public synchronized void initiate() throws ValueOutOfRangeException, InsufficientMoneyException {
   final NetworkParameters params = wallet.getParams();
   Transaction template = new Transaction(params);
   // We always place the client key before the server key because, if either side wants some
   // privacy, they can
   // use a fresh key for the the multisig contract and nowhere else
   List<ECKey> keys = Lists.newArrayList(myKey, serverMultisigKey);
   // There is also probably a change output, but we don't bother shuffling them as it's obvious
   // from the
   // format which one is the change. If we start obfuscating the change output better in future
   // this may
   // be worth revisiting.
   TransactionOutput multisigOutput =
       template.addOutput(totalValue, ScriptBuilder.createMultiSigOutputScript(2, keys));
   if (multisigOutput.getMinNonDustValue().compareTo(totalValue) > 0)
     throw new ValueOutOfRangeException("totalValue too small to use");
   Wallet.SendRequest req = Wallet.SendRequest.forTx(template);
   req.coinSelector = AllowUnconfirmedCoinSelector.get();
   editContractSendRequest(req);
   req.shuffleOutputs = false; // TODO: Fix things so shuffling is usable.
   wallet.completeTx(req);
   Coin multisigFee = req.tx.getFee();
   multisigContract = req.tx;
   // Build a refund transaction that protects us in the case of a bad server that's just trying to
   // cause havoc
   // by locking up peoples money (perhaps as a precursor to a ransom attempt). We time lock it so
   // the server
   // has an assurance that we cannot take back our money by claiming a refund before the channel
   // closes - this
   // relies on the fact that since Bitcoin 0.8 time locked transactions are non-final. This will
   // need to change
   // in future as it breaks the intended design of timelocking/tx replacement, but for now it
   // simplifies this
   // specific protocol somewhat.
   refundTx = new Transaction(params);
   refundTx
       .addInput(multisigOutput)
       .setSequenceNumber(0); // Allow replacement when it's eventually reactivated.
   refundTx.setLockTime(expiryTime);
   if (totalValue.compareTo(Coin.CENT) < 0) {
     // Must pay min fee.
     final Coin valueAfterFee = totalValue.subtract(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE);
     if (Transaction.MIN_NONDUST_OUTPUT.compareTo(valueAfterFee) > 0)
       throw new ValueOutOfRangeException("totalValue too small to use");
     refundTx.addOutput(valueAfterFee, myKey.toAddress(params));
     refundFees = multisigFee.add(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE);
   } else {
     refundTx.addOutput(totalValue, myKey.toAddress(params));
     refundFees = multisigFee;
   }
   refundTx.getConfidence().setSource(TransactionConfidence.Source.SELF);
   log.info(
       "initiated channel with multi-sig contract {}, refund {}",
       multisigContract.getHashAsString(),
       refundTx.getHashAsString());
   state = State.INITIATED;
   // Client should now call getIncompleteRefundTransaction() and send it to the server.
 }
 public static ECKey getEncryptedECKey(String decrypted, String password) {
   try {
     ECKey key = new DumpedPrivateKey(MainNetParams.get(), decrypted).getKey();
     KeyCrypterScrypt crypter = new KeyCrypterScrypt();
     return key.encrypt(crypter, crypter.deriveKey(password));
   } catch (Exception e) {
     return null;
   }
 }
Beispiel #8
0
 public static List<String> getAddresses() {
   Blocks blocks = Blocks.getInstance();
   List<ECKey> keys = blocks.wallet.getKeys();
   List<String> addresses = new ArrayList<String>();
   for (ECKey key : keys) {
     addresses.add(key.toAddress(blocks.params).toString());
   }
   return addresses;
 }
 @Override
 public void showKey(ECKey key, String dir, boolean testnet) throws IOException {
   NetworkParameters params = LotteryTx.getNetworkParameters(testnet);
   writeln("Generated new <public key, secret key> pair" + (testnet ? " (for the testnet)" : ""));
   writeln("They were saved under the " + dir + " directory");
   writeln("The address, public key and the private key are:");
   writeln(key.toAddress(params).toString());
   writeln(Utils.bytesToHexString(key.getPubKey()));
   writeln(key.getPrivateKeyEncoded(params).toString());
 }
  private byte[] determinePaymentRequest(final boolean includeBluetoothMac) {
    final ECKey key = (ECKey) addressView.getSelectedItem();
    final Address address = key.toAddress(Constants.NETWORK_PARAMETERS);

    return PaymentProtocol.createPaymentRequest(
            amountCalculatorLink.getAmount(),
            address,
            null,
            includeBluetoothMac && bluetoothMac != null ? "bt:" + bluetoothMac : null)
        .toByteArray();
  }
Beispiel #11
0
 @Test
 public void encryptionWhilstEmpty() throws Exception {
   group = new KeyChainGroup(params);
   group.setLookaheadSize(5);
   KeyCrypterScrypt scrypt = new KeyCrypterScrypt(2);
   final KeyParameter aesKey = scrypt.deriveKey("password");
   group.encrypt(scrypt, aesKey);
   assertTrue(group.freshKey(KeyChain.KeyPurpose.RECEIVE_FUNDS).isEncrypted());
   final ECKey key = group.currentKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
   group.decrypt(aesKey);
   assertFalse(checkNotNull(group.findKeyFromPubKey(key.getPubKey())).isEncrypted());
 }
  private String determineBitcoinRequestStr(final boolean includeBluetoothMac) {
    final ECKey key = (ECKey) addressView.getSelectedItem();
    final Address address = key.toAddress(Constants.NETWORK_PARAMETERS);
    final BigInteger amount = amountCalculatorLink.getAmount();

    final StringBuilder uri =
        new StringBuilder(BitcoinURI.convertToBitcoinURI(address, amount, null, null));
    if (includeBluetoothMac && bluetoothMac != null) {
      uri.append(amount == null ? '?' : '&');
      uri.append(Bluetooth.MAC_URI_PARAM).append('=').append(bluetoothMac);
    }
    return uri.toString();
  }
 public static String getPrivateKeyStringFromAllPrivateAddresses() {
   String content = "";
   List<BitherAddressWithPrivateKey> privates = WalletUtils.getPrivateAddressList();
   for (int i = 0; i < privates.size(); i++) {
     BitherAddressWithPrivateKey wallet = privates.get(i);
     ECKey key = wallet.getKeys().get(0);
     content += getPrivateKeyString(key.getEncryptedPrivateKey(), key.getKeyCrypter());
     if (i < privates.size() - 1) {
       content += StringUtil.QR_CODE_SPLIT;
     }
   }
   return content;
 }
Beispiel #14
0
  public Address determineSelectedAddress() {
    final String selectedAddress = prefs.getString(Constants.PREFS_KEY_SELECTED_ADDRESS, null);

    Address firstAddress = null;
    for (final ECKey key : wallet.getKeys()) {
      if (!wallet.isKeyRotating(key)) {
        final Address address = key.toAddress(Constants.NETWORK_PARAMETERS);

        if (address.toString().equals(selectedAddress)) return address;

        if (firstAddress == null) firstAddress = address;
      }
    }

    return firstAddress;
  }
Beispiel #15
0
 @Test
 public void earliestKeyTime() throws Exception {
   long now = Utils.currentTimeSeconds(); // mock
   long yesterday = now - 86400;
   assertEquals(now, group.getEarliestKeyCreationTime());
   Utils.rollMockClock(10000);
   group.freshKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
   Utils.rollMockClock(10000);
   group.freshKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
   // Check that all keys are assumed to be created at the same instant the seed is.
   assertEquals(now, group.getEarliestKeyCreationTime());
   ECKey key = new ECKey();
   key.setCreationTimeSeconds(yesterday);
   group.importKeys(key);
   assertEquals(yesterday, group.getEarliestKeyCreationTime());
 }
    @Override
    public void parse() {
      if (input.startsWith("bitcoin:")) {
        try {
          final BitcoinURI bitcoinUri = new BitcoinURI(null, input);
          final Address address = bitcoinUri.getAddress();
          final String addressLabel = bitcoinUri.getLabel();
          final BigInteger amount = bitcoinUri.getAmount();
          final String bluetoothMac =
              (String) bitcoinUri.getParameterByName(Bluetooth.MAC_URI_PARAM);

          bitcoinRequest(address, addressLabel, amount, bluetoothMac);
        } catch (final BitcoinURIParseException x) {
          error(R.string.input_parser_invalid_bitcoin_uri, input);
        }
      } else if (PATTERN_BITCOIN_ADDRESS.matcher(input).matches()) {
        try {
          final Address address = new Address(Constants.NETWORK_PARAMETERS, input);

          bitcoinRequest(address, null, null, null);
        } catch (final AddressFormatException x) {
          error(R.string.input_parser_invalid_address);
        }
      } else if (PATTERN_PRIVATE_KEY.matcher(input).matches()) {
        try {
          final ECKey key = new DumpedPrivateKey(Constants.NETWORK_PARAMETERS, input).getKey();
          final Address address = new Address(Constants.NETWORK_PARAMETERS, key.getPubKeyHash());

          bitcoinRequest(address, null, null, null);
        } catch (final AddressFormatException x) {
          error(R.string.input_parser_invalid_address);
        }
      } else if (PATTERN_TRANSACTION.matcher(input).matches()) {
        try {
          final Transaction tx =
              new Transaction(Constants.NETWORK_PARAMETERS, Qr.decodeBinary(input));

          directTransaction(tx);
        } catch (final IOException x) {
          error(R.string.input_parser_invalid_transaction, x.getMessage());
        } catch (final ProtocolException x) {
          error(R.string.input_parser_invalid_transaction, x.getMessage());
        }
      } else {
        cannotClassify(input);
      }
    }
Beispiel #17
0
 @Test
 public void deterministicUpgradeRotating() throws Exception {
   group = new KeyChainGroup(params);
   group.setLookaheadSize(LOOKAHEAD_SIZE); // Don't want slow tests.
   long now = Utils.currentTimeSeconds();
   ECKey key1 = new ECKey();
   Utils.rollMockClock(86400);
   ECKey key2 = new ECKey();
   Utils.rollMockClock(86400);
   ECKey key3 = new ECKey();
   group.importKeys(key2, key1, key3);
   group.upgradeToDeterministic(now + 10, null);
   DeterministicSeed seed = group.getActiveKeyChain().getSeed();
   assertNotNull(seed);
   // Check we used the right key: oldest non rotating.
   byte[] truncatedBytes = Arrays.copyOfRange(key2.getSecretBytes(), 0, 16);
   assertArrayEquals(seed.getEntropyBytes(), truncatedBytes);
 }
 private synchronized Transaction makeUnsignedChannelContract(Coin valueToMe)
     throws ValueOutOfRangeException {
   Transaction tx = new Transaction(wallet.getParams());
   tx.addInput(multisigContract.getOutput(0));
   // Our output always comes first.
   // TODO: We should drop myKey in favor of output key + multisig key separation
   // (as its always obvious who the client is based on T2 output order)
   tx.addOutput(valueToMe, myKey.toAddress(wallet.getParams()));
   return tx;
 }
Beispiel #19
0
  public void sweepKey(ECKey key, long fee, int accountId, JSONArray outputs) {
    mLogger.info("sweepKey starting");

    mLogger.info("key addr " + key.toAddress(mParams).toString());

    Transaction tx = new Transaction(mParams);

    long balance = 0;
    ArrayList<Script> scripts = new ArrayList<Script>();
    try {
      for (int ii = 0; ii < outputs.length(); ++ii) {
        JSONObject output;
        output = outputs.getJSONObject(ii);

        String tx_hash = output.getString("tx_hash");
        int tx_output_n = output.getInt("tx_output_n");
        String script = output.getString("script");

        // Reverse byte order, create hash.
        Sha256Hash hash = new Sha256Hash(WalletUtil.msgHexToBytes(tx_hash));

        tx.addInput(
            new TransactionInput(
                mParams, tx, new byte[] {}, new TransactionOutPoint(mParams, tx_output_n, hash)));

        scripts.add(new Script(Hex.decode(script)));

        balance += output.getLong("value");
      }
    } catch (JSONException e) {
      e.printStackTrace();
      throw new RuntimeException("trouble parsing unspent outputs");
    }

    // Compute balance - fee.
    long amount = balance - fee;
    mLogger.info(String.format("sweeping %d", amount));

    // Figure out the destination address.
    Address to = mHDWallet.nextReceiveAddress(accountId);
    mLogger.info("sweeping to " + to.toString());

    // Add output.
    tx.addOutput(BigInteger.valueOf(amount), to);

    WalletUtil.signTransactionInputs(tx, Transaction.SigHash.ALL, key, scripts);

    mLogger.info("tx bytes: " + new String(Hex.encode(tx.bitcoinSerialize())));
    // mKit.peerGroup().broadcastTransaction(tx);
    broadcastTransaction(mKit.peerGroup(), tx);

    mLogger.info("sweepKey finished");
  }
Beispiel #20
0
  @Test
  public void freshCurrentKeys() throws Exception {
    int numKeys =
        ((group.getLookaheadSize() + group.getLookaheadThreshold())
                * 2) // * 2 because of internal/external
            + 1 // keys issued
            + 3 /* account key + int/ext parent keys */;
    assertEquals(numKeys, group.numKeys());
    assertEquals(2 * numKeys, group.getBloomFilterElementCount());
    ECKey r1 = group.currentKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
    assertEquals(numKeys, group.numKeys());
    assertEquals(2 * numKeys, group.getBloomFilterElementCount());

    ECKey i1 = new ECKey();
    group.importKeys(i1);
    numKeys++;
    assertEquals(numKeys, group.numKeys());
    assertEquals(2 * numKeys, group.getBloomFilterElementCount());

    ECKey r2 = group.currentKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
    assertEquals(r1, r2);
    ECKey c1 = group.currentKey(KeyChain.KeyPurpose.CHANGE);
    assertNotEquals(r1, c1);
    ECKey r3 = group.freshKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
    assertNotEquals(r1, r3);
    ECKey c2 = group.freshKey(KeyChain.KeyPurpose.CHANGE);
    assertNotEquals(r3, c2);
    // Current key has not moved and will not under marked as used.
    ECKey r4 = group.currentKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
    assertEquals(r2, r4);
    ECKey c3 = group.currentKey(KeyChain.KeyPurpose.CHANGE);
    assertEquals(c1, c3);
    // Mark as used. Current key is now different.
    group.markPubKeyAsUsed(r4.getPubKey());
    ECKey r5 = group.currentKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
    assertNotEquals(r4, r5);
  }
Beispiel #21
0
 private static RawKeyBytes deriveChildKeyBytesFromPublic(
     DeterministicKey parent, ChildNumber childNumber) throws HDDerivationException {
   checkArgument(!childNumber.isHardened(), "Can't use private derivation with public keys only.");
   byte[] parentPublicKey = ECKey.compressPoint(parent.getPubKeyPoint()).getEncoded();
   assert parentPublicKey.length == 33 : parentPublicKey.length;
   ByteBuffer data = ByteBuffer.allocate(37);
   data.put(parentPublicKey);
   data.putInt(childNumber.i());
   byte[] i = HDUtils.hmacSha512(parent.getChainCode(), data.array());
   assert 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");
   ECPoint Ki = ECKey.CURVE.getG().multiply(ilInt).add(parent.getPubKeyPoint());
   assertNonInfinity(Ki, "Illegal derived key: derived public key equals infinity.");
   return new RawKeyBytes(Ki.getEncoded(true), chainCode);
 }
  public void setUp(BlockStore blockStore) throws Exception {
    BriefLogFormatter.init();

    unitTestParams = UnitTestParams.get();
    Wallet.SendRequest.DEFAULT_FEE_PER_KB = BigInteger.ZERO;
    this.blockStore = blockStore;
    wallet = new Wallet(unitTestParams);
    key = new ECKey();
    address = key.toAddress(unitTestParams);
    wallet.addKey(key);
    blockChain = new BlockChain(unitTestParams, wallet, blockStore);

    startPeerServers();
    if (clientType == ClientType.NIO_CLIENT_MANAGER
        || clientType == ClientType.BLOCKING_CLIENT_MANAGER) {
      channels.startAsync();
      channels.awaitRunning();
    }

    socketAddress = new InetSocketAddress("127.0.0.1", 1111);
  }
 public static ECKey getECKeyFromSingleString(String str, String password) {
   String[] strs = str.split(StringUtil.QR_CODE_SPLIT);
   if (strs.length != 3) {
     Log.e("Backup", "PrivateKeyFromString format error");
     return null;
   }
   EncryptedPrivateKey epk =
       new EncryptedPrivateKey(
           StringUtil.hexStringToByteArray(strs[1]), StringUtil.hexStringToByteArray(strs[0]));
   byte[] salt = StringUtil.hexStringToByteArray(strs[2]);
   KeyCrypterScrypt crypter =
       new KeyCrypterScrypt(
           ScryptParameters.newBuilder().setSalt(ByteString.copyFrom(salt)).build());
   try {
     byte[] pub =
         ECKey.publicKeyFromPrivate(
             new BigInteger(1, crypter.decrypt(epk, crypter.deriveKey(password))), true);
     return new ECKey(epk, pub, crypter);
   } catch (Exception e) {
     e.printStackTrace();
     return null;
   }
 }
Beispiel #24
0
 private static RawKeyBytes deriveChildKeyBytesFromPrivate(
     DeterministicKey parent, ChildNumber childNumber) throws HDDerivationException {
   checkArgument(parent.hasPrivKey(), "Parent key must have private key bytes for this method.");
   byte[] parentPublicKey = ECKey.compressPoint(parent.getPubKeyPoint()).getEncoded();
   assert parentPublicKey.length == 33 : 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());
   assert 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);
 }
  @Test
  public void testReplayManagerSyncSingleWallet() throws Exception {
    // Get the system property runFunctionalTest to see if the functional
    // tests need running.
    String runFunctionalTests = System.getProperty(Constants.RUN_FUNCTIONAL_TESTS_PARAMETER);
    if (Boolean.TRUE.toString().equalsIgnoreCase(runFunctionalTests)) {
      // Date format is UTC with century, T time separator and Z for UTC
      // timezone.
      formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.ENGLISH);
      formatter.setTimeZone(TimeZone.getTimeZone("UTC"));

      // Initialise replay manager
      ReplayManager replayManager = ReplayManager.INSTANCE;
      assertNotNull(replayManager);

      replayManager.initialise(controller, true);

      String replayWalletPath =
          multiBitDirectory.getAbsolutePath() + File.separator + "replay.wallet";

      // Create a new wallet.
      Wallet replayWallet = new Wallet(NetworkParameters.prodNet());

      // Add in the replay key.
      DumpedPrivateKey replayDumpedPrivateKey =
          new DumpedPrivateKey(NetworkParameters.prodNet(), REPLAY1_PRIVATE_KEY);
      ECKey replayKey = replayDumpedPrivateKey.getKey();
      replayKey.setCreationTimeSeconds(formatter.parse(START_OF_REPLAY_PERIOD).getTime() / 1000);
      log.debug("replayPrivateKey getCreationTimeSeconds = " + replayKey.getCreationTimeSeconds());

      replayWallet.addKey(replayKey);
      WalletData perWalletModelData = new WalletData();
      perWalletModelData.setWalletInfo(
          new WalletInfoData(replayWalletPath, replayWallet, MultiBitWalletVersion.PROTOBUF));
      perWalletModelData.setWallet(replayWallet);
      perWalletModelData.setWalletFilename(replayWalletPath);
      perWalletModelData.setWalletDescription("testReplayManagerSyncSingleWallet test");
      controller.getModel().getPerWalletModelDataList().add(perWalletModelData);

      log.debug("Replay wallet before replay = \n" + replayWallet.toString());

      assertEquals(BALANCE_AT_START, replayWallet.getBalance());

      log.debug("Replaying blockchain");
      // Create a ReplayTask to replay the replay wallet from the
      // START_OF_REPLAY_PERIOD.
      List<WalletData> perWalletModelDataList = new ArrayList<WalletData>();
      perWalletModelDataList.add(perWalletModelData);

      ReplayTask replayTask =
          new ReplayTask(
              perWalletModelDataList,
              formatter.parse(START_OF_REPLAY_PERIOD),
              ReplayTask.UNKNOWN_START_HEIGHT);
      replayManager.offerReplayTask(replayTask);

      // Run for a while.
      log.debug("Twiddling thumbs for 60 seconds ...");
      Thread.sleep(60000);
      log.debug("... 60 seconds later.");

      // Check the wallet - there should be some transactions in there.
      if (replayWallet.getTransactions(true).size() > 0) {
        // We are done.
      } else {
        // Run for a while longer.
        log.debug("Twiddling thumbs for another 60 seconds ...");
        Thread.sleep(60000);
        log.debug("... 60 seconds later.");
        if (replayWallet.getTransactions(true).size() > 0) {
          // We are done.
        } else {
          if (simpleViewSystem.getNumberOfBlocksDownloaded() > 0) {
            // Well it tried but probably got a slow connection -
            // give it a pass.
          } else {
            fail("No blocks were downloaded on replay");
          }
        }
      }

      // Print out replay wallet after replay.
      log.debug("Replay wallet after replay = \n" + replayWallet);
    } else {
      log.debug(
          "Not running functional test: ReplayManagerTest#testReplayManagerSyncSingleWallet. Add '-DrunFunctionalTests=true' to run");
    }
  }
Beispiel #26
0
  public void encryption(boolean withImported) throws Exception {
    Utils.rollMockClock(0);
    long now = Utils.currentTimeSeconds();
    ECKey a = group.freshKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
    assertEquals(now, group.getEarliestKeyCreationTime());
    Utils.rollMockClock(-86400);
    long yesterday = Utils.currentTimeSeconds();
    ECKey b = new ECKey();

    assertFalse(group.isEncrypted());
    try {
      group.checkPassword("foo"); // Cannot check password of an unencrypted group.
      fail();
    } catch (IllegalStateException e) {
    }
    if (withImported) {
      assertEquals(now, group.getEarliestKeyCreationTime());
      group.importKeys(b);
      assertEquals(yesterday, group.getEarliestKeyCreationTime());
    }
    KeyCrypterScrypt scrypt = new KeyCrypterScrypt(2);
    final KeyParameter aesKey = scrypt.deriveKey("password");
    group.encrypt(scrypt, aesKey);
    assertTrue(group.isEncrypted());
    assertTrue(group.checkPassword("password"));
    assertFalse(group.checkPassword("wrong password"));
    final ECKey ea = group.findKeyFromPubKey(a.getPubKey());
    assertTrue(checkNotNull(ea).isEncrypted());
    if (withImported) {
      assertTrue(checkNotNull(group.findKeyFromPubKey(b.getPubKey())).isEncrypted());
      assertEquals(yesterday, group.getEarliestKeyCreationTime());
    } else {
      assertEquals(now, group.getEarliestKeyCreationTime());
    }
    try {
      ea.sign(Sha256Hash.ZERO_HASH);
      fail();
    } catch (ECKey.KeyIsEncryptedException e) {
      // Ignored.
    }
    if (withImported) {
      ECKey c = new ECKey();
      try {
        group.importKeys(c);
        fail();
      } catch (KeyCrypterException e) {
      }
      group.importKeysAndEncrypt(ImmutableList.of(c), aesKey);
      ECKey ec = group.findKeyFromPubKey(c.getPubKey());
      try {
        group.importKeysAndEncrypt(ImmutableList.of(ec), aesKey);
        fail();
      } catch (IllegalArgumentException e) {
      }
    }

    try {
      group.decrypt(scrypt.deriveKey("WRONG PASSWORD"));
      fail();
    } catch (KeyCrypterException e) {
    }

    group.decrypt(aesKey);
    assertFalse(group.isEncrypted());
    assertFalse(checkNotNull(group.findKeyFromPubKey(a.getPubKey())).isEncrypted());
    if (withImported) {
      assertFalse(checkNotNull(group.findKeyFromPubKey(b.getPubKey())).isEncrypted());
      assertEquals(yesterday, group.getEarliestKeyCreationTime());
    } else {
      assertEquals(now, group.getEarliestKeyCreationTime());
    }
  }
  /**
   * Converts the given wallet to the object representation of the protocol buffers. This can be
   * modified, or additional data fields set, before serialization takes place.
   */
  public Protos.Wallet walletToProto(Wallet wallet) {
    Protos.Wallet.Builder walletBuilder = Protos.Wallet.newBuilder();
    walletBuilder.setNetworkIdentifier(wallet.getNetworkParameters().getId());
    if (wallet.getDescription() != null) {
      walletBuilder.setDescription(wallet.getDescription());
    }

    for (WalletTransaction wtx : wallet.getWalletTransactions()) {
      Protos.Transaction txProto = makeTxProto(wtx);
      walletBuilder.addTransaction(txProto);
    }

    for (ECKey key : wallet.getKeys()) {
      Protos.Key.Builder keyBuilder =
          Protos.Key.newBuilder()
              .setCreationTimestamp(key.getCreationTimeSeconds() * 1000)
              // .setLabel() TODO
              .setType(Protos.Key.Type.ORIGINAL);
      if (key.getPrivKeyBytes() != null)
        keyBuilder.setPrivateKey(ByteString.copyFrom(key.getPrivKeyBytes()));

      EncryptedPrivateKey encryptedPrivateKey = key.getEncryptedPrivateKey();
      if (encryptedPrivateKey != null) {
        // Key is encrypted.
        Protos.EncryptedPrivateKey.Builder encryptedKeyBuilder =
            Protos.EncryptedPrivateKey.newBuilder()
                .setEncryptedPrivateKey(
                    ByteString.copyFrom(encryptedPrivateKey.getEncryptedBytes()))
                .setInitialisationVector(
                    ByteString.copyFrom(encryptedPrivateKey.getInitialisationVector()));

        if (key.getKeyCrypter() == null) {
          throw new IllegalStateException(
              "The encrypted key " + key.toString() + " has no KeyCrypter.");
        } else {
          // If it is a Scrypt + AES encrypted key, set the persisted key type.
          if (key.getKeyCrypter().getUnderstoodEncryptionType()
              == Protos.Wallet.EncryptionType.ENCRYPTED_SCRYPT_AES) {
            keyBuilder.setType(Protos.Key.Type.ENCRYPTED_SCRYPT_AES);
          } else {
            throw new IllegalArgumentException(
                "The key "
                    + key.toString()
                    + " is encrypted with a KeyCrypter of type "
                    + key.getKeyCrypter().getUnderstoodEncryptionType()
                    + ". This WalletProtobufSerialiser does not understand that type of encryption.");
          }
        }
        keyBuilder.setEncryptedPrivateKey(encryptedKeyBuilder);
      }

      // We serialize the public key even if the private key is present for speed reasons: we don't
      // want to do
      // lots of slow EC math to load the wallet, we prefer to store the redundant data instead. It
      // matters more
      // on mobile platforms.
      keyBuilder.setPublicKey(ByteString.copyFrom(key.getPubKey()));
      walletBuilder.addKey(keyBuilder);
    }

    // Populate the lastSeenBlockHash field.
    Sha256Hash lastSeenBlockHash = wallet.getLastBlockSeenHash();
    if (lastSeenBlockHash != null) {
      walletBuilder.setLastSeenBlockHash(hashToByteString(lastSeenBlockHash));
      walletBuilder.setLastSeenBlockHeight(wallet.getLastBlockSeenHeight());
    }

    // Populate the scrypt parameters.
    KeyCrypter keyCrypter = wallet.getKeyCrypter();
    if (keyCrypter == null) {
      // The wallet is unencrypted.
      walletBuilder.setEncryptionType(EncryptionType.UNENCRYPTED);
    } else {
      // The wallet is encrypted.
      walletBuilder.setEncryptionType(keyCrypter.getUnderstoodEncryptionType());
      if (keyCrypter instanceof KeyCrypterScrypt) {
        KeyCrypterScrypt keyCrypterScrypt = (KeyCrypterScrypt) keyCrypter;
        walletBuilder.setEncryptionParameters(keyCrypterScrypt.getScryptParameters());
      } else {
        // Some other form of encryption has been specified that we do not know how to persist.
        throw new RuntimeException(
            "The wallet has encryption of type '"
                + keyCrypter.getUnderstoodEncryptionType()
                + "' but this WalletProtobufSerializer does not know how to persist this.");
      }
    }

    populateExtensions(wallet, walletBuilder);

    // Populate the wallet version.
    walletBuilder.setVersion(wallet.getVersion());

    return walletBuilder.build();
  }
  /**
   * Loads wallet data from the given protocol buffer and inserts it into the given Wallet object.
   * This is primarily useful when you wish to pre-register extension objects. Note that if loading
   * fails the provided Wallet object may be in an indeterminate state and should be thrown away.
   *
   * @throws IOException if there is a problem reading the stream.
   * @throws IllegalArgumentException if the wallet is corrupt.
   */
  public void readWallet(Protos.Wallet walletProto, Wallet wallet) throws IOException {
    // TODO: This method should throw more specific exception types than IllegalArgumentException.
    // Read the scrypt parameters that specify how encryption and decryption is performed.
    if (walletProto.hasEncryptionParameters()) {
      Protos.ScryptParameters encryptionParameters = walletProto.getEncryptionParameters();
      wallet.setKeyCrypter(new KeyCrypterScrypt(encryptionParameters));
    }

    if (walletProto.hasDescription()) {
      wallet.setDescription(walletProto.getDescription());
    }

    // Read all keys
    for (Protos.Key keyProto : walletProto.getKeyList()) {
      if (!(keyProto.getType() == Protos.Key.Type.ORIGINAL
          || keyProto.getType() == Protos.Key.Type.ENCRYPTED_SCRYPT_AES)) {
        throw new IllegalArgumentException(
            "Unknown key type in wallet, type = " + keyProto.getType());
      }

      byte[] privKey = keyProto.hasPrivateKey() ? keyProto.getPrivateKey().toByteArray() : null;
      EncryptedPrivateKey encryptedPrivateKey = null;
      if (keyProto.hasEncryptedPrivateKey()) {
        Protos.EncryptedPrivateKey encryptedPrivateKeyProto = keyProto.getEncryptedPrivateKey();
        encryptedPrivateKey =
            new EncryptedPrivateKey(
                encryptedPrivateKeyProto.getInitialisationVector().toByteArray(),
                encryptedPrivateKeyProto.getEncryptedPrivateKey().toByteArray());
      }

      byte[] pubKey = keyProto.hasPublicKey() ? keyProto.getPublicKey().toByteArray() : null;

      ECKey ecKey;
      final KeyCrypter keyCrypter = wallet.getKeyCrypter();
      if (keyCrypter != null
          && keyCrypter.getUnderstoodEncryptionType() != EncryptionType.UNENCRYPTED) {
        // If the key is encrypted construct an ECKey using the encrypted private key bytes.
        ecKey = new ECKey(encryptedPrivateKey, pubKey, keyCrypter);
      } else {
        // Construct an unencrypted private key.
        ecKey = new ECKey(privKey, pubKey);
      }
      ecKey.setCreationTimeSeconds((keyProto.getCreationTimestamp() + 500) / 1000);
      wallet.addKey(ecKey);
    }

    // Read all transactions and insert into the txMap.
    for (Protos.Transaction txProto : walletProto.getTransactionList()) {
      readTransaction(txProto, wallet.getParams());
    }

    // Update transaction outputs to point to inputs that spend them
    for (Protos.Transaction txProto : walletProto.getTransactionList()) {
      WalletTransaction wtx = connectTransactionOutputs(txProto);
      wallet.addWalletTransaction(wtx);
    }

    // Update the lastBlockSeenHash.
    if (!walletProto.hasLastSeenBlockHash()) {
      wallet.setLastBlockSeenHash(null);
    } else {
      wallet.setLastBlockSeenHash(byteStringToHash(walletProto.getLastSeenBlockHash()));
    }
    if (!walletProto.hasLastSeenBlockHeight()) {
      wallet.setLastBlockSeenHeight(-1);
    } else {
      wallet.setLastBlockSeenHeight(walletProto.getLastSeenBlockHeight());
    }

    loadExtensions(wallet, walletProto);

    if (walletProto.hasVersion()) {
      wallet.setVersion(walletProto.getVersion());
    }

    // Make sure the object can be re-used to read another wallet without corruption.
    txMap.clear();
  }
Beispiel #29
0
 @Test
 public void findKey() throws Exception {
   ECKey a = group.freshKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
   ECKey b = group.freshKey(KeyChain.KeyPurpose.CHANGE);
   ECKey c = new ECKey();
   ECKey d = new ECKey(); // Not imported.
   group.importKeys(c);
   assertTrue(group.hasKey(a));
   assertTrue(group.hasKey(b));
   assertTrue(group.hasKey(c));
   assertFalse(group.hasKey(d));
   ECKey result = group.findKeyFromPubKey(a.getPubKey());
   assertEquals(a, result);
   result = group.findKeyFromPubKey(b.getPubKey());
   assertEquals(b, result);
   result = group.findKeyFromPubHash(a.getPubKeyHash());
   assertEquals(a, result);
   result = group.findKeyFromPubHash(b.getPubKeyHash());
   assertEquals(b, result);
   result = group.findKeyFromPubKey(c.getPubKey());
   assertEquals(c, result);
   result = group.findKeyFromPubHash(c.getPubKeyHash());
   assertEquals(c, result);
   assertNull(group.findKeyFromPubKey(d.getPubKey()));
   assertNull(group.findKeyFromPubHash(d.getPubKeyHash()));
 }
    @Override
    public void parse() {
      if (input.startsWith("MINTCOIN:-")) {
        try {
          final byte[] serializedPaymentRequest = Qr.decodeBinary(input.substring(9));

          parseAndHandlePaymentRequest(serializedPaymentRequest);
        } catch (final IOException x) {
          log.info("i/o error while fetching payment request", x);

          error(R.string.input_parser_io_error, x.getMessage());
        } catch (final PkiVerificationException x) {
          log.info("got unverifyable payment request", x);

          error(R.string.input_parser_unverifyable_paymentrequest, x.getMessage());
        } catch (final PaymentRequestException x) {
          log.info("got invalid payment request", x);

          error(R.string.input_parser_invalid_paymentrequest, x.getMessage());
        }
      }
      if (input.startsWith("mintcoin:")) {
        try {
          final BitcoinURI bitcoinUri = new BitcoinURI(null, input);

          final Address address = bitcoinUri.getAddress();
          if (address == null) throw new BitcoinURIParseException("missing address");

          if (address.getParameters().equals(Constants.NETWORK_PARAMETERS))
            handlePaymentIntent(PaymentIntent.fromBitcoinUri(bitcoinUri));
          else error(R.string.input_parser_invalid_address, input);
        } catch (final BitcoinURIParseException x) {
          log.info("got invalid mintcoin uri: '" + input + "'", x);

          error(R.string.input_parser_invalid_bitcoin_uri, input);
        }
      } else if (PATTERN_BITCOIN_ADDRESS.matcher(input).matches()) {
        try {
          final Address address = new Address(Constants.NETWORK_PARAMETERS, input);

          handlePaymentIntent(PaymentIntent.fromAddress(address, null));
        } catch (final AddressFormatException x) {
          log.info("got invalid address", x);

          error(R.string.input_parser_invalid_address);
        }
      } else if (PATTERN_PRIVATE_KEY.matcher(input).matches()) {
        try {
          final ECKey key = new DumpedPrivateKey(Constants.NETWORK_PARAMETERS, input).getKey();
          final Address address = new Address(Constants.NETWORK_PARAMETERS, key.getPubKeyHash());

          handlePaymentIntent(PaymentIntent.fromAddress(address, null));
        } catch (final AddressFormatException x) {
          log.info("got invalid address", x);

          error(R.string.input_parser_invalid_address);
        }
      } else if (PATTERN_TRANSACTION.matcher(input).matches()) {
        try {
          final Transaction tx =
              new Transaction(Constants.NETWORK_PARAMETERS, Qr.decodeDecompressBinary(input));

          handleDirectTransaction(tx);
        } catch (final IOException x) {
          log.info("i/o error while fetching transaction", x);

          error(R.string.input_parser_invalid_transaction, x.getMessage());
        } catch (final ProtocolException x) {
          log.info("got invalid transaction", x);

          error(R.string.input_parser_invalid_transaction, x.getMessage());
        }
      } else {
        cannotClassify(input);
      }
    }