Broadcasts. Receiving seems to work, but there still seems to be a problem with sending them.

This commit is contained in:
2015-06-09 22:45:24 +02:00
parent f76864eebd
commit b4683bba68
26 changed files with 466 additions and 172 deletions

View File

@ -19,10 +19,11 @@ package ch.dissem.bitmessage;
import ch.dissem.bitmessage.entity.BitmessageAddress;
import ch.dissem.bitmessage.entity.ObjectMessage;
import ch.dissem.bitmessage.entity.Plaintext;
import ch.dissem.bitmessage.entity.Plaintext.Encoding;
import ch.dissem.bitmessage.entity.payload.*;
import ch.dissem.bitmessage.entity.payload.Pubkey.Feature;
import ch.dissem.bitmessage.entity.valueobject.PrivateKey;
import ch.dissem.bitmessage.exception.DecryptionFailedException;
import ch.dissem.bitmessage.factory.Factory;
import ch.dissem.bitmessage.ports.*;
import ch.dissem.bitmessage.utils.Security;
import ch.dissem.bitmessage.utils.UnixTime;
@ -35,6 +36,8 @@ import java.util.Collection;
import java.util.TreeSet;
import static ch.dissem.bitmessage.entity.Plaintext.Status.*;
import static ch.dissem.bitmessage.entity.Plaintext.Type.BROADCAST;
import static ch.dissem.bitmessage.entity.Plaintext.Type.MSG;
import static ch.dissem.bitmessage.utils.UnixTime.DAY;
/**
@ -59,6 +62,8 @@ public class BitmessageContext {
private final InternalContext ctx;
private Listener listener;
private BitmessageContext(Builder builder) {
ctx = new InternalContext(builder);
}
@ -89,12 +94,34 @@ public class BitmessageContext {
// TODO
}
public void broadcast(BitmessageAddress from, String subject, String message) {
// TODO: all this should happen in a separate thread
Plaintext msg = new Plaintext.Builder(BROADCAST)
.from(from)
.message(subject, message)
.build();
LOG.info("Sending message.");
msg.setStatus(DOING_PROOF_OF_WORK);
ctx.getMessageRepository().save(msg);
ctx.send(
from,
from,
Factory.getBroadcast(from, msg),
+2 * DAY,
0,
0
);
msg.setStatus(SENT);
ctx.getMessageRepository().save(msg);
}
public void send(BitmessageAddress from, BitmessageAddress to, String subject, String message) {
if (from.getPrivateKey() == null) {
throw new IllegalArgumentException("'From' must be an identity, i.e. have a private key.");
}
// TODO: all this should happen in a separate thread
Plaintext msg = new Plaintext.Builder()
Plaintext msg = new Plaintext.Builder(MSG)
.from(from)
.to(to)
.message(subject, message)
@ -154,6 +181,7 @@ public class BitmessageContext {
}
public void startup(Listener listener) {
this.listener = listener;
ctx.getNetworkHandler().start(new DefaultMessageListener(ctx, listener));
}
@ -176,7 +204,7 @@ public class BitmessageContext {
if (address.getVersion() == 4) {
V4Pubkey v4Pubkey = (V4Pubkey) pubkey;
if (Arrays.equals(address.getTag(), v4Pubkey.getTag())) {
v4Pubkey.decrypt(address.getPubkeyDecryptionKey());
v4Pubkey.decrypt(address.getPublicDecryptionKey());
if (object.isSignatureValid(v4Pubkey)) {
address.setPubkey(v4Pubkey);
ctx.getAddressRepo().save(address);
@ -198,6 +226,25 @@ public class BitmessageContext {
}
}
public void addSubscribtion(BitmessageAddress address) {
address.setSubscribed(true);
ctx.getAddressRepo().save(address);
tryToFindBroadcastsForAddress(address);
}
private void tryToFindBroadcastsForAddress(BitmessageAddress address) {
for (ObjectMessage object : ctx.getInventory().getObjects(address.getStream(), Broadcast.getVersion(address), ObjectType.BROADCAST)) {
try {
Broadcast broadcast = (Broadcast) object.getPayload();
broadcast.decrypt(address);
listener.receive(broadcast.getPlaintext());
} catch (DecryptionFailedException ignore) {
} catch (Exception e) {
LOG.debug(e.getMessage(), e);
}
}
}
public interface Listener {
void receive(Plaintext plaintext);
}

View File

@ -82,7 +82,7 @@ class DefaultMessageListener implements NetworkHandler.MessageListener {
V4Pubkey v4Pubkey = (V4Pubkey) pubkey;
address = ctx.getAddressRepo().findContact(v4Pubkey.getTag());
if (address != null) {
v4Pubkey.decrypt(address.getPubkeyDecryptionKey());
v4Pubkey.decrypt(address.getPublicDecryptionKey());
}
} else {
address = ctx.getAddressRepo().findContact(pubkey.getRipe());
@ -91,8 +91,8 @@ class DefaultMessageListener implements NetworkHandler.MessageListener {
address.setPubkey(pubkey);
LOG.debug("Got pubkey for contact " + address);
List<Plaintext> messages = ctx.getMessageRepository().findMessages(Plaintext.Status.PUBKEY_REQUESTED, address);
LOG.debug("Sending " + messages.size() + " messages for contact " + address);
for (Plaintext msg : messages) {
// TODO: send messages enqueued for this address
msg.setStatus(DOING_PROOF_OF_WORK);
ctx.getMessageRepository().save(msg);
ctx.send(
@ -118,14 +118,18 @@ class DefaultMessageListener implements NetworkHandler.MessageListener {
try {
msg.decrypt(identity.getPrivateKey().getPrivateEncryptionKey());
msg.getPlaintext().setTo(identity);
object.isSignatureValid(msg.getPlaintext().getFrom().getPubkey());
msg.getPlaintext().setStatus(RECEIVED);
msg.getPlaintext().addLabels(ctx.getMessageRepository().getLabels(Label.Type.INBOX, Label.Type.UNREAD));
ctx.getMessageRepository().save(msg.getPlaintext());
listener.receive(msg.getPlaintext());
if (!object.isSignatureValid(msg.getPlaintext().getFrom().getPubkey())) {
LOG.warn("Msg with IV " + object.getInventoryVector() + " was successfully decrypted, but signature check failed. Ignoring.");
} else {
msg.getPlaintext().setStatus(RECEIVED);
msg.getPlaintext().addLabels(ctx.getMessageRepository().getLabels(Label.Type.INBOX, Label.Type.UNREAD));
msg.getPlaintext().setInventoryVector(object.getInventoryVector());
ctx.getMessageRepository().save(msg.getPlaintext());
listener.receive(msg.getPlaintext());
}
break;
} catch (DecryptionFailedException ignore) {
LOG.debug(ignore.getMessage(), ignore);
LOG.trace(ignore.getMessage(), ignore);
}
}
}
@ -135,9 +139,13 @@ class DefaultMessageListener implements NetworkHandler.MessageListener {
// V5Broadcast v5 = broadcast instanceof V5Broadcast ? (V5Broadcast) broadcast : null;
for (BitmessageAddress subscription : ctx.getAddressRepo().getSubscriptions()) {
try {
broadcast.decrypt(subscription.getPubkeyDecryptionKey());
object.isSignatureValid(broadcast.getPlaintext().getFrom().getPubkey());
listener.receive(broadcast.getPlaintext());
broadcast.decrypt(subscription.getPublicDecryptionKey());
if (!object.isSignatureValid(broadcast.getPlaintext().getFrom().getPubkey())) {
LOG.warn("Broadcast with IV " + object.getInventoryVector() + " was successfully decrypted, but signature check failed. Ignoring.");
} else {
broadcast.getPlaintext().setInventoryVector(object.getInventoryVector());
listener.receive(broadcast.getPlaintext());
}
} catch (DecryptionFailedException ignore) {
}
}

View File

@ -16,9 +16,8 @@
package ch.dissem.bitmessage;
import ch.dissem.bitmessage.entity.BitmessageAddress;
import ch.dissem.bitmessage.entity.Encrypted;
import ch.dissem.bitmessage.entity.ObjectMessage;
import ch.dissem.bitmessage.entity.*;
import ch.dissem.bitmessage.entity.payload.Broadcast;
import ch.dissem.bitmessage.entity.payload.GetPubkey;
import ch.dissem.bitmessage.entity.payload.ObjectPayload;
import ch.dissem.bitmessage.ports.*;
@ -141,6 +140,7 @@ public class InternalContext {
public void send(BitmessageAddress from, BitmessageAddress to, ObjectPayload payload, long timeToLive, long nonceTrialsPerByte, long extraBytes) {
try {
if (to == null) to = from;
long expires = UnixTime.now(+timeToLive);
LOG.info("Expires at " + expires);
ObjectMessage object = new ObjectMessage.Builder()
@ -151,10 +151,17 @@ public class InternalContext {
if (object.isSigned()) {
object.sign(from.getPrivateKey());
}
if (payload instanceof Encrypted) {
if (payload instanceof Broadcast) {
((Broadcast) payload).encrypt();
} else if (payload instanceof Encrypted) {
object.encrypt(to.getPubkey());
}
Security.doProofOfWork(object, proofOfWorkEngine, nonceTrialsPerByte, extraBytes);
if (payload instanceof PlaintextHolder) {
Plaintext plaintext = ((PlaintextHolder) payload).getPlaintext();
plaintext.setInventoryVector(object.getInventoryVector());
messageRepository.save(plaintext);
}
inventory.storeObject(object);
networkHandler.offer(object.getInventoryVector());
} catch (IOException e) {
@ -172,13 +179,13 @@ public class InternalContext {
.payload(identity.getPubkey())
.build();
response.sign(identity.getPrivateKey());
response.encrypt(Security.createPublicKey(identity.getPubkeyDecryptionKey()).getEncoded(false));
response.encrypt(Security.createPublicKey(identity.getPublicDecryptionKey()).getEncoded(false));
Security.doProofOfWork(response, proofOfWorkEngine, networkNonceTrialsPerByte, networkExtraBytes);
if (response.isSigned()) {
response.sign(identity.getPrivateKey());
}
if (response instanceof Encrypted) {
response.encrypt(Security.createPublicKey(identity.getPubkeyDecryptionKey()).getEncoded(false));
response.encrypt(Security.createPublicKey(identity.getPublicDecryptionKey()).getEncoded(false));
}
inventory.storeObject(response);
networkHandler.offer(response.getInventoryVector());

View File

@ -42,7 +42,7 @@ public class BitmessageAddress {
/**
* Used for V4 address encryption. It's easier to just create it regardless of address version.
*/
private final byte[] pubkeyDecryptionKey;
private final byte[] publicDecryptionKey;
private String address;
@ -61,14 +61,20 @@ public class BitmessageAddress {
ByteArrayOutputStream os = new ByteArrayOutputStream();
Encode.varInt(version, os);
Encode.varInt(stream, os);
// for the tag, the checksum has to be created with 0x00 padding
byte[] checksum = Security.doubleSha512(os.toByteArray(), ripe);
this.tag = Arrays.copyOfRange(checksum, 32, 64);
this.pubkeyDecryptionKey = Arrays.copyOfRange(checksum, 0, 32);
if (version < 4) {
byte[] checksum = Security.sha512(os.toByteArray(), ripe);
this.tag = null;
this.publicDecryptionKey = Arrays.copyOfRange(checksum, 0, 32);
} else {
// for tag and decryption key, the checksum has to be created with 0x00 padding
byte[] checksum = Security.doubleSha512(os.toByteArray(), ripe);
this.tag = Arrays.copyOfRange(checksum, 32, 64);
this.publicDecryptionKey = Arrays.copyOfRange(checksum, 0, 32);
}
// but for the address and its checksum they need to be stripped
int offset = Bytes.numberOfLeadingZeros(ripe);
os.write(ripe, offset, ripe.length - offset);
checksum = Security.doubleSha512(os.toByteArray());
byte[] checksum = Security.doubleSha512(os.toByteArray());
os.write(checksum, 0, 4);
this.address = "BM-" + Base58.encode(os.toByteArray());
} catch (IOException e) {
@ -103,9 +109,15 @@ public class BitmessageAddress {
if (expectedChecksum[i] != checksum[i])
throw new IllegalArgumentException("Checksum of address failed");
}
checksum = Security.doubleSha512(Arrays.copyOfRange(bytes, 0, counter.length()), ripe);
this.tag = Arrays.copyOfRange(checksum, 32, 64);
this.pubkeyDecryptionKey = Arrays.copyOfRange(checksum, 0, 32);
if (version < 4) {
checksum = Security.sha512(Arrays.copyOfRange(bytes, 0, counter.length()), ripe);
this.tag = null;
this.publicDecryptionKey = Arrays.copyOfRange(checksum, 0, 32);
} else {
checksum = Security.doubleSha512(Arrays.copyOfRange(bytes, 0, counter.length()), ripe);
this.tag = Arrays.copyOfRange(checksum, 32, 64);
this.publicDecryptionKey = Arrays.copyOfRange(checksum, 0, 32);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
@ -145,8 +157,11 @@ public class BitmessageAddress {
this.pubkey = pubkey;
}
public byte[] getPubkeyDecryptionKey() {
return pubkeyDecryptionKey;
/**
* Returns the private key used to decrypt Pubkey objects (for v4 addresses) and broadcasts.
*/
public byte[] getPublicDecryptionKey() {
return publicDecryptionKey;
}
public PrivateKey getPrivateKey() {
@ -165,10 +180,6 @@ public class BitmessageAddress {
this.alias = alias;
}
public void setSubscribed(boolean subscribed) {
this.subscribed = subscribed;
}
@Override
public String toString() {
return alias != null ? alias : address;
@ -196,4 +207,12 @@ public class BitmessageAddress {
public int hashCode() {
return Arrays.hashCode(ripe);
}
public boolean isSubscribed() {
return subscribed;
}
public void setSubscribed(boolean subscribed) {
this.subscribed = subscribed;
}
}

View File

@ -16,6 +16,7 @@
package ch.dissem.bitmessage.entity;
import ch.dissem.bitmessage.entity.valueobject.InventoryVector;
import ch.dissem.bitmessage.entity.valueobject.Label;
import ch.dissem.bitmessage.factory.Factory;
import ch.dissem.bitmessage.utils.Decode;
@ -28,11 +29,13 @@ import java.util.*;
* The unencrypted message to be sent by 'msg' or 'broadcast'.
*/
public class Plaintext implements Streamable {
private final Type type;
private final BitmessageAddress from;
private final long encoding;
private final byte[] message;
private final byte[] ack;
private Object id;
private InventoryVector inventoryVector;
private BitmessageAddress to;
private byte[] signature;
private Status status;
@ -43,6 +46,8 @@ public class Plaintext implements Streamable {
private Plaintext(Builder builder) {
id = builder.id;
inventoryVector = builder.inventoryVector;
type = builder.type;
from = builder.from;
to = builder.to;
encoding = builder.encoding;
@ -55,14 +60,14 @@ public class Plaintext implements Streamable {
labels = builder.labels;
}
public static Plaintext read(InputStream in) throws IOException {
return readWithoutSignature(in)
public static Plaintext read(Type type, InputStream in) throws IOException {
return readWithoutSignature(type, in)
.signature(Decode.varBytes(in))
.build();
}
public static Plaintext.Builder readWithoutSignature(InputStream in) throws IOException {
return new Builder()
public static Plaintext.Builder readWithoutSignature(Type type, InputStream in) throws IOException {
return new Builder(type)
.addressVersion(Decode.varInt(in))
.stream(Decode.varInt(in))
.behaviorBitfield(Decode.int32(in))
@ -70,10 +75,22 @@ public class Plaintext implements Streamable {
.publicEncryptionKey(Decode.bytes(in, 64))
.nonceTrialsPerByte(Decode.varInt(in))
.extraBytes(Decode.varInt(in))
.destinationRipe(Decode.bytes(in, 20))
.destinationRipe(type == Type.MSG ? Decode.bytes(in, 20) : null)
.encoding(Decode.varInt(in))
.message(Decode.varBytes(in))
.ack(Decode.varBytes(in));
.ack(type == Type.MSG ? Decode.varBytes(in) : null);
}
public InventoryVector getInventoryVector() {
return inventoryVector;
}
public void setInventoryVector(InventoryVector inventoryVector) {
this.inventoryVector = inventoryVector;
}
public Type getType() {
return type;
}
public byte[] getMessage() {
@ -121,12 +138,16 @@ public class Plaintext implements Streamable {
out.write(from.getPubkey().getEncryptionKey(), 1, 64);
Encode.varInt(from.getPubkey().getNonceTrialsPerByte(), out);
Encode.varInt(from.getPubkey().getExtraBytes(), out);
out.write(to.getRipe());
if (type == Type.MSG) {
out.write(to.getRipe());
}
Encode.varInt(encoding, out);
Encode.varInt(message.length, out);
out.write(message);
Encode.varInt(ack.length, out);
out.write(ack);
if (type == Type.MSG) {
Encode.varInt(ack.length, out);
out.write(ack);
}
if (includeSignature) {
if (signature == null) {
Encode.varInt(0, out);
@ -249,8 +270,14 @@ public class Plaintext implements Streamable {
RECEIVED
}
public enum Type {
MSG, BROADCAST
}
public static final class Builder {
private Object id;
private InventoryVector inventoryVector;
private Type type;
private BitmessageAddress from;
private BitmessageAddress to;
private long addressVersion;
@ -270,7 +297,8 @@ public class Plaintext implements Streamable {
private Status status;
private Set<Label> labels = new HashSet<>();
public Builder() {
public Builder(Type type) {
this.type = type;
}
public Builder id(Object id) {
@ -278,12 +306,19 @@ public class Plaintext implements Streamable {
return this;
}
public Builder IV(InventoryVector iv) {
this.inventoryVector = iv;
return this;
}
public Builder from(BitmessageAddress address) {
from = address;
return this;
}
public Builder to(BitmessageAddress address) {
if (type != Type.MSG && to != null)
throw new IllegalArgumentException("recipient address only allowed for msg");
to = address;
return this;
}
@ -324,6 +359,7 @@ public class Plaintext implements Streamable {
}
private Builder destinationRipe(byte[] ripe) {
if (type != Type.MSG && ripe != null) throw new IllegalArgumentException("ripe only allowed for msg");
this.destinationRipe = ripe;
return this;
}
@ -354,6 +390,7 @@ public class Plaintext implements Streamable {
}
public Builder ack(byte[] ack) {
if (type != Type.MSG && ack != null) throw new IllegalArgumentException("ack only allowed for msg");
this.ack = ack;
return this;
}
@ -395,7 +432,7 @@ public class Plaintext implements Streamable {
behaviorBitfield
));
}
if (to == null) {
if (to == null && type != Type.BROADCAST) {
to = new BitmessageAddress(0, 0, destinationRipe);
}
return new Plaintext(this);

View File

@ -0,0 +1,21 @@
/*
* Copyright 2015 Christian Basler
*
* 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 ch.dissem.bitmessage.entity;
public interface PlaintextHolder {
Plaintext getPlaintext();
}

View File

@ -16,17 +16,22 @@
package ch.dissem.bitmessage.entity.payload;
import ch.dissem.bitmessage.entity.BitmessageAddress;
import ch.dissem.bitmessage.entity.Encrypted;
import ch.dissem.bitmessage.entity.Plaintext;
import ch.dissem.bitmessage.entity.PlaintextHolder;
import ch.dissem.bitmessage.exception.DecryptionFailedException;
import ch.dissem.bitmessage.utils.Security;
import java.io.IOException;
import static ch.dissem.bitmessage.entity.Plaintext.Type.BROADCAST;
/**
* Users who are subscribed to the sending address will see the message appear in their inbox.
* Broadcasts are version 4 or 5.
*/
public abstract class Broadcast extends ObjectPayload implements Encrypted {
public abstract class Broadcast extends ObjectPayload implements Encrypted, PlaintextHolder {
protected final long stream;
protected CryptoBox encrypted;
protected Plaintext plaintext;
@ -38,11 +43,16 @@ public abstract class Broadcast extends ObjectPayload implements Encrypted {
this.plaintext = plaintext;
}
public static long getVersion(BitmessageAddress address) {
return address.getVersion() < 4 ? 4 : 5;
}
@Override
public long getStream() {
return stream;
}
@Override
public Plaintext getPlaintext() {
return plaintext;
}
@ -52,9 +62,17 @@ public abstract class Broadcast extends ObjectPayload implements Encrypted {
this.encrypted = new CryptoBox(plaintext, publicKey);
}
public void encrypt() throws IOException {
encrypt(Security.createPublicKey(plaintext.getFrom().getPublicDecryptionKey()).getEncoded(false));
}
@Override
public void decrypt(byte[] privateKey) throws IOException, DecryptionFailedException {
plaintext = Plaintext.read(encrypted.decrypt(privateKey));
plaintext = Plaintext.read(BROADCAST, encrypted.decrypt(privateKey));
}
public void decrypt(BitmessageAddress address) throws IOException, DecryptionFailedException {
decrypt(address.getPublicDecryptionKey());
}
@Override

View File

@ -18,16 +18,19 @@ package ch.dissem.bitmessage.entity.payload;
import ch.dissem.bitmessage.entity.Encrypted;
import ch.dissem.bitmessage.entity.Plaintext;
import ch.dissem.bitmessage.entity.PlaintextHolder;
import ch.dissem.bitmessage.exception.DecryptionFailedException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import static ch.dissem.bitmessage.entity.Plaintext.Type.MSG;
/**
* Used for person-to-person messages.
*/
public class Msg extends ObjectPayload implements Encrypted {
public class Msg extends ObjectPayload implements Encrypted, PlaintextHolder {
private long stream;
private CryptoBox encrypted;
private Plaintext plaintext;
@ -48,6 +51,7 @@ public class Msg extends ObjectPayload implements Encrypted {
return new Msg(stream, CryptoBox.read(in, length));
}
@Override
public Plaintext getPlaintext() {
return plaintext;
}
@ -89,7 +93,7 @@ public class Msg extends ObjectPayload implements Encrypted {
@Override
public void decrypt(byte[] privateKey) throws IOException, DecryptionFailedException {
plaintext = Plaintext.read(encrypted.decrypt(privateKey));
plaintext = Plaintext.read(MSG, encrypted.decrypt(privateKey));
}
@Override

View File

@ -16,6 +16,9 @@
package ch.dissem.bitmessage.entity.payload;
import ch.dissem.bitmessage.entity.BitmessageAddress;
import ch.dissem.bitmessage.entity.Plaintext;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@ -25,12 +28,18 @@ import java.io.OutputStream;
* Broadcasts are version 4 or 5.
*/
public class V4Broadcast extends Broadcast {
protected V4Broadcast(long version, long stream, CryptoBox encrypted) {
super(version, stream, encrypted, null);
protected V4Broadcast(long version, long stream, CryptoBox encrypted, Plaintext plaintext) {
super(version, stream, encrypted, plaintext);
}
public V4Broadcast(BitmessageAddress senderAddress, Plaintext plaintext) {
super(4, senderAddress.getStream(), null, plaintext);
if (senderAddress.getVersion() >= 4)
throw new IllegalArgumentException("Address version 3 or older expected, but was " + senderAddress.getVersion());
}
public static V4Broadcast read(InputStream in, long stream, int length) throws IOException {
return new V4Broadcast(4, stream, CryptoBox.read(in, length));
return new V4Broadcast(4, stream, CryptoBox.read(in, length), null);
}
@Override

View File

@ -16,6 +16,8 @@
package ch.dissem.bitmessage.entity.payload;
import ch.dissem.bitmessage.entity.BitmessageAddress;
import ch.dissem.bitmessage.entity.Plaintext;
import ch.dissem.bitmessage.utils.Decode;
import java.io.IOException;
@ -29,10 +31,17 @@ public class V5Broadcast extends V4Broadcast {
private byte[] tag;
private V5Broadcast(long stream, byte[] tag, CryptoBox encrypted) {
super(5, stream, encrypted);
super(5, stream, encrypted, null);
this.tag = tag;
}
public V5Broadcast(BitmessageAddress senderAddress, Plaintext plaintext) {
super(5, senderAddress.getStream(), null, plaintext);
if (senderAddress.getVersion() < 4)
throw new IllegalArgumentException("Address version 4 (or newer) expected, but was " + senderAddress.getVersion());
this.tag = senderAddress.getTag();
}
public static V5Broadcast read(InputStream is, long stream, int length) throws IOException {
return new V5Broadcast(stream, Decode.bytes(is, 32), CryptoBox.read(is, length - 32));
}

View File

@ -19,6 +19,7 @@ package ch.dissem.bitmessage.factory;
import ch.dissem.bitmessage.entity.BitmessageAddress;
import ch.dissem.bitmessage.entity.NetworkMessage;
import ch.dissem.bitmessage.entity.ObjectMessage;
import ch.dissem.bitmessage.entity.Plaintext;
import ch.dissem.bitmessage.entity.payload.*;
import ch.dissem.bitmessage.entity.valueobject.PrivateKey;
import org.slf4j.Logger;
@ -164,4 +165,12 @@ public class Factory {
return GenericPayload.read(version, stream, streamNumber, length);
}
}
public static ObjectPayload getBroadcast(BitmessageAddress sendingAddress, Plaintext plaintext) {
if (sendingAddress.getVersion() < 4) {
return new V4Broadcast(sendingAddress, plaintext);
} else {
return new V5Broadcast(sendingAddress, plaintext);
}
}
}

View File

@ -0,0 +1,39 @@
/*
* Copyright 2015 Christian Basler
*
* 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 ch.dissem.bitmessage.utils;
import ch.dissem.bitmessage.entity.ObjectMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class DebugUtils {
private final static Logger LOG = LoggerFactory.getLogger(DebugUtils.class);
public static void saveToFile(ObjectMessage objectMessage) {
try {
File f = new File(System.getProperty("user.home") + "/jabit.error/" + objectMessage.getInventoryVector() + ".inv");
f.createNewFile();
objectMessage.write(new FileOutputStream(f));
} catch (IOException e) {
LOG.debug(e.getMessage(), e);
}
}
}

View File

@ -0,0 +1,47 @@
/*
* Copyright 2015 Christian Basler
*
* 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 ch.dissem.bitmessage;
import ch.dissem.bitmessage.entity.BitmessageAddress;
import ch.dissem.bitmessage.entity.ObjectMessage;
import ch.dissem.bitmessage.entity.payload.V4Broadcast;
import ch.dissem.bitmessage.entity.payload.V5Broadcast;
import ch.dissem.bitmessage.exception.DecryptionFailedException;
import ch.dissem.bitmessage.utils.TestUtils;
import org.junit.Test;
import java.io.IOException;
import static org.junit.Assert.assertEquals;
public class DecryptionTest {
@Test
public void ensureV4BroadcastIsDecryptedCorrectly() throws IOException, DecryptionFailedException {
ObjectMessage objectMessage = TestUtils.loadObjectMessage(5, "V4Broadcast.payload");
V4Broadcast broadcast = (V4Broadcast) objectMessage.getPayload();
broadcast.decrypt(new BitmessageAddress("BM-2D9Vc5rFxxR5vTi53T9gkLfemViHRMVLQZ"));
assertEquals("Test-Broadcast", broadcast.getPlaintext().getSubject());
}
@Test
public void ensureV5BroadcastIsDecryptedCorrectly() throws IOException, DecryptionFailedException {
ObjectMessage objectMessage = TestUtils.loadObjectMessage(5, "V5Broadcast.payload");
V5Broadcast broadcast = (V5Broadcast) objectMessage.getPayload();
broadcast.decrypt(new BitmessageAddress("BM-2cXxfcSetKnbHJX2Y85rSkaVpsdNUZ5q9h"));
assertEquals("Test-Broadcast", broadcast.getPlaintext().getSubject());
}
}

View File

@ -84,7 +84,7 @@ public class BitmessageAddressTest {
public void testV4PubkeyImport() throws IOException, DecryptionFailedException {
BitmessageAddress address = new BitmessageAddress("BM-2cXxfcSetKnbHJX2Y85rSkaVpsdNUZ5q9h");
ObjectMessage object = TestUtils.loadObjectMessage(4, "V4Pubkey.payload");
object.decrypt(address.getPubkeyDecryptionKey());
object.decrypt(address.getPublicDecryptionKey());
V4Pubkey pubkey = (V4Pubkey) object.getPayload();
assertTrue(object.isSignatureValid(pubkey));
address.setPubkey(pubkey);

View File

@ -27,6 +27,7 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import static ch.dissem.bitmessage.entity.Plaintext.Type.MSG;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
@ -78,7 +79,7 @@ public class SerializationTest {
@Test
public void ensurePlaintextIsSerializedAndDeserializedCorrectly() throws IOException, DecryptionFailedException {
Plaintext p1 = new Plaintext.Builder()
Plaintext p1 = new Plaintext.Builder(MSG)
.from(TestUtils.loadIdentity("BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8"))
.to(TestUtils.loadContact())
.message("Subject", "Message")
@ -88,7 +89,7 @@ public class SerializationTest {
ByteArrayOutputStream out = new ByteArrayOutputStream();
p1.write(out);
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
Plaintext p2 = Plaintext.read(in);
Plaintext p2 = Plaintext.read(MSG, in);
assertEquals(p1, p2);
}

View File

@ -72,7 +72,7 @@ public class TestUtils {
public static BitmessageAddress loadContact() throws IOException, DecryptionFailedException {
BitmessageAddress address = new BitmessageAddress("BM-2cXxfcSetKnbHJX2Y85rSkaVpsdNUZ5q9h");
ObjectMessage object = TestUtils.loadObjectMessage(4, "V4Pubkey.payload");
object.decrypt(address.getPubkeyDecryptionKey());
object.decrypt(address.getPublicDecryptionKey());
address.setPubkey((V4Pubkey) object.getPayload());
return address;
}