Search in sources :

Example 1 with DecoderException

use of org.bouncycastle.util.encoders.DecoderException in project nifi by apache.

the class AESSensitivePropertyProvider method unprotect.

/**
 * Returns the decrypted plaintext.
 *
 * @param protectedValue the cipher text read from the {@code nifi.properties} file
 * @return the raw value to be used by the application
 * @throws SensitivePropertyProtectionException if there is an error decrypting the cipher text
 */
@Override
public String unprotect(String protectedValue) throws SensitivePropertyProtectionException {
    if (protectedValue == null || protectedValue.trim().length() < MIN_CIPHER_TEXT_LENGTH) {
        throw new IllegalArgumentException("Cannot decrypt a cipher text shorter than " + MIN_CIPHER_TEXT_LENGTH + " chars");
    }
    if (!protectedValue.contains(DELIMITER)) {
        throw new IllegalArgumentException("The cipher text does not contain the delimiter " + DELIMITER + " -- it should be of the form Base64(IV) || Base64(cipherText)");
    }
    protectedValue = protectedValue.trim();
    final String IV_B64 = protectedValue.substring(0, protectedValue.indexOf(DELIMITER));
    byte[] iv = Base64.decode(IV_B64);
    if (iv.length < IV_LENGTH) {
        throw new IllegalArgumentException("The IV (" + iv.length + " bytes) must be at least " + IV_LENGTH + " bytes");
    }
    String CIPHERTEXT_B64 = protectedValue.substring(protectedValue.indexOf(DELIMITER) + 2);
    // Restore the = padding if necessary to reconstitute the GCM MAC check
    if (CIPHERTEXT_B64.length() % 4 != 0) {
        final int paddedLength = CIPHERTEXT_B64.length() + 4 - (CIPHERTEXT_B64.length() % 4);
        CIPHERTEXT_B64 = StringUtils.rightPad(CIPHERTEXT_B64, paddedLength, '=');
    }
    try {
        byte[] cipherBytes = Base64.decode(CIPHERTEXT_B64);
        cipher.init(Cipher.DECRYPT_MODE, this.key, new IvParameterSpec(iv));
        byte[] plainBytes = cipher.doFinal(cipherBytes);
        logger.debug(getName() + " decrypted a sensitive value successfully");
        return new String(plainBytes, StandardCharsets.UTF_8);
    } catch (BadPaddingException | IllegalBlockSizeException | DecoderException | InvalidAlgorithmParameterException | InvalidKeyException e) {
        final String msg = "Error decrypting a protected value";
        logger.error(msg, e);
        throw new SensitivePropertyProtectionException(msg, e);
    }
}
Also used : DecoderException(org.bouncycastle.util.encoders.DecoderException) InvalidAlgorithmParameterException(java.security.InvalidAlgorithmParameterException) IllegalBlockSizeException(javax.crypto.IllegalBlockSizeException) IvParameterSpec(javax.crypto.spec.IvParameterSpec) BadPaddingException(javax.crypto.BadPaddingException) InvalidKeyException(java.security.InvalidKeyException)

Example 2 with DecoderException

use of org.bouncycastle.util.encoders.DecoderException in project samourai-wallet-android by Samourai-Wallet.

the class BIP47Activity method onActivityResult.

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (resultCode == Activity.RESULT_OK && requestCode == SCAN_PCODE) {
        if (data != null && data.getStringExtra(ZBarConstants.SCAN_RESULT) != null) {
            String strResult = data.getStringExtra(ZBarConstants.SCAN_RESULT);
            processScan(strResult);
        }
    } else if (resultCode == Activity.RESULT_CANCELED && requestCode == SCAN_PCODE) {
        ;
    } else if (resultCode == Activity.RESULT_OK && requestCode == EDIT_PCODE) {
        if (data.hasExtra("pcode")) {
            String pcode = data.getStringExtra("pcode");
            if (BIP47Meta.getInstance().getOutgoingStatus(pcode) == BIP47Meta.STATUS_NOT_SENT) {
                doNotifTx(pcode);
            }
        }
    } else if (resultCode == Activity.RESULT_CANCELED && requestCode == EDIT_PCODE) {
        ;
    } else if (resultCode == Activity.RESULT_OK && requestCode == RECOMMENDED_PCODE) {
        if (data.hasExtra("pcode") && data.hasExtra("label")) {
            String pcode = data.getStringExtra("pcode");
            String label = data.getStringExtra("label");
            BIP47Meta.getInstance().setLabel(pcode, label);
            new Thread(new Runnable() {

                @Override
                public void run() {
                    Looper.prepare();
                    try {
                        PayloadUtil.getInstance(BIP47Activity.this).saveWalletToJSON(new CharSequenceX(AccessFactory.getInstance(BIP47Activity.this).getGUID() + AccessFactory.getInstance().getPIN()));
                    } catch (MnemonicException.MnemonicLengthException mle) {
                        mle.printStackTrace();
                        Toast.makeText(BIP47Activity.this, R.string.decryption_error, Toast.LENGTH_SHORT).show();
                    } catch (DecoderException de) {
                        de.printStackTrace();
                        Toast.makeText(BIP47Activity.this, R.string.decryption_error, Toast.LENGTH_SHORT).show();
                    } catch (JSONException je) {
                        je.printStackTrace();
                        Toast.makeText(BIP47Activity.this, R.string.decryption_error, Toast.LENGTH_SHORT).show();
                    } catch (IOException ioe) {
                        ioe.printStackTrace();
                        Toast.makeText(BIP47Activity.this, R.string.decryption_error, Toast.LENGTH_SHORT).show();
                    } catch (java.lang.NullPointerException npe) {
                        npe.printStackTrace();
                        Toast.makeText(BIP47Activity.this, R.string.decryption_error, Toast.LENGTH_SHORT).show();
                    } catch (DecryptionException de) {
                        de.printStackTrace();
                        Toast.makeText(BIP47Activity.this, R.string.decryption_error, Toast.LENGTH_SHORT).show();
                    } finally {
                        ;
                    }
                    Looper.loop();
                }
            }).start();
            if (BIP47Meta.getInstance().getOutgoingStatus(pcode) == BIP47Meta.STATUS_NOT_SENT) {
                doNotifTx(pcode);
            }
        }
    } else if (resultCode == Activity.RESULT_CANCELED && requestCode == RECOMMENDED_PCODE) {
        ;
    } else {
        ;
    }
}
Also used : DecoderException(org.bouncycastle.util.encoders.DecoderException) MnemonicException(org.bitcoinj.crypto.MnemonicException) CharSequenceX(com.samourai.wallet.util.CharSequenceX) JSONException(org.json.JSONException) IOException(java.io.IOException) DecryptionException(com.samourai.wallet.crypto.DecryptionException)

