mirror of
https://github.com/Qortal/altcoinj.git
synced 2025-08-02 00:31:24 +00:00
ECKey: If DER-encoded signatures cannot be parsed, throw SignatureDecodeException rather than RuntimeException.
This commit is contained in:
@@ -115,7 +115,11 @@ public class AlertMessage extends Message {
|
|||||||
* doesn't verify, because that would allow arbitrary attackers to spam your users.
|
* doesn't verify, because that would allow arbitrary attackers to spam your users.
|
||||||
*/
|
*/
|
||||||
public boolean isSignatureValid() {
|
public boolean isSignatureValid() {
|
||||||
|
try {
|
||||||
return ECKey.verify(Sha256Hash.hashTwice(content), signature, params.getAlertSigningKey());
|
return ECKey.verify(Sha256Hash.hashTwice(content), signature, params.getAlertSigningKey());
|
||||||
|
} catch (SignatureDecodeException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@@ -564,7 +564,10 @@ public class ECKey implements EncryptableItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ECDSASignature decodeFromDER(byte[] bytes) throws IllegalArgumentException {
|
/**
|
||||||
|
* @throws SignatureDecodeException if the signature is unparseable in some way.
|
||||||
|
*/
|
||||||
|
public static ECDSASignature decodeFromDER(byte[] bytes) throws SignatureDecodeException {
|
||||||
ASN1InputStream decoder = null;
|
ASN1InputStream decoder = null;
|
||||||
try {
|
try {
|
||||||
// BouncyCastle by default is strict about parsing ASN.1 integers. We relax this check, because some
|
// BouncyCastle by default is strict about parsing ASN.1 integers. We relax this check, because some
|
||||||
@@ -573,22 +576,22 @@ public class ECKey implements EncryptableItem {
|
|||||||
decoder = new ASN1InputStream(bytes);
|
decoder = new ASN1InputStream(bytes);
|
||||||
final ASN1Primitive seqObj = decoder.readObject();
|
final ASN1Primitive seqObj = decoder.readObject();
|
||||||
if (seqObj == null)
|
if (seqObj == null)
|
||||||
throw new IllegalArgumentException("Reached past end of ASN.1 stream.");
|
throw new SignatureDecodeException("Reached past end of ASN.1 stream.");
|
||||||
if (!(seqObj instanceof DLSequence))
|
if (!(seqObj instanceof DLSequence))
|
||||||
throw new IllegalArgumentException("Read unexpected class: " + seqObj.getClass().getName());
|
throw new SignatureDecodeException("Read unexpected class: " + seqObj.getClass().getName());
|
||||||
final DLSequence seq = (DLSequence) seqObj;
|
final DLSequence seq = (DLSequence) seqObj;
|
||||||
ASN1Integer r, s;
|
ASN1Integer r, s;
|
||||||
try {
|
try {
|
||||||
r = (ASN1Integer) seq.getObjectAt(0);
|
r = (ASN1Integer) seq.getObjectAt(0);
|
||||||
s = (ASN1Integer) seq.getObjectAt(1);
|
s = (ASN1Integer) seq.getObjectAt(1);
|
||||||
} catch (ClassCastException e) {
|
} catch (ClassCastException e) {
|
||||||
throw new IllegalArgumentException(e);
|
throw new SignatureDecodeException(e);
|
||||||
}
|
}
|
||||||
// OpenSSL deviates from the DER spec by interpreting these values as unsigned, though they should not be
|
// OpenSSL deviates from the DER spec by interpreting these values as unsigned, though they should not be
|
||||||
// Thus, we always use the positive versions. See: http://r6.ca/blog/20111119T211504Z.html
|
// Thus, we always use the positive versions. See: http://r6.ca/blog/20111119T211504Z.html
|
||||||
return new ECDSASignature(r.getPositiveValue(), s.getPositiveValue());
|
return new ECDSASignature(r.getPositiveValue(), s.getPositiveValue());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new IllegalArgumentException(e);
|
throw new SignatureDecodeException(e);
|
||||||
} finally {
|
} finally {
|
||||||
if (decoder != null)
|
if (decoder != null)
|
||||||
try { decoder.close(); } catch (IOException x) {}
|
try { decoder.close(); } catch (IOException x) {}
|
||||||
@@ -674,6 +677,8 @@ public class ECKey implements EncryptableItem {
|
|||||||
} catch (NativeSecp256k1Util.AssertFailException e) {
|
} catch (NativeSecp256k1Util.AssertFailException e) {
|
||||||
log.error("Caught AssertFailException inside secp256k1", e);
|
log.error("Caught AssertFailException inside secp256k1", e);
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
|
} catch (SignatureDecodeException e) {
|
||||||
|
throw new RuntimeException(e); // cannot happen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (FAKE_SIGNATURES)
|
if (FAKE_SIGNATURES)
|
||||||
@@ -728,8 +733,9 @@ public class ECKey implements EncryptableItem {
|
|||||||
* @param data Hash of the data to verify.
|
* @param data Hash of the data to verify.
|
||||||
* @param signature ASN.1 encoded signature.
|
* @param signature ASN.1 encoded signature.
|
||||||
* @param pub The public key bytes to use.
|
* @param pub The public key bytes to use.
|
||||||
|
* @throws SignatureDecodeException if the signature is unparseable in some way.
|
||||||
*/
|
*/
|
||||||
public static boolean verify(byte[] data, byte[] signature, byte[] pub) {
|
public static boolean verify(byte[] data, byte[] signature, byte[] pub) throws SignatureDecodeException {
|
||||||
if (Secp256k1Context.isEnabled()) {
|
if (Secp256k1Context.isEnabled()) {
|
||||||
try {
|
try {
|
||||||
return NativeSecp256k1.verify(data, signature, pub);
|
return NativeSecp256k1.verify(data, signature, pub);
|
||||||
@@ -746,8 +752,9 @@ public class ECKey implements EncryptableItem {
|
|||||||
*
|
*
|
||||||
* @param hash Hash of the data to verify.
|
* @param hash Hash of the data to verify.
|
||||||
* @param signature ASN.1 encoded signature.
|
* @param signature ASN.1 encoded signature.
|
||||||
|
* @throws SignatureDecodeException if the signature is unparseable in some way.
|
||||||
*/
|
*/
|
||||||
public boolean verify(byte[] hash, byte[] signature) {
|
public boolean verify(byte[] hash, byte[] signature) throws SignatureDecodeException {
|
||||||
return ECKey.verify(hash, signature, getPubKey());
|
return ECKey.verify(hash, signature, getPubKey());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -761,9 +768,10 @@ public class ECKey implements EncryptableItem {
|
|||||||
/**
|
/**
|
||||||
* Verifies the given ASN.1 encoded ECDSA signature against a hash using the public key, and throws an exception
|
* Verifies the given ASN.1 encoded ECDSA signature against a hash using the public key, and throws an exception
|
||||||
* if the signature doesn't match
|
* if the signature doesn't match
|
||||||
|
* @throws SignatureDecodeException if the signature is unparseable in some way.
|
||||||
* @throws java.security.SignatureException if the signature does not match.
|
* @throws java.security.SignatureException if the signature does not match.
|
||||||
*/
|
*/
|
||||||
public void verifyOrThrow(byte[] hash, byte[] signature) throws SignatureException {
|
public void verifyOrThrow(byte[] hash, byte[] signature) throws SignatureDecodeException, SignatureException {
|
||||||
if (!verify(hash, signature))
|
if (!verify(hash, signature))
|
||||||
throw new SignatureException();
|
throw new SignatureException();
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Andreas Schildbach
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.bitcoinj.core;
|
||||||
|
|
||||||
|
public class SignatureDecodeException extends Exception {
|
||||||
|
public SignatureDecodeException() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public SignatureDecodeException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SignatureDecodeException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SignatureDecodeException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package org.bitcoinj.crypto;
|
package org.bitcoinj.crypto;
|
||||||
|
|
||||||
|
import org.bitcoinj.core.SignatureDecodeException;
|
||||||
import org.bitcoinj.core.ECKey;
|
import org.bitcoinj.core.ECKey;
|
||||||
import org.bitcoinj.core.Transaction;
|
import org.bitcoinj.core.Transaction;
|
||||||
import org.bitcoinj.core.VerificationException;
|
import org.bitcoinj.core.VerificationException;
|
||||||
@@ -163,20 +164,15 @@ public class TransactionSignature extends ECKey.ECDSASignature {
|
|||||||
* be canonical.
|
* be canonical.
|
||||||
* @param requireCanonicalSValue if the S-value must be canonical (below half
|
* @param requireCanonicalSValue if the S-value must be canonical (below half
|
||||||
* the order of the curve).
|
* the order of the curve).
|
||||||
* @throws RuntimeException if the signature is invalid or unparseable in some way.
|
* @throws SignatureDecodeException if the signature is unparseable in some way.
|
||||||
|
* @throws VerificationException if the signature is invalid.
|
||||||
*/
|
*/
|
||||||
public static TransactionSignature decodeFromBitcoin(byte[] bytes,
|
public static TransactionSignature decodeFromBitcoin(byte[] bytes, boolean requireCanonicalEncoding,
|
||||||
boolean requireCanonicalEncoding,
|
boolean requireCanonicalSValue) throws SignatureDecodeException, VerificationException {
|
||||||
boolean requireCanonicalSValue) throws VerificationException {
|
|
||||||
// Bitcoin encoding is DER signature + sighash byte.
|
// Bitcoin encoding is DER signature + sighash byte.
|
||||||
if (requireCanonicalEncoding && !isEncodingCanonical(bytes))
|
if (requireCanonicalEncoding && !isEncodingCanonical(bytes))
|
||||||
throw new VerificationException("Signature encoding is not canonical.");
|
throw new VerificationException("Signature encoding is not canonical.");
|
||||||
ECKey.ECDSASignature sig;
|
ECKey.ECDSASignature sig = ECKey.ECDSASignature.decodeFromDER(bytes);
|
||||||
try {
|
|
||||||
sig = ECKey.ECDSASignature.decodeFromDER(bytes);
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
throw new VerificationException("Could not decode DER", e);
|
|
||||||
}
|
|
||||||
if (requireCanonicalSValue && !sig.isCanonical())
|
if (requireCanonicalSValue && !sig.isCanonical())
|
||||||
throw new VerificationException("S-value is not canonical.");
|
throw new VerificationException("S-value is not canonical.");
|
||||||
|
|
||||||
|
@@ -114,7 +114,8 @@ public class HttpDiscovery implements PeerDiscovery {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public InetSocketAddress[] protoToAddrs(PeerSeedProtos.SignedPeerSeeds proto) throws PeerDiscoveryException, InvalidProtocolBufferException, SignatureException {
|
public InetSocketAddress[] protoToAddrs(PeerSeedProtos.SignedPeerSeeds proto) throws PeerDiscoveryException,
|
||||||
|
InvalidProtocolBufferException, SignatureDecodeException, SignatureException {
|
||||||
if (details.pubkey != null) {
|
if (details.pubkey != null) {
|
||||||
if (!Arrays.equals(proto.getPubkey().toByteArray(), details.pubkey.getPubKey()))
|
if (!Arrays.equals(proto.getPubkey().toByteArray(), details.pubkey.getPubKey()))
|
||||||
throw new PeerDiscoveryException("Public key mismatch");
|
throw new PeerDiscoveryException("Public key mismatch");
|
||||||
|
@@ -349,7 +349,8 @@ public class PaymentChannelClient implements IPaymentChannelClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@GuardedBy("lock")
|
@GuardedBy("lock")
|
||||||
private void receiveRefund(Protos.TwoWayChannelMessage refundMsg, @Nullable KeyParameter userKey) throws VerificationException {
|
private void receiveRefund(Protos.TwoWayChannelMessage refundMsg, @Nullable KeyParameter userKey)
|
||||||
|
throws SignatureDecodeException, VerificationException {
|
||||||
checkState(majorVersion == 1);
|
checkState(majorVersion == 1);
|
||||||
checkState(step == InitStep.WAITING_FOR_REFUND_RETURN && refundMsg.hasReturnRefund());
|
checkState(step == InitStep.WAITING_FOR_REFUND_RETURN && refundMsg.hasReturnRefund());
|
||||||
log.info("Got RETURN_REFUND message, providing signed contract");
|
log.info("Got RETURN_REFUND message, providing signed contract");
|
||||||
@@ -469,7 +470,7 @@ public class PaymentChannelClient implements IPaymentChannelClient {
|
|||||||
closeReason = CloseReason.REMOTE_SENT_INVALID_MESSAGE;
|
closeReason = CloseReason.REMOTE_SENT_INVALID_MESSAGE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} catch (VerificationException e) {
|
} catch (SignatureDecodeException | VerificationException e) {
|
||||||
log.error("Caught verification exception handling message from server", e);
|
log.error("Caught verification exception handling message from server", e);
|
||||||
errorBuilder = Protos.Error.newBuilder()
|
errorBuilder = Protos.Error.newBuilder()
|
||||||
.setCode(Protos.Error.ErrorCode.BAD_TRANSACTION);
|
.setCode(Protos.Error.ErrorCode.BAD_TRANSACTION);
|
||||||
|
@@ -373,7 +373,7 @@ public class PaymentChannelServer {
|
|||||||
state.storeChannelInWallet(PaymentChannelServer.this);
|
state.storeChannelInWallet(PaymentChannelServer.this);
|
||||||
try {
|
try {
|
||||||
receiveUpdatePaymentMessage(providedContract.getInitialPayment(), false /* no ack msg */);
|
receiveUpdatePaymentMessage(providedContract.getInitialPayment(), false /* no ack msg */);
|
||||||
} catch (VerificationException e) {
|
} catch (SignatureDecodeException | VerificationException e) {
|
||||||
log.error("Initial payment failed to verify", e);
|
log.error("Initial payment failed to verify", e);
|
||||||
error(e.getMessage(), Protos.Error.ErrorCode.BAD_TRANSACTION, CloseReason.REMOTE_SENT_INVALID_MESSAGE);
|
error(e.getMessage(), Protos.Error.ErrorCode.BAD_TRANSACTION, CloseReason.REMOTE_SENT_INVALID_MESSAGE);
|
||||||
return;
|
return;
|
||||||
@@ -424,7 +424,8 @@ public class PaymentChannelServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@GuardedBy("lock")
|
@GuardedBy("lock")
|
||||||
private void receiveUpdatePaymentMessage(Protos.UpdatePayment msg, boolean sendAck) throws VerificationException, ValueOutOfRangeException, InsufficientMoneyException {
|
private void receiveUpdatePaymentMessage(Protos.UpdatePayment msg, boolean sendAck) throws SignatureDecodeException,
|
||||||
|
VerificationException, ValueOutOfRangeException, InsufficientMoneyException {
|
||||||
log.info("Got a payment update");
|
log.info("Got a payment update");
|
||||||
|
|
||||||
Coin lastBestPayment = state.getBestValueToMe();
|
Coin lastBestPayment = state.getBestValueToMe();
|
||||||
@@ -513,7 +514,7 @@ public class PaymentChannelServer {
|
|||||||
} catch (InsufficientMoneyException e) {
|
} catch (InsufficientMoneyException e) {
|
||||||
log.error("Caught insufficient money exception handling message from client", e);
|
log.error("Caught insufficient money exception handling message from client", e);
|
||||||
error(e.getMessage(), Protos.Error.ErrorCode.BAD_TRANSACTION, CloseReason.REMOTE_SENT_INVALID_MESSAGE);
|
error(e.getMessage(), Protos.Error.ErrorCode.BAD_TRANSACTION, CloseReason.REMOTE_SENT_INVALID_MESSAGE);
|
||||||
} catch (IllegalStateException e) {
|
} catch (SignatureDecodeException e) {
|
||||||
log.error("Caught illegal state exception handling message from client", e);
|
log.error("Caught illegal state exception handling message from client", e);
|
||||||
error(e.getMessage(), Protos.Error.ErrorCode.SYNTAX_ERROR, CloseReason.REMOTE_SENT_INVALID_MESSAGE);
|
error(e.getMessage(), Protos.Error.ErrorCode.SYNTAX_ERROR, CloseReason.REMOTE_SENT_INVALID_MESSAGE);
|
||||||
}
|
}
|
||||||
|
@@ -236,7 +236,9 @@ public abstract class PaymentChannelServerState {
|
|||||||
* @throws VerificationException If the signature does not verify or size is out of range (incl being rejected by the network as dust).
|
* @throws VerificationException If the signature does not verify or size is out of range (incl being rejected by the network as dust).
|
||||||
* @return true if there is more value left on the channel, false if it is now fully used up.
|
* @return true if there is more value left on the channel, false if it is now fully used up.
|
||||||
*/
|
*/
|
||||||
public synchronized boolean incrementPayment(Coin refundSize, byte[] signatureBytes) throws VerificationException, ValueOutOfRangeException, InsufficientMoneyException {
|
public synchronized boolean incrementPayment(Coin refundSize, byte[] signatureBytes)
|
||||||
|
throws SignatureDecodeException, VerificationException, ValueOutOfRangeException,
|
||||||
|
InsufficientMoneyException {
|
||||||
stateMachine.checkState(State.READY);
|
stateMachine.checkState(State.READY);
|
||||||
checkNotNull(refundSize);
|
checkNotNull(refundSize);
|
||||||
checkNotNull(signatureBytes);
|
checkNotNull(signatureBytes);
|
||||||
|
@@ -227,7 +227,7 @@ public class PaymentChannelV1ClientState extends PaymentChannelClientState {
|
|||||||
* the appropriate time if necessary.</p>
|
* the appropriate time if necessary.</p>
|
||||||
*/
|
*/
|
||||||
public synchronized void provideRefundSignature(byte[] theirSignature, @Nullable KeyParameter userKey)
|
public synchronized void provideRefundSignature(byte[] theirSignature, @Nullable KeyParameter userKey)
|
||||||
throws VerificationException {
|
throws SignatureDecodeException, VerificationException {
|
||||||
checkNotNull(theirSignature);
|
checkNotNull(theirSignature);
|
||||||
stateMachine.checkState(State.WAITING_FOR_SIGNED_REFUND);
|
stateMachine.checkState(State.WAITING_FOR_SIGNED_REFUND);
|
||||||
TransactionSignature theirSig = TransactionSignature.decodeFromBitcoin(theirSignature, true, false);
|
TransactionSignature theirSig = TransactionSignature.decodeFromBitcoin(theirSignature, true, false);
|
||||||
|
@@ -431,8 +431,12 @@ public class Script {
|
|||||||
// OP_0, skip
|
// OP_0, skip
|
||||||
} else {
|
} else {
|
||||||
checkNotNull(chunk.data);
|
checkNotNull(chunk.data);
|
||||||
|
try {
|
||||||
if (myIndex < redeemScript.findSigInRedeem(chunk.data, hash))
|
if (myIndex < redeemScript.findSigInRedeem(chunk.data, hash))
|
||||||
return sigCount;
|
return sigCount;
|
||||||
|
} catch (SignatureDecodeException e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
sigCount++;
|
sigCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -467,7 +471,7 @@ public class Script {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int findSigInRedeem(byte[] signatureBytes, Sha256Hash hash) {
|
private int findSigInRedeem(byte[] signatureBytes, Sha256Hash hash) throws SignatureDecodeException {
|
||||||
checkArgument(chunks.get(0).isOpCode()); // P2SH scriptSig
|
checkArgument(chunks.get(0).isOpCode()); // P2SH scriptSig
|
||||||
int numKeys = Script.decodeFromOpN(chunks.get(chunks.size() - 2).opcode);
|
int numKeys = Script.decodeFromOpN(chunks.get(chunks.size() - 2).opcode);
|
||||||
TransactionSignature signature = TransactionSignature.decodeFromBitcoin(signatureBytes, true, false);
|
TransactionSignature signature = TransactionSignature.decodeFromBitcoin(signatureBytes, true, false);
|
||||||
@@ -1410,17 +1414,16 @@ public class Script {
|
|||||||
// TODO: Should check hash type is known
|
// TODO: Should check hash type is known
|
||||||
Sha256Hash hash = txContainingThis.hashForSignature(index, connectedScript, (byte) sig.sighashFlags);
|
Sha256Hash hash = txContainingThis.hashForSignature(index, connectedScript, (byte) sig.sighashFlags);
|
||||||
sigValid = ECKey.verify(hash.getBytes(), sig, pubKey);
|
sigValid = ECKey.verify(hash.getBytes(), sig, pubKey);
|
||||||
} catch (Exception e1) {
|
} catch (SignatureDecodeException e) {
|
||||||
// There is (at least) one exception that could be hit here (EOFException, if the sig is too short)
|
// This exception occurs when signing as we run partial/invalid scripts to see if they need more
|
||||||
// Because I can't verify there aren't more, we use a very generic Exception catch
|
|
||||||
|
|
||||||
// This RuntimeException occurs when signing as we run partial/invalid scripts to see if they need more
|
|
||||||
// signing work to be done inside LocalTransactionSigner.signInputs.
|
// signing work to be done inside LocalTransactionSigner.signInputs.
|
||||||
// FIXME don't rely on exception message
|
// FIXME don't rely on exception message
|
||||||
if (e1.getMessage() != null && !e1.getMessage().contains("Reached past end of ASN.1 stream"))
|
if (e.getMessage() != null && !e.getMessage().contains("Reached past end of ASN.1 stream"))
|
||||||
// Don't put critical code here; the above check is not reliable on HotSpot due to optimization:
|
// Don't put critical code here; the above check is not reliable on HotSpot due to optimization:
|
||||||
// http://jawspeak.com/2010/05/26/hotspot-caused-exceptions-to-lose-their-stack-traces-in-production-and-the-fix/
|
// http://jawspeak.com/2010/05/26/hotspot-caused-exceptions-to-lose-their-stack-traces-in-production-and-the-fix/
|
||||||
log.warn("Signature checking failed!", e1);
|
log.warn("Signature parsing failed!", e);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("Signature checking failed!", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opcode == OP_CHECKSIG)
|
if (opcode == OP_CHECKSIG)
|
||||||
|
@@ -21,6 +21,7 @@ import org.bitcoinj.core.Coin;
|
|||||||
import org.bitcoinj.core.ECKey;
|
import org.bitcoinj.core.ECKey;
|
||||||
import org.bitcoinj.core.ECKey.ECDSASignature;
|
import org.bitcoinj.core.ECKey.ECDSASignature;
|
||||||
import org.bitcoinj.core.NetworkParameters;
|
import org.bitcoinj.core.NetworkParameters;
|
||||||
|
import org.bitcoinj.core.SignatureDecodeException;
|
||||||
import org.bitcoinj.core.Transaction;
|
import org.bitcoinj.core.Transaction;
|
||||||
import org.bitcoinj.core.TransactionConfidence;
|
import org.bitcoinj.core.TransactionConfidence;
|
||||||
import org.bitcoinj.core.TransactionInput;
|
import org.bitcoinj.core.TransactionInput;
|
||||||
@@ -190,7 +191,7 @@ public class DefaultRiskAnalysis implements RiskAnalysis {
|
|||||||
ECDSASignature signature;
|
ECDSASignature signature;
|
||||||
try {
|
try {
|
||||||
signature = ECKey.ECDSASignature.decodeFromDER(chunk.data);
|
signature = ECKey.ECDSASignature.decodeFromDER(chunk.data);
|
||||||
} catch (IllegalArgumentException x) {
|
} catch (SignatureDecodeException x) {
|
||||||
// Doesn't look like a signature.
|
// Doesn't look like a signature.
|
||||||
signature = null;
|
signature = null;
|
||||||
}
|
}
|
||||||
|
@@ -176,7 +176,7 @@ public class DefaultRiskAnalysisTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void canonicalSignatureLowS() {
|
public void canonicalSignatureLowS() throws Exception {
|
||||||
// First, a synthetic test.
|
// First, a synthetic test.
|
||||||
TransactionSignature sig = TransactionSignature.dummy();
|
TransactionSignature sig = TransactionSignature.dummy();
|
||||||
Script scriptHighS = ScriptBuilder
|
Script scriptHighS = ScriptBuilder
|
||||||
|
@@ -28,10 +28,12 @@ import org.bitcoinj.core.LegacyAddress;
|
|||||||
import org.bitcoinj.core.Coin;
|
import org.bitcoinj.core.Coin;
|
||||||
import org.bitcoinj.core.ECKey;
|
import org.bitcoinj.core.ECKey;
|
||||||
import org.bitcoinj.core.NetworkParameters;
|
import org.bitcoinj.core.NetworkParameters;
|
||||||
|
import org.bitcoinj.core.SignatureDecodeException;
|
||||||
import org.bitcoinj.core.Transaction;
|
import org.bitcoinj.core.Transaction;
|
||||||
import org.bitcoinj.core.TransactionInput;
|
import org.bitcoinj.core.TransactionInput;
|
||||||
import org.bitcoinj.core.TransactionOutput;
|
import org.bitcoinj.core.TransactionOutput;
|
||||||
import org.bitcoinj.core.Utils;
|
import org.bitcoinj.core.Utils;
|
||||||
|
import org.bitcoinj.core.VerificationException;
|
||||||
import org.bitcoinj.crypto.TransactionSignature;
|
import org.bitcoinj.crypto.TransactionSignature;
|
||||||
import org.bitcoinj.params.MainNetParams;
|
import org.bitcoinj.params.MainNetParams;
|
||||||
import org.bitcoinj.script.Script;
|
import org.bitcoinj.script.Script;
|
||||||
@@ -54,7 +56,8 @@ import org.bitcoinj.wallet.RedeemData;
|
|||||||
public class GenerateLowSTests {
|
public class GenerateLowSTests {
|
||||||
public static final BigInteger HIGH_S_DIFFERENCE = new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 16);
|
public static final BigInteger HIGH_S_DIFFERENCE = new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 16);
|
||||||
|
|
||||||
public static void main(final String[] argv) throws NoSuchAlgorithmException, IOException {
|
public static void main(final String[] argv)
|
||||||
|
throws NoSuchAlgorithmException, IOException, VerificationException, SignatureDecodeException {
|
||||||
final NetworkParameters params = new MainNetParams();
|
final NetworkParameters params = new MainNetParams();
|
||||||
final LocalTransactionSigner signer = new LocalTransactionSigner();
|
final LocalTransactionSigner signer = new LocalTransactionSigner();
|
||||||
final SecureRandom secureRandom = SecureRandom.getInstanceStrong();
|
final SecureRandom secureRandom = SecureRandom.getInstanceStrong();
|
||||||
|
Reference in New Issue
Block a user