diff --git a/briar-api/src/net/sf/briar/api/protocol/Group.java b/briar-api/src/net/sf/briar/api/protocol/Group.java
index cc1f6ccf07a313240adc2c5ad4ffd43573d2f7df..2887c8478ac870af952f52bcbfac707a6ef273a2 100644
--- a/briar-api/src/net/sf/briar/api/protocol/Group.java
+++ b/briar-api/src/net/sf/briar/api/protocol/Group.java
@@ -1,17 +1,43 @@
 package net.sf.briar.api.protocol;
 
 /** A group to which users may subscribe. */
-public interface Group {
+public class Group {
+
+	private final GroupId id;
+	private final String name;
+	private final byte[] publicKey;
+
+	public Group(GroupId id, String name, byte[] publicKey) {
+		this.id = id;
+		this.name = name;
+		this.publicKey = publicKey;
+	}
 
 	/** Returns the group's unique identifier. */
-	GroupId getId();
+	public GroupId getId() {
+		return id;
+	}
 
 	/** Returns the group's name. */
-	String getName();
+	public String getName() {
+		return name;
+	}
 
 	/**
 	 * If the group is restricted, returns the public key that is used to
 	 * authorise all messages sent to the group. Otherwise returns null.
 	 */
-	byte[] getPublicKey();
+	public byte[] getPublicKey() {
+		return publicKey;
+	}
+
+	@Override
+	public int hashCode() {
+		return id.hashCode();
+	}
+
+	@Override
+	public boolean equals(Object o) {
+		return o instanceof Group && id.equals(((Group) o).id);
+	}
 }
diff --git a/briar-api/src/net/sf/briar/api/protocol/GroupFactory.java b/briar-api/src/net/sf/briar/api/protocol/GroupFactory.java
index e3b1a29ba86fc226a6dd85c21e36f0f113d2bf9a..b1db22d6dbb1eb39b276a5ed0f44dc1f883bd332 100644
--- a/briar-api/src/net/sf/briar/api/protocol/GroupFactory.java
+++ b/briar-api/src/net/sf/briar/api/protocol/GroupFactory.java
@@ -5,6 +5,4 @@ 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/briar-core/src/net/sf/briar/db/DatabaseModule.java b/briar-core/src/net/sf/briar/db/DatabaseModule.java
index 0d36cd348c0b6deb23d566e1b78ac61f65b84fef..6ed65d9b8d1f01422014908aa49e708b4211d15c 100644
--- a/briar-core/src/net/sf/briar/db/DatabaseModule.java
+++ b/briar-core/src/net/sf/briar/db/DatabaseModule.java
@@ -8,7 +8,6 @@ import net.sf.briar.api.db.DatabaseComponent;
 import net.sf.briar.api.db.DatabaseConfig;
 import net.sf.briar.api.db.DatabaseExecutor;
 import net.sf.briar.api.lifecycle.ShutdownManager;
-import net.sf.briar.api.protocol.GroupFactory;
 import net.sf.briar.api.protocol.PacketFactory;
 import net.sf.briar.util.BoundedExecutor;
 
@@ -42,9 +41,8 @@ public class DatabaseModule extends AbstractModule {
 	}
 
 	@Provides
-	Database<Connection> getDatabase(DatabaseConfig config,
-			GroupFactory groupFactory, Clock clock) {
-		return new H2Database(config, groupFactory, clock);
+	Database<Connection> getDatabase(Clock clock, DatabaseConfig config) {
+		return new H2Database(clock, config);
 	}
 
 	@Provides @Singleton
diff --git a/briar-core/src/net/sf/briar/db/H2Database.java b/briar-core/src/net/sf/briar/db/H2Database.java
index ed6fdaa75caa7e3d70c81d260c166c681a840950..4c00ec8c22e5637f9a8fca78fd4546a88018ccf9 100644
--- a/briar-core/src/net/sf/briar/db/H2Database.java
+++ b/briar-core/src/net/sf/briar/db/H2Database.java
@@ -12,7 +12,6 @@ import net.sf.briar.api.clock.Clock;
 import net.sf.briar.api.crypto.Password;
 import net.sf.briar.api.db.DatabaseConfig;
 import net.sf.briar.api.db.DbException;
-import net.sf.briar.api.protocol.GroupFactory;
 import net.sf.briar.util.FileUtils;
 
 import com.google.inject.Inject;
@@ -31,9 +30,8 @@ class H2Database extends JdbcDatabase {
 	private final long maxSize;
 
 	@Inject
-	H2Database(DatabaseConfig config, GroupFactory groupFactory, Clock clock) {
-		super(groupFactory, clock, HASH_TYPE, BINARY_TYPE, COUNTER_TYPE,
-				SECRET_TYPE);
+	H2Database(Clock clock, DatabaseConfig config) {
+		super(clock, HASH_TYPE, BINARY_TYPE, COUNTER_TYPE, SECRET_TYPE);
 		home = new File(config.getDataDirectory(), "db");
 		url = "jdbc:h2:split:" + home.getPath()
 				+ ";CIPHER=AES;DB_CLOSE_ON_EXIT=false";
diff --git a/briar-core/src/net/sf/briar/db/JdbcDatabase.java b/briar-core/src/net/sf/briar/db/JdbcDatabase.java
index f44accc83a35922a20d4fca113c173884ed4881e..15d89cd6660ed9d843e61d14d8ce3d1cbfa55e8b 100644
--- a/briar-core/src/net/sf/briar/db/JdbcDatabase.java
+++ b/briar-core/src/net/sf/briar/db/JdbcDatabase.java
@@ -35,7 +35,6 @@ import net.sf.briar.api.db.MessageHeader;
 import net.sf.briar.api.protocol.AuthorId;
 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.MessageId;
@@ -262,8 +261,6 @@ abstract class JdbcDatabase implements Database<Connection> {
 	private static final Logger LOG =
 			Logger.getLogger(JdbcDatabase.class.getName());
 
-	// FIXME: Can this factory be done away with?
-	private final GroupFactory groupFactory;
 	private final Clock clock;
 	// Different database libraries use different names for certain types
 	private final String hashType, binaryType, counterType, secretType;
@@ -276,9 +273,8 @@ abstract class JdbcDatabase implements Database<Connection> {
 
 	protected abstract Connection createConnection() throws SQLException;
 
-	JdbcDatabase(GroupFactory groupFactory, Clock clock, String hashType,
-			String binaryType, String counterType, String secretType) {
-		this.groupFactory = groupFactory;
+	JdbcDatabase(Clock clock, String hashType, String binaryType,
+			String counterType, String secretType) {
 		this.clock = clock;
 		this.hashType = hashType;
 		this.binaryType = binaryType;
@@ -1772,7 +1768,7 @@ abstract class JdbcDatabase implements Database<Connection> {
 				GroupId id = new GroupId(rs.getBytes(1));
 				String name = rs.getString(2);
 				byte[] publicKey = rs.getBytes(3);
-				subs.add(groupFactory.createGroup(id, name, publicKey));
+				subs.add(new Group(id, name, publicKey));
 			}
 			rs.close();
 			ps.close();
@@ -1800,7 +1796,7 @@ abstract class JdbcDatabase implements Database<Connection> {
 				GroupId id = new GroupId(rs.getBytes(1));
 				String name = rs.getString(2);
 				byte[] publicKey = rs.getBytes(3);
-				subs.add(groupFactory.createGroup(id, name, publicKey));
+				subs.add(new Group(id, name, publicKey));
 			}
 			rs.close();
 			ps.close();
@@ -1962,7 +1958,7 @@ abstract class JdbcDatabase implements Database<Connection> {
 				byte[] publicKey = rs.getBytes(3);
 				long start = rs.getLong(4);
 				if(subs == null) subs = new HashMap<Group, Long>();
-				subs.put(groupFactory.createGroup(id, name, publicKey), start);
+				subs.put(new Group(id, name, publicKey), start);
 			}
 			rs.close();
 			ps.close();
diff --git a/briar-core/src/net/sf/briar/protocol/GroupFactoryImpl.java b/briar-core/src/net/sf/briar/protocol/GroupFactoryImpl.java
index ccd719bd7066b1dc43792e22df858631978a9800..7702e2aba77042a90620bf7c193ad23adf44b3ea 100644
--- a/briar-core/src/net/sf/briar/protocol/GroupFactoryImpl.java
+++ b/briar-core/src/net/sf/briar/protocol/GroupFactoryImpl.java
@@ -35,10 +35,6 @@ class GroupFactoryImpl implements GroupFactory {
 		MessageDigest messageDigest = crypto.getMessageDigest();
 		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);
+		return new Group(id, name, publicKey);
 	}
 }
diff --git a/briar-core/src/net/sf/briar/protocol/GroupImpl.java b/briar-core/src/net/sf/briar/protocol/GroupImpl.java
deleted file mode 100644
index d3a84ba5ac8df3eae511d476736dfbc76a5459bb..0000000000000000000000000000000000000000
--- a/briar-core/src/net/sf/briar/protocol/GroupImpl.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package net.sf.briar.protocol;
-
-import net.sf.briar.api.protocol.Group;
-import net.sf.briar.api.protocol.GroupId;
-
-class GroupImpl implements Group {
-
-	private final GroupId id;
-	private final String name;
-	private final byte[] publicKey;
-
-	GroupImpl(GroupId id, String name, byte[] publicKey) {
-		this.id = id;
-		this.name = name;
-		this.publicKey = publicKey;
-	}
-
-	public GroupId getId() {
-		return id;
-	}
-
-	public String getName() {
-		return name;
-	}
-
-	public byte[] getPublicKey() {
-		return publicKey;
-	}
-
-	@Override
-	public int hashCode() {
-		return id.hashCode();
-	}
-
-	@Override
-	public boolean equals(Object o) {
-		return o instanceof Group && id.equals(((Group) o).getId());
-	}
-}
diff --git a/briar-core/src/net/sf/briar/protocol/GroupReader.java b/briar-core/src/net/sf/briar/protocol/GroupReader.java
index 7e58b92c27d84a8f97bec359e9ee9cae1096022c..0317e177ed4e607e8fe5211608715be5599c330d 100644
--- a/briar-core/src/net/sf/briar/protocol/GroupReader.java
+++ b/briar-core/src/net/sf/briar/protocol/GroupReader.java
@@ -8,7 +8,6 @@ import java.io.IOException;
 import net.sf.briar.api.crypto.CryptoComponent;
 import net.sf.briar.api.crypto.MessageDigest;
 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.Types;
 import net.sf.briar.api.serial.DigestingConsumer;
@@ -18,11 +17,9 @@ import net.sf.briar.api.serial.StructReader;
 class GroupReader implements StructReader<Group> {
 
 	private final MessageDigest messageDigest;
-	private final GroupFactory groupFactory;
 
-	GroupReader(CryptoComponent crypto, GroupFactory groupFactory) {
+	GroupReader(CryptoComponent crypto) {
 		messageDigest = crypto.getMessageDigest();
-		this.groupFactory = groupFactory;
 	}
 
 	public Group readStruct(Reader r) throws IOException {
@@ -38,6 +35,6 @@ class GroupReader implements StructReader<Group> {
 		r.removeConsumer(digesting);
 		// Build and return the group
 		GroupId id = new GroupId(messageDigest.digest());
-		return groupFactory.createGroup(id, name, publicKey);
+		return new Group(id, name, publicKey);
 	}
 }
diff --git a/briar-core/src/net/sf/briar/protocol/ProtocolModule.java b/briar-core/src/net/sf/briar/protocol/ProtocolModule.java
index 6b35262237942a281764028d219411627cccb878..49b0bd55bccb28dee14f5d24176a8dc035c18069 100644
--- a/briar-core/src/net/sf/briar/protocol/ProtocolModule.java
+++ b/briar-core/src/net/sf/briar/protocol/ProtocolModule.java
@@ -39,7 +39,7 @@ public class ProtocolModule extends AbstractModule {
 
 	/** The maximum number of verification threads. */
 	private static final int MAX_VERIFIER_THREADS =
-		Runtime.getRuntime().availableProcessors();
+			Runtime.getRuntime().availableProcessors();
 
 	@Override
 	protected void configure() {
@@ -76,9 +76,8 @@ public class ProtocolModule extends AbstractModule {
 	}
 
 	@Provides
-	StructReader<Group> getGroupReader(CryptoComponent crypto,
-			GroupFactory groupFactory) {
-		return new GroupReader(crypto, groupFactory);
+	StructReader<Group> getGroupReader(CryptoComponent crypto) {
+		return new GroupReader(crypto);
 	}
 
 	@Provides
diff --git a/briar-tests/src/net/sf/briar/db/DatabaseComponentTest.java b/briar-tests/src/net/sf/briar/db/DatabaseComponentTest.java
index 73a4545dfde556f8858c778506420c38130803ca..aa598ac70226f46cfb2118f6c373aff763f4f984 100644
--- a/briar-tests/src/net/sf/briar/db/DatabaseComponentTest.java
+++ b/briar-tests/src/net/sf/briar/db/DatabaseComponentTest.java
@@ -79,7 +79,7 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
 				timestamp, raw);
 		privateMessage = new TestMessage(messageId, null, null, null, subject,
 				timestamp, raw);
-		group = new TestGroup(groupId, "The really exciting group", null);
+		group = new Group(groupId, "The really exciting group", null);
 		transportId = new TransportId(TestUtils.getRandomId());
 		TransportProperties properties = new TransportProperties(
 				Collections.singletonMap("foo", "bar"));
@@ -104,7 +104,6 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
 		final DatabaseCleaner cleaner = context.mock(DatabaseCleaner.class);
 		final ShutdownManager shutdown = context.mock(ShutdownManager.class);
 		final PacketFactory packetFactory = context.mock(PacketFactory.class);
-		final Group group = context.mock(Group.class);
 		final DatabaseListener listener = context.mock(DatabaseListener.class);
 		context.checking(new Expectations() {{
 			allowing(database).startTransaction();
@@ -140,14 +139,10 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
 			oneOf(database).getRemoteProperties(txn, transportId);
 			will(returnValue(Collections.emptyMap()));
 			// subscribe(group)
-			oneOf(group).getId();
-			will(returnValue(groupId));
 			oneOf(database).containsSubscription(txn, groupId);
 			will(returnValue(false));
 			oneOf(database).addSubscription(txn, group);
 			// subscribe(group) again
-			oneOf(group).getId();
-			will(returnValue(groupId));
 			oneOf(database).containsSubscription(txn, groupId);
 			will(returnValue(true));
 			// getMessageHeaders(groupId)
diff --git a/briar-tests/src/net/sf/briar/db/H2DatabaseTest.java b/briar-tests/src/net/sf/briar/db/H2DatabaseTest.java
index 842caa434eded9133a4434b48470bf7c494c9d5e..e1a6ec5ca9383ef269ce8579535e1321dea94cac 100644
--- a/briar-tests/src/net/sf/briar/db/H2DatabaseTest.java
+++ b/briar-tests/src/net/sf/briar/db/H2DatabaseTest.java
@@ -31,7 +31,6 @@ import net.sf.briar.api.db.MessageHeader;
 import net.sf.briar.api.protocol.AuthorId;
 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.MessageId;
@@ -52,7 +51,6 @@ public class H2DatabaseTest extends BriarTestCase {
 
 	private final File testDir = TestUtils.getTestDirectory();
 	private final Random random = new Random();
-	private final GroupFactory groupFactory;
 	private final Group group;
 	private final AuthorId authorId;
 	private final BatchId batchId;
@@ -68,14 +66,13 @@ public class H2DatabaseTest extends BriarTestCase {
 
 	public H2DatabaseTest() throws Exception {
 		super();
-		groupFactory = new TestGroupFactory();
 		authorId = new AuthorId(TestUtils.getRandomId());
 		batchId = new BatchId(TestUtils.getRandomId());
 		contactId = new ContactId(1);
 		groupId = new GroupId(TestUtils.getRandomId());
 		messageId = new MessageId(TestUtils.getRandomId());
 		privateMessageId = new MessageId(TestUtils.getRandomId());
-		group = new TestGroup(groupId, "Foo", null);
+		group = new Group(groupId, "Foo", null);
 		subject = "Foo";
 		timestamp = System.currentTimeMillis();
 		size = 1234;
@@ -798,7 +795,7 @@ public class H2DatabaseTest extends BriarTestCase {
 		MessageId childId2 = new MessageId(TestUtils.getRandomId());
 		MessageId childId3 = new MessageId(TestUtils.getRandomId());
 		GroupId groupId1 = new GroupId(TestUtils.getRandomId());
-		Group group1 = groupFactory.createGroup(groupId1, "Another group name",
+		Group group1 = new Group(groupId1, "Another group name",
 				null);
 		Message child1 = new TestMessage(childId1, messageId, groupId,
 				authorId, subject, timestamp, raw);
@@ -1391,7 +1388,7 @@ public class H2DatabaseTest extends BriarTestCase {
 	public void testGetGroupMessageParentWithParentInAnotherGroup()
 			throws Exception {
 		GroupId groupId1 = new GroupId(TestUtils.getRandomId());
-		Group group1 = groupFactory.createGroup(groupId1, "Group name", null);
+		Group group1 = new Group(groupId1, "Group name", null);
 		Database<Connection> db = open(false);
 		Connection txn = db.startTransaction();
 
@@ -1641,8 +1638,7 @@ public class H2DatabaseTest extends BriarTestCase {
 		// Subscribe to a couple of groups
 		db.addSubscription(txn, group);
 		GroupId groupId1 = new GroupId(TestUtils.getRandomId());
-		Group group1 = groupFactory.createGroup(groupId1, "Another group",
-				null);
+		Group group1 = new Group(groupId1, "Another group", null);
 		db.addSubscription(txn, group1);
 
 		// Store two messages in the first group
@@ -1695,7 +1691,7 @@ public class H2DatabaseTest extends BriarTestCase {
 		List<Group> groups = new ArrayList<Group>();
 		for(int i = 0; i < 100; i++) {
 			GroupId id = new GroupId(TestUtils.getRandomId());
-			groups.add(groupFactory.createGroup(id, "Group name", null));
+			groups.add(new Group(id, "Group name", null));
 		}
 
 		Database<Connection> db = open(false);
@@ -2030,9 +2026,8 @@ public class H2DatabaseTest extends BriarTestCase {
 	}
 
 	private Database<Connection> open(boolean resume) throws Exception {
-		Database<Connection> db = new H2Database(
-				new TestDatabaseConfig(testDir, MAX_SIZE), groupFactory,
-				new SystemClock());
+		Database<Connection> db = new H2Database(new SystemClock(),
+				new TestDatabaseConfig(testDir, MAX_SIZE));
 		db.open(resume);
 		return db;
 	}
diff --git a/briar-tests/src/net/sf/briar/db/TestGroup.java b/briar-tests/src/net/sf/briar/db/TestGroup.java
deleted file mode 100644
index 4e78e0788036179499b1ce2472ae1c8af8a7679e..0000000000000000000000000000000000000000
--- a/briar-tests/src/net/sf/briar/db/TestGroup.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package net.sf.briar.db;
-
-import net.sf.briar.api.protocol.Group;
-import net.sf.briar.api.protocol.GroupId;
-
-class TestGroup implements Group {
-
-	private final GroupId id;
-	private final String name;
-	private final byte[] publicKey;
-
-	public TestGroup(GroupId id, String name, byte[] publicKey) {
-		this.id = id;
-		this.name = name;
-		this.publicKey = publicKey;
-	}
-
-	public GroupId getId() {
-		return id;
-	}
-
-	public String getName() {
-		return name;
-	}
-
-	public byte[] getPublicKey() {
-		return publicKey;
-	}
-}
diff --git a/briar-tests/src/net/sf/briar/db/TestGroupFactory.java b/briar-tests/src/net/sf/briar/db/TestGroupFactory.java
deleted file mode 100644
index 89f29b92d14c217bdfad67c5f60ee3d399971313..0000000000000000000000000000000000000000
--- a/briar-tests/src/net/sf/briar/db/TestGroupFactory.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package net.sf.briar.db;
-
-import java.io.IOException;
-
-import net.sf.briar.TestUtils;
-import net.sf.briar.api.protocol.Group;
-import net.sf.briar.api.protocol.GroupFactory;
-import net.sf.briar.api.protocol.GroupId;
-
-class TestGroupFactory implements GroupFactory {
-
-	public Group createGroup(String name, byte[] publicKey) throws IOException {
-		GroupId id = new GroupId(TestUtils.getRandomId());
-		return new TestGroup(id, name, publicKey);
-	}
-
-	public Group createGroup(GroupId id, String name, byte[] publicKey) {
-		return new TestGroup(id, name, publicKey);
-	}
-}
\ No newline at end of file
diff --git a/briar-tests/src/net/sf/briar/protocol/UnverifiedBatchImplTest.java b/briar-tests/src/net/sf/briar/protocol/UnverifiedBatchImplTest.java
index 126f8a983aa3894f385a1f694ce90d8afb90cda1..08fdb3adbb8e0dbc3d81f12b777fdd236c66a190 100644
--- a/briar-tests/src/net/sf/briar/protocol/UnverifiedBatchImplTest.java
+++ b/briar-tests/src/net/sf/briar/protocol/UnverifiedBatchImplTest.java
@@ -126,6 +126,9 @@ public class UnverifiedBatchImplTest extends BriarTestCase {
 		final int signedByAuthor = 100, signedByGroup = 110;
 		final KeyPair authorKeyPair = crypto.generateSignatureKeyPair();
 		final KeyPair groupKeyPair = crypto.generateSignatureKeyPair();
+		GroupId groupId = new GroupId(TestUtils.getRandomId());
+		final Group group = new Group(groupId, "Group name",
+				groupKeyPair.getPublic().getEncoded());
 		Signature signature = crypto.getSignature();
 		// Calculate the expected author and group signatures
 		signature.initSign(authorKeyPair.getPrivate());
@@ -139,7 +142,6 @@ public class UnverifiedBatchImplTest extends BriarTestCase {
 		final UnverifiedMessage message =
 				context.mock(UnverifiedMessage.class, "message");
 		final Author author = context.mock(Author.class);
-		final Group group = context.mock(Group.class);
 		final UnverifiedMessage message1 =
 				context.mock(UnverifiedMessage.class, "message1");
 		context.checking(new Expectations() {{
@@ -156,16 +158,12 @@ public class UnverifiedBatchImplTest extends BriarTestCase {
 			will(returnValue(authorSignature));
 			oneOf(message).getGroup();
 			will(returnValue(group));
-			exactly(2).of(group).getPublicKey();
-			will(returnValue(groupKeyPair.getPublic().getEncoded()));
 			oneOf(message).getLengthSignedByGroup();
 			will(returnValue(signedByGroup));
 			oneOf(message).getGroupSignature();
 			will(returnValue(groupSignature));
 			oneOf(author).getId();
 			will(returnValue(new AuthorId(TestUtils.getRandomId())));
-			oneOf(group).getId();
-			will(returnValue(new GroupId(TestUtils.getRandomId())));
 			oneOf(message).getParent();
 			will(returnValue(null));
 			oneOf(message).getSubject();