Example 3 with DecoderException

use of org.bouncycastle.util.encoders.DecoderException in project samourai-wallet-android by Samourai-Wallet.

the class BIP47Activity method doNotifTx.

private void doNotifTx(final String pcode) {
    // 
    // get wallet balance
    // 
    long balance = 0L;
    try {
        balance = APIFactory.getInstance(BIP47Activity.this).getXpubAmounts().get(HD_WalletFactory.getInstance(BIP47Activity.this).get().getAccount(0).xpubstr());
    } catch (IOException ioe) {
        balance = 0L;
    } catch (MnemonicException.MnemonicLengthException mle) {
        balance = 0L;
    } catch (java.lang.NullPointerException npe) {
        balance = 0L;
    }
    final List<UTXO> selectedUTXO = new ArrayList<UTXO>();
    long totalValueSelected = 0L;
    // long change = 0L;
    BigInteger fee = null;
    // 
    // spend dust threshold amount to notification address
    // 
    long amount = SendNotifTxFactory._bNotifTxValue.longValue();
    // 
    // calc btc fee from USD Samourai fee
    // 
    double btc_fx = ExchangeRateFactory.getInstance(BIP47Activity.this).getBitfinexPrice("USD");
    BigInteger currentSWFee = BigInteger.valueOf((long) ((btc_fx / SendNotifTxFactory._dSWFeeUSD) * 1e8));
    if (currentSWFee.longValue() < SendNotifTxFactory._bSWFee.longValue() || currentSWFee.longValue() > SendNotifTxFactory._bSWCeilingFee.longValue()) {
        currentSWFee = SendNotifTxFactory._bSWFee;
    }
    // 
    // add Samourai Wallet fee to total amount
    // 
    amount += currentSWFee.longValue();
    // 
    // get unspents
    // 
    List<UTXO> utxos = null;
    if (UTXOFactory.getInstance().getTotalP2SH_P2WPKH() > amount + FeeUtil.getInstance().estimatedFeeSegwit(0, 1, 4).longValue()) {
        utxos = new ArrayList<UTXO>();
        utxos.addAll(UTXOFactory.getInstance().getP2SH_P2WPKH().values());
    } else {
        utxos = APIFactory.getInstance(BIP47Activity.this).getUtxos(true);
    }
    // sort in ascending order by value
    final List<UTXO> _utxos = utxos;
    Collections.sort(_utxos, new UTXO.UTXOComparator());
    Collections.reverse(_utxos);
    // 
    for (UTXO u : _utxos) {
        if (u.getValue() >= (amount + SamouraiWallet.bDust.longValue() + FeeUtil.getInstance().estimatedFee(1, 4).longValue())) {
            selectedUTXO.add(u);
            totalValueSelected += u.getValue();
            Log.d("BIP47Activity", "single output");
            Log.d("BIP47Activity", "value selected:" + u.getValue());
            Log.d("BIP47Activity", "total value selected:" + totalValueSelected);
            Log.d("BIP47Activity", "nb inputs:" + u.getOutpoints().size());
            break;
        }
    }
    // 
    // use low fee settings
    // 
    SuggestedFee suggestedFee = FeeUtil.getInstance().getSuggestedFee();
    FeeUtil.getInstance().setSuggestedFee(FeeUtil.getInstance().getLowFee());
    if (selectedUTXO.size() == 0) {
        // sort in descending order by value
        Collections.sort(_utxos, new UTXO.UTXOComparator());
        int selected = 0;
        // get largest UTXOs > than spend + fee + dust
        for (UTXO u : _utxos) {
            selectedUTXO.add(u);
            totalValueSelected += u.getValue();
            selected += u.getOutpoints().size();
            if (totalValueSelected >= (amount + SamouraiWallet.bDust.longValue() + FeeUtil.getInstance().estimatedFee(selected, 4).longValue())) {
                Log.d("BIP47Activity", "multiple outputs");
                Log.d("BIP47Activity", "total value selected:" + totalValueSelected);
                Log.d("BIP47Activity", "nb inputs:" + u.getOutpoints().size());
                break;
            }
        }
        fee = FeeUtil.getInstance().estimatedFee(selected, 4);
    } else {
        fee = FeeUtil.getInstance().estimatedFee(1, 4);
    }
    // 
    // reset fee to previous setting
    // 
    FeeUtil.getInstance().setSuggestedFee(suggestedFee);
    // 
    if ((amount + fee.longValue()) >= balance) {
        String message = getText(R.string.bip47_notif_tx_insufficient_funds_1) + " ";
        BigInteger biAmount = SendNotifTxFactory._bSWFee.add(SendNotifTxFactory._bNotifTxValue.add(FeeUtil.getInstance().estimatedFee(1, 4, FeeUtil.getInstance().getLowFee().getDefaultPerKB())));
        String strAmount = MonetaryUtil.getInstance().getBTCFormat().format(((double) biAmount.longValue()) / 1e8) + " BTC ";
        message += strAmount;
        message += " " + getText(R.string.bip47_notif_tx_insufficient_funds_2);
        AlertDialog.Builder dlg = new AlertDialog.Builder(BIP47Activity.this).setTitle(R.string.app_name).setMessage(message).setCancelable(false).setPositiveButton(R.string.help, new DialogInterface.OnClickListener() {

            public void onClick(DialogInterface dialog, int whichButton) {
                Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://support.samourai.io/article/58-connecting-to-a-paynym-contact"));
                startActivity(browserIntent);
            }
        }).setNegativeButton(R.string.close, new DialogInterface.OnClickListener() {

            public void onClick(DialogInterface dialog, int whichButton) {
                dialog.dismiss();
            }
        });
        if (!isFinishing()) {
            dlg.show();
        }
        return;
    }
    // 
    // payment code to be notified
    // 
    PaymentCode payment_code;
    try {
        payment_code = new PaymentCode(pcode);
    } catch (AddressFormatException afe) {
        payment_code = null;
    }
    if (payment_code == null) {
        return;
    }
    // 
    // create outpoints for spend later
    // 
    final List<MyTransactionOutPoint> outpoints = new ArrayList<MyTransactionOutPoint>();
    for (UTXO u : selectedUTXO) {
        outpoints.addAll(u.getOutpoints());
    }
    // 
    // create inputs from outpoints
    // 
    List<MyTransactionInput> inputs = new ArrayList<MyTransactionInput>();
    for (MyTransactionOutPoint o : outpoints) {
        Script script = new Script(o.getScriptBytes());
        if (script.getScriptType() == Script.ScriptType.NO_TYPE) {
            continue;
        }
        MyTransactionInput input = new MyTransactionInput(SamouraiWallet.getInstance().getCurrentNetworkParams(), null, new byte[0], o, o.getTxHash().toString(), o.getTxOutputN());
        inputs.add(input);
    }
    // 
    // sort inputs
    // 
    Collections.sort(inputs, new SendFactory.BIP69InputComparator());
    // 
    // find outpoint that corresponds to 0th input
    // 
    MyTransactionOutPoint outPoint = null;
    for (MyTransactionOutPoint o : outpoints) {
        if (o.getTxHash().toString().equals(inputs.get(0).getTxHash()) && o.getTxOutputN() == inputs.get(0).getTxPos()) {
            outPoint = o;
            break;
        }
    }
    if (outPoint == null) {
        Toast.makeText(BIP47Activity.this, R.string.bip47_cannot_identify_outpoint, Toast.LENGTH_SHORT).show();
        return;
    }
    byte[] op_return = null;
    // 
    try {
        Script inputScript = new Script(outPoint.getConnectedPubKeyScript());
        String address = inputScript.getToAddress(SamouraiWallet.getInstance().getCurrentNetworkParams()).toString();
        ECKey ecKey = SendFactory.getPrivKey(address);
        if (ecKey == null || !ecKey.hasPrivKey()) {
            Toast.makeText(BIP47Activity.this, R.string.bip47_cannot_compose_notif_tx, Toast.LENGTH_SHORT).show();
            return;
        }
        // 
        // use outpoint for payload masking
        // 
        byte[] privkey = ecKey.getPrivKeyBytes();
        byte[] pubkey = payment_code.notificationAddress().getPubKey();
        byte[] outpoint = outPoint.bitcoinSerialize();
        // Log.i("BIP47Activity", "outpoint:" + Hex.toHexString(outpoint));
        // Log.i("BIP47Activity", "payer shared secret:" + Hex.toHexString(new SecretPoint(privkey, pubkey).ECDHSecretAsBytes()));
        byte[] mask = PaymentCode.getMask(new SecretPoint(privkey, pubkey).ECDHSecretAsBytes(), outpoint);
        // Log.i("BIP47Activity", "mask:" + Hex.toHexString(mask));
        // Log.i("BIP47Activity", "mask length:" + mask.length);
        // Log.i("BIP47Activity", "payload0:" + Hex.toHexString(BIP47Util.getInstance(context).getPaymentCode().getPayload()));
        op_return = PaymentCode.blind(BIP47Util.getInstance(BIP47Activity.this).getPaymentCode().getPayload(), mask);
    // Log.i("BIP47Activity", "payload1:" + Hex.toHexString(op_return));
    } catch (InvalidKeyException ike) {
        Toast.makeText(BIP47Activity.this, ike.getMessage(), Toast.LENGTH_SHORT).show();
        return;
    } catch (InvalidKeySpecException ikse) {
        Toast.makeText(BIP47Activity.this, ikse.getMessage(), Toast.LENGTH_SHORT).show();
        return;
    } catch (NoSuchAlgorithmException nsae) {
        Toast.makeText(BIP47Activity.this, nsae.getMessage(), Toast.LENGTH_SHORT).show();
        return;
    } catch (NoSuchProviderException nspe) {
        Toast.makeText(BIP47Activity.this, nspe.getMessage(), Toast.LENGTH_SHORT).show();
        return;
    }
    final HashMap<String, BigInteger> receivers = new HashMap<String, BigInteger>();
    receivers.put(Hex.toHexString(op_return), BigInteger.ZERO);
    receivers.put(payment_code.notificationAddress().getAddressString(), SendNotifTxFactory._bNotifTxValue);
    receivers.put(SamouraiWallet.getInstance().isTestNet() ? SendNotifTxFactory.TESTNET_SAMOURAI_NOTIF_TX_FEE_ADDRESS : SendNotifTxFactory.SAMOURAI_NOTIF_TX_FEE_ADDRESS, currentSWFee);
    final long change = totalValueSelected - (amount + fee.longValue());
    if (change > 0L) {
        String change_address = BIP49Util.getInstance(BIP47Activity.this).getAddressAt(AddressFactory.CHANGE_CHAIN, BIP49Util.getInstance(BIP47Activity.this).getWallet().getAccount(0).getChange().getAddrIdx()).getAddressAsString();
        receivers.put(change_address, BigInteger.valueOf(change));
    }
    Log.d("BIP47Activity", "outpoints:" + outpoints.size());
    Log.d("BIP47Activity", "totalValueSelected:" + BigInteger.valueOf(totalValueSelected).toString());
    Log.d("BIP47Activity", "amount:" + BigInteger.valueOf(amount).toString());
    Log.d("BIP47Activity", "change:" + BigInteger.valueOf(change).toString());
    Log.d("BIP47Activity", "fee:" + fee.toString());
    if (change < 0L) {
        Toast.makeText(BIP47Activity.this, R.string.bip47_cannot_compose_notif_tx, Toast.LENGTH_SHORT).show();
        return;
    }
    final MyTransactionOutPoint _outPoint = outPoint;
    String strNotifTxMsg = getText(R.string.bip47_setup4_text1) + " ";
    long notifAmount = amount;
    String strAmount = MonetaryUtil.getInstance().getBTCFormat().format(((double) notifAmount + fee.longValue()) / 1e8) + " BTC ";
    strNotifTxMsg += strAmount + getText(R.string.bip47_setup4_text2);
    AlertDialog.Builder dlg = new AlertDialog.Builder(BIP47Activity.this).setTitle(R.string.bip47_setup4_title).setMessage(strNotifTxMsg).setPositiveButton(R.string.confirm, new DialogInterface.OnClickListener() {

        public void onClick(DialogInterface dialog, int whichButton) {
            new Thread(new Runnable() {

                @Override
                public void run() {
                    Looper.prepare();
                    Transaction tx = SendFactory.getInstance(BIP47Activity.this).makeTransaction(0, outpoints, receivers);
                    if (tx != null) {
                        String input0hash = tx.getInput(0L).getOutpoint().getHash().toString();
                        Log.d("BIP47Activity", "input0 hash:" + input0hash);
                        Log.d("BIP47Activity", "_outPoint hash:" + _outPoint.getTxHash().toString());
                        int input0index = (int) tx.getInput(0L).getOutpoint().getIndex();
                        Log.d("BIP47Activity", "input0 index:" + input0index);
                        Log.d("BIP47Activity", "_outPoint index:" + _outPoint.getTxOutputN());
                        if (!input0hash.equals(_outPoint.getTxHash().toString()) || input0index != _outPoint.getTxOutputN()) {
                            Toast.makeText(BIP47Activity.this, R.string.bip47_cannot_compose_notif_tx, Toast.LENGTH_SHORT).show();
                            return;
                        }
                        tx = SendFactory.getInstance(BIP47Activity.this).signTransaction(tx);
                        final String hexTx = new String(org.bouncycastle.util.encoders.Hex.encode(tx.bitcoinSerialize()));
                        Log.d("SendActivity", tx.getHashAsString());
                        Log.d("SendActivity", hexTx);
                        boolean isOK = false;
                        String response = null;
                        try {
                            response = PushTx.getInstance(BIP47Activity.this).samourai(hexTx);
                            Log.d("SendActivity", "pushTx:" + response);
                            if (response != null) {
                                org.json.JSONObject jsonObject = new org.json.JSONObject(response);
                                if (jsonObject.has("status")) {
                                    if (jsonObject.getString("status").equals("ok")) {
                                        isOK = true;
                                    }
                                }
                            } else {
                                Toast.makeText(BIP47Activity.this, R.string.pushtx_returns_null, Toast.LENGTH_SHORT).show();
                                return;
                            }
                            if (isOK) {
                                Toast.makeText(BIP47Activity.this, R.string.payment_channel_init, Toast.LENGTH_SHORT).show();
                                // 
                                // set outgoing index for payment code to 0
                                // 
                                BIP47Meta.getInstance().setOutgoingIdx(pcode, 0);
                                // Log.i("SendNotifTxFactory", "tx hash:" + tx.getHashAsString());
                                // 
                                // status to NO_CFM
                                // 
                                BIP47Meta.getInstance().setOutgoingStatus(pcode, tx.getHashAsString(), BIP47Meta.STATUS_SENT_NO_CFM);
                                // 
                                if (change > 0L) {
                                    BIP49Util.getInstance(BIP47Activity.this).getWallet().getAccount(0).getChange().incAddrIdx();
                                }
                                PayloadUtil.getInstance(BIP47Activity.this).saveWalletToJSON(new CharSequenceX(AccessFactory.getInstance(BIP47Activity.this).getGUID() + AccessFactory.getInstance(BIP47Activity.this).getPIN()));
                            } else {
                                Toast.makeText(BIP47Activity.this, R.string.tx_failed, Toast.LENGTH_SHORT).show();
                            }
                        } catch (JSONException je) {
                            Toast.makeText(BIP47Activity.this, "pushTx:" + je.getMessage(), Toast.LENGTH_SHORT).show();
                            return;
                        } catch (MnemonicException.MnemonicLengthException mle) {
                            Toast.makeText(BIP47Activity.this, "pushTx:" + mle.getMessage(), Toast.LENGTH_SHORT).show();
                            return;
                        } catch (DecoderException de) {
                            Toast.makeText(BIP47Activity.this, "pushTx:" + de.getMessage(), Toast.LENGTH_SHORT).show();
                            return;
                        } catch (IOException ioe) {
                            Toast.makeText(BIP47Activity.this, "pushTx:" + ioe.getMessage(), Toast.LENGTH_SHORT).show();
                            return;
                        } catch (DecryptionException de) {
                            Toast.makeText(BIP47Activity.this, "pushTx:" + de.getMessage(), Toast.LENGTH_SHORT).show();
                            return;
                        }
                    }
                    Looper.loop();
                }
            }).start();
        }
    }).setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {

        public void onClick(DialogInterface dialog, int whichButton) {
            ;
        }
    });
    dlg.show();
}
Also used : AlertDialog(android.app.AlertDialog) CharSequenceX(com.samourai.wallet.util.CharSequenceX) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) MyTransactionOutPoint(com.samourai.wallet.send.MyTransactionOutPoint) ECKey(org.bitcoinj.core.ECKey) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) JSONObject(org.json.JSONObject) InvalidKeySpecException(java.security.spec.InvalidKeySpecException) SecretPoint(com.samourai.wallet.bip47.rpc.SecretPoint) AddressFormatException(org.bitcoinj.core.AddressFormatException) Script(org.bitcoinj.script.Script) SuggestedFee(com.samourai.wallet.send.SuggestedFee) Transaction(org.bitcoinj.core.Transaction) JSONObject(org.json.JSONObject) BigInteger(java.math.BigInteger) DialogInterface(android.content.DialogInterface) MnemonicException(org.bitcoinj.crypto.MnemonicException) PaymentCode(com.samourai.wallet.bip47.rpc.PaymentCode) SendFactory(com.samourai.wallet.send.SendFactory) JSONException(org.json.JSONException) Intent(android.content.Intent) IOException(java.io.IOException) InvalidKeyException(java.security.InvalidKeyException) MyTransactionOutPoint(com.samourai.wallet.send.MyTransactionOutPoint) SecretPoint(com.samourai.wallet.bip47.rpc.SecretPoint) Point(android.graphics.Point) UTXO(com.samourai.wallet.send.UTXO) DecoderException(org.bouncycastle.util.encoders.DecoderException) MyTransactionInput(com.samourai.wallet.send.MyTransactionInput) NoSuchProviderException(java.security.NoSuchProviderException) DecryptionException(com.samourai.wallet.crypto.DecryptionException)

