diff --git a/api/net/sf/briar/api/protocol/Author.java b/api/net/sf/briar/api/protocol/Author.java new file mode 100644 index 000000000..48eb32c50 --- /dev/null +++ b/api/net/sf/briar/api/protocol/Author.java @@ -0,0 +1,12 @@ +package net.sf.briar.api.protocol; + +import net.sf.briar.api.serial.Writable; + +public interface Author extends Writable { + + AuthorId getId(); + + String getName(); + + byte[] getPublicKey(); +} diff --git a/api/net/sf/briar/api/protocol/AuthorFactory.java b/api/net/sf/briar/api/protocol/AuthorFactory.java new file mode 100644 index 000000000..24b211197 --- /dev/null +++ b/api/net/sf/briar/api/protocol/AuthorFactory.java @@ -0,0 +1,10 @@ +package net.sf.briar.api.protocol; + +import java.io.IOException; + +public interface AuthorFactory { + + Author createAuthor(String name, byte[] publicKey) throws IOException; + + Author createAuthor(AuthorId id, String name, byte[] publicKey); +} diff --git a/api/net/sf/briar/api/protocol/AuthorId.java b/api/net/sf/briar/api/protocol/AuthorId.java index e628511b6..a353f2766 100644 --- a/api/net/sf/briar/api/protocol/AuthorId.java +++ b/api/net/sf/briar/api/protocol/AuthorId.java @@ -8,6 +8,9 @@ import net.sf.briar.api.serial.Writer; /** Type-safe wrapper for a byte array that uniquely identifies an author. */ public class AuthorId extends UniqueId { + /** Used to indicate that a message is anonymous. */ + public static final AuthorId NONE = new AuthorId(new byte[UniqueId.LENGTH]); + public AuthorId(byte[] id) { super(id); } diff --git a/api/net/sf/briar/api/protocol/GroupFactory.java b/api/net/sf/briar/api/protocol/GroupFactory.java index cd6f711e5..e3b1a29ba 100644 --- a/api/net/sf/briar/api/protocol/GroupFactory.java +++ b/api/net/sf/briar/api/protocol/GroupFactory.java @@ -1,6 +1,10 @@ package net.sf.briar.api.protocol; +import java.io.IOException; + public interface GroupFactory { + Group createGroup(String name, byte[] publicKey) throws IOException; + Group createGroup(GroupId id, String name, byte[] publicKey); } diff --git a/api/net/sf/briar/api/protocol/MessageEncoder.java b/api/net/sf/briar/api/protocol/MessageEncoder.java index 95b26e1bf..7a2ff390d 100644 --- a/api/net/sf/briar/api/protocol/MessageEncoder.java +++ b/api/net/sf/briar/api/protocol/MessageEncoder.java @@ -2,11 +2,14 @@ package net.sf.briar.api.protocol; import java.io.IOException; import java.security.GeneralSecurityException; -import java.security.KeyPair; +import java.security.PrivateKey; public interface MessageEncoder { - Message encodeMessage(MessageId parent, GroupId group, String nick, - KeyPair keyPair, byte[] body) throws IOException, + Message encodeMessage(MessageId parent, Group group, byte[] body) + throws IOException; + + Message encodeMessage(MessageId parent, Group group, Author author, + PrivateKey privateKey, byte[] body) throws IOException, GeneralSecurityException; } diff --git a/api/net/sf/briar/api/protocol/MessageId.java b/api/net/sf/briar/api/protocol/MessageId.java index e3109ef08..10ba76d73 100644 --- a/api/net/sf/briar/api/protocol/MessageId.java +++ b/api/net/sf/briar/api/protocol/MessageId.java @@ -9,10 +9,8 @@ import net.sf.briar.api.serial.Writer; public class MessageId extends UniqueId { /** Used to indicate that the first message in a thread has no parent. */ - public static final MessageId NONE = new MessageId(new byte[] { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }); + public static final MessageId NONE = + new MessageId(new byte[UniqueId.LENGTH]); public MessageId(byte[] id) { super(id); diff --git a/api/net/sf/briar/api/protocol/Tags.java b/api/net/sf/briar/api/protocol/Tags.java index b8edfb5d0..59726ca5a 100644 --- a/api/net/sf/briar/api/protocol/Tags.java +++ b/api/net/sf/briar/api/protocol/Tags.java @@ -8,13 +8,14 @@ package net.sf.briar.api.protocol; public interface Tags { static final int ACK = 0; - static final int AUTHOR_ID = 1; - static final int BATCH = 2; - static final int BATCH_ID = 3; - static final int GROUP = 4; - static final int GROUP_ID = 5; - static final int MESSAGE = 6; - static final int MESSAGE_ID = 7; - static final int SUBSCRIPTIONS = 8; - static final int TRANSPORTS = 9; + static final int AUTHOR = 1; + static final int AUTHOR_ID = 2; + static final int BATCH = 3; + static final int BATCH_ID = 4; + static final int GROUP = 5; + static final int GROUP_ID = 6; + static final int MESSAGE = 7; + static final int MESSAGE_ID = 8; + static final int SUBSCRIPTIONS = 9; + static final int TRANSPORTS = 10; } diff --git a/components/net/sf/briar/protocol/AuthorFactoryImpl.java b/components/net/sf/briar/protocol/AuthorFactoryImpl.java new file mode 100644 index 000000000..f617e5fc8 --- /dev/null +++ b/components/net/sf/briar/protocol/AuthorFactoryImpl.java @@ -0,0 +1,42 @@ +package net.sf.briar.protocol; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.security.MessageDigest; + +import net.sf.briar.api.crypto.CryptoComponent; +import net.sf.briar.api.protocol.Author; +import net.sf.briar.api.protocol.AuthorFactory; +import net.sf.briar.api.protocol.AuthorId; +import net.sf.briar.api.serial.Writer; +import net.sf.briar.api.serial.WriterFactory; + +import com.google.inject.Inject; + +class AuthorFactoryImpl implements AuthorFactory { + + private final CryptoComponent crypto; + private final WriterFactory writerFactory; + + @Inject + AuthorFactoryImpl(CryptoComponent crypto, WriterFactory writerFactory) { + this.crypto = crypto; + this.writerFactory = writerFactory; + } + + public Author createAuthor(String name, byte[] publicKey) + throws IOException { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + Writer w = writerFactory.createWriter(out); + new AuthorImpl(null, name, publicKey).writeTo(w); + MessageDigest messageDigest = crypto.getMessageDigest(); + messageDigest.reset(); + messageDigest.update(out.toByteArray()); + AuthorId id = new AuthorId(messageDigest.digest()); + return new AuthorImpl(id, name, publicKey); + } + + public Author createAuthor(AuthorId id, String name, byte[] publicKey) { + return new AuthorImpl(id, name, publicKey); + } +} diff --git a/components/net/sf/briar/protocol/AuthorImpl.java b/components/net/sf/briar/protocol/AuthorImpl.java new file mode 100644 index 000000000..2bbc960d2 --- /dev/null +++ b/components/net/sf/briar/protocol/AuthorImpl.java @@ -0,0 +1,39 @@ +package net.sf.briar.protocol; + +import java.io.IOException; + +import net.sf.briar.api.protocol.Author; +import net.sf.briar.api.protocol.AuthorId; +import net.sf.briar.api.protocol.Tags; +import net.sf.briar.api.serial.Writer; + +class AuthorImpl implements Author { + + private final AuthorId id; + private final String name; + private final byte[] publicKey; + + AuthorImpl(AuthorId id, String name, byte[] publicKey) { + this.id = id; + this.name = name; + this.publicKey = publicKey; + } + + public AuthorId getId() { + return id; + } + + public String getName() { + return name; + } + + public byte[] getPublicKey() { + return publicKey; + } + + public void writeTo(Writer w) throws IOException { + w.writeUserDefinedTag(Tags.AUTHOR); + w.writeString(name); + w.writeBytes(publicKey); + } +} diff --git a/components/net/sf/briar/protocol/AuthorReader.java b/components/net/sf/briar/protocol/AuthorReader.java new file mode 100644 index 000000000..7988f0d59 --- /dev/null +++ b/components/net/sf/briar/protocol/AuthorReader.java @@ -0,0 +1,38 @@ +package net.sf.briar.protocol; + +import java.io.IOException; +import java.security.MessageDigest; + +import net.sf.briar.api.crypto.CryptoComponent; +import net.sf.briar.api.protocol.Author; +import net.sf.briar.api.protocol.AuthorFactory; +import net.sf.briar.api.protocol.AuthorId; +import net.sf.briar.api.protocol.Tags; +import net.sf.briar.api.serial.ObjectReader; +import net.sf.briar.api.serial.Reader; + +class AuthorReader implements ObjectReader { + + private final MessageDigest messageDigest; + private final AuthorFactory authorFactory; + + AuthorReader(CryptoComponent crypto, AuthorFactory authorFactory) { + messageDigest = crypto.getMessageDigest(); + this.authorFactory = authorFactory; + } + + public Author readObject(Reader r) throws IOException { + // Initialise the consumer + DigestingConsumer digesting = new DigestingConsumer(messageDigest); + messageDigest.reset(); + // Read and digest the data + r.addConsumer(digesting); + r.readUserDefinedTag(Tags.AUTHOR); + String name = r.readString(); + byte[] publicKey = r.readBytes(); + r.removeConsumer(digesting); + // Build and return the author + AuthorId id = new AuthorId(messageDigest.digest()); + return authorFactory.createAuthor(id, name, publicKey); + } +} diff --git a/components/net/sf/briar/protocol/BatchReader.java b/components/net/sf/briar/protocol/BatchReader.java index 3bbc04c79..4b467e030 100644 --- a/components/net/sf/briar/protocol/BatchReader.java +++ b/components/net/sf/briar/protocol/BatchReader.java @@ -4,6 +4,7 @@ import java.io.IOException; import java.security.MessageDigest; import java.util.List; +import net.sf.briar.api.crypto.CryptoComponent; import net.sf.briar.api.protocol.Batch; import net.sf.briar.api.protocol.BatchId; import net.sf.briar.api.protocol.Message; @@ -17,9 +18,9 @@ class BatchReader implements ObjectReader { private final ObjectReader messageReader; private final BatchFactory batchFactory; - BatchReader(MessageDigest messageDigest, - ObjectReader messageReader, BatchFactory batchFactory) { - this.messageDigest = messageDigest; + BatchReader(CryptoComponent crypto, ObjectReader messageReader, + BatchFactory batchFactory) { + messageDigest = crypto.getMessageDigest(); this.messageReader = messageReader; this.batchFactory = batchFactory; } diff --git a/components/net/sf/briar/protocol/GroupFactoryImpl.java b/components/net/sf/briar/protocol/GroupFactoryImpl.java index f1d85b7fa..a8411c091 100644 --- a/components/net/sf/briar/protocol/GroupFactoryImpl.java +++ b/components/net/sf/briar/protocol/GroupFactoryImpl.java @@ -1,11 +1,40 @@ package net.sf.briar.protocol; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.security.MessageDigest; + +import net.sf.briar.api.crypto.CryptoComponent; import net.sf.briar.api.protocol.Group; import net.sf.briar.api.protocol.GroupFactory; import net.sf.briar.api.protocol.GroupId; +import net.sf.briar.api.serial.Writer; +import net.sf.briar.api.serial.WriterFactory; + +import com.google.inject.Inject; class GroupFactoryImpl implements GroupFactory { + private final CryptoComponent crypto; + private final WriterFactory writerFactory; + + @Inject + GroupFactoryImpl(CryptoComponent crypto, WriterFactory writerFactory) { + this.crypto = crypto; + this.writerFactory = writerFactory; + } + + public Group createGroup(String name, byte[] publicKey) throws IOException { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + Writer w = writerFactory.createWriter(out); + new GroupImpl(null, name, publicKey).writeTo(w); + MessageDigest messageDigest = crypto.getMessageDigest(); + messageDigest.reset(); + messageDigest.update(out.toByteArray()); + GroupId id = new GroupId(messageDigest.digest()); + return new GroupImpl(id, name, publicKey); + } + public Group createGroup(GroupId id, String name, byte[] publicKey) { return new GroupImpl(id, name, publicKey); } diff --git a/components/net/sf/briar/protocol/GroupReader.java b/components/net/sf/briar/protocol/GroupReader.java index 61b4721ef..ceadff74b 100644 --- a/components/net/sf/briar/protocol/GroupReader.java +++ b/components/net/sf/briar/protocol/GroupReader.java @@ -3,6 +3,7 @@ package net.sf.briar.protocol; import java.io.IOException; import java.security.MessageDigest; +import net.sf.briar.api.crypto.CryptoComponent; import net.sf.briar.api.protocol.Group; import net.sf.briar.api.protocol.GroupFactory; import net.sf.briar.api.protocol.GroupId; @@ -15,8 +16,8 @@ class GroupReader implements ObjectReader { private final MessageDigest messageDigest; private final GroupFactory groupFactory; - GroupReader(MessageDigest messageDigest, GroupFactory groupFactory) { - this.messageDigest = messageDigest; + GroupReader(CryptoComponent crypto, GroupFactory groupFactory) { + messageDigest = crypto.getMessageDigest(); this.groupFactory = groupFactory; } diff --git a/components/net/sf/briar/protocol/MessageEncoderImpl.java b/components/net/sf/briar/protocol/MessageEncoderImpl.java index ef1107bae..458cf2a63 100644 --- a/components/net/sf/briar/protocol/MessageEncoderImpl.java +++ b/components/net/sf/briar/protocol/MessageEncoderImpl.java @@ -3,13 +3,14 @@ package net.sf.briar.protocol; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.security.GeneralSecurityException; -import java.security.KeyPair; import java.security.MessageDigest; +import java.security.PrivateKey; import java.security.Signature; import net.sf.briar.api.crypto.CryptoComponent; +import net.sf.briar.api.protocol.Author; import net.sf.briar.api.protocol.AuthorId; -import net.sf.briar.api.protocol.GroupId; +import net.sf.briar.api.protocol.Group; import net.sf.briar.api.protocol.Message; import net.sf.briar.api.protocol.MessageEncoder; import net.sf.briar.api.protocol.MessageId; @@ -32,8 +33,30 @@ class MessageEncoderImpl implements MessageEncoder { this.writerFactory = writerFactory; } - public Message encodeMessage(MessageId parent, GroupId group, String nick, - KeyPair keyPair, byte[] body) throws IOException, + public Message encodeMessage(MessageId parent, Group group, byte[] body) + throws IOException { + long timestamp = System.currentTimeMillis(); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + Writer w = writerFactory.createWriter(out); + // Write the message + w.writeUserDefinedTag(Tags.MESSAGE); + parent.writeTo(w); + group.writeTo(w); + w.writeNull(); // No author + w.writeInt64(timestamp); + w.writeBytes(body); + w.writeNull(); // No author's signature + byte[] raw = out.toByteArray(); + // The message ID is the hash of the entire message + messageDigest.reset(); + messageDigest.update(raw); + MessageId id = new MessageId(messageDigest.digest()); + return new MessageImpl(id, parent, group.getId(), AuthorId.NONE, + timestamp, raw); + } + + public Message encodeMessage(MessageId parent, Group group, Author author, + PrivateKey privateKey, byte[] body) throws IOException, GeneralSecurityException { long timestamp = System.currentTimeMillis(); ByteArrayOutputStream out = new ByteArrayOutputStream(); @@ -42,13 +65,12 @@ class MessageEncoderImpl implements MessageEncoder { w.writeUserDefinedTag(Tags.MESSAGE); parent.writeTo(w); group.writeTo(w); + author.writeTo(w); w.writeInt64(timestamp); - w.writeString(nick); - w.writeBytes(keyPair.getPublic().getEncoded()); w.writeBytes(body); // Sign the message byte[] signable = out.toByteArray(); - signature.initSign(keyPair.getPrivate()); + signature.initSign(privateKey); signature.update(signable); byte[] sig = signature.sign(); signable = null; @@ -59,14 +81,14 @@ class MessageEncoderImpl implements MessageEncoder { messageDigest.reset(); messageDigest.update(raw); MessageId id = new MessageId(messageDigest.digest()); - // The author ID is the hash of the author's nick and public key + // The author ID is the hash of the author object out.reset(); w = writerFactory.createWriter(out); - w.writeString(nick); - w.writeBytes(keyPair.getPublic().getEncoded()); + author.writeTo(w); messageDigest.reset(); messageDigest.update(out.toByteArray()); AuthorId authorId = new AuthorId(messageDigest.digest()); - return new MessageImpl(id, parent, group, authorId, timestamp, raw); + return new MessageImpl(id, parent, group.getId(), authorId, timestamp, + raw); } } diff --git a/components/net/sf/briar/protocol/MessageReader.java b/components/net/sf/briar/protocol/MessageReader.java index 0bb9f7f4a..8e3125533 100644 --- a/components/net/sf/briar/protocol/MessageReader.java +++ b/components/net/sf/briar/protocol/MessageReader.java @@ -6,11 +6,12 @@ import java.security.MessageDigest; import java.security.PublicKey; import java.security.Signature; import java.security.SignatureException; -import java.security.spec.InvalidKeySpecException; +import net.sf.briar.api.crypto.CryptoComponent; import net.sf.briar.api.crypto.KeyParser; +import net.sf.briar.api.protocol.Author; import net.sf.briar.api.protocol.AuthorId; -import net.sf.briar.api.protocol.GroupId; +import net.sf.briar.api.protocol.Group; import net.sf.briar.api.protocol.Message; import net.sf.briar.api.protocol.MessageId; import net.sf.briar.api.protocol.Tags; @@ -21,15 +22,19 @@ import net.sf.briar.api.serial.Reader; class MessageReader implements ObjectReader { + private final ObjectReader groupReader; + private final ObjectReader authorReader; private final KeyParser keyParser; private final Signature signature; private final MessageDigest messageDigest; - MessageReader(KeyParser keyParser, Signature signature, - MessageDigest messageDigest) { - this.keyParser = keyParser; - this.signature = signature; - this.messageDigest = messageDigest; + MessageReader(CryptoComponent crypto, ObjectReader groupReader, + ObjectReader authorReader) { + this.groupReader = groupReader; + this.authorReader = authorReader; + keyParser = crypto.getKeyParser(); + signature = crypto.getSignature(); + messageDigest = crypto.getMessageDigest(); } public Message readObject(Reader r) throws IOException { @@ -44,49 +49,49 @@ class MessageReader implements ObjectReader { byte[] b = r.readBytes(); if(b.length != UniqueId.LENGTH) throw new FormatException(); MessageId parent = new MessageId(b); - // Read the group ID - r.readUserDefinedTag(Tags.GROUP_ID); - b = r.readBytes(); - if(b.length != UniqueId.LENGTH) throw new FormatException(); - GroupId group = new GroupId(b); + // Read the group + r.addObjectReader(Tags.GROUP, groupReader); + Group group = r.readUserDefined(Tags.GROUP, Group.class); + r.removeObjectReader(Tags.GROUP); + // Read the author, if there is one + r.addObjectReader(Tags.AUTHOR, authorReader); + Author author = null; + if(r.hasNull()) r.readNull(); + else author = r.readUserDefined(Tags.AUTHOR, Author.class); + r.removeObjectReader(Tags.AUTHOR); // Read the timestamp long timestamp = r.readInt64(); if(timestamp < 0L) throw new FormatException(); - // Hash the author's nick and public key to get the author ID - DigestingConsumer digesting = new DigestingConsumer(messageDigest); - messageDigest.reset(); - r.addConsumer(digesting); - r.readString(); - byte[] encodedKey = r.readBytes(); - r.removeConsumer(digesting); - AuthorId author = new AuthorId(messageDigest.digest()); // Skip the message body r.readBytes(); // Record the length of the signed data int messageLength = (int) counting.getCount(); - // Read the signature - byte[] sig = r.readBytes(); + // Read the author's signature, if there is one + byte[] authorSig = null; + if(author == null) r.readNull(); + else authorSig = r.readBytes(); + // That's all, folks r.removeConsumer(counting); r.removeConsumer(copying); - // Verify the signature - PublicKey publicKey; - try { - publicKey = keyParser.parsePublicKey(encodedKey); - } catch(InvalidKeySpecException e) { - throw new FormatException(); - } byte[] raw = copying.getCopy(); - try { - signature.initVerify(publicKey); - signature.update(raw, 0, messageLength); - if(!signature.verify(sig)) throw new SignatureException(); - } catch(GeneralSecurityException e) { - throw new FormatException(); + // Verify the author's signature, if there is one + if(author != null) { + try { + PublicKey publicKey = + keyParser.parsePublicKey(author.getPublicKey()); + signature.initVerify(publicKey); + signature.update(raw, 0, messageLength); + if(!signature.verify(authorSig)) throw new SignatureException(); + } catch(GeneralSecurityException e) { + throw new FormatException(); + } } // Hash the message, including the signature, to get the message ID messageDigest.reset(); messageDigest.update(raw); MessageId id = new MessageId(messageDigest.digest()); - return new MessageImpl(id, parent, group, author, timestamp, raw); + AuthorId authorId = author == null ? AuthorId.NONE : author.getId(); + return new MessageImpl(id, parent, group.getId(), authorId, timestamp, + raw); } } diff --git a/components/net/sf/briar/protocol/ProtocolModule.java b/components/net/sf/briar/protocol/ProtocolModule.java index d7d2311c7..09c45dfb1 100644 --- a/components/net/sf/briar/protocol/ProtocolModule.java +++ b/components/net/sf/briar/protocol/ProtocolModule.java @@ -1,5 +1,6 @@ package net.sf.briar.protocol; +import net.sf.briar.api.protocol.AuthorFactory; import net.sf.briar.api.protocol.GroupFactory; import net.sf.briar.api.protocol.MessageEncoder; @@ -10,6 +11,7 @@ public class ProtocolModule extends AbstractModule { @Override protected void configure() { bind(AckFactory.class).to(AckFactoryImpl.class); + bind(AuthorFactory.class).to(AuthorFactoryImpl.class); bind(BatchFactory.class).to(BatchFactoryImpl.class); bind(GroupFactory.class).to(GroupFactoryImpl.class); bind(MessageEncoder.class).to(MessageEncoderImpl.class); diff --git a/test/net/sf/briar/protocol/BatchReaderTest.java b/test/net/sf/briar/protocol/BatchReaderTest.java index 54bb5042c..e1b6d4467 100644 --- a/test/net/sf/briar/protocol/BatchReaderTest.java +++ b/test/net/sf/briar/protocol/BatchReaderTest.java @@ -23,7 +23,6 @@ import net.sf.briar.serial.SerialModule; import org.jmock.Expectations; import org.jmock.Mockery; -import org.junit.Before; import org.junit.Test; import com.google.inject.Guice; @@ -33,7 +32,7 @@ public class BatchReaderTest extends TestCase { private final ReaderFactory readerFactory; private final WriterFactory writerFactory; - private final MessageDigest messageDigest; + private final CryptoComponent crypto; private final Mockery context; private final Message message; @@ -43,21 +42,16 @@ public class BatchReaderTest extends TestCase { new CryptoModule()); readerFactory = i.getInstance(ReaderFactory.class); writerFactory = i.getInstance(WriterFactory.class); - messageDigest = i.getInstance(CryptoComponent.class).getMessageDigest(); + crypto = i.getInstance(CryptoComponent.class); context = new Mockery(); message = context.mock(Message.class); } - @Before - public void setUp() { - messageDigest.reset(); - } - @Test public void testFormatExceptionIfBatchIsTooLarge() throws Exception { ObjectReader messageReader = new TestMessageReader(); BatchFactory batchFactory = context.mock(BatchFactory.class); - BatchReader batchReader = new BatchReader(messageDigest, messageReader, + BatchReader batchReader = new BatchReader(crypto, messageReader, batchFactory); byte[] b = createBatch(Batch.MAX_SIZE + 1); @@ -76,7 +70,7 @@ public class BatchReaderTest extends TestCase { public void testNoFormatExceptionIfBatchIsMaximumSize() throws Exception { ObjectReader messageReader = new TestMessageReader(); final BatchFactory batchFactory = context.mock(BatchFactory.class); - BatchReader batchReader = new BatchReader(messageDigest, messageReader, + BatchReader batchReader = new BatchReader(crypto, messageReader, batchFactory); final Batch batch = context.mock(Batch.class); context.checking(new Expectations() {{ @@ -98,13 +92,14 @@ public class BatchReaderTest extends TestCase { public void testBatchId() throws Exception { byte[] b = createBatch(Batch.MAX_SIZE); // Calculate the expected batch ID + MessageDigest messageDigest = crypto.getMessageDigest(); + messageDigest.reset(); messageDigest.update(b); final BatchId id = new BatchId(messageDigest.digest()); - messageDigest.reset(); ObjectReader messageReader = new TestMessageReader(); final BatchFactory batchFactory = context.mock(BatchFactory.class); - BatchReader batchReader = new BatchReader(messageDigest, messageReader, + BatchReader batchReader = new BatchReader(crypto, messageReader, batchFactory); final Batch batch = context.mock(Batch.class); context.checking(new Expectations() {{ @@ -126,7 +121,7 @@ public class BatchReaderTest extends TestCase { public void testEmptyBatch() throws Exception { ObjectReader messageReader = new TestMessageReader(); final BatchFactory batchFactory = context.mock(BatchFactory.class); - BatchReader batchReader = new BatchReader(messageDigest, messageReader, + BatchReader batchReader = new BatchReader(crypto, messageReader, batchFactory); final Batch batch = context.mock(Batch.class); context.checking(new Expectations() {{ diff --git a/test/net/sf/briar/protocol/FileReadWriteTest.java b/test/net/sf/briar/protocol/FileReadWriteTest.java index e06f1156f..92cdf83f1 100644 --- a/test/net/sf/briar/protocol/FileReadWriteTest.java +++ b/test/net/sf/briar/protocol/FileReadWriteTest.java @@ -1,12 +1,9 @@ package net.sf.briar.protocol; -import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.security.KeyPair; -import java.security.MessageDigest; -import java.security.Signature; import java.util.Arrays; import java.util.Collections; import java.util.Iterator; @@ -14,13 +11,13 @@ import java.util.Iterator; import junit.framework.TestCase; import net.sf.briar.TestUtils; import net.sf.briar.api.crypto.CryptoComponent; -import net.sf.briar.api.crypto.KeyParser; import net.sf.briar.api.protocol.Ack; +import net.sf.briar.api.protocol.Author; +import net.sf.briar.api.protocol.AuthorFactory; import net.sf.briar.api.protocol.Batch; import net.sf.briar.api.protocol.BatchId; import net.sf.briar.api.protocol.Group; import net.sf.briar.api.protocol.GroupFactory; -import net.sf.briar.api.protocol.GroupId; import net.sf.briar.api.protocol.Message; import net.sf.briar.api.protocol.MessageEncoder; import net.sf.briar.api.protocol.MessageId; @@ -33,16 +30,13 @@ import net.sf.briar.api.protocol.writers.BatchWriter; import net.sf.briar.api.protocol.writers.PacketWriterFactory; import net.sf.briar.api.protocol.writers.SubscriptionWriter; import net.sf.briar.api.protocol.writers.TransportWriter; -import net.sf.briar.api.serial.ObjectReader; import net.sf.briar.api.serial.Reader; import net.sf.briar.api.serial.ReaderFactory; -import net.sf.briar.api.serial.Writer; import net.sf.briar.api.serial.WriterFactory; import net.sf.briar.crypto.CryptoModule; import net.sf.briar.protocol.writers.WritersModule; import net.sf.briar.serial.SerialModule; -import org.apache.commons.io.output.ByteArrayOutputStream; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -56,19 +50,17 @@ public class FileReadWriteTest extends TestCase { private final File file = new File(testDir, "foo"); private final BatchId ack = new BatchId(TestUtils.getRandomId()); - private final GroupId sub = new GroupId(TestUtils.getRandomId()); - private final String nick = "Foo Bar"; + private final String authorName = "Foo Bar"; private final String messageBody = "This is the message body! Wooooooo!"; private final long start = System.currentTimeMillis(); private final ReaderFactory readerFactory; private final WriterFactory writerFactory; private final PacketWriterFactory packetWriterFactory; - private final Signature signature; - private final MessageDigest messageDigest, batchDigest; - private final KeyParser keyParser; - private final Message message; + private final CryptoComponent crypto; + private final Author author; private final Group group; + private final Message message; public FileReadWriteTest() throws Exception { super(); @@ -78,30 +70,21 @@ public class FileReadWriteTest extends TestCase { readerFactory = i.getInstance(ReaderFactory.class); writerFactory = i.getInstance(WriterFactory.class); packetWriterFactory = i.getInstance(PacketWriterFactory.class); - CryptoComponent crypto = i.getInstance(CryptoComponent.class); - keyParser = crypto.getKeyParser(); - signature = crypto.getSignature(); - messageDigest = crypto.getMessageDigest(); - batchDigest = crypto.getMessageDigest(); - assertEquals(messageDigest.getDigestLength(), UniqueId.LENGTH); - assertEquals(batchDigest.getDigestLength(), UniqueId.LENGTH); - // Create and encode a test message - MessageEncoder messageEncoder = i.getInstance(MessageEncoder.class); - KeyPair keyPair = crypto.generateKeyPair(); - message = messageEncoder.encodeMessage(MessageId.NONE, sub, nick, - keyPair, messageBody.getBytes("UTF-8")); - // Create a test group, then write and read it to calculate its ID + crypto = i.getInstance(CryptoComponent.class); + assertEquals(crypto.getMessageDigest().getDigestLength(), + UniqueId.LENGTH); + // Create a group GroupFactory groupFactory = i.getInstance(GroupFactory.class); - Group noId = groupFactory.createGroup( - new GroupId(new byte[UniqueId.LENGTH]), "Group name", null); - ByteArrayOutputStream out = new ByteArrayOutputStream(); - Writer w = writerFactory.createWriter(out); - noId.writeTo(w); - ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); - Reader r = readerFactory.createReader(in); - ObjectReader groupReader = new GroupReader(batchDigest, - groupFactory); - group = groupReader.readObject(r); + group = groupFactory.createGroup("Group name", null); + // Create an author + AuthorFactory authorFactory = i.getInstance(AuthorFactory.class); + KeyPair keyPair = crypto.generateKeyPair(); + author = authorFactory.createAuthor(authorName, + keyPair.getPublic().getEncoded()); + // Create and encode a test message, signed by the author + MessageEncoder messageEncoder = i.getInstance(MessageEncoder.class); + message = messageEncoder.encodeMessage(MessageId.NONE, group, author, + keyPair.getPrivate(), messageBody.getBytes("UTF-8")); } @Before @@ -138,17 +121,19 @@ public class FileReadWriteTest extends TestCase { testWriteFile(); - MessageReader messageReader = - new MessageReader(keyParser, signature, messageDigest); - ObjectReader ackReader = new AckReader(new BatchIdReader(), + GroupReader groupReader = new GroupReader(crypto, + new GroupFactoryImpl(crypto, writerFactory)); + AuthorReader authorReader = new AuthorReader(crypto, + new AuthorFactoryImpl(crypto, writerFactory)); + MessageReader messageReader = new MessageReader(crypto, groupReader, + authorReader); + AckReader ackReader = new AckReader(new BatchIdReader(), new AckFactoryImpl()); - ObjectReader batchReader = new BatchReader(batchDigest, - messageReader, new BatchFactoryImpl()); - ObjectReader groupReader = new GroupReader(batchDigest, - new GroupFactoryImpl()); - ObjectReader subscriptionReader = + BatchReader batchReader = new BatchReader(crypto, messageReader, + new BatchFactoryImpl()); + SubscriptionReader subscriptionReader = new SubscriptionReader(groupReader, new SubscriptionFactoryImpl()); - ObjectReader transportReader = + TransportReader transportReader = new TransportReader(new TransportFactoryImpl()); FileInputStream in = new FileInputStream(file);