mirror of
https://github.com/bisq-network/bisq.git
synced 2024-11-20 10:22:18 +01:00
Fix missing params in PrivateNotificationPayload constr. Use static fromProto methods. Removed readObject from SealedAndSigned and PrivateNotificationPayload. Add Sig.getSigPublicKeyFromBytes.
This commit is contained in:
parent
98e702905d
commit
b3d0d25d72
@ -18,10 +18,6 @@
|
||||
package io.bisq.common.crypto;
|
||||
|
||||
public class CryptoException extends Exception {
|
||||
|
||||
private CryptoException() {
|
||||
}
|
||||
|
||||
public CryptoException(String message) {
|
||||
super(message);
|
||||
}
|
||||
@ -33,8 +29,4 @@ public class CryptoException extends Exception {
|
||||
public CryptoException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
private CryptoException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* This file is part of bisq.
|
||||
*
|
||||
* bisq is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* bisq is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with bisq. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.bisq.common.crypto;
|
||||
|
||||
public class KeyConversionException extends RuntimeException {
|
||||
public KeyConversionException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
@ -20,27 +20,20 @@ package io.bisq.common.crypto;
|
||||
import com.google.protobuf.ByteString;
|
||||
import io.bisq.common.network.NetworkPayload;
|
||||
import io.bisq.generated.protobuffer.PB;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import java.security.PublicKey;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
import java.util.Arrays;
|
||||
|
||||
@Slf4j
|
||||
@EqualsAndHashCode
|
||||
public final class SealedAndSigned implements NetworkPayload {
|
||||
// Payload
|
||||
public final byte[] encryptedSecretKey;
|
||||
public final byte[] encryptedPayloadWithHmac;
|
||||
public final byte[] signature;
|
||||
private final byte[] sigPublicKeyBytes;
|
||||
|
||||
// Domain
|
||||
public transient PublicKey sigPublicKey;
|
||||
public PublicKey sigPublicKey;
|
||||
|
||||
public SealedAndSigned(byte[] encryptedSecretKey, byte[] encryptedPayloadWithHmac, byte[] signature, PublicKey sigPublicKey) {
|
||||
this.encryptedSecretKey = encryptedSecretKey;
|
||||
@ -50,64 +43,18 @@ public final class SealedAndSigned implements NetworkPayload {
|
||||
this.sigPublicKeyBytes = new X509EncodedKeySpec(this.sigPublicKey.getEncoded()).getEncoded();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// PROTO BUFFER
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public SealedAndSigned(byte[] encryptedSecretKey, byte[] encryptedPayloadWithHmac, byte[] signature, byte[] sigPublicKeyBytes) {
|
||||
this(encryptedSecretKey, encryptedPayloadWithHmac, signature, SealedAndSigned.init(sigPublicKeyBytes));
|
||||
this(encryptedSecretKey, encryptedPayloadWithHmac, signature, Sig.getSigPublicKeyFromBytes(sigPublicKeyBytes));
|
||||
}
|
||||
|
||||
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||
try {
|
||||
in.defaultReadObject();
|
||||
sigPublicKey = init(sigPublicKeyBytes);
|
||||
} catch (Throwable t) {
|
||||
log.warn("Exception at readObject: " + t.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* We have the bytes, now recreate the sigPublicKey. This happens when receiving this class over the wire,
|
||||
* because the public key is transient.
|
||||
*/
|
||||
static PublicKey init(byte[] sigPublicKeyBytes) {
|
||||
PublicKey publicKey = null;
|
||||
try {
|
||||
publicKey = KeyFactory.getInstance(Sig.KEY_ALGO, "BC")
|
||||
.generatePublic(new X509EncodedKeySpec(sigPublicKeyBytes));
|
||||
} catch (InvalidKeySpecException | NoSuchAlgorithmException | NoSuchProviderException e) {
|
||||
log.error("Error creating sigPublicKey", e);
|
||||
}
|
||||
return publicKey;
|
||||
}
|
||||
|
||||
|
||||
public PB.SealedAndSigned toProtoMessage() {
|
||||
return PB.SealedAndSigned.newBuilder().setEncryptedSecretKey(ByteString.copyFrom(encryptedSecretKey))
|
||||
.setEncryptedPayloadWithHmac(ByteString.copyFrom(encryptedPayloadWithHmac))
|
||||
.setSignature(ByteString.copyFrom(signature)).setSigPublicKeyBytes(ByteString.copyFrom(sigPublicKeyBytes))
|
||||
.build();
|
||||
}
|
||||
|
||||
@SuppressWarnings("SimplifiableIfStatement")
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof SealedAndSigned)) return false;
|
||||
|
||||
SealedAndSigned that = (SealedAndSigned) o;
|
||||
|
||||
if (!Arrays.equals(encryptedSecretKey, that.encryptedSecretKey)) return false;
|
||||
if (!Arrays.equals(encryptedPayloadWithHmac, that.encryptedPayloadWithHmac)) return false;
|
||||
if (!Arrays.equals(signature, that.signature)) return false;
|
||||
return !(sigPublicKey != null ? !sigPublicKey.equals(that.sigPublicKey) : that.sigPublicKey != null);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = encryptedSecretKey != null ? Arrays.hashCode(encryptedSecretKey) : 0;
|
||||
result = 31 * result + (encryptedPayloadWithHmac != null ? Arrays.hashCode(encryptedPayloadWithHmac) : 0);
|
||||
result = 31 * result + (signature != null ? Arrays.hashCode(signature) : 0);
|
||||
result = 31 * result + (sigPublicKey != null ? sigPublicKey.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -19,10 +19,13 @@ package io.bisq.common.crypto;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
import org.bouncycastle.util.encoders.Base64;
|
||||
import org.bouncycastle.util.encoders.Hex;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.security.*;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
|
||||
/**
|
||||
* StorageSignatureKeyPair/STORAGE_SIGN_KEY_ALGO: That is used for signing the data to be stored to the P2P network (by flooding).
|
||||
@ -122,5 +125,19 @@ public class Sig {
|
||||
public static boolean verify(PublicKey publicKey, String message, String signature) throws CryptoException {
|
||||
return verify(publicKey, message.getBytes(Charsets.UTF_8), Base64.decode(signature));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param sigPublicKeyBytes
|
||||
* @return
|
||||
*/
|
||||
public static PublicKey getSigPublicKeyFromBytes(byte[] sigPublicKeyBytes) {
|
||||
try {
|
||||
return KeyFactory.getInstance(Sig.KEY_ALGO, "BC").generatePublic(new X509EncodedKeySpec(sigPublicKeyBytes));
|
||||
} catch (InvalidKeySpecException | NoSuchAlgorithmException | NoSuchProviderException e) {
|
||||
log.error("Error creating sigPublicKey from bytes. sigPublicKeyBytes as hex={}, error={}", Hex.toHexString(sigPublicKeyBytes), e);
|
||||
e.printStackTrace();
|
||||
throw new KeyConversionException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -785,7 +785,7 @@ message USPostalMoneyOrderAccountPayload {
|
||||
message PrivateNotificationPayload {
|
||||
string message = 1;
|
||||
string signature_as_base64 = 2;
|
||||
bytes public_key_bytes = 3;
|
||||
bytes sig_public_key_bytes = 3;
|
||||
}
|
||||
|
||||
|
||||
|
@ -80,7 +80,7 @@ public class PrivateNotificationManager {
|
||||
PrivateNotificationMessage privateNotificationMessage = (PrivateNotificationMessage) wireEnvelope;
|
||||
log.trace("Received privateNotificationMessage: " + privateNotificationMessage);
|
||||
if (privateNotificationMessage.getSenderNodeAddress().equals(senderNodeAddress)) {
|
||||
final PrivateNotificationPayload privateNotification = privateNotificationMessage.privateNotificationPayload;
|
||||
final PrivateNotificationPayload privateNotification = privateNotificationMessage.getPrivateNotificationPayload();
|
||||
if (verifySignature(privateNotification))
|
||||
privateNotificationMessageProperty.set(privateNotification);
|
||||
} else {
|
||||
@ -128,13 +128,13 @@ public class PrivateNotificationManager {
|
||||
}
|
||||
|
||||
private void signAndAddSignatureToPrivateNotificationMessage(PrivateNotificationPayload privateNotification) {
|
||||
String privateNotificationMessageAsHex = Utils.HEX.encode(privateNotification.message.getBytes());
|
||||
String privateNotificationMessageAsHex = Utils.HEX.encode(privateNotification.getMessage().getBytes());
|
||||
String signatureAsBase64 = privateNotificationSigningKey.signMessage(privateNotificationMessageAsHex);
|
||||
privateNotification.setSigAndPubKey(signatureAsBase64, keyRing.getSignatureKeyPair().getPublic());
|
||||
}
|
||||
|
||||
private boolean verifySignature(PrivateNotificationPayload privateNotification) {
|
||||
String privateNotificationMessageAsHex = Utils.HEX.encode(privateNotification.message.getBytes());
|
||||
String privateNotificationMessageAsHex = Utils.HEX.encode(privateNotification.getMessage().getBytes());
|
||||
try {
|
||||
ECKey.fromPublicOnly(HEX.decode(pubKeyAsHex)).verifyMessage(privateNotificationMessageAsHex, privateNotification.getSignatureAsBase64());
|
||||
return true;
|
||||
|
@ -5,16 +5,14 @@ import io.bisq.common.network.NetworkEnvelope;
|
||||
import io.bisq.generated.protobuffer.PB;
|
||||
import io.bisq.network.p2p.MailboxMessage;
|
||||
import io.bisq.network.p2p.NodeAddress;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
import lombok.Value;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@EqualsAndHashCode
|
||||
@ToString
|
||||
@Value
|
||||
@Slf4j
|
||||
public class PrivateNotificationMessage implements MailboxMessage {
|
||||
private final NodeAddress myNodeAddress;
|
||||
public final PrivateNotificationPayload privateNotificationPayload;
|
||||
private final PrivateNotificationPayload privateNotificationPayload;
|
||||
private final String uid;
|
||||
private final int messageVersion = Version.getP2PMessageVersion();
|
||||
|
||||
@ -26,6 +24,27 @@ public class PrivateNotificationMessage implements MailboxMessage {
|
||||
this.uid = uid;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// PROTO BUFFER
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public static NetworkEnvelope fromProto(PB.PrivateNotificationMessage proto) {
|
||||
return new PrivateNotificationMessage(PrivateNotificationPayload.fromProto(proto.getPrivateNotificationPayload()),
|
||||
NodeAddress.fromProto(proto.getMyNodeAddress()),
|
||||
proto.getUid());
|
||||
}
|
||||
|
||||
@Override
|
||||
public PB.NetworkEnvelope toProtoNetworkEnvelope() {
|
||||
PB.NetworkEnvelope.Builder msgBuilder = NetworkEnvelope.getDefaultBuilder();
|
||||
return msgBuilder.setPrivateNotificationMessage(msgBuilder.getPrivateNotificationMessageBuilder()
|
||||
.setMessageVersion(messageVersion)
|
||||
.setUid(uid)
|
||||
.setMyNodeAddress(myNodeAddress.toProtoMessage())
|
||||
.setPrivateNotificationPayload(privateNotificationPayload.toProtoMessage())).build();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public NodeAddress getSenderNodeAddress() {
|
||||
return myNodeAddress;
|
||||
@ -41,13 +60,7 @@ public class PrivateNotificationMessage implements MailboxMessage {
|
||||
return messageVersion;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PB.NetworkEnvelope toProtoNetworkEnvelope() {
|
||||
PB.NetworkEnvelope.Builder msgBuilder = NetworkEnvelope.getDefaultBuilder();
|
||||
return msgBuilder.setPrivateNotificationMessage(msgBuilder.getPrivateNotificationMessageBuilder()
|
||||
.setMessageVersion(messageVersion)
|
||||
.setUid(uid)
|
||||
.setMyNodeAddress(myNodeAddress.toProtoMessage())
|
||||
.setPrivateNotificationPayload(privateNotificationPayload.toProtoMessage())).build();
|
||||
public PrivateNotificationPayload getPrivateNotificationPayload() {
|
||||
return privateNotificationPayload;
|
||||
}
|
||||
}
|
||||
|
@ -22,72 +22,69 @@ import io.bisq.common.crypto.Sig;
|
||||
import io.bisq.common.network.NetworkPayload;
|
||||
import io.bisq.generated.protobuffer.PB;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.bouncycastle.util.encoders.Hex;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import javax.annotation.Nullable;
|
||||
import java.security.PublicKey;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
|
||||
@EqualsAndHashCode
|
||||
@Slf4j
|
||||
@Getter
|
||||
public final class PrivateNotificationPayload implements NetworkPayload {
|
||||
// Payload
|
||||
public final String message;
|
||||
private final String message;
|
||||
@Nullable
|
||||
private String signatureAsBase64;
|
||||
private byte[] publicKeyBytes;
|
||||
|
||||
// Domain
|
||||
private transient PublicKey publicKey;
|
||||
@Nullable
|
||||
private byte[] sigPublicKeyBytes;
|
||||
@Nullable
|
||||
private PublicKey publicKey;
|
||||
|
||||
public PrivateNotificationPayload(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public PrivateNotificationPayload(String message, String signatureAsBase64, byte[] publicKeyBytes) {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// PROTO BUFFER
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private PrivateNotificationPayload(String message, String signatureAsBase64, byte[] sigPublicKeyBytes) {
|
||||
this(message);
|
||||
this.signatureAsBase64 = signatureAsBase64;
|
||||
this.publicKeyBytes = publicKeyBytes;
|
||||
init();
|
||||
this.sigPublicKeyBytes = sigPublicKeyBytes;
|
||||
publicKey = Sig.getSigPublicKeyFromBytes(sigPublicKeyBytes);
|
||||
}
|
||||
|
||||
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||
try {
|
||||
in.defaultReadObject();
|
||||
init();
|
||||
} catch (Throwable t) {
|
||||
log.warn("Exception at readObject: " + t.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void init() {
|
||||
try {
|
||||
publicKey = KeyFactory.getInstance(Sig.KEY_ALGO, "BC").generatePublic(new X509EncodedKeySpec(publicKeyBytes));
|
||||
} catch (InvalidKeySpecException | NoSuchAlgorithmException | NoSuchProviderException e) {
|
||||
log.error("Could not create public key from bytes", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void setSigAndPubKey(String signatureAsBase64, PublicKey storagePublicKey) {
|
||||
this.signatureAsBase64 = signatureAsBase64;
|
||||
this.publicKey = storagePublicKey;
|
||||
this.publicKeyBytes = new X509EncodedKeySpec(this.publicKey.getEncoded()).getEncoded();
|
||||
}
|
||||
|
||||
public String getSignatureAsBase64() {
|
||||
return signatureAsBase64;
|
||||
public static PrivateNotificationPayload fromProto(PB.PrivateNotificationPayload proto) {
|
||||
return new PrivateNotificationPayload(proto.getMessage(),
|
||||
proto.getSignatureAsBase64(),
|
||||
proto.getSignatureAsBase64Bytes().toByteArray());
|
||||
}
|
||||
|
||||
@Override
|
||||
public PB.PrivateNotificationPayload toProtoMessage() {
|
||||
checkNotNull(sigPublicKeyBytes, "sigPublicKeyBytes must nto be null");
|
||||
return PB.PrivateNotificationPayload.newBuilder()
|
||||
.setMessage(message)
|
||||
.setSignatureAsBase64(signatureAsBase64)
|
||||
.setPublicKeyBytes(ByteString.copyFrom(publicKeyBytes)).build();
|
||||
.setSigPublicKeyBytes(ByteString.copyFrom(sigPublicKeyBytes)).build();
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// API
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void setSigAndPubKey(String signatureAsBase64, PublicKey storagePublicKey) {
|
||||
this.signatureAsBase64 = signatureAsBase64;
|
||||
this.publicKey = storagePublicKey;
|
||||
this.sigPublicKeyBytes = new X509EncodedKeySpec(this.publicKey.getEncoded()).getEncoded();
|
||||
}
|
||||
|
||||
// Hex
|
||||
@ -96,7 +93,7 @@ public final class PrivateNotificationPayload implements NetworkPayload {
|
||||
return "PrivateNotification{" +
|
||||
"message='" + message + '\'' +
|
||||
", signatureAsBase64='" + signatureAsBase64 + '\'' +
|
||||
", publicKeyBytes=" + Hex.toHexString(publicKeyBytes) +
|
||||
", publicKeyBytes=" + Hex.toHexString(sigPublicKeyBytes) +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
@ -183,7 +183,7 @@ public class CoreNetworkProtoResolver implements NetworkProtoResolver {
|
||||
result = getPayoutTxPublishedMessage(msg.getPayoutTxPublishedMessage());
|
||||
break;
|
||||
case PRIVATE_NOTIFICATION_MESSAGE:
|
||||
result = getPrivateNotificationMessage(msg.getPrivateNotificationMessage());
|
||||
result = PrivateNotificationMessage.fromProto(msg.getPrivateNotificationMessage());
|
||||
break;
|
||||
default:
|
||||
log.warn("Unknown message case:{}:{}", msg.getMessageCase());
|
||||
@ -200,11 +200,6 @@ public class CoreNetworkProtoResolver implements NetworkProtoResolver {
|
||||
return new OfferAvailabilityRequest(msg.getOfferId(), PubKeyRing.fromProto(msg.getPubKeyRing()), msg.getTakersTradePrice());
|
||||
}
|
||||
|
||||
private static NetworkEnvelope getPrivateNotificationMessage(PB.PrivateNotificationMessage privateNotificationMessage) {
|
||||
return new PrivateNotificationMessage(getPrivateNotification(privateNotificationMessage.getPrivateNotificationPayload()),
|
||||
NodeAddress.fromProto(privateNotificationMessage.getMyNodeAddress()),
|
||||
privateNotificationMessage.getUid());
|
||||
}
|
||||
|
||||
private static NetworkEnvelope getPayoutTxPublishedMessage(PB.PayoutTxPublishedMessage payoutTxPublishedMessage) {
|
||||
return new PayoutTxPublishedMessage(payoutTxPublishedMessage.getTradeId(),
|
||||
|
@ -918,7 +918,7 @@ public class MainViewModel implements ViewModel {
|
||||
|
||||
private void displayPrivateNotification(PrivateNotificationPayload privateNotification) {
|
||||
new Popup<>().headLine(Res.get("popup.privateNotification.headline"))
|
||||
.attention(privateNotification.message)
|
||||
.attention(privateNotification.getMessage())
|
||||
.setHeadlineStyle("-fx-text-fill: -bs-error-red; -fx-font-weight: bold; -fx-font-size: 16;")
|
||||
.onClose(privateNotificationManager::removePrivateNotification)
|
||||
.useIUnderstandButton()
|
||||
|
Loading…
Reference in New Issue
Block a user