Example 4 with DecoderException

use of org.bouncycastle.util.encoders.DecoderException in project samourai-wallet-android by Samourai-Wallet.

the class PayNymDetailsActivity method doNotifTx.

private void doNotifTx() {
    // 
    // get wallet balance
    // 
    long balance = 0L;
    try {
        balance = APIFactory.getInstance(PayNymDetailsActivity.this).getXpubAmounts().get(HD_WalletFactory.getInstance(PayNymDetailsActivity.this).get().getAccount(0).xpubstr());
    } catch (IOException ioe) {
        balance = 0L;
    } catch (MnemonicException.MnemonicLengthException mle) {
        balance = 0L;
    } catch (java.lang.NullPointerException npe) {
        balance = 0L;
    }
    final List<UTXO> selectedUTXO = new ArrayList<UTXO>();
    long totalValueSelected = 0L;
    // long change = 0L;
    BigInteger fee = null;
    // 
    // spend dust threshold amount to notification address
    // 
    long amount = SendNotifTxFactory._bNotifTxValue.longValue();
    // 
    // add Samourai Wallet fee to total amount
    // 
    amount += SendNotifTxFactory._bSWFee.longValue();
    // 
    // get unspents
    // 
    List<UTXO> utxos = null;
    if (UTXOFactory.getInstance().getTotalP2SH_P2WPKH() > amount + FeeUtil.getInstance().estimatedFeeSegwit(0, 1, 4).longValue()) {
        utxos = new ArrayList<UTXO>();
        utxos.addAll(UTXOFactory.getInstance().getAllP2SH_P2WPKH().values());
    } else {
        utxos = APIFactory.getInstance(PayNymDetailsActivity.this).getUtxos(true);
    }
    // sort in ascending order by value
    final List<UTXO> _utxos = utxos;
    Collections.sort(_utxos, new UTXO.UTXOComparator());
    Collections.reverse(_utxos);
    // 
    for (UTXO u : _utxos) {
        if (u.getValue() >= (amount + SamouraiWallet.bDust.longValue() + FeeUtil.getInstance().estimatedFee(1, 4).longValue())) {
            selectedUTXO.add(u);
            totalValueSelected += u.getValue();
            Log.d("PayNymDetailsActivity", "single output");
            Log.d("PayNymDetailsActivity", "value selected:" + u.getValue());
            Log.d("PayNymDetailsActivity", "total value selected:" + totalValueSelected);
            Log.d("PayNymDetailsActivity", "nb inputs:" + u.getOutpoints().size());
            break;
        }
    }
    // 
    // use normal fee settings
    // 
    SuggestedFee suggestedFee = FeeUtil.getInstance().getSuggestedFee();
    long lo = FeeUtil.getInstance().getLowFee().getDefaultPerKB().longValue() / 1000L;
    long mi = FeeUtil.getInstance().getNormalFee().getDefaultPerKB().longValue() / 1000L;
    long hi = FeeUtil.getInstance().getHighFee().getDefaultPerKB().longValue() / 1000L;
    if (lo == mi && mi == hi) {
        SuggestedFee hi_sf = new SuggestedFee();
        hi_sf.setDefaultPerKB(BigInteger.valueOf((long) (hi * 1.15 * 1000.0)));
        FeeUtil.getInstance().setSuggestedFee(hi_sf);
    } else if (lo == mi) {
        FeeUtil.getInstance().setSuggestedFee(FeeUtil.getInstance().getHighFee());
    } else {
        FeeUtil.getInstance().setSuggestedFee(FeeUtil.getInstance().getNormalFee());
    }
    if (selectedUTXO.size() == 0) {
        // sort in descending order by value
        Collections.sort(_utxos, new UTXO.UTXOComparator());
        int selected = 0;
        // get largest UTXOs > than spend + fee + dust
        for (UTXO u : _utxos) {
            selectedUTXO.add(u);
            totalValueSelected += u.getValue();
            selected += u.getOutpoints().size();
            if (totalValueSelected >= (amount + SamouraiWallet.bDust.longValue() + FeeUtil.getInstance().estimatedFee(selected, 4).longValue())) {
                Log.d("PayNymDetailsActivity", "multiple outputs");
                Log.d("PayNymDetailsActivity", "total value selected:" + totalValueSelected);
                Log.d("PayNymDetailsActivity", "nb inputs:" + u.getOutpoints().size());
                break;
            }
        }
        // fee = FeeUtil.getInstance().estimatedFee(selected, 4);
        fee = FeeUtil.getInstance().estimatedFee(selected, 7);
    } else {
        // fee = FeeUtil.getInstance().estimatedFee(1, 4);
        fee = FeeUtil.getInstance().estimatedFee(1, 7);
    }
    // 
    // reset fee to previous setting
    // 
    FeeUtil.getInstance().setSuggestedFee(suggestedFee);
    // 
    if ((amount + fee.longValue()) >= balance) {
        String message = getText(R.string.bip47_notif_tx_insufficient_funds_1) + " ";
        BigInteger biAmount = SendNotifTxFactory._bSWFee.add(SendNotifTxFactory._bNotifTxValue.add(FeeUtil.getInstance().estimatedFee(1, 4, FeeUtil.getInstance().getLowFee().getDefaultPerKB())));
        String strAmount = MonetaryUtil.getInstance().getBTCFormat().format(((double) biAmount.longValue()) / 1e8) + " BTC ";
        message += strAmount;
        message += " " + getText(R.string.bip47_notif_tx_insufficient_funds_2);
        AlertDialog.Builder dlg = new AlertDialog.Builder(PayNymDetailsActivity.this).setTitle(R.string.app_name).setMessage(message).setCancelable(false).setPositiveButton(R.string.help, new DialogInterface.OnClickListener() {

            public void onClick(DialogInterface dialog, int whichButton) {
                Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://support.samourai.io/article/58-connecting-to-a-paynym-contact"));
                startActivity(browserIntent);
            }
        }).setNegativeButton(R.string.close, new DialogInterface.OnClickListener() {

            public void onClick(DialogInterface dialog, int whichButton) {
                dialog.dismiss();
            }
        });
        if (!isFinishing()) {
            dlg.show();
        }
        return;
    }
    // 
    // payment code to be notified
    // 
    PaymentCode payment_code;
    try {
        payment_code = new PaymentCode(pcode);
    } catch (AddressFormatException afe) {
        payment_code = null;
    }
    if (payment_code == null) {
        return;
    }
    // 
    // create outpoints for spend later
    // 
    final List<MyTransactionOutPoint> outpoints = new ArrayList<MyTransactionOutPoint>();
    for (UTXO u : selectedUTXO) {
        outpoints.addAll(u.getOutpoints());
    }
    // 
    // create inputs from outpoints
    // 
    List<MyTransactionInput> inputs = new ArrayList<MyTransactionInput>();
    for (MyTransactionOutPoint o : outpoints) {
        Script script = new Script(o.getScriptBytes());
        if (script.getScriptType() == Script.ScriptType.NO_TYPE) {
            continue;
        }
        MyTransactionInput input = new MyTransactionInput(SamouraiWallet.getInstance().getCurrentNetworkParams(), null, new byte[0], o, o.getTxHash().toString(), o.getTxOutputN());
        inputs.add(input);
    }
    // 
    // sort inputs
    // 
    Collections.sort(inputs, new SendFactory.BIP69InputComparator());
    // 
    // find outpoint that corresponds to 0th input
    // 
    MyTransactionOutPoint outPoint = null;
    for (MyTransactionOutPoint o : outpoints) {
        if (o.getTxHash().toString().equals(inputs.get(0).getTxHash()) && o.getTxOutputN() == inputs.get(0).getTxPos()) {
            outPoint = o;
            break;
        }
    }
    if (outPoint == null) {
        Toast.makeText(PayNymDetailsActivity.this, R.string.bip47_cannot_identify_outpoint, Toast.LENGTH_SHORT).show();
        return;
    }
    byte[] op_return = null;
    // 
    try {
        // Script inputScript = new Script(outPoint.getConnectedPubKeyScript());
        byte[] scriptBytes = outPoint.getConnectedPubKeyScript();
        String address = null;
        if (Bech32Util.getInstance().isBech32Script(Hex.toHexString(scriptBytes))) {
            address = Bech32Util.getInstance().getAddressFromScript(Hex.toHexString(scriptBytes));
        } else {
            address = new Script(scriptBytes).getToAddress(SamouraiWallet.getInstance().getCurrentNetworkParams()).toString();
        }
        // String address = inputScript.getToAddress(SamouraiWallet.getInstance().getCurrentNetworkParams()).toString();
        ECKey ecKey = SendFactory.getPrivKey(address, 0);
        if (ecKey == null || !ecKey.hasPrivKey()) {
            Toast.makeText(PayNymDetailsActivity.this, R.string.bip47_cannot_compose_notif_tx, Toast.LENGTH_SHORT).show();
            return;
        }
        // 
        // use outpoint for payload masking
        // 
        byte[] privkey = ecKey.getPrivKeyBytes();
        byte[] pubkey = payment_code.notificationAddress(SamouraiWallet.getInstance().getCurrentNetworkParams()).getPubKey();
        byte[] outpoint = outPoint.bitcoinSerialize();
        // Log.i("PayNymDetailsActivity", "outpoint:" + Hex.toHexString(outpoint));
        // Log.i("PayNymDetailsActivity", "payer shared secret:" + Hex.toHexString(new SecretPoint(privkey, pubkey).ECDHSecretAsBytes()));
        byte[] mask = PaymentCode.getMask(new SecretPoint(privkey, pubkey).ECDHSecretAsBytes(), outpoint);
        // Log.i("PayNymDetailsActivity", "mask:" + Hex.toHexString(mask));
        // Log.i("PayNymDetailsActivity", "mask length:" + mask.length);
        // Log.i("PayNymDetailsActivity", "payload0:" + Hex.toHexString(BIP47Util.getInstance(context).getPaymentCode().getPayload()));
        op_return = PaymentCode.blind(BIP47Util.getInstance(PayNymDetailsActivity.this).getPaymentCode().getPayload(), mask);
    // Log.i("PayNymDetailsActivity", "payload1:" + Hex.toHexString(op_return));
    } catch (InvalidKeyException ike) {
        Toast.makeText(PayNymDetailsActivity.this, ike.getMessage(), Toast.LENGTH_SHORT).show();
        return;
    } catch (InvalidKeySpecException ikse) {
        Toast.makeText(PayNymDetailsActivity.this, ikse.getMessage(), Toast.LENGTH_SHORT).show();
        return;
    } catch (NoSuchAlgorithmException nsae) {
        Toast.makeText(PayNymDetailsActivity.this, nsae.getMessage(), Toast.LENGTH_SHORT).show();
        return;
    } catch (NoSuchProviderException nspe) {
        Toast.makeText(PayNymDetailsActivity.this, nspe.getMessage(), Toast.LENGTH_SHORT).show();
        return;
    } catch (Exception e) {
        Toast.makeText(PayNymDetailsActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show();
        return;
    }
    final HashMap<String, BigInteger> receivers = new HashMap<String, BigInteger>();
    receivers.put(Hex.toHexString(op_return), BigInteger.ZERO);
    receivers.put(payment_code.notificationAddress(SamouraiWallet.getInstance().getCurrentNetworkParams()).getAddressString(), SendNotifTxFactory._bNotifTxValue);
    receivers.put(SamouraiWallet.getInstance().isTestNet() ? SendNotifTxFactory.TESTNET_SAMOURAI_NOTIF_TX_FEE_ADDRESS : SendNotifTxFactory.SAMOURAI_NOTIF_TX_FEE_ADDRESS, SendNotifTxFactory._bSWFee);
    final long change = totalValueSelected - (amount + fee.longValue());
    if (change > 0L) {
        String change_address = BIP84Util.getInstance(PayNymDetailsActivity.this).getAddressAt(AddressFactory.CHANGE_CHAIN, BIP84Util.getInstance(PayNymDetailsActivity.this).getWallet().getAccount(0).getChange().getAddrIdx()).getBech32AsString();
        receivers.put(change_address, BigInteger.valueOf(change));
    }
    Log.d("PayNymDetailsActivity", "outpoints:" + outpoints.size());
    Log.d("PayNymDetailsActivity", "totalValueSelected:" + BigInteger.valueOf(totalValueSelected).toString());
    Log.d("PayNymDetailsActivity", "amount:" + BigInteger.valueOf(amount).toString());
    Log.d("PayNymDetailsActivity", "change:" + BigInteger.valueOf(change).toString());
    Log.d("PayNymDetailsActivity", "fee:" + fee.toString());
    if (change < 0L) {
        Toast.makeText(PayNymDetailsActivity.this, R.string.bip47_cannot_compose_notif_tx, Toast.LENGTH_SHORT).show();
        return;
    }
    final MyTransactionOutPoint _outPoint = outPoint;
    String strNotifTxMsg = getText(R.string.bip47_setup4_text1) + " ";
    long notifAmount = amount;
    String strAmount = MonetaryUtil.getInstance().getBTCFormat().format(((double) notifAmount + fee.longValue()) / 1e8) + " BTC ";
    strNotifTxMsg += strAmount + getText(R.string.bip47_setup4_text2);
    showFollowAlert(strAmount, view -> {
        new Thread(new Runnable() {

            @Override
            public void run() {
                Looper.prepare();
                Transaction tx = SendFactory.getInstance(PayNymDetailsActivity.this).makeTransaction(0, outpoints, receivers);
                if (tx != null) {
                    String input0hash = tx.getInput(0L).getOutpoint().getHash().toString();
                    Log.d("PayNymDetailsActivity", "input0 hash:" + input0hash);
                    Log.d("PayNymDetailsActivity", "_outPoint hash:" + _outPoint.getTxHash().toString());
                    int input0index = (int) tx.getInput(0L).getOutpoint().getIndex();
                    Log.d("PayNymDetailsActivity", "input0 index:" + input0index);
                    Log.d("PayNymDetailsActivity", "_outPoint index:" + _outPoint.getTxOutputN());
                    if (!input0hash.equals(_outPoint.getTxHash().toString()) || input0index != _outPoint.getTxOutputN()) {
                        Toast.makeText(PayNymDetailsActivity.this, R.string.bip47_cannot_compose_notif_tx, Toast.LENGTH_SHORT).show();
                        return;
                    }
                    tx = SendFactory.getInstance(PayNymDetailsActivity.this).signTransaction(tx, 0);
                    final String hexTx = new String(org.bouncycastle.util.encoders.Hex.encode(tx.bitcoinSerialize()));
                    Log.d("SendActivity", tx.getHashAsString());
                    Log.d("SendActivity", hexTx);
                    boolean isOK = false;
                    String response = null;
                    try {
                        response = PushTx.getInstance(PayNymDetailsActivity.this).samourai(hexTx);
                        Log.d("SendActivity", "pushTx:" + response);
                        if (response != null) {
                            org.json.JSONObject jsonObject = new org.json.JSONObject(response);
                            if (jsonObject.has("status")) {
                                if (jsonObject.getString("status").equals("ok")) {
                                    isOK = true;
                                }
                            }
                        } else {
                            Toast.makeText(PayNymDetailsActivity.this, R.string.pushtx_returns_null, Toast.LENGTH_SHORT).show();
                            return;
                        }
                        if (isOK) {
                            Toast.makeText(PayNymDetailsActivity.this, R.string.payment_channel_init, Toast.LENGTH_SHORT).show();
                            // 
                            // set outgoing index for payment code to 0
                            // 
                            BIP47Meta.getInstance().setOutgoingIdx(pcode, 0);
                            // Log.i("SendNotifTxFactory", "tx hash:" + tx.getHashAsString());
                            // 
                            // status to NO_CFM
                            // 
                            BIP47Meta.getInstance().setOutgoingStatus(pcode, tx.getHashAsString(), BIP47Meta.STATUS_SENT_NO_CFM);
                            // 
                            if (change > 0L) {
                                BIP49Util.getInstance(PayNymDetailsActivity.this).getWallet().getAccount(0).getChange().incAddrIdx();
                            }
                            savePayLoad();
                        } else {
                            Toast.makeText(PayNymDetailsActivity.this, R.string.tx_failed, Toast.LENGTH_SHORT).show();
                        }
                        runOnUiThread(() -> {
                            setPayNym();
                        });
                    } catch (JSONException je) {
                        Toast.makeText(PayNymDetailsActivity.this, "pushTx:" + je.getMessage(), Toast.LENGTH_SHORT).show();
                        return;
                    } catch (MnemonicException.MnemonicLengthException mle) {
                        Toast.makeText(PayNymDetailsActivity.this, "pushTx:" + mle.getMessage(), Toast.LENGTH_SHORT).show();
                        return;
                    } catch (DecoderException de) {
                        Toast.makeText(PayNymDetailsActivity.this, "pushTx:" + de.getMessage(), Toast.LENGTH_SHORT).show();
                        return;
                    } catch (IOException ioe) {
                        Toast.makeText(PayNymDetailsActivity.this, "pushTx:" + ioe.getMessage(), Toast.LENGTH_SHORT).show();
                        return;
                    } catch (DecryptionException de) {
                        Toast.makeText(PayNymDetailsActivity.this, "pushTx:" + de.getMessage(), Toast.LENGTH_SHORT).show();
                        return;
                    }
                }
                Looper.loop();
            }
        }).start();
    });
}
Also used : AlertDialog(android.app.AlertDialog) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) MyTransactionOutPoint(com.samourai.wallet.send.MyTransactionOutPoint) ECKey(org.bitcoinj.core.ECKey) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) JSONObject(org.json.JSONObject) InvalidKeySpecException(java.security.spec.InvalidKeySpecException) SecretPoint(com.samourai.wallet.bip47.rpc.SecretPoint) AddressFormatException(org.bitcoinj.core.AddressFormatException) Script(org.bitcoinj.script.Script) SuggestedFee(com.samourai.wallet.send.SuggestedFee) Transaction(org.bitcoinj.core.Transaction) JSONObject(org.json.JSONObject) BigInteger(java.math.BigInteger) DialogInterface(android.content.DialogInterface) MnemonicException(org.bitcoinj.crypto.MnemonicException) PaymentCode(com.samourai.wallet.bip47.rpc.PaymentCode) SendFactory(com.samourai.wallet.send.SendFactory) JSONException(org.json.JSONException) Intent(android.content.Intent) IOException(java.io.IOException) InvalidKeyException(java.security.InvalidKeyException) MyTransactionOutPoint(com.samourai.wallet.send.MyTransactionOutPoint) SecretPoint(com.samourai.wallet.bip47.rpc.SecretPoint) JSONException(org.json.JSONException) DecoderException(org.bouncycastle.util.encoders.DecoderException) AddressFormatException(org.bitcoinj.core.AddressFormatException) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) InvalidKeyException(java.security.InvalidKeyException) InvalidKeySpecException(java.security.spec.InvalidKeySpecException) MnemonicException(org.bitcoinj.crypto.MnemonicException) DecryptionException(com.samourai.wallet.crypto.DecryptionException) IOException(java.io.IOException) NoSuchProviderException(java.security.NoSuchProviderException) UTXO(com.samourai.wallet.send.UTXO) DecoderException(org.bouncycastle.util.encoders.DecoderException) MyTransactionInput(com.samourai.wallet.send.MyTransactionInput) NoSuchProviderException(java.security.NoSuchProviderException) DecryptionException(com.samourai.wallet.crypto.DecryptionException)

