package org.briarproject.messaging; import static org.briarproject.api.AuthorConstants.MAX_AUTHOR_NAME_LENGTH; import static org.briarproject.api.AuthorConstants.MAX_PUBLIC_KEY_LENGTH; import static org.briarproject.api.AuthorConstants.MAX_SIGNATURE_LENGTH; import static org.briarproject.api.TransportPropertyConstants.MAX_PROPERTIES_PER_TRANSPORT; import static org.briarproject.api.TransportPropertyConstants.MAX_PROPERTY_LENGTH; import static org.briarproject.api.TransportPropertyConstants.MAX_TRANSPORT_ID_LENGTH; import static org.briarproject.api.messaging.MessagingConstants.MAX_BODY_LENGTH; import static org.briarproject.api.messaging.MessagingConstants.MAX_CONTENT_TYPE_LENGTH; import static org.briarproject.api.messaging.MessagingConstants.MAX_GROUP_NAME_LENGTH; import static org.briarproject.api.messaging.MessagingConstants.MAX_PACKET_LENGTH; import static org.briarproject.api.messaging.MessagingConstants.MAX_SUBSCRIPTIONS; import java.io.ByteArrayOutputStream; import java.util.ArrayList; import java.util.Collection; import java.util.Random; import org.briarproject.BriarTestCase; import org.briarproject.TestDatabaseModule; import org.briarproject.TestLifecycleModule; import org.briarproject.TestSystemModule; import org.briarproject.TestUtils; import org.briarproject.api.Author; import org.briarproject.api.AuthorFactory; import org.briarproject.api.TransportId; import org.briarproject.api.TransportProperties; import org.briarproject.api.UniqueId; import org.briarproject.api.crypto.CryptoComponent; import org.briarproject.api.crypto.KeyPair; import org.briarproject.api.crypto.PrivateKey; import org.briarproject.api.crypto.Signature; import org.briarproject.api.messaging.Ack; import org.briarproject.api.messaging.Group; import org.briarproject.api.messaging.GroupFactory; import org.briarproject.api.messaging.Message; import org.briarproject.api.messaging.MessageFactory; import org.briarproject.api.messaging.MessageId; import org.briarproject.api.messaging.Offer; import org.briarproject.api.messaging.PacketWriter; import org.briarproject.api.messaging.PacketWriterFactory; import org.briarproject.api.messaging.Request; import org.briarproject.api.messaging.SubscriptionUpdate; import org.briarproject.api.messaging.TransportUpdate; import org.briarproject.crypto.CryptoModule; import org.briarproject.db.DatabaseModule; import org.briarproject.event.EventModule; import org.briarproject.serial.SerialModule; import org.junit.Test; import com.google.inject.Guice; import com.google.inject.Injector; public class ConstantsTest extends BriarTestCase { private final CryptoComponent crypto; private final GroupFactory groupFactory; private final AuthorFactory authorFactory; private final MessageFactory messageFactory; private final PacketWriterFactory packetWriterFactory; public ConstantsTest() throws Exception { Injector i = Guice.createInjector(new TestDatabaseModule(), new TestLifecycleModule(), new TestSystemModule(), new CryptoModule(), new DatabaseModule(), new EventModule(), new MessagingModule(), new SerialModule()); crypto = i.getInstance(CryptoComponent.class); groupFactory = i.getInstance(GroupFactory.class); authorFactory = i.getInstance(AuthorFactory.class); messageFactory = i.getInstance(MessageFactory.class); packetWriterFactory = i.getInstance(PacketWriterFactory.class); } @Test public void testAgreementPublicKeys() throws Exception { // Generate 10 agreement key pairs for(int i = 0; i < 10; i++) { KeyPair keyPair = crypto.generateSignatureKeyPair(); // Check the length of the public key byte[] publicKey = keyPair.getPublic().getEncoded(); assertTrue(publicKey.length <= MAX_PUBLIC_KEY_LENGTH); } } @Test public void testSignaturePublicKeys() throws Exception { Random random = new Random(); Signature sig = crypto.getSignature(); // Generate 10 signature key pairs for(int i = 0; i < 10; i++) { KeyPair keyPair = crypto.generateSignatureKeyPair(); // Check the length of the public key byte[] publicKey = keyPair.getPublic().getEncoded(); assertTrue(publicKey.length <= MAX_PUBLIC_KEY_LENGTH); // Sign some random data and check the length of the signature byte[] toBeSigned = new byte[1234]; random.nextBytes(toBeSigned); sig.initSign(keyPair.getPrivate()); sig.update(toBeSigned); byte[] signature = sig.sign(); assertTrue("Length " + signature.length, signature.length <= MAX_SIGNATURE_LENGTH); } } @Test public void testMessageIdsFitIntoLargeAck() throws Exception { testMessageIdsFitIntoAck(MAX_PACKET_LENGTH); } @Test public void testMessageIdsFitIntoSmallAck() throws Exception { testMessageIdsFitIntoAck(1000); } @Test public void testMessageFitsIntoPacket() throws Exception { MessageId parent = new MessageId(TestUtils.getRandomId()); // Create a maximum-length group String groupName = TestUtils.createRandomString(MAX_GROUP_NAME_LENGTH); Group group = groupFactory.createGroup(groupName); // Create a maximum-length author String authorName = TestUtils.createRandomString(MAX_AUTHOR_NAME_LENGTH); byte[] authorPublic = new byte[MAX_PUBLIC_KEY_LENGTH]; Author author = authorFactory.createAuthor(authorName, authorPublic); // Create a maximum-length message PrivateKey privateKey = crypto.generateSignatureKeyPair().getPrivate(); String contentType = TestUtils.createRandomString(MAX_CONTENT_TYPE_LENGTH); long timestamp = Long.MAX_VALUE; byte[] body = new byte[MAX_BODY_LENGTH]; Message message = messageFactory.createPseudonymousMessage(parent, group, author, privateKey, contentType, timestamp, body); // Check the size of the serialised message int length = message.getSerialised().length; assertTrue(length > UniqueId.LENGTH + MAX_GROUP_NAME_LENGTH + MAX_PUBLIC_KEY_LENGTH + MAX_AUTHOR_NAME_LENGTH + MAX_PUBLIC_KEY_LENGTH + MAX_CONTENT_TYPE_LENGTH + MAX_BODY_LENGTH); assertTrue(length <= MAX_PACKET_LENGTH); } @Test public void testMessageIdsFitIntoLargeOffer() throws Exception { testMessageIdsFitIntoOffer(MAX_PACKET_LENGTH); } @Test public void testMessageIdsFitIntoSmallOffer() throws Exception { testMessageIdsFitIntoOffer(1000); } @Test public void testMessageIdsFitIntoLargeRequest() throws Exception { testMessageIdsFitIntoRequest(MAX_PACKET_LENGTH); } @Test public void testMessageIdsFitIntoSmallRequest() throws Exception { testMessageIdsFitIntoRequest(1000); } @Test public void testPropertiesFitIntoTransportUpdate() throws Exception { // Create the maximum number of properties with the maximum length TransportProperties p = new TransportProperties(); for(int i = 0; i < MAX_PROPERTIES_PER_TRANSPORT; i++) { String key = TestUtils.createRandomString(MAX_PROPERTY_LENGTH); String value = TestUtils.createRandomString(MAX_PROPERTY_LENGTH); p.put(key, value); } // Create a maximum-length transport update String idString = TestUtils.createRandomString(MAX_TRANSPORT_ID_LENGTH); TransportId id = new TransportId(idString); TransportUpdate u = new TransportUpdate(id, p, Long.MAX_VALUE); // Serialise the update ByteArrayOutputStream out = new ByteArrayOutputStream(); PacketWriter writer = packetWriterFactory.createPacketWriter(out); writer.writeTransportUpdate(u); // Check the size of the serialised transport update assertTrue(out.size() <= MAX_PACKET_LENGTH); } @Test public void testGroupsFitIntoSubscriptionUpdate() throws Exception { // Create the maximum number of maximum-length groups Collection<Group> groups = new ArrayList<Group>(); for(int i = 0; i < MAX_SUBSCRIPTIONS; i++) { String name = TestUtils.createRandomString(MAX_GROUP_NAME_LENGTH); groups.add(groupFactory.createGroup(name)); } // Create a maximum-length subscription update SubscriptionUpdate u = new SubscriptionUpdate(groups, Long.MAX_VALUE); // Serialise the update ByteArrayOutputStream out = new ByteArrayOutputStream(); PacketWriter writer = packetWriterFactory.createPacketWriter(out); writer.writeSubscriptionUpdate(u); // Check the size of the serialised subscription update assertTrue(out.size() <= MAX_PACKET_LENGTH); } private void testMessageIdsFitIntoAck(int length) throws Exception { // Create an ack with as many message IDs as possible ByteArrayOutputStream out = new ByteArrayOutputStream(length); PacketWriter writer = packetWriterFactory.createPacketWriter(out); int maxMessages = writer.getMaxMessagesForAck(length); Collection<MessageId> ids = new ArrayList<MessageId>(); for(int i = 0; i < maxMessages; i++) ids.add(new MessageId(TestUtils.getRandomId())); writer.writeAck(new Ack(ids)); // Check the size of the serialised ack assertTrue(out.size() <= length); } private void testMessageIdsFitIntoRequest(int length) throws Exception { // Create a request with as many message IDs as possible ByteArrayOutputStream out = new ByteArrayOutputStream(length); PacketWriter writer = packetWriterFactory.createPacketWriter(out); int maxMessages = writer.getMaxMessagesForRequest(length); Collection<MessageId> ids = new ArrayList<MessageId>(); for(int i = 0; i < maxMessages; i++) ids.add(new MessageId(TestUtils.getRandomId())); writer.writeRequest(new Request(ids)); // Check the size of the serialised request assertTrue(out.size() <= length); } private void testMessageIdsFitIntoOffer(int length) throws Exception { // Create an offer with as many message IDs as possible ByteArrayOutputStream out = new ByteArrayOutputStream(length); PacketWriter writer = packetWriterFactory.createPacketWriter(out); int maxMessages = writer.getMaxMessagesForOffer(length); Collection<MessageId> ids = new ArrayList<MessageId>(); for(int i = 0; i < maxMessages; i++) ids.add(new MessageId(TestUtils.getRandomId())); writer.writeOffer(new Offer(ids)); // Check the size of the serialised offer assertTrue(out.size() <= length); } }