diff --git a/core/src/main/java/haveno/core/offer/OfferPayload.java b/core/src/main/java/haveno/core/offer/OfferPayload.java index a108f2f2b8..1a24f72128 100644 --- a/core/src/main/java/haveno/core/offer/OfferPayload.java +++ b/core/src/main/java/haveno/core/offer/OfferPayload.java @@ -20,12 +20,15 @@ package haveno.core.offer; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonSerializationContext; +import com.google.protobuf.ByteString; + import haveno.common.crypto.Hash; import haveno.common.crypto.PubKeyRing; import haveno.common.proto.ProtoUtil; import haveno.common.util.CollectionUtils; import haveno.common.util.Hex; import haveno.common.util.JsonExclude; +import haveno.common.util.Utilities; import haveno.network.p2p.NodeAddress; import haveno.network.p2p.storage.payload.ExpirablePayload; import haveno.network.p2p.storage.payload.ProtectedStoragePayload; @@ -81,7 +84,7 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay protected NodeAddress arbitratorSigner; @Setter @Nullable - protected String arbitratorSignature; + protected byte[] arbitratorSignature; @Setter @Nullable protected List reserveTxKeyImages; @@ -191,7 +194,7 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay @Nullable Map extraDataMap, int protocolVersion, @Nullable NodeAddress arbitratorSigner, - @Nullable String arbitratorSignature, + @Nullable byte[] arbitratorSignature, @Nullable List reserveTxKeyImages) { this.id = id; this.date = date; @@ -302,7 +305,7 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay Optional.ofNullable(acceptedCountryCodes).ifPresent(builder::addAllAcceptedCountryCodes); Optional.ofNullable(hashOfChallenge).ifPresent(builder::setHashOfChallenge); Optional.ofNullable(extraDataMap).ifPresent(builder::putAllExtraData); - Optional.ofNullable(arbitratorSignature).ifPresent(builder::setArbitratorSignature); + Optional.ofNullable(arbitratorSignature).ifPresent(e -> builder.setArbitratorSignature(ByteString.copyFrom(e))); Optional.ofNullable(reserveTxKeyImages).ifPresent(builder::addAllReserveTxKeyImages); return protobuf.StoragePayload.newBuilder().setOfferPayload(builder).build(); @@ -352,7 +355,7 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay extraDataMapMap, proto.getProtocolVersion(), proto.hasArbitratorSigner() ? NodeAddress.fromProto(proto.getArbitratorSigner()) : null, - ProtoUtil.stringOrNullFromProto(proto.getArbitratorSignature()), + ProtoUtil.byteArrayOrNullFromProto(proto.getArbitratorSignature()), proto.getReserveTxKeyImagesList() == null ? null : new ArrayList(proto.getReserveTxKeyImagesList())); } @@ -375,8 +378,6 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay ",\r\n pubKeyRing=" + pubKeyRing + ",\r\n hash=" + (hash != null ? Hex.encode(hash) : "null") + ",\r\n extraDataMap=" + extraDataMap + - ",\r\n arbitratorSigner=" + arbitratorSigner + - ",\r\n arbitratorSignature=" + arbitratorSignature + ",\r\n reserveTxKeyImages=" + reserveTxKeyImages + ",\r\n marketPriceMargin=" + marketPriceMarginPct + ",\r\n useMarketBasedPrice=" + useMarketBasedPrice + @@ -398,7 +399,7 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay ",\r\n isPrivateOffer=" + isPrivateOffer + ",\r\n hashOfChallenge='" + hashOfChallenge + '\'' + ",\n arbitratorSigner=" + arbitratorSigner + - ",\n arbitratorSignature=" + arbitratorSignature + + ",\n arbitratorSignature=" + Utilities.bytesAsHexString(arbitratorSignature) + "\r\n} "; } diff --git a/core/src/main/java/haveno/core/offer/OpenOfferManager.java b/core/src/main/java/haveno/core/offer/OpenOfferManager.java index 356ee4e9f0..8f9d230634 100644 --- a/core/src/main/java/haveno/core/offer/OpenOfferManager.java +++ b/core/src/main/java/haveno/core/offer/OpenOfferManager.java @@ -25,7 +25,6 @@ import haveno.common.app.Capability; import haveno.common.app.Version; import haveno.common.crypto.KeyRing; import haveno.common.crypto.PubKeyRing; -import haveno.common.crypto.Sig; import haveno.common.handlers.ErrorMessageHandler; import haveno.common.handlers.ResultHandler; import haveno.common.persistence.PersistenceManager; @@ -1000,7 +999,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe // arbitrator signs offer to certify they have valid reserve tx String offerPayloadAsJson = JsonUtil.objectToJson(request.getOfferPayload()); - String signature = Sig.sign(keyRing.getSignatureKeyPair().getPrivate(), offerPayloadAsJson); + byte[] signature = HavenoUtils.sign(keyRing, offerPayloadAsJson); OfferPayload signedOfferPayload = request.getOfferPayload(); signedOfferPayload.setArbitratorSignature(signature); @@ -1119,7 +1118,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe try { Optional openOfferOptional = getOpenOfferById(request.offerId); AvailabilityResult availabilityResult; - String makerSignature = null; + byte[] makerSignature = null; if (openOfferOptional.isPresent()) { OpenOffer openOffer = openOfferOptional.get(); if (!apiUserDeniedByOffer(request)) { @@ -1130,7 +1129,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe // maker signs taker's request String tradeRequestAsJson = JsonUtil.objectToJson(request.getTradeRequest()); - makerSignature = Sig.sign(keyRing.getSignatureKeyPair().getPrivate(), tradeRequestAsJson); + makerSignature = HavenoUtils.sign(keyRing, tradeRequestAsJson); try { // Check also tradePrice to avoid failures after taker fee is paid caused by a too big difference diff --git a/core/src/main/java/haveno/core/offer/SignedOffer.java b/core/src/main/java/haveno/core/offer/SignedOffer.java index d4d757944a..ac040dc46b 100644 --- a/core/src/main/java/haveno/core/offer/SignedOffer.java +++ b/core/src/main/java/haveno/core/offer/SignedOffer.java @@ -17,10 +17,14 @@ package haveno.core.offer; +import haveno.common.proto.ProtoUtil; import haveno.common.proto.persistable.PersistablePayload; import haveno.core.util.JsonUtil; import java.util.List; + +import com.google.protobuf.ByteString; + import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.extern.slf4j.Slf4j; @@ -48,7 +52,7 @@ public final class SignedOffer implements PersistablePayload { @Getter private final long reserveTxMinerFee; @Getter - private final String arbitratorSignature; + private final byte[] arbitratorSignature; public SignedOffer(long timeStamp, int traderId, @@ -59,7 +63,7 @@ public final class SignedOffer implements PersistablePayload { String reserveTxHex, List reserveTxKeyImages, long reserveTxMinerFee, - String arbitratorSignature) { + byte[] arbitratorSignature) { this.timeStamp = timeStamp; this.traderId = traderId; this.offerId = offerId; @@ -88,7 +92,7 @@ public final class SignedOffer implements PersistablePayload { .setReserveTxHex(reserveTxHex) .addAllReserveTxKeyImages(reserveTxKeyImages) .setReserveTxMinerFee(reserveTxMinerFee) - .setArbitratorSignature(arbitratorSignature); + .setArbitratorSignature(ByteString.copyFrom(arbitratorSignature)); return builder.build(); } @@ -102,7 +106,7 @@ public final class SignedOffer implements PersistablePayload { proto.getReserveTxHex(), proto.getReserveTxKeyImagesList(), proto.getReserveTxMinerFee(), - proto.getArbitratorSignature()); + ProtoUtil.byteArrayOrNullFromProto(proto.getArbitratorSignature())); } diff --git a/core/src/main/java/haveno/core/offer/availability/OfferAvailabilityModel.java b/core/src/main/java/haveno/core/offer/availability/OfferAvailabilityModel.java index 68c47a5dad..7b98e39d62 100644 --- a/core/src/main/java/haveno/core/offer/availability/OfferAvailabilityModel.java +++ b/core/src/main/java/haveno/core/offer/availability/OfferAvailabilityModel.java @@ -61,7 +61,7 @@ public class OfferAvailabilityModel implements Model { @Nullable @Setter @Getter - private String makerSignature; + private byte[] makerSignature; // Added in v1.5.5 @Getter diff --git a/core/src/main/java/haveno/core/offer/availability/tasks/SendOfferAvailabilityRequest.java b/core/src/main/java/haveno/core/offer/availability/tasks/SendOfferAvailabilityRequest.java index 6bf0cb6fad..3b6ae67ede 100644 --- a/core/src/main/java/haveno/core/offer/availability/tasks/SendOfferAvailabilityRequest.java +++ b/core/src/main/java/haveno/core/offer/availability/tasks/SendOfferAvailabilityRequest.java @@ -17,9 +17,7 @@ package haveno.core.offer.availability.tasks; -import com.google.common.base.Charsets; import haveno.common.app.Version; -import haveno.common.crypto.Sig; import haveno.common.taskrunner.Task; import haveno.common.taskrunner.TaskRunner; import haveno.core.monetary.Price; @@ -59,7 +57,7 @@ public class SendOfferAvailabilityRequest extends Task { String payoutAddress = walletService.getOrCreateAddressEntry(offer.getId(), XmrAddressEntry.Context.TRADE_PAYOUT).getAddressString(); // reserve new payout address // taker signs offer using offer id as nonce to avoid challenge protocol - byte[] sig = Sig.sign(model.getP2PService().getKeyRing().getSignatureKeyPair().getPrivate(), offer.getId().getBytes(Charsets.UTF_8)); + byte[] sig = HavenoUtils.sign(model.getP2PService().getKeyRing(), offer.getId()); // get price Price price = offer.getPrice(); diff --git a/core/src/main/java/haveno/core/offer/messages/OfferAvailabilityResponse.java b/core/src/main/java/haveno/core/offer/messages/OfferAvailabilityResponse.java index 383abe53b1..b38071b058 100644 --- a/core/src/main/java/haveno/core/offer/messages/OfferAvailabilityResponse.java +++ b/core/src/main/java/haveno/core/offer/messages/OfferAvailabilityResponse.java @@ -31,6 +31,8 @@ import lombok.Value; import javax.annotation.Nullable; +import com.google.protobuf.ByteString; + // We add here the SupportedCapabilitiesMessage interface as that message always predates a direct connection // to the trading peer @EqualsAndHashCode(callSuper = true) @@ -41,11 +43,11 @@ public final class OfferAvailabilityResponse extends OfferMessage implements Sup private final Capabilities supportedCapabilities; @Nullable - private final String makerSignature; + private byte[] makerSignature; public OfferAvailabilityResponse(String offerId, AvailabilityResult availabilityResult, - String makerSignature) { + @Nullable byte[] makerSignature) { this(offerId, availabilityResult, Capabilities.app, @@ -64,7 +66,7 @@ public final class OfferAvailabilityResponse extends OfferMessage implements Sup @Nullable Capabilities supportedCapabilities, String messageVersion, @Nullable String uid, - String makerSignature) { + byte[] makerSignature) { super(messageVersion, offerId, uid); this.availabilityResult = availabilityResult; this.supportedCapabilities = supportedCapabilities; @@ -79,7 +81,7 @@ public final class OfferAvailabilityResponse extends OfferMessage implements Sup Optional.ofNullable(supportedCapabilities).ifPresent(e -> builder.addAllSupportedCapabilities(Capabilities.toIntList(supportedCapabilities))); Optional.ofNullable(uid).ifPresent(e -> builder.setUid(uid)); - Optional.ofNullable(makerSignature).ifPresent(e -> builder.setMakerSignature(makerSignature)); + Optional.ofNullable(makerSignature).ifPresent(e -> builder.setMakerSignature(ByteString.copyFrom(e))); return getNetworkEnvelopeBuilder() .setOfferAvailabilityResponse(builder) @@ -92,6 +94,6 @@ public final class OfferAvailabilityResponse extends OfferMessage implements Sup Capabilities.fromIntList(proto.getSupportedCapabilitiesList()), messageVersion, proto.getUid().isEmpty() ? null : proto.getUid(), - proto.getMakerSignature().isEmpty() ? null : proto.getMakerSignature()); + ProtoUtil.byteArrayOrNullFromProto(proto.getMakerSignature())); } } diff --git a/core/src/main/java/haveno/core/support/dispute/Dispute.java b/core/src/main/java/haveno/core/support/dispute/Dispute.java index a33f52d353..7fdfb98ba9 100644 --- a/core/src/main/java/haveno/core/support/dispute/Dispute.java +++ b/core/src/main/java/haveno/core/support/dispute/Dispute.java @@ -104,9 +104,9 @@ public final class Dispute implements NetworkPayload, PersistablePayload { private final String payoutTxId; private String contractAsJson; @Nullable - private final String makerContractSignature; + private final byte[] makerContractSignature; @Nullable - private final String takerContractSignature; + private final byte[] takerContractSignature; private final PubKeyRing agentPubKeyRing; // dispute agent private final boolean isSupportTicket; private final ObservableList chatMessages = FXCollections.observableArrayList(); @@ -179,8 +179,8 @@ public final class Dispute implements NetworkPayload, PersistablePayload { @Nullable String depositTxId, @Nullable String payoutTxId, String contractAsJson, - @Nullable String makerContractSignature, - @Nullable String takerContractSignature, + @Nullable byte[] makerContractSignature, + @Nullable byte[] takerContractSignature, @Nullable PaymentAccountPayload makerPaymentAccountPayload, @Nullable PaymentAccountPayload takerPaymentAccountPayload, PubKeyRing agentPubKeyRing, @@ -251,8 +251,8 @@ public final class Dispute implements NetworkPayload, PersistablePayload { Optional.ofNullable(depositTxId).ifPresent(builder::setDepositTxId); Optional.ofNullable(payoutTxId).ifPresent(builder::setPayoutTxId); Optional.ofNullable(disputePayoutTxId).ifPresent(builder::setDisputePayoutTxId); - Optional.ofNullable(makerContractSignature).ifPresent(builder::setMakerContractSignature); - Optional.ofNullable(takerContractSignature).ifPresent(builder::setTakerContractSignature); + Optional.ofNullable(makerContractSignature).ifPresent(e -> builder.setMakerContractSignature(ByteString.copyFrom(e))); + Optional.ofNullable(takerContractSignature).ifPresent(e -> builder.setTakerContractSignature(ByteString.copyFrom(e))); Optional.ofNullable(makerPaymentAccountPayload).ifPresent(e -> builder.setMakerPaymentAccountPayload((protobuf.PaymentAccountPayload) makerPaymentAccountPayload.toProtoMessage())); Optional.ofNullable(takerPaymentAccountPayload).ifPresent(e -> builder.setTakerPaymentAccountPayload((protobuf.PaymentAccountPayload) takerPaymentAccountPayload.toProtoMessage())); Optional.ofNullable(disputeResultProperty.get()).ifPresent(result -> builder.setDisputeResult(disputeResultProperty.get().toProtoMessage())); @@ -281,8 +281,8 @@ public final class Dispute implements NetworkPayload, PersistablePayload { ProtoUtil.stringOrNullFromProto(proto.getDepositTxId()), ProtoUtil.stringOrNullFromProto(proto.getPayoutTxId()), proto.getContractAsJson(), - ProtoUtil.stringOrNullFromProto(proto.getMakerContractSignature()), - ProtoUtil.stringOrNullFromProto(proto.getTakerContractSignature()), + ProtoUtil.byteArrayOrNullFromProto(proto.getMakerContractSignature()), + ProtoUtil.byteArrayOrNullFromProto(proto.getTakerContractSignature()), proto.hasMakerPaymentAccountPayload() ? coreProtoResolver.fromProto(proto.getMakerPaymentAccountPayload()) : null, proto.hasTakerPaymentAccountPayload() ? coreProtoResolver.fromProto(proto.getTakerPaymentAccountPayload()) : null, PubKeyRing.fromProto(proto.getAgentPubKeyRing()), @@ -524,8 +524,8 @@ public final class Dispute implements NetworkPayload, PersistablePayload { ",\n depositTxId='" + depositTxId + '\'' + ",\n payoutTxId='" + payoutTxId + '\'' + ",\n contractAsJson='" + contractAsJson + '\'' + - ",\n makerContractSignature='" + makerContractSignature + '\'' + - ",\n takerContractSignature='" + takerContractSignature + '\'' + + ",\n makerContractSignature='" + Utilities.bytesAsHexString(makerContractSignature) + '\'' + + ",\n takerContractSignature='" + Utilities.bytesAsHexString(takerContractSignature) + '\'' + ",\n agentPubKeyRing=" + agentPubKeyRing + ",\n isSupportTicket=" + isSupportTicket + ",\n chatMessages=" + chatMessages + diff --git a/core/src/main/java/haveno/core/support/dispute/DisputeSummaryVerification.java b/core/src/main/java/haveno/core/support/dispute/DisputeSummaryVerification.java index 863120960b..3c9f1df730 100644 --- a/core/src/main/java/haveno/core/support/dispute/DisputeSummaryVerification.java +++ b/core/src/main/java/haveno/core/support/dispute/DisputeSummaryVerification.java @@ -17,16 +17,14 @@ package haveno.core.support.dispute; -import haveno.common.crypto.CryptoException; import haveno.common.crypto.Hash; -import haveno.common.crypto.Sig; import haveno.common.util.Utilities; import haveno.core.locale.Res; import haveno.core.support.dispute.agent.DisputeAgent; import haveno.core.support.dispute.arbitration.arbitrator.ArbitratorManager; +import haveno.core.trade.HavenoUtils; import haveno.network.p2p.NodeAddress; import java.security.KeyPair; -import java.security.PublicKey; import lombok.extern.slf4j.Slf4j; @@ -46,10 +44,10 @@ public class DisputeSummaryVerification { KeyPair signatureKeyPair = disputeManager.getSignatureKeyPair(); String sigAsHex; try { - byte[] signature = Sig.sign(signatureKeyPair.getPrivate(), hash); + byte[] signature = HavenoUtils.sign(signatureKeyPair.getPrivate(), hash); sigAsHex = Utilities.encodeToHex(signature); disputeResult.setArbitratorSignature(signature); - } catch (CryptoException e) { + } catch (Exception e) { sigAsHex = "Signing failed"; } @@ -69,19 +67,13 @@ public class DisputeSummaryVerification { NodeAddress nodeAddress = new NodeAddress(fullAddress); DisputeAgent disputeAgent = arbitratorMediator.getDisputeAgentByNodeAddress(nodeAddress).orElse(null); checkNotNull(disputeAgent, "Dispute agent is null"); - PublicKey pubKey = disputeAgent.getPubKeyRing().getSignaturePubKey(); String sigString = parts[1].split(SEPARATOR2)[0]; byte[] sig = Utilities.decodeFromHex(sigString); byte[] hash = Hash.getSha256Hash(textToSign); try { - boolean result = Sig.verify(pubKey, hash, sig); - if (result) { - return; - } else { - throw new IllegalArgumentException(Res.get("support.sigCheck.popup.failed")); - } - } catch (CryptoException e) { + HavenoUtils.verifySignature(disputeAgent.getPubKeyRing(), hash, sig); + } catch (Exception e) { throw new IllegalArgumentException(Res.get("support.sigCheck.popup.failed")); } } catch (Throwable e) { diff --git a/core/src/main/java/haveno/core/support/dispute/DisputeValidation.java b/core/src/main/java/haveno/core/support/dispute/DisputeValidation.java index b8e8832863..4c685dc66e 100644 --- a/core/src/main/java/haveno/core/support/dispute/DisputeValidation.java +++ b/core/src/main/java/haveno/core/support/dispute/DisputeValidation.java @@ -18,12 +18,11 @@ package haveno.core.support.dispute; import haveno.common.config.Config; -import haveno.common.crypto.CryptoException; import haveno.common.crypto.Hash; -import haveno.common.crypto.Sig; import haveno.common.util.Tuple3; import haveno.core.support.SupportType; import haveno.core.trade.Contract; +import haveno.core.trade.HavenoUtils; import haveno.core.trade.Trade; import haveno.core.util.JsonUtil; import haveno.core.util.validation.RegexValidatorFactory; @@ -64,23 +63,11 @@ public class DisputeValidation { checkArgument(Arrays.equals(Objects.requireNonNull(dispute.getContractHash()), Hash.getSha256Hash(checkNotNull(dispute.getContractAsJson()))), "Invalid contractHash"); - try { - // Only the dispute opener has set the signature - String makerContractSignature = dispute.getMakerContractSignature(); - if (makerContractSignature != null) { - Sig.verify(contract.getMakerPubKeyRing().getSignaturePubKey(), - dispute.getContractAsJson(), - makerContractSignature); - } - String takerContractSignature = dispute.getTakerContractSignature(); - if (takerContractSignature != null) { - Sig.verify(contract.getTakerPubKeyRing().getSignaturePubKey(), - dispute.getContractAsJson(), - takerContractSignature); - } - } catch (CryptoException e) { - throw new ValidationException(dispute, e.getMessage()); - } + // Only the dispute opener has set the signature + byte[] makerContractSignature = dispute.getMakerContractSignature(); + if (makerContractSignature != null) HavenoUtils.verifySignature(contract.getMakerPubKeyRing(), dispute.getContractAsJson(), makerContractSignature); + byte[] takerContractSignature = dispute.getTakerContractSignature(); + if (takerContractSignature != null) HavenoUtils.verifySignature(contract.getTakerPubKeyRing(), dispute.getContractAsJson(), takerContractSignature); } catch (Throwable t) { throw new ValidationException(dispute, t.getMessage()); } diff --git a/core/src/main/java/haveno/core/trade/HavenoUtils.java b/core/src/main/java/haveno/core/trade/HavenoUtils.java index d74eab2394..d9100cb05b 100644 --- a/core/src/main/java/haveno/core/trade/HavenoUtils.java +++ b/core/src/main/java/haveno/core/trade/HavenoUtils.java @@ -23,6 +23,7 @@ import com.google.common.base.CaseFormat; import com.google.common.base.Charsets; import haveno.common.config.Config; import haveno.common.crypto.Hash; +import haveno.common.crypto.KeyRing; import haveno.common.crypto.PubKeyRing; import haveno.common.crypto.Sig; import haveno.common.util.Utilities; @@ -39,7 +40,7 @@ import java.text.DecimalFormat; import java.text.SimpleDateFormat; import java.net.URI; - +import java.security.PrivateKey; import java.math.BigDecimal; import java.math.BigInteger; @@ -236,6 +237,170 @@ public class HavenoUtils { return feePerXmrAsDecimal.multiply(amountMultiplier).toBigInteger(); } + // ------------------------ SIGNING AND VERIFYING ------------------------- + + public static byte[] sign(KeyRing keyRing, String message) { + return sign(keyRing.getSignatureKeyPair().getPrivate(), message); + } + + public static byte[] sign(PrivateKey privateKey, String message) { + return sign(privateKey, message.getBytes(Charsets.UTF_8)); + } + + public static byte[] sign(PrivateKey privateKey, byte[] bytes) { + try { + return Sig.sign(privateKey, bytes); + } catch (Exception e) { + throw new IllegalArgumentException(e); + } + } + + public static void verifySignature(PubKeyRing pubKeyRing, String message, byte[] signature) { + verifySignature(pubKeyRing, message.getBytes(Charsets.UTF_8), signature); + } + + public static void verifySignature(PubKeyRing pubKeyRing, byte[] bytes, byte[] signature) { + try { + Sig.verify(pubKeyRing.getSignaturePubKey(), bytes, signature); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static boolean isSignatureValid(PubKeyRing pubKeyRing, String message, byte[] signature) { + return isSignatureValid(pubKeyRing, message.getBytes(Charsets.UTF_8), signature); + } + + public static boolean isSignatureValid(PubKeyRing pubKeyRing, byte[] bytes, byte[] signature) { + try { + verifySignature(pubKeyRing, bytes, signature); + return true; + } catch (Exception e) { + return false; + } + } + + /** + * Check if the arbitrator signature is valid for an offer. + * + * @param offer is a signed offer with payload + * @param arbitrator is the original signing arbitrator + * @return true if the arbitrator's signature is valid for the offer + */ + public static boolean isArbitratorSignatureValid(Offer offer, Arbitrator arbitrator) { + + // copy offer payload + OfferPayload offerPayloadCopy = OfferPayload.fromProto(offer.toProtoMessage().getOfferPayload()); + + // remove arbitrator signature from signed payload + byte[] signature = offerPayloadCopy.getArbitratorSignature(); + offerPayloadCopy.setArbitratorSignature(null); + + // get unsigned offer payload as json string + String unsignedOfferAsJson = JsonUtil.objectToJson(offerPayloadCopy); + + // verify signature + return isSignatureValid(arbitrator.getPubKeyRing(), unsignedOfferAsJson, signature); + } + + /** + * Check if the maker signature for a trade request is valid. + * + * @param request is the trade request to check + * @return true if the maker's signature is valid for the trade request + */ + public static boolean isMakerSignatureValid(InitTradeRequest request, byte[] signature, PubKeyRing makerPubKeyRing) { + + // re-create trade request with signed fields + InitTradeRequest signedRequest = new InitTradeRequest( + request.getTradeId(), + request.getSenderNodeAddress(), + request.getPubKeyRing(), + request.getTradeAmount(), + request.getTradePrice(), + request.getTradeFee(), + request.getAccountId(), + request.getPaymentAccountId(), + request.getPaymentMethodId(), + request.getUid(), + request.getMessageVersion(), + request.getAccountAgeWitnessSignatureOfOfferId(), + request.getCurrentDate(), + request.getMakerNodeAddress(), + request.getTakerNodeAddress(), + null, + null, + null, + null, + request.getPayoutAddress(), + null + ); + + // get trade request as string + String tradeRequestAsJson = JsonUtil.objectToJson(signedRequest); + + // verify maker signature + return isSignatureValid(makerPubKeyRing, tradeRequestAsJson, signature); + } + + /** + * Verify the buyer signature for a PaymentSentMessage. + * + * @param trade - the trade to verify + * @param message - signed payment sent message to verify + * @return true if the buyer's signature is valid for the message + */ + public static void verifyPaymentSentMessage(Trade trade, PaymentSentMessage message) { + + // remove signature from message + byte[] signature = message.getBuyerSignature(); + message.setBuyerSignature(null); + + // get unsigned message as json string + String unsignedMessageAsJson = JsonUtil.objectToJson(message); + + // replace signature + message.setBuyerSignature(signature); + + // verify signature + if (!isSignatureValid(trade.getBuyer().getPubKeyRing(), unsignedMessageAsJson, signature)) { + throw new IllegalArgumentException("The buyer signature is invalid for the " + message.getClass().getSimpleName() + " for " + trade.getClass().getSimpleName() + " " + trade.getId()); + } + + // verify trade id + if (!trade.getId().equals(message.getTradeId())) throw new IllegalArgumentException("The " + message.getClass().getSimpleName() + " has the wrong trade id, expected " + trade.getId() + " but was " + message.getTradeId()); + } + + /** + * Verify the seller signature for a PaymentReceivedMessage. + * + * @param trade - the trade to verify + * @param message - signed payment received message to verify + * @return true if the seller's signature is valid for the message + */ + public static void verifyPaymentReceivedMessage(Trade trade, PaymentReceivedMessage message) { + + // remove signature from message + byte[] signature = message.getSellerSignature(); + message.setSellerSignature(null); + + // get unsigned message as json string + String unsignedMessageAsJson = JsonUtil.objectToJson(message); + + // replace signature + message.setSellerSignature(signature); + + // verify signature + if (!isSignatureValid(trade.getSeller().getPubKeyRing(), unsignedMessageAsJson, signature)) { + throw new IllegalArgumentException("The seller signature is invalid for the " + message.getClass().getSimpleName() + " for " + trade.getClass().getSimpleName() + " " + trade.getId()); + } + + // verify trade id + if (!trade.getId().equals(message.getTradeId())) throw new IllegalArgumentException("The " + message.getClass().getSimpleName() + " has the wrong trade id, expected " + trade.getId() + " but was " + message.getTradeId()); + + // verify buyer signature of payment sent message + verifyPaymentSentMessage(trade, message.getPaymentSentMessage()); + } // ----------------------------- OTHER UTILS ------------------------------ @@ -282,144 +447,6 @@ public class HavenoUtils { return Utilities.bytesAsHexString(Hash.getSha256Ripemd160hash(uniqueId.getBytes(Charsets.UTF_8))); } - /** - * Check if the arbitrator signature is valid for an offer. - * - * @param offer is a signed offer with payload - * @param arbitrator is the original signing arbitrator - * @return true if the arbitrator's signature is valid for the offer - */ - public static boolean isArbitratorSignatureValid(Offer offer, Arbitrator arbitrator) { - - // copy offer payload - OfferPayload offerPayloadCopy = OfferPayload.fromProto(offer.toProtoMessage().getOfferPayload()); - - // remove arbitrator signature from signed payload - String signature = offerPayloadCopy.getArbitratorSignature(); - offerPayloadCopy.setArbitratorSignature(null); - - // get unsigned offer payload as json string - String unsignedOfferAsJson = JsonUtil.objectToJson(offerPayloadCopy); - - // verify arbitrator signature - try { - return Sig.verify(arbitrator.getPubKeyRing().getSignaturePubKey(), unsignedOfferAsJson, signature); - } catch (Exception e) { - return false; - } - } - - /** - * Check if the maker signature for a trade request is valid. - * - * @param request is the trade request to check - * @return true if the maker's signature is valid for the trade request - */ - public static boolean isMakerSignatureValid(InitTradeRequest request, String signature, PubKeyRing makerPubKeyRing) { - - // re-create trade request with signed fields - InitTradeRequest signedRequest = new InitTradeRequest( - request.getTradeId(), - request.getSenderNodeAddress(), - request.getPubKeyRing(), - request.getTradeAmount(), - request.getTradePrice(), - request.getTradeFee(), - request.getAccountId(), - request.getPaymentAccountId(), - request.getPaymentMethodId(), - request.getUid(), - request.getMessageVersion(), - request.getAccountAgeWitnessSignatureOfOfferId(), - request.getCurrentDate(), - request.getMakerNodeAddress(), - request.getTakerNodeAddress(), - null, - null, - null, - null, - request.getPayoutAddress(), - null - ); - - // get trade request as string - String tradeRequestAsJson = JsonUtil.objectToJson(signedRequest); - - // verify maker signature - try { - return Sig.verify(makerPubKeyRing.getSignaturePubKey(), - tradeRequestAsJson, - signature); - } catch (Exception e) { - return false; - } - } - - /** - * Verify the buyer signature for a PaymentSentMessage. - * - * @param trade - the trade to verify - * @param message - signed payment sent message to verify - * @return true if the buyer's signature is valid for the message - */ - public static void verifyPaymentSentMessage(Trade trade, PaymentSentMessage message) { - - // remove signature from message - byte[] signature = message.getBuyerSignature(); - message.setBuyerSignature(null); - - // get unsigned message as json string - String unsignedMessageAsJson = JsonUtil.objectToJson(message); - - // replace signature - message.setBuyerSignature(signature); - - // verify signature - String errMessage = "The buyer signature is invalid for the " + message.getClass().getSimpleName() + " for " + trade.getClass().getSimpleName() + " " + trade.getId(); - try { - if (!Sig.verify(trade.getBuyer().getPubKeyRing().getSignaturePubKey(), unsignedMessageAsJson.getBytes(Charsets.UTF_8), signature)) throw new IllegalArgumentException(errMessage); - } catch (Exception e) { - throw new IllegalArgumentException(errMessage); - } - - // verify trade id - if (!trade.getId().equals(message.getTradeId())) throw new IllegalArgumentException("The " + message.getClass().getSimpleName() + " has the wrong trade id, expected " + trade.getId() + " but was " + message.getTradeId()); - } - - /** - * Verify the seller signature for a PaymentReceivedMessage. - * - * @param trade - the trade to verify - * @param message - signed payment received message to verify - * @return true if the seller's signature is valid for the message - */ - public static void verifyPaymentReceivedMessage(Trade trade, PaymentReceivedMessage message) { - - // remove signature from message - byte[] signature = message.getSellerSignature(); - message.setSellerSignature(null); - - // get unsigned message as json string - String unsignedMessageAsJson = JsonUtil.objectToJson(message); - - // replace signature - message.setSellerSignature(signature); - - // verify signature - String errMessage = "The seller signature is invalid for the " + message.getClass().getSimpleName() + " for " + trade.getClass().getSimpleName() + " " + trade.getId(); - try { - if (!Sig.verify(trade.getSeller().getPubKeyRing().getSignaturePubKey(), unsignedMessageAsJson.getBytes(Charsets.UTF_8), signature)) throw new IllegalArgumentException(errMessage); - } catch (Exception e) { - throw new IllegalArgumentException(errMessage); - } - - // verify trade id - if (!trade.getId().equals(message.getTradeId())) throw new IllegalArgumentException("The " + message.getClass().getSimpleName() + " has the wrong trade id, expected " + trade.getId() + " but was " + message.getTradeId()); - - // verify buyer signature of payment sent message - verifyPaymentSentMessage(trade, message.getPaymentSentMessage()); - } - public static void awaitLatch(CountDownLatch latch) { try { latch.await(); diff --git a/core/src/main/java/haveno/core/trade/messages/DepositRequest.java b/core/src/main/java/haveno/core/trade/messages/DepositRequest.java index 884f76f05a..0807c2dd62 100644 --- a/core/src/main/java/haveno/core/trade/messages/DepositRequest.java +++ b/core/src/main/java/haveno/core/trade/messages/DepositRequest.java @@ -19,6 +19,7 @@ package haveno.core.trade.messages; import com.google.protobuf.ByteString; import haveno.common.proto.ProtoUtil; +import haveno.common.util.Utilities; import haveno.core.proto.CoreProtoResolver; import haveno.network.p2p.DirectMessage; import java.util.Optional; @@ -30,7 +31,7 @@ import lombok.Value; @Value public final class DepositRequest extends TradeMessage implements DirectMessage { private final long currentDate; - private final String contractSignature; + private final byte[] contractSignature; private final String depositTxHex; private final String depositTxKey; @Nullable @@ -40,7 +41,7 @@ public final class DepositRequest extends TradeMessage implements DirectMessage String uid, String messageVersion, long currentDate, - String contractSignature, + byte[] contractSignature, String depositTxHex, String depositTxKey, @Nullable byte[] paymentAccountKey) { @@ -62,11 +63,11 @@ public final class DepositRequest extends TradeMessage implements DirectMessage protobuf.DepositRequest.Builder builder = protobuf.DepositRequest.newBuilder() .setTradeId(tradeId) .setUid(uid) - .setContractSignature(contractSignature) .setDepositTxHex(depositTxHex) .setDepositTxKey(depositTxKey); builder.setCurrentDate(currentDate); Optional.ofNullable(paymentAccountKey).ifPresent(e -> builder.setPaymentAccountKey(ByteString.copyFrom(e))); + Optional.ofNullable(contractSignature).ifPresent(e -> builder.setContractSignature(ByteString.copyFrom(e))); return getNetworkEnvelopeBuilder().setDepositRequest(builder).build(); } @@ -78,7 +79,7 @@ public final class DepositRequest extends TradeMessage implements DirectMessage proto.getUid(), messageVersion, proto.getCurrentDate(), - proto.getContractSignature(), + ProtoUtil.byteArrayOrNullFromProto(proto.getContractSignature()), proto.getDepositTxHex(), proto.getDepositTxKey(), ProtoUtil.byteArrayOrNullFromProto(proto.getPaymentAccountKey())); @@ -88,7 +89,7 @@ public final class DepositRequest extends TradeMessage implements DirectMessage public String toString() { return "DepositRequest {" + ",\n currentDate=" + currentDate + - ",\n contractSignature=" + contractSignature + + ",\n contractSignature=" + Utilities.bytesAsHexString(contractSignature) + ",\n depositTxHex='" + depositTxHex + ",\n depositTxKey='" + depositTxKey + ",\n paymentAccountKey='" + paymentAccountKey + diff --git a/core/src/main/java/haveno/core/trade/messages/InitTradeRequest.java b/core/src/main/java/haveno/core/trade/messages/InitTradeRequest.java index 7abc1fc056..ec8d3a32db 100644 --- a/core/src/main/java/haveno/core/trade/messages/InitTradeRequest.java +++ b/core/src/main/java/haveno/core/trade/messages/InitTradeRequest.java @@ -62,7 +62,7 @@ public final class InitTradeRequest extends TradeMessage implements DirectMessag @Nullable private final String payoutAddress; @Nullable - private final String makerSignature; + private final byte[] makerSignature; public InitTradeRequest(String tradeId, NodeAddress senderNodeAddress, @@ -84,7 +84,7 @@ public final class InitTradeRequest extends TradeMessage implements DirectMessag @Nullable String reserveTxHex, @Nullable String reserveTxKey, @Nullable String payoutAddress, - @Nullable String makerSignature) { + @Nullable byte[] makerSignature) { super(messageVersion, tradeId, uid); this.senderNodeAddress = senderNodeAddress; this.pubKeyRing = pubKeyRing; @@ -133,7 +133,7 @@ public final class InitTradeRequest extends TradeMessage implements DirectMessag Optional.ofNullable(reserveTxKey).ifPresent(e -> builder.setReserveTxKey(reserveTxKey)); Optional.ofNullable(payoutAddress).ifPresent(e -> builder.setPayoutAddress(payoutAddress)); Optional.ofNullable(accountAgeWitnessSignatureOfOfferId).ifPresent(e -> builder.setAccountAgeWitnessSignatureOfOfferId(ByteString.copyFrom(e))); - Optional.ofNullable(makerSignature).ifPresent(e -> builder.setMakerSignature(makerSignature)); + Optional.ofNullable(makerSignature).ifPresent(e -> builder.setMakerSignature(ByteString.copyFrom(e))); builder.setCurrentDate(currentDate); return getNetworkEnvelopeBuilder().setInitTradeRequest(builder).build(); @@ -162,7 +162,7 @@ public final class InitTradeRequest extends TradeMessage implements DirectMessag ProtoUtil.stringOrNullFromProto(proto.getReserveTxHex()), ProtoUtil.stringOrNullFromProto(proto.getReserveTxKey()), ProtoUtil.stringOrNullFromProto(proto.getPayoutAddress()), - ProtoUtil.stringOrNullFromProto(proto.getMakerSignature())); + ProtoUtil.byteArrayOrNullFromProto(proto.getMakerSignature())); } @Override @@ -183,7 +183,7 @@ public final class InitTradeRequest extends TradeMessage implements DirectMessag ",\n reserveTxHex=" + reserveTxHex + ",\n reserveTxKey=" + reserveTxKey + ",\n payoutAddress=" + payoutAddress + - ",\n makerSignature=" + makerSignature + + ",\n makerSignature=" + Utilities.byteArrayToInteger(makerSignature) + "\n} " + super.toString(); } } diff --git a/core/src/main/java/haveno/core/trade/messages/SignContractResponse.java b/core/src/main/java/haveno/core/trade/messages/SignContractResponse.java index 7b40e61f7d..0026ad50c7 100644 --- a/core/src/main/java/haveno/core/trade/messages/SignContractResponse.java +++ b/core/src/main/java/haveno/core/trade/messages/SignContractResponse.java @@ -18,11 +18,10 @@ package haveno.core.trade.messages; import com.google.protobuf.ByteString; -import haveno.common.crypto.PubKeyRing; import haveno.common.proto.ProtoUtil; +import haveno.common.util.Utilities; import haveno.core.proto.CoreProtoResolver; import haveno.network.p2p.DirectMessage; -import haveno.network.p2p.NodeAddress; import java.util.Optional; import javax.annotation.Nullable; import lombok.EqualsAndHashCode; @@ -33,7 +32,7 @@ import lombok.Value; public final class SignContractResponse extends TradeMessage implements DirectMessage { private final long currentDate; private final String contractAsJson; - private final String contractSignature; + private final byte[] contractSignature; private final byte[] encryptedPaymentAccountPayload; public SignContractResponse(String tradeId, @@ -41,7 +40,7 @@ public final class SignContractResponse extends TradeMessage implements DirectMe String messageVersion, long currentDate, String contractAsJson, - String contractSignature, + byte[] contractSignature, @Nullable byte[] encryptedPaymentAccountPayload) { super(messageVersion, tradeId, uid); this.currentDate = currentDate; @@ -62,7 +61,7 @@ public final class SignContractResponse extends TradeMessage implements DirectMe .setUid(uid); Optional.ofNullable(contractAsJson).ifPresent(e -> builder.setContractAsJson(contractAsJson)); - Optional.ofNullable(contractSignature).ifPresent(e -> builder.setContractSignature(contractSignature)); + Optional.ofNullable(contractSignature).ifPresent(e -> builder.setContractSignature(ByteString.copyFrom(e))); Optional.ofNullable(encryptedPaymentAccountPayload).ifPresent(e -> builder.setEncryptedPaymentAccountPayload(ByteString.copyFrom(e))); builder.setCurrentDate(currentDate); @@ -78,7 +77,7 @@ public final class SignContractResponse extends TradeMessage implements DirectMe messageVersion, proto.getCurrentDate(), ProtoUtil.stringOrNullFromProto(proto.getContractAsJson()), - ProtoUtil.stringOrNullFromProto(proto.getContractSignature()), + ProtoUtil.byteArrayOrNullFromProto(proto.getContractSignature()), proto.getEncryptedPaymentAccountPayload().toByteArray()); } @@ -87,7 +86,7 @@ public final class SignContractResponse extends TradeMessage implements DirectMe return "SignContractResponse {" + ",\n currentDate=" + currentDate + ",\n contractAsJson='" + contractAsJson + - ",\n contractSignature='" + contractSignature + + ",\n contractSignature='" + Utilities.bytesAsHexString(contractSignature) + "\n} " + super.toString(); } } diff --git a/core/src/main/java/haveno/core/trade/protocol/ProcessModel.java b/core/src/main/java/haveno/core/trade/protocol/ProcessModel.java index eb27383074..0ba36cb50a 100644 --- a/core/src/main/java/haveno/core/trade/protocol/ProcessModel.java +++ b/core/src/main/java/haveno/core/trade/protocol/ProcessModel.java @@ -137,7 +137,7 @@ public class ProcessModel implements Model, PersistablePayload { transient private TradeMessage tradeMessage; @Getter @Setter - private String makerSignature; + private byte[] makerSignature; @Nullable @Getter @Setter @@ -220,7 +220,8 @@ public class ProcessModel implements Model, PersistablePayload { Optional.ofNullable(takeOfferFeeTxId).ifPresent(builder::setTakeOfferFeeTxId); Optional.ofNullable(payoutTxSignature).ifPresent(e -> builder.setPayoutTxSignature(ByteString.copyFrom(payoutTxSignature))); Optional.ofNullable(tempTradePeerNodeAddress).ifPresent(e -> builder.setTempTradePeerNodeAddress(tempTradePeerNodeAddress.toProtoMessage())); - Optional.ofNullable(makerSignature).ifPresent(e -> builder.setMakerSignature(makerSignature)); + Optional.ofNullable(mediatedPayoutTxSignature).ifPresent(e -> builder.setMediatedPayoutTxSignature(ByteString.copyFrom(e))); + Optional.ofNullable(makerSignature).ifPresent(e -> builder.setMakerSignature(ByteString.copyFrom(e))); Optional.ofNullable(multisigAddress).ifPresent(e -> builder.setMultisigAddress(multisigAddress)); Optional.ofNullable(paymentSentMessage).ifPresent(e -> builder.setPaymentSentMessage(paymentSentMessage.toProtoNetworkEnvelope().getPaymentSentMessage())); Optional.ofNullable(paymentReceivedMessage).ifPresent(e -> builder.setPaymentReceivedMessage(paymentReceivedMessage.toProtoNetworkEnvelope().getPaymentReceivedMessage())); @@ -245,7 +246,7 @@ public class ProcessModel implements Model, PersistablePayload { processModel.setPayoutTxSignature(ProtoUtil.byteArrayOrNullFromProto(proto.getPayoutTxSignature())); processModel.setTempTradePeerNodeAddress(proto.hasTempTradePeerNodeAddress() ? NodeAddress.fromProto(proto.getTempTradePeerNodeAddress()) : null); processModel.setMediatedPayoutTxSignature(ProtoUtil.byteArrayOrNullFromProto(proto.getMediatedPayoutTxSignature())); - processModel.setMakerSignature(proto.getMakerSignature()); + processModel.setMakerSignature(ProtoUtil.byteArrayOrNullFromProto(proto.getMakerSignature())); processModel.setMultisigAddress(ProtoUtil.stringOrNullFromProto(proto.getMultisigAddress())); String paymentSentMessageStateString = ProtoUtil.stringOrNullFromProto(proto.getPaymentSentMessageState()); diff --git a/core/src/main/java/haveno/core/trade/protocol/TradePeer.java b/core/src/main/java/haveno/core/trade/protocol/TradePeer.java index 64f8ab8707..31c728d7a1 100644 --- a/core/src/main/java/haveno/core/trade/protocol/TradePeer.java +++ b/core/src/main/java/haveno/core/trade/protocol/TradePeer.java @@ -79,7 +79,7 @@ public final class TradePeer implements PersistablePayload { @Nullable private String contractAsJson; @Nullable - private String contractSignature; + private byte[] contractSignature; // added in v 0.6 @Nullable @@ -146,7 +146,7 @@ public final class TradePeer implements PersistablePayload { Optional.ofNullable(paymentAccountPayload).ifPresent(e -> builder.setPaymentAccountPayload((protobuf.PaymentAccountPayload) e.toProtoMessage())); Optional.ofNullable(payoutAddressString).ifPresent(builder::setPayoutAddressString); Optional.ofNullable(contractAsJson).ifPresent(builder::setContractAsJson); - Optional.ofNullable(contractSignature).ifPresent(builder::setContractSignature); + Optional.ofNullable(contractSignature).ifPresent(e -> builder.setContractSignature(ByteString.copyFrom(e))); Optional.ofNullable(pubKeyRing).ifPresent(e -> builder.setPubKeyRing(e.toProtoMessage())); Optional.ofNullable(accountAgeWitnessNonce).ifPresent(e -> builder.setAccountAgeWitnessNonce(ByteString.copyFrom(e))); Optional.ofNullable(accountAgeWitnessSignature).ifPresent(e -> builder.setAccountAgeWitnessSignature(ByteString.copyFrom(e))); @@ -185,7 +185,7 @@ public final class TradePeer implements PersistablePayload { tradePeer.setPaymentAccountPayload(proto.hasPaymentAccountPayload() ? coreProtoResolver.fromProto(proto.getPaymentAccountPayload()) : null); tradePeer.setPayoutAddressString(ProtoUtil.stringOrNullFromProto(proto.getPayoutAddressString())); tradePeer.setContractAsJson(ProtoUtil.stringOrNullFromProto(proto.getContractAsJson())); - tradePeer.setContractSignature(ProtoUtil.stringOrNullFromProto(proto.getContractSignature())); + tradePeer.setContractSignature(ProtoUtil.byteArrayOrNullFromProto(proto.getContractSignature())); tradePeer.setPubKeyRing(proto.hasPubKeyRing() ? PubKeyRing.fromProto(proto.getPubKeyRing()) : null); tradePeer.setAccountAgeWitnessNonce(ProtoUtil.byteArrayOrNullFromProto(proto.getAccountAgeWitnessNonce())); tradePeer.setAccountAgeWitnessSignature(ProtoUtil.byteArrayOrNullFromProto(proto.getAccountAgeWitnessSignature())); diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/ArbitratorProcessDepositRequest.java b/core/src/main/java/haveno/core/trade/protocol/tasks/ArbitratorProcessDepositRequest.java index 24bb911e5b..f6f189c672 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/ArbitratorProcessDepositRequest.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/ArbitratorProcessDepositRequest.java @@ -24,6 +24,7 @@ import haveno.common.crypto.PubKeyRing; import haveno.common.crypto.Sig; import haveno.common.taskrunner.TaskRunner; import haveno.core.offer.Offer; +import haveno.core.trade.HavenoUtils; import haveno.core.trade.Trade; import haveno.core.trade.messages.DepositRequest; import haveno.core.trade.messages.DepositResponse; @@ -58,7 +59,7 @@ public class ArbitratorProcessDepositRequest extends TradeTask { // get contract and signature String contractAsJson = trade.getContractAsJson(); DepositRequest request = (DepositRequest) processModel.getTradeMessage(); // TODO (woodser): verify response - String signature = request.getContractSignature(); + byte[] signature = request.getContractSignature(); // get trader info TradePeer trader = trade.getTradePeer(processModel.getTempTradePeerNodeAddress()); @@ -66,7 +67,9 @@ public class ArbitratorProcessDepositRequest extends TradeTask { PubKeyRing peerPubKeyRing = trader.getPubKeyRing(); // verify signature - if (!Sig.verify(peerPubKeyRing.getSignaturePubKey(), contractAsJson, signature)) throw new RuntimeException("Peer's contract signature is invalid"); + if (!HavenoUtils.isSignatureValid(peerPubKeyRing, contractAsJson, signature)) { + throw new RuntimeException("Peer's contract signature is invalid"); + } // set peer's signature trader.setContractSignature(signature); diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/BuyerSendPaymentSentMessage.java b/core/src/main/java/haveno/core/trade/protocol/tasks/BuyerSendPaymentSentMessage.java index 2dab6887a8..93ce52b486 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/BuyerSendPaymentSentMessage.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/BuyerSendPaymentSentMessage.java @@ -17,10 +17,8 @@ package haveno.core.trade.protocol.tasks; -import com.google.common.base.Charsets; import haveno.common.Timer; import haveno.common.crypto.PubKeyRing; -import haveno.common.crypto.Sig; import haveno.common.taskrunner.TaskRunner; import haveno.core.network.MessageState; import haveno.core.trade.HavenoUtils; @@ -94,7 +92,7 @@ public abstract class BuyerSendPaymentSentMessage extends SendMailboxMessageTask // sign message try { String messageAsJson = JsonUtil.objectToJson(message); - byte[] sig = Sig.sign(processModel.getP2PService().getKeyRing().getSignatureKeyPair().getPrivate(), messageAsJson.getBytes(Charsets.UTF_8)); + byte[] sig = HavenoUtils.sign(processModel.getP2PService().getKeyRing(), messageAsJson); message.setBuyerSignature(sig); processModel.setPaymentSentMessage(message); trade.requestPersistence(); diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/MaybeSendSignContractRequest.java b/core/src/main/java/haveno/core/trade/protocol/tasks/MaybeSendSignContractRequest.java index 9bef140f0a..5c38b6fa06 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/MaybeSendSignContractRequest.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/MaybeSendSignContractRequest.java @@ -22,11 +22,10 @@ import java.util.Date; import java.util.List; import java.util.UUID; -import com.google.common.base.Charsets; import haveno.common.app.Version; -import haveno.common.crypto.Sig; import haveno.common.taskrunner.TaskRunner; import haveno.core.trade.ArbitratorTrade; +import haveno.core.trade.HavenoUtils; import haveno.core.trade.MakerTrade; import haveno.core.trade.Trade; import haveno.core.trade.Trade.State; @@ -90,7 +89,7 @@ public class MaybeSendSignContractRequest extends TradeTask { // maker signs deposit hash nonce to avoid challenge protocol byte[] sig = null; if (trade instanceof MakerTrade) { - sig = Sig.sign(processModel.getP2PService().getKeyRing().getSignatureKeyPair().getPrivate(), depositTx.getHash().getBytes(Charsets.UTF_8)); + sig = HavenoUtils.sign(processModel.getP2PService().getKeyRing(), depositTx.getHash()); } // create request for peer and arbitrator to sign contract diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessSignContractRequest.java b/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessSignContractRequest.java index 4951f2ab0a..9e51303e11 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessSignContractRequest.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessSignContractRequest.java @@ -30,10 +30,10 @@ import haveno.common.crypto.Encryption; import haveno.common.crypto.Hash; import haveno.common.crypto.PubKeyRing; import haveno.common.crypto.ScryptUtil; -import haveno.common.crypto.Sig; import haveno.common.taskrunner.TaskRunner; import haveno.core.trade.ArbitratorTrade; import haveno.core.trade.Contract; +import haveno.core.trade.HavenoUtils; import haveno.core.trade.Trade; import haveno.core.trade.Trade.State; import haveno.core.trade.messages.SignContractRequest; @@ -85,7 +85,7 @@ public class ProcessSignContractRequest extends TradeTask { // create and sign contract Contract contract = trade.createContract(); String contractAsJson = JsonUtil.objectToJson(contract); - String signature = Sig.sign(processModel.getKeyRing().getSignatureKeyPair().getPrivate(), contractAsJson); + byte[] signature = HavenoUtils.sign(processModel.getKeyRing(), contractAsJson); // save contract and signature trade.setContract(contract); diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessSignContractResponse.java b/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessSignContractResponse.java index b75bb29e6f..7faace96c1 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessSignContractResponse.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessSignContractResponse.java @@ -20,8 +20,8 @@ package haveno.core.trade.protocol.tasks; import haveno.common.app.Version; import haveno.common.crypto.PubKeyRing; -import haveno.common.crypto.Sig; import haveno.common.taskrunner.TaskRunner; +import haveno.core.trade.HavenoUtils; import haveno.core.trade.Trade; import haveno.core.trade.messages.DepositRequest; import haveno.core.trade.messages.SignContractResponse; @@ -63,8 +63,8 @@ public class ProcessSignContractResponse extends TradeTask { // verify signature // TODO (woodser): transfer contract for convenient comparison? - String signature = response.getContractSignature(); - if (!Sig.verify(peerPubKeyRing.getSignaturePubKey(), contractAsJson, signature)) throw new RuntimeException("Peer's contract signature is invalid"); + byte[] signature = response.getContractSignature(); + if (!HavenoUtils.isSignatureValid(peerPubKeyRing, contractAsJson, signature)) throw new RuntimeException("Peer's contract signature is invalid"); // set peer's signature peer.setContractSignature(signature); diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/SellerSendPaymentReceivedMessage.java b/core/src/main/java/haveno/core/trade/protocol/tasks/SellerSendPaymentReceivedMessage.java index 4abeff07ef..f76026480b 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/SellerSendPaymentReceivedMessage.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/SellerSendPaymentReceivedMessage.java @@ -22,9 +22,7 @@ import lombok.extern.slf4j.Slf4j; import static com.google.common.base.Preconditions.checkNotNull; -import com.google.common.base.Charsets; import haveno.common.crypto.PubKeyRing; -import haveno.common.crypto.Sig; import haveno.common.taskrunner.TaskRunner; import haveno.core.account.sign.SignedWitness; import haveno.core.account.witness.AccountAgeWitnessService; @@ -92,7 +90,7 @@ public abstract class SellerSendPaymentReceivedMessage extends SendMailboxMessag // sign message try { String messageAsJson = JsonUtil.objectToJson(message); - byte[] sig = Sig.sign(processModel.getP2PService().getKeyRing().getSignatureKeyPair().getPrivate(), messageAsJson.getBytes(Charsets.UTF_8)); + byte[] sig = HavenoUtils.sign(processModel.getP2PService().getKeyRing(), messageAsJson); message.setSellerSignature(sig); processModel.setPaymentReceivedMessage(message); trade.requestPersistence(); diff --git a/desktop/src/main/java/haveno/desktop/main/support/dispute/agent/SignedOfferView.java b/desktop/src/main/java/haveno/desktop/main/support/dispute/agent/SignedOfferView.java index 17df7407c1..9059d621f4 100644 --- a/desktop/src/main/java/haveno/desktop/main/support/dispute/agent/SignedOfferView.java +++ b/desktop/src/main/java/haveno/desktop/main/support/dispute/agent/SignedOfferView.java @@ -18,6 +18,7 @@ package haveno.desktop.main.support.dispute.agent; import haveno.common.UserThread; +import haveno.common.util.Utilities; import haveno.core.locale.Res; import haveno.core.offer.OpenOfferManager; import haveno.core.offer.SignedOffer; @@ -379,7 +380,7 @@ public class SignedOfferView extends ActivatableView { public void updateItem(final SignedOffer item, boolean empty) { super.updateItem(item, empty); if (item != null && !empty) - setText(item.getArbitratorSignature()); + setText(Utilities.bytesAsHexString(item.getArbitratorSignature())); else setText(""); } diff --git a/proto/src/main/proto/pb.proto b/proto/src/main/proto/pb.proto index 38ea007916..5d764216cc 100644 --- a/proto/src/main/proto/pb.proto +++ b/proto/src/main/proto/pb.proto @@ -165,7 +165,7 @@ message OfferAvailabilityResponse { AvailabilityResult availability_result = 2; repeated int32 supported_capabilities = 3; string uid = 4; - string maker_signature = 5; + bytes maker_signature = 5; } message RefreshOfferMessage { @@ -233,7 +233,7 @@ message InitTradeRequest { string reserve_tx_hex = 17; string reserve_tx_key = 18; string payout_address = 19; - string maker_signature = 20; + bytes maker_signature = 20; } message InitMultisigRequest { @@ -261,7 +261,7 @@ message SignContractResponse { string uid = 2; int64 current_date = 3; string contract_as_json = 4; - string contract_signature = 5; + bytes contract_signature = 5; bytes encrypted_payment_account_payload = 6; } @@ -269,7 +269,7 @@ message DepositRequest { string trade_id = 1; string uid = 2; int64 current_date = 3; - string contract_signature = 4; + bytes contract_signature = 4; string deposit_tx_hex = 5; string deposit_tx_key = 6; bytes payment_account_key = 7; @@ -636,7 +636,7 @@ message OfferPayload { int32 protocol_version = 34; NodeAddress arbitrator_signer = 1001; - string arbitrator_signature = 1002; + bytes arbitrator_signature = 1002; repeated string reserve_tx_key_images = 1003; } @@ -696,8 +696,8 @@ message Dispute { string deposit_tx_id = 14; string payout_tx_id = 15; string contract_as_json = 16; - string maker_contract_signature = 17; - string taker_contract_signature = 18; + bytes maker_contract_signature = 17; + bytes taker_contract_signature = 18; PaymentAccountPayload maker_payment_account_payload = 19; PaymentAccountPayload taker_payment_account_payload = 20; PubKeyRing agent_pub_key_ring = 21; @@ -1356,7 +1356,7 @@ message SignedOffer { string reserve_tx_hex = 7; repeated string reserve_tx_key_images = 8; uint64 reserve_tx_miner_fee = 9; - string arbitrator_signature = 10; + bytes arbitrator_signature = 10; } message OpenOffer { @@ -1531,7 +1531,7 @@ message ProcessModel { int64 funds_needed_for_trade = 7; string payment_sent_message_state = 8; bool deposits_confirmed_messages_delivered = 9; - string maker_signature = 10; + bytes maker_signature = 10; TradePeer maker = 11; TradePeer taker = 12; TradePeer arbitrator = 13; @@ -1557,7 +1557,7 @@ message TradePeer { PaymentAccountPayload payment_account_payload = 9; string payout_address_string = 10; string contract_as_json = 11; - string contract_signature = 12; + bytes contract_signature = 12; bytes account_age_witness_nonce = 18; bytes account_age_witness_signature = 19; AccountAgeWitness account_age_witness = 20;