Example 5 with DecoderException

use of org.bouncycastle.util.encoders.DecoderException in project samourai-wallet-android by Samourai-Wallet.

the class BIP47Add method onOptionsItemSelected.

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    int id = item.getItemId();
    if (id == android.R.id.home) {
        finish();
    } else if (id == R.id.action_add) {
        View view = BIP47Add.this.getCurrentFocus();
        if (view != null) {
            InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
            imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
        }
        String label = edLabel.getText().toString();
        final String pcode = edPCode.getText().toString();
        if (pcode == null || pcode.length() < 1 || !FormatsUtil.getInstance().isValidPaymentCode(pcode)) {
            Toast.makeText(BIP47Add.this, R.string.invalid_payment_code, Toast.LENGTH_SHORT).show();
        } else if (label == null || label.length() < 1) {
            Toast.makeText(BIP47Add.this, R.string.bip47_no_label_error, Toast.LENGTH_SHORT).show();
        } else {
            BIP47Meta.getInstance().setLabel(pcode, label);
            new Thread(new Runnable() {

                @Override
                public void run() {
                    Looper.prepare();
                    try {
                        PayloadUtil.getInstance(BIP47Add.this).saveWalletToJSON(new CharSequenceX(AccessFactory.getInstance(BIP47Add.this).getGUID() + AccessFactory.getInstance().getPIN()));
                    } catch (MnemonicException.MnemonicLengthException mle) {
                        mle.printStackTrace();
                        Toast.makeText(BIP47Add.this, R.string.decryption_error, Toast.LENGTH_SHORT).show();
                    } catch (DecoderException de) {
                        de.printStackTrace();
                        Toast.makeText(BIP47Add.this, R.string.decryption_error, Toast.LENGTH_SHORT).show();
                    } catch (JSONException je) {
                        je.printStackTrace();
                        Toast.makeText(BIP47Add.this, R.string.decryption_error, Toast.LENGTH_SHORT).show();
                    } catch (IOException ioe) {
                        ioe.printStackTrace();
                        Toast.makeText(BIP47Add.this, R.string.decryption_error, Toast.LENGTH_SHORT).show();
                    } catch (java.lang.NullPointerException npe) {
                        npe.printStackTrace();
                        Toast.makeText(BIP47Add.this, R.string.decryption_error, Toast.LENGTH_SHORT).show();
                    } catch (DecryptionException de) {
                        de.printStackTrace();
                        Toast.makeText(BIP47Add.this, R.string.decryption_error, Toast.LENGTH_SHORT).show();
                    } finally {
                        ;
                    }
                    Looper.loop();
                }
            }).start();
            Intent resultIntent = new Intent();
            resultIntent.putExtra("pcode", pcode);
            setResult(Activity.RESULT_OK, resultIntent);
            finish();
        }
    } else {
        ;
    }
    return super.onOptionsItemSelected(item);
}
Also used : CharSequenceX(com.samourai.wallet.util.CharSequenceX) JSONException(org.json.JSONException) InputMethodManager(android.view.inputmethod.InputMethodManager) Intent(android.content.Intent) IOException(java.io.IOException) View(android.view.View) DecoderException(org.bouncycastle.util.encoders.DecoderException) MnemonicException(org.bitcoinj.crypto.MnemonicException) DecryptionException(com.samourai.wallet.crypto.DecryptionException)

Aggregations

DecoderException (org.bouncycastle.util.encoders.DecoderException)12 IOException (java.io.IOException)9 MnemonicException (org.bitcoinj.crypto.MnemonicException)8 JSONException (org.json.JSONException)8 Intent (android.content.Intent)6 AlertDialog (android.app.AlertDialog)5 DialogInterface (android.content.DialogInterface)5 MyTransactionOutPoint (com.samourai.wallet.send.MyTransactionOutPoint)5 SuggestedFee (com.samourai.wallet.send.SuggestedFee)5 UTXO (com.samourai.wallet.send.UTXO)5 BigInteger (java.math.BigInteger)5 ArrayList (java.util.ArrayList)5 Transaction (org.bitcoinj.core.Transaction)5 Script (org.bitcoinj.script.Script)5 JSONObject (org.json.JSONObject)5 DecryptionException (com.samourai.wallet.crypto.DecryptionException)4 InvalidKeyException (java.security.InvalidKeyException)4 HashMap (java.util.HashMap)4 CharSequenceX (com.samourai.wallet.util.CharSequenceX)3 Point (android.graphics.Point)2