diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/payload/Broadcast.java b/domain/src/main/java/ch/dissem/bitmessage/entity/payload/Broadcast.java index 9d16766..eb4890d 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/entity/payload/Broadcast.java +++ b/domain/src/main/java/ch/dissem/bitmessage/entity/payload/Broadcast.java @@ -16,30 +16,10 @@ package ch.dissem.bitmessage.entity.payload; -import java.io.IOException; -import java.io.OutputStream; - /** - * Created by chris on 07.04.15. + * Users who are subscribed to the sending address will see the message appear in their inbox. + * Broadcasts are version 4 or 5. */ -public class Broadcast implements ObjectPayload { - private long stream; - private byte[] tag; - private byte[] encrypted; - - public Broadcast(long stream, byte[] tag, byte[] encrypted) { - this.stream = stream; - this.tag = tag; - this.encrypted = encrypted; - } - - @Override - public long getStream() { - return stream; - } - - @Override - public void write(OutputStream stream) throws IOException { - - } +public interface Broadcast extends ObjectPayload { + byte[] getEncrypted(); } diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/payload/GenericPayload.java b/domain/src/main/java/ch/dissem/bitmessage/entity/payload/GenericPayload.java index 5742dee..f5957e3 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/entity/payload/GenericPayload.java +++ b/domain/src/main/java/ch/dissem/bitmessage/entity/payload/GenericPayload.java @@ -20,7 +20,8 @@ import java.io.IOException; import java.io.OutputStream; /** - * Created by chris on 24.03.15. + * In cases we don't know what to do with an object, we just store its bytes and send it again - we don't really + * have to know what it is. */ public class GenericPayload implements ObjectPayload { private long stream; diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/payload/GetPubkey.java b/domain/src/main/java/ch/dissem/bitmessage/entity/payload/GetPubkey.java index 132e573..13a390d 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/entity/payload/GetPubkey.java +++ b/domain/src/main/java/ch/dissem/bitmessage/entity/payload/GetPubkey.java @@ -20,7 +20,7 @@ import java.io.IOException; import java.io.OutputStream; /** - * Created by chris on 24.03.15. + * Request for a public key. */ public class GetPubkey implements ObjectPayload { private long stream; @@ -28,7 +28,7 @@ public class GetPubkey implements ObjectPayload { private byte[] tag; public GetPubkey(long stream, byte[] ripeOrTag) { - this.stream=stream; + this.stream = stream; switch (ripeOrTag.length) { case 20: ripe = ripeOrTag; @@ -37,7 +37,7 @@ public class GetPubkey implements ObjectPayload { tag = ripeOrTag; break; default: - throw new RuntimeException("ripe (20 bytes) or tag (32 bytes) expected, but pubkey was " + ripeOrTag.length + " bytes."); + throw new RuntimeException("ripe (20 bytes) or tag (32 bytes) expected, but pubkey was " + ripeOrTag.length + " bytes long."); } } diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/payload/Msg.java b/domain/src/main/java/ch/dissem/bitmessage/entity/payload/Msg.java index b93e618..391139a 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/entity/payload/Msg.java +++ b/domain/src/main/java/ch/dissem/bitmessage/entity/payload/Msg.java @@ -20,24 +20,37 @@ import java.io.IOException; import java.io.OutputStream; /** - * Created by chris on 07.04.15. + * Used for person-to-person messages. */ public class Msg implements ObjectPayload { private long stream; private byte[] encrypted; + private UnencryptedMessage unencrypted; public Msg(long stream, byte[] encrypted) { this.stream = stream; this.encrypted = encrypted; } + public Msg(UnencryptedMessage unencrypted) { + this.stream = unencrypted.getStream(); + this.unencrypted = unencrypted; + } + @Override public long getStream() { return stream; } + public byte[] getEncrypted() { + if (encrypted == null) { + // TODO + } + return encrypted; + } + @Override public void write(OutputStream stream) throws IOException { - stream.write(encrypted); + stream.write(getEncrypted()); } } diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/payload/Pubkey.java b/domain/src/main/java/ch/dissem/bitmessage/entity/payload/Pubkey.java index c36e1c7..80caf94 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/entity/payload/Pubkey.java +++ b/domain/src/main/java/ch/dissem/bitmessage/entity/payload/Pubkey.java @@ -17,7 +17,7 @@ package ch.dissem.bitmessage.entity.payload; /** - * Created by chris on 24.03.15. + * Public keys for signing and encryption, the answer to a 'getpubkey' request. */ public interface Pubkey extends ObjectPayload { long getVersion(); diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/payload/UnencryptedMessage.java b/domain/src/main/java/ch/dissem/bitmessage/entity/payload/UnencryptedMessage.java new file mode 100644 index 0000000..3abd04f --- /dev/null +++ b/domain/src/main/java/ch/dissem/bitmessage/entity/payload/UnencryptedMessage.java @@ -0,0 +1,142 @@ +/* + * 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.payload; + +import ch.dissem.bitmessage.entity.Streamable; +import ch.dissem.bitmessage.utils.Encode; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * The unencrypted message to be sent by 'msg' or 'broadcast'. + */ +public class UnencryptedMessage implements Streamable { + private final long addressVersion; + private final long stream; + private final int behaviorBitfield; + private final byte[] publicSigningKey; + private final byte[] publicEncryptionKey; + private final long nonceTrialsPerByte; + private final long extraBytes; + private final long encoding; + private final byte[] message; + private final byte[] signature; + + public long getStream() { + return stream; + } + + private UnencryptedMessage(Builder builder) { + addressVersion = builder.addressVersion; + stream = builder.stream; + behaviorBitfield = builder.behaviorBitfield; + publicSigningKey = builder.publicSigningKey; + publicEncryptionKey = builder.publicEncryptionKey; + nonceTrialsPerByte = builder.nonceTrialsPerByte; + extraBytes = builder.extraBytes; + encoding = builder.encoding; + message = builder.message; + signature = builder.signature; + } + + @Override + public void write(OutputStream os) throws IOException { + Encode.varInt(addressVersion, os); + Encode.varInt(stream, os); + Encode.int32(behaviorBitfield, os); + os.write(publicSigningKey); + os.write(publicEncryptionKey); + Encode.varInt(nonceTrialsPerByte, os); + Encode.varInt(extraBytes, os); + Encode.varInt(encoding, os); + Encode.varInt(message.length, os); + os.write(message); + Encode.varInt(signature.length, os); + os.write(signature); + } + + public static final class Builder { + private long addressVersion; + private long stream; + private int behaviorBitfield; + private byte[] publicSigningKey; + private byte[] publicEncryptionKey; + private long nonceTrialsPerByte; + private long extraBytes; + private long encoding; + private byte[] message; + private byte[] signature; + + public Builder() { + } + + public Builder addressVersion(long addressVersion) { + this.addressVersion = addressVersion; + return this; + } + + public Builder stream(long stream) { + this.stream = stream; + return this; + } + + public Builder behaviorBitfield(int behaviorBitfield) { + this.behaviorBitfield = behaviorBitfield; + return this; + } + + public Builder publicSigningKey(byte[] publicSigningKey) { + this.publicSigningKey = publicSigningKey; + return this; + } + + public Builder publicEncryptionKey(byte[] publicEncryptionKey) { + this.publicEncryptionKey = publicEncryptionKey; + return this; + } + + public Builder nonceTrialsPerByte(long nonceTrialsPerByte) { + this.nonceTrialsPerByte = nonceTrialsPerByte; + return this; + } + + public Builder extraBytes(long extraBytes) { + this.extraBytes = extraBytes; + return this; + } + + public Builder encoding(long encoding) { + this.encoding = encoding; + return this; + } + + public Builder message(byte[] message) { + this.message = message; + return this; + } + + public Builder signature(byte[] signature) { + this.signature = signature; + return this; + } + + public UnencryptedMessage build() { + return new UnencryptedMessage(this); + } + } +} diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/payload/V2Pubkey.java b/domain/src/main/java/ch/dissem/bitmessage/entity/payload/V2Pubkey.java index 1f77af3..8cc242a 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/entity/payload/V2Pubkey.java +++ b/domain/src/main/java/ch/dissem/bitmessage/entity/payload/V2Pubkey.java @@ -22,11 +22,11 @@ import java.io.IOException; import java.io.OutputStream; /** - * Created by chris on 24.03.15. + * A version 2 public key. */ public class V2Pubkey implements Pubkey { protected long stream; - protected long behaviorBitfield; + protected int behaviorBitfield; protected byte[] publicSigningKey; protected byte[] publicEncryptionKey; @@ -61,15 +61,15 @@ public class V2Pubkey implements Pubkey { } @Override - public void write(OutputStream stream) throws IOException { - Encode.int32(behaviorBitfield, stream); - stream.write(publicSigningKey); - stream.write(publicEncryptionKey); + public void write(OutputStream os) throws IOException { + Encode.int32(behaviorBitfield, os); + os.write(publicSigningKey); + os.write(publicEncryptionKey); } public static class Builder { private long streamNumber; - private long behaviorBitfield; + private int behaviorBitfield; private byte[] publicSigningKey; private byte[] publicEncryptionKey; @@ -81,7 +81,7 @@ public class V2Pubkey implements Pubkey { return this; } - public Builder behaviorBitfield(long behaviorBitfield) { + public Builder behaviorBitfield(int behaviorBitfield) { this.behaviorBitfield = behaviorBitfield; return this; } diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/payload/V3Pubkey.java b/domain/src/main/java/ch/dissem/bitmessage/entity/payload/V3Pubkey.java index 081063d..4b1f5f1 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/entity/payload/V3Pubkey.java +++ b/domain/src/main/java/ch/dissem/bitmessage/entity/payload/V3Pubkey.java @@ -22,7 +22,7 @@ import java.io.IOException; import java.io.OutputStream; /** - * Created by chris on 27.03.15. + * A version 3 public key. */ public class V3Pubkey extends V2Pubkey { long nonceTrialsPerByte; @@ -41,12 +41,12 @@ public class V3Pubkey extends V2Pubkey { } @Override - public void write(OutputStream stream) throws IOException { - super.write(stream); - Encode.varInt(nonceTrialsPerByte, stream); - Encode.varInt(extraBytes, stream); - Encode.varInt(signature.length, stream); - stream.write(signature); + public void write(OutputStream os) throws IOException { + super.write(os); + Encode.varInt(nonceTrialsPerByte, os); + Encode.varInt(extraBytes, os); + Encode.varInt(signature.length, os); + os.write(signature); } @Override @@ -56,7 +56,7 @@ public class V3Pubkey extends V2Pubkey { public static class Builder extends V2Pubkey.Builder { private long streamNumber; - private long behaviorBitfield; + private int behaviorBitfield; private byte[] publicSigningKey; private byte[] publicEncryptionKey; @@ -72,7 +72,7 @@ public class V3Pubkey extends V2Pubkey { return this; } - public Builder behaviorBitfield(long behaviorBitfield) { + public Builder behaviorBitfield(int behaviorBitfield) { this.behaviorBitfield = behaviorBitfield; return this; } diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/payload/V4Broadcast.java b/domain/src/main/java/ch/dissem/bitmessage/entity/payload/V4Broadcast.java new file mode 100644 index 0000000..a5f4b32 --- /dev/null +++ b/domain/src/main/java/ch/dissem/bitmessage/entity/payload/V4Broadcast.java @@ -0,0 +1,49 @@ +/* + * 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.payload; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * Users who are subscribed to the sending address will see the message appear in their inbox. + * Broadcasts are version 4 or 5. + */ +public class V4Broadcast implements Broadcast { + private long stream; + private byte[] encrypted; + private UnencryptedMessage unencrypted; + + public V4Broadcast(long stream, byte[] encrypted) { + this.stream = stream; + this.encrypted = encrypted; + } + + @Override + public long getStream() { + return stream; + } + + public byte[] getEncrypted() { + return encrypted; + } + + @Override + public void write(OutputStream stream) throws IOException { + stream.write(getEncrypted()); + } +} diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/payload/V4Pubkey.java b/domain/src/main/java/ch/dissem/bitmessage/entity/payload/V4Pubkey.java index 2737744..96a0e2b 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/entity/payload/V4Pubkey.java +++ b/domain/src/main/java/ch/dissem/bitmessage/entity/payload/V4Pubkey.java @@ -20,7 +20,10 @@ import java.io.IOException; import java.io.OutputStream; /** - * Created by chris on 27.03.15. + * A version 4 public key. When version 4 pubkeys are created, most of the data in the pubkey is encrypted. This is + * done in such a way that only someone who has the Bitmessage address which corresponds to a pubkey can decrypt and + * use that pubkey. This prevents people from gathering pubkeys sent around the network and using the data from them + * to create messages to be used in spam or in flooding attacks. */ public class V4Pubkey implements Pubkey { private long stream; @@ -38,7 +41,7 @@ public class V4Pubkey implements Pubkey { this.stream = decrypted.stream; // TODO: this.tag = new BitmessageAddress(this).doubleHash this.decrypted = decrypted; - + // TODO: this.encrypted } @Override @@ -57,6 +60,10 @@ public class V4Pubkey implements Pubkey { return stream; } + public byte[] getTag() { + return tag; + } + @Override public byte[] getSigningKey() { return decrypted.getSigningKey(); diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/payload/V5Broadcast.java b/domain/src/main/java/ch/dissem/bitmessage/entity/payload/V5Broadcast.java new file mode 100644 index 0000000..f758f72 --- /dev/null +++ b/domain/src/main/java/ch/dissem/bitmessage/entity/payload/V5Broadcast.java @@ -0,0 +1,42 @@ +/* + * 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.payload; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * Users who are subscribed to the sending address will see the message appear in their inbox. + */ +public class V5Broadcast extends V4Broadcast { + private byte[] tag; + + public V5Broadcast(long stream, byte[] tag, byte[] encrypted) { + super(stream, encrypted); + this.tag = tag; + } + + public byte[] getTag() { + return tag; + } + + @Override + public void write(OutputStream stream) throws IOException { + stream.write(tag); + super.write(stream); + } +} diff --git a/domain/src/main/java/ch/dissem/bitmessage/factory/Factory.java b/domain/src/main/java/ch/dissem/bitmessage/factory/Factory.java index 4bdde80..2d7379b 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/factory/Factory.java +++ b/domain/src/main/java/ch/dissem/bitmessage/factory/Factory.java @@ -39,7 +39,7 @@ public class Factory { if (objectType < 4) { switch ((int) objectType) { case 0: // getpubkey - return new GetPubkey(streamNumber, Decode.bytes(stream, length)); + return parseGetPubkey((int) version, streamNumber, stream, length); case 1: // pubkey return parsePubkey((int) version, streamNumber, stream, length); case 2: // msg @@ -54,6 +54,10 @@ public class Factory { return new GenericPayload(streamNumber, Decode.bytes(stream, length)); } + private static ObjectPayload parseGetPubkey(int version, long streamNumber, InputStream stream, int length) throws IOException { + return new GetPubkey(streamNumber, Decode.bytes(stream, length)); + } + private static ObjectPayload parsePubkey(int version, long streamNumber, InputStream stream, int length) throws IOException { switch (version) { case 2: @@ -75,7 +79,7 @@ public class Factory { v3.signature(Decode.bytes(stream, sigLength)); return v3.build(); case 4: - // TODO + return new V4Pubkey(streamNumber, Decode.bytes(stream, 32), Decode.bytes(stream, length - 32)); } LOG.debug("Unexpected pubkey version " + version + ", handling as generic payload object"); return new GenericPayload(streamNumber, Decode.bytes(stream, length)); @@ -86,6 +90,14 @@ public class Factory { } private static ObjectPayload parseBroadcast(int version, long streamNumber, InputStream stream, int length) throws IOException { - return new Broadcast(streamNumber, Decode.bytes(stream, 32), Decode.bytes(stream, length - 32)); + switch (version) { + case 4: + return new V4Broadcast(streamNumber, Decode.bytes(stream, length)); + case 5: + return new V5Broadcast(streamNumber, Decode.bytes(stream, 32), Decode.bytes(stream, length - 32)); + default: + LOG.debug("Encountered unknown broadcast version " + version); + return new GenericPayload(streamNumber, Decode.bytes(stream, length)); + } } }