diff --git a/briar-android-tests/src/test/java/org/briarproject/BlogSharingIntegrationTest.java b/briar-android-tests/src/test/java/org/briarproject/BlogSharingIntegrationTest.java
index 92bbedd71b774b22b9abc16e25a6717d115e074b..41fe53fff3ee27be453ddcc3d4b781890df97cde 100644
--- a/briar-android-tests/src/test/java/org/briarproject/BlogSharingIntegrationTest.java
+++ b/briar-android-tests/src/test/java/org/briarproject/BlogSharingIntegrationTest.java
@@ -57,6 +57,7 @@ import java.util.logging.Logger;
 import javax.inject.Inject;
 
 import static org.briarproject.TestPluginsModule.MAX_LATENCY;
+import static org.briarproject.api.blogs.BlogSharingManager.CLIENT_ID;
 import static org.briarproject.api.sync.ValidationManager.State.DELIVERED;
 import static org.briarproject.api.sync.ValidationManager.State.INVALID;
 import static org.junit.Assert.assertEquals;
@@ -189,9 +190,8 @@ public class BlogSharingIntegrationTest extends BriarIntegrationTest {
 		assertEquals(2, blogManager1.getBlogs().size());
 
 		// get sharing group and assert group message count
-		GroupId g = contactGroupFactory
-				.createContactGroup(blogSharingManager0.getClientId(),
-						contact1).getId();
+		GroupId g = contactGroupFactory.createContactGroup(CLIENT_ID, contact1)
+				.getId();
 		assertGroupCount(blogSharingManager0, g, 1, 0);
 
 		// sync first request message
diff --git a/briar-android-tests/src/test/java/org/briarproject/ForumSharingIntegrationTest.java b/briar-android-tests/src/test/java/org/briarproject/ForumSharingIntegrationTest.java
index 6cc770b1583c636567710de0b49e2c28592ef7c6..896e54e694c7cde207b202a707dafdcce322a467 100644
--- a/briar-android-tests/src/test/java/org/briarproject/ForumSharingIntegrationTest.java
+++ b/briar-android-tests/src/test/java/org/briarproject/ForumSharingIntegrationTest.java
@@ -68,6 +68,7 @@ import javax.inject.Inject;
 
 import static org.briarproject.TestPluginsModule.MAX_LATENCY;
 import static org.briarproject.api.forum.ForumConstants.FORUM_SALT_LENGTH;
+import static org.briarproject.api.forum.ForumSharingManager.CLIENT_ID;
 import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_INVITATION;
 import static org.briarproject.api.sync.ValidationManager.State.DELIVERED;
 import static org.briarproject.api.sync.ValidationManager.State.INVALID;
@@ -495,8 +496,7 @@ public class ForumSharingIntegrationTest extends BriarTestCase {
 			MessageQueueManager queue = t0.getMessageQueueManager();
 			Contact c1 = contactManager0.getContact(contactId1);
 			ContactGroupFactory groupFactory = t0.getContactGroupFactory();
-			Group group = groupFactory
-					.createContactGroup(forumSharingManager0.getClientId(), c1);
+			Group group = groupFactory.createContactGroup(CLIENT_ID, c1);
 			long time = clock.currentTimeMillis();
 			BdfList bodyList = BdfList.of(SHARE_MSG_TYPE_INVITATION,
 					sessionId.getBytes(),
@@ -691,8 +691,7 @@ public class ForumSharingIntegrationTest extends BriarTestCase {
 			MessageQueueManager queue = t0.getMessageQueueManager();
 			Contact c1 = contactManager0.getContact(contactId1);
 			ContactGroupFactory groupFactory = t0.getContactGroupFactory();
-			Group group = groupFactory
-					.createContactGroup(forumSharingManager0.getClientId(), c1);
+			Group group = groupFactory.createContactGroup(CLIENT_ID, c1);
 			long time = clock.currentTimeMillis();
 
 			// construct a new message re-using the old SessionId
diff --git a/briar-android-tests/src/test/java/org/briarproject/PrivateGroupManagerTest.java b/briar-android-tests/src/test/java/org/briarproject/PrivateGroupManagerTest.java
index 2b07de345275602b50c8edcdb1bcf942bc2a6b79..38ace43a3eae587d873785d1c7175185b17b1706 100644
--- a/briar-android-tests/src/test/java/org/briarproject/PrivateGroupManagerTest.java
+++ b/briar-android-tests/src/test/java/org/briarproject/PrivateGroupManagerTest.java
@@ -60,6 +60,7 @@ import javax.inject.Inject;
 import static org.briarproject.TestPluginsModule.MAX_LATENCY;
 import static org.briarproject.TestUtils.getRandomBytes;
 import static org.briarproject.api.identity.Author.Status.VERIFIED;
+import static org.briarproject.api.privategroup.invitation.GroupInvitationManager.CLIENT_ID;
 import static org.briarproject.api.sync.ValidationManager.State.DELIVERED;
 import static org.briarproject.api.sync.ValidationManager.State.INVALID;
 import static org.briarproject.api.sync.ValidationManager.State.PENDING;
@@ -341,8 +342,8 @@ public class PrivateGroupManagerTest extends BriarIntegrationTest {
 		joinTime = clock.currentTimeMillis();
 		long inviteTime = joinTime;
 		Group invitationGroup = contactGroupFactory
-				.createContactGroup(groupInvitationManager.getClientId(),
-						author0.getId(), author1.getId());
+				.createContactGroup(CLIENT_ID, author0.getId(),
+						author1.getId());
 		BdfList toSign = BdfList.of(0, inviteTime, invitationGroup.getId(),
 				privateGroup0.getId());
 		byte[] creatorSignature =
@@ -386,8 +387,8 @@ public class PrivateGroupManagerTest extends BriarIntegrationTest {
 		long joinTime = clock.currentTimeMillis();
 		long inviteTime = joinTime - 1;
 		Group invitationGroup = contactGroupFactory
-				.createContactGroup(groupInvitationManager.getClientId(),
-						author0.getId(), author0.getId());
+				.createContactGroup(CLIENT_ID, author0.getId(),
+						author0.getId());
 		BdfList toSign = BdfList.of(0, inviteTime, invitationGroup.getId(),
 				privateGroup0.getId());
 		byte[] creatorSignature =
@@ -412,8 +413,8 @@ public class PrivateGroupManagerTest extends BriarIntegrationTest {
 		joinTime = clock.currentTimeMillis();
 		inviteTime = joinTime - 1;
 		invitationGroup = contactGroupFactory
-				.createContactGroup(groupInvitationManager.getClientId(),
-						author0.getId(), author1.getId());
+				.createContactGroup(CLIENT_ID, author0.getId(),
+						author1.getId());
 		toSign = BdfList.of(0, inviteTime, invitationGroup.getId(),
 				privateGroup0.getId());
 		// signature uses joiner's key, not creator's key
@@ -540,8 +541,8 @@ public class PrivateGroupManagerTest extends BriarIntegrationTest {
 		joinTime = clock.currentTimeMillis();
 		long inviteTime = joinTime - 1;
 		Group invitationGroup = contactGroupFactory
-				.createContactGroup(groupInvitationManager.getClientId(),
-						author0.getId(), author1.getId());
+				.createContactGroup(CLIENT_ID, author0.getId(),
+						author1.getId());
 		BdfList toSign = BdfList.of(0, inviteTime, invitationGroup.getId(),
 				privateGroup0.getId());
 		byte[] creatorSignature =
diff --git a/briar-android-tests/src/test/java/org/briarproject/SyncIntegrationTest.java b/briar-android-tests/src/test/java/org/briarproject/SyncIntegrationTest.java
index 5b8aae38c6ec190c2c74cbe945f219f5cdfa858c..07a671747d7c65c17169ae9829da9327e03060b8 100644
--- a/briar-android-tests/src/test/java/org/briarproject/SyncIntegrationTest.java
+++ b/briar-android-tests/src/test/java/org/briarproject/SyncIntegrationTest.java
@@ -74,7 +74,7 @@ public class SyncIntegrationTest extends BriarTestCase {
 		headerKey = TestUtils.getSecretKey();
 		streamNumber = 123;
 		// Create a group
-		ClientId clientId = new ClientId(TestUtils.getRandomId());
+		ClientId clientId = new ClientId(TestUtils.getRandomString(5));
 		byte[] descriptor = new byte[0];
 		Group group = groupFactory.createGroup(clientId, descriptor);
 		// Add two messages to the group
diff --git a/briar-android/src/org/briarproject/android/blogs/FeedControllerImpl.java b/briar-android/src/org/briarproject/android/blogs/FeedControllerImpl.java
index faf626b5462e281dd83e95e61a52f7eda29e6fa3..33cce78e29c60a2b1357dd58c74baa1df3cce36d 100644
--- a/briar-android/src/org/briarproject/android/blogs/FeedControllerImpl.java
+++ b/briar-android/src/org/briarproject/android/blogs/FeedControllerImpl.java
@@ -25,6 +25,7 @@ import javax.inject.Inject;
 
 import static java.util.logging.Level.INFO;
 import static java.util.logging.Level.WARNING;
+import static org.briarproject.api.blogs.BlogManager.CLIENT_ID;
 
 public class FeedControllerImpl extends BaseControllerImpl
 		implements FeedController {
@@ -62,7 +63,7 @@ public class FeedControllerImpl extends BaseControllerImpl
 			onBlogPostAdded(b.getHeader(), b.isLocal());
 		} else if (e instanceof GroupRemovedEvent) {
 			GroupRemovedEvent g = (GroupRemovedEvent) e;
-			if (g.getGroup().getClientId().equals(blogManager.getClientId())) {
+			if (g.getGroup().getClientId().equals(CLIENT_ID)) {
 				LOG.info("Blog removed");
 				onBlogRemoved();
 			}
diff --git a/briar-android/src/org/briarproject/android/forum/ForumListFragment.java b/briar-android/src/org/briarproject/android/forum/ForumListFragment.java
index 2afce83162282ceba6787edbe82ddb17d963b1d3..9fb886f43551b36319678589eba46feccfd062d5 100644
--- a/briar-android/src/org/briarproject/android/forum/ForumListFragment.java
+++ b/briar-android/src/org/briarproject/android/forum/ForumListFragment.java
@@ -44,6 +44,7 @@ import javax.inject.Inject;
 import static android.support.design.widget.Snackbar.LENGTH_INDEFINITE;
 import static java.util.logging.Level.INFO;
 import static java.util.logging.Level.WARNING;
+import static org.briarproject.api.forum.ForumManager.CLIENT_ID;
 
 public class ForumListFragment extends BaseEventFragment implements
 		OnClickListener {
@@ -236,13 +237,13 @@ public class ForumListFragment extends BaseEventFragment implements
 			loadAvailableForums();
 		} else if (e instanceof GroupAddedEvent) {
 			GroupAddedEvent g = (GroupAddedEvent) e;
-			if (g.getGroup().getClientId().equals(forumManager.getClientId())) {
+			if (g.getGroup().getClientId().equals(CLIENT_ID)) {
 				LOG.info("Forum added, reloading forums");
 				loadForums();
 			}
 		} else if (e instanceof GroupRemovedEvent) {
 			GroupRemovedEvent g = (GroupRemovedEvent) e;
-			if (g.getGroup().getClientId().equals(forumManager.getClientId())) {
+			if (g.getGroup().getClientId().equals(CLIENT_ID)) {
 				LOG.info("Forum removed, removing from list");
 				removeForum(g.getGroup().getId());
 			}
diff --git a/briar-android/src/org/briarproject/android/privategroup/invitation/GroupInvitationControllerImpl.java b/briar-android/src/org/briarproject/android/privategroup/invitation/GroupInvitationControllerImpl.java
index b48a8743774d67ac6b5f0195a95bceb4c375723d..9dba77d895f3e4bc009d4c4e1b90c6748c0ebeb6 100644
--- a/briar-android/src/org/briarproject/android/privategroup/invitation/GroupInvitationControllerImpl.java
+++ b/briar-android/src/org/briarproject/android/privategroup/invitation/GroupInvitationControllerImpl.java
@@ -21,6 +21,7 @@ import java.util.concurrent.Executor;
 import javax.inject.Inject;
 
 import static java.util.logging.Level.WARNING;
+import static org.briarproject.api.privategroup.PrivateGroupManager.CLIENT_ID;
 
 public class GroupInvitationControllerImpl
 		extends InvitationControllerImpl<GroupInvitationItem>
@@ -51,7 +52,7 @@ public class GroupInvitationControllerImpl
 
 	@Override
 	protected ClientId getShareableClientId() {
-		return privateGroupManager.getClientId();
+		return CLIENT_ID;
 	}
 
 	@Override
diff --git a/briar-android/src/org/briarproject/android/privategroup/list/GroupListControllerImpl.java b/briar-android/src/org/briarproject/android/privategroup/list/GroupListControllerImpl.java
index 4524e484b399b3cbcdcb91a2edd0f38d508615b6..ee5cb7be46cdebe781273dbf2612510a94ca872d 100644
--- a/briar-android/src/org/briarproject/android/privategroup/list/GroupListControllerImpl.java
+++ b/briar-android/src/org/briarproject/android/privategroup/list/GroupListControllerImpl.java
@@ -33,6 +33,7 @@ import javax.inject.Inject;
 
 import static java.util.logging.Level.INFO;
 import static java.util.logging.Level.WARNING;
+import static org.briarproject.api.privategroup.PrivateGroupManager.CLIENT_ID;
 
 public class GroupListControllerImpl extends DbControllerImpl
 		implements GroupListController, EventListener {
@@ -92,14 +93,14 @@ public class GroupListControllerImpl extends DbControllerImpl
 		} else if (e instanceof GroupAddedEvent) {
 			GroupAddedEvent g = (GroupAddedEvent) e;
 			ClientId id = g.getGroup().getClientId();
-			if (id.equals(groupManager.getClientId())) {
+			if (id.equals(CLIENT_ID)) {
 				LOG.info("Private group added");
 				onGroupAdded(g.getGroup().getId());
 			}
 		} else if (e instanceof GroupRemovedEvent) {
 			GroupRemovedEvent g = (GroupRemovedEvent) e;
 			ClientId id = g.getGroup().getClientId();
-			if (id.equals(groupManager.getClientId())) {
+			if (id.equals(CLIENT_ID)) {
 				LOG.info("Private group removed");
 				onGroupRemoved(g.getGroup().getId());
 			}
diff --git a/briar-android/src/org/briarproject/android/sharing/BlogInvitationControllerImpl.java b/briar-android/src/org/briarproject/android/sharing/BlogInvitationControllerImpl.java
index 49507b4f4036bf7d0bb7444266ed180482d0181b..54227624f436ad02c75e5b525f67b1441dc6a6f6 100644
--- a/briar-android/src/org/briarproject/android/sharing/BlogInvitationControllerImpl.java
+++ b/briar-android/src/org/briarproject/android/sharing/BlogInvitationControllerImpl.java
@@ -20,6 +20,7 @@ import java.util.concurrent.Executor;
 import javax.inject.Inject;
 
 import static java.util.logging.Level.WARNING;
+import static org.briarproject.api.blogs.BlogManager.CLIENT_ID;
 
 public class BlogInvitationControllerImpl
 		extends InvitationControllerImpl<SharingInvitationItem>
@@ -49,7 +50,7 @@ public class BlogInvitationControllerImpl
 
 	@Override
 	protected ClientId getShareableClientId() {
-		return blogManager.getClientId();
+		return CLIENT_ID;
 	}
 
 	@Override
diff --git a/briar-android/src/org/briarproject/android/sharing/ForumInvitationControllerImpl.java b/briar-android/src/org/briarproject/android/sharing/ForumInvitationControllerImpl.java
index 4418900b821007374e46e6aca24fe70364e19ba9..ef563492753dba0152ff53b9c0708591fc0f9d95 100644
--- a/briar-android/src/org/briarproject/android/sharing/ForumInvitationControllerImpl.java
+++ b/briar-android/src/org/briarproject/android/sharing/ForumInvitationControllerImpl.java
@@ -20,6 +20,7 @@ import java.util.concurrent.Executor;
 import javax.inject.Inject;
 
 import static java.util.logging.Level.WARNING;
+import static org.briarproject.api.forum.ForumManager.CLIENT_ID;
 
 public class ForumInvitationControllerImpl
 		extends InvitationControllerImpl<SharingInvitationItem>
@@ -50,7 +51,7 @@ public class ForumInvitationControllerImpl
 
 	@Override
 	protected ClientId getShareableClientId() {
-		return forumManager.getClientId();
+		return CLIENT_ID;
 	}
 
 	@Override
diff --git a/briar-api/src/org/briarproject/api/blogs/BlogManager.java b/briar-api/src/org/briarproject/api/blogs/BlogManager.java
index 62e4349dde7e1d1d6dc208bf2023071fd0fc01bd..6b0f28ec16d6ae1e4855e5c8ee279e832827a29b 100644
--- a/briar-api/src/org/briarproject/api/blogs/BlogManager.java
+++ b/briar-api/src/org/briarproject/api/blogs/BlogManager.java
@@ -13,8 +13,8 @@ import java.util.Collection;
 
 public interface BlogManager {
 
-	/** Returns the unique ID of the blog client. */
-	ClientId getClientId();
+	/** Unique ID of the blog client. */
+	ClientId CLIENT_ID = new ClientId("org.briarproject.briar.blogs");
 
 	/** Returns true if a blog can be removed. */
 	boolean canBeRemoved(GroupId g) throws DbException;
diff --git a/briar-api/src/org/briarproject/api/blogs/BlogSharingManager.java b/briar-api/src/org/briarproject/api/blogs/BlogSharingManager.java
index 8584dff59a58243709a24eeb14cba59bbcf690b0..10ee0ff84217c61a62021d4f0441165dd785016c 100644
--- a/briar-api/src/org/briarproject/api/blogs/BlogSharingManager.java
+++ b/briar-api/src/org/briarproject/api/blogs/BlogSharingManager.java
@@ -1,7 +1,10 @@
 package org.briarproject.api.blogs;
 
 import org.briarproject.api.sharing.SharingManager;
+import org.briarproject.api.sync.ClientId;
 
 public interface BlogSharingManager extends SharingManager<Blog> {
 
+	ClientId CLIENT_ID = new ClientId("org.briarproject.briar.blogs.sharing");
+
 }
diff --git a/briar-api/src/org/briarproject/api/feed/FeedManager.java b/briar-api/src/org/briarproject/api/feed/FeedManager.java
index 2edb0d9be3cbbc96a485968517e3d8988b22cb3e..a643cc429b32d0ebf48f2813241e4efa5e6f8557 100644
--- a/briar-api/src/org/briarproject/api/feed/FeedManager.java
+++ b/briar-api/src/org/briarproject/api/feed/FeedManager.java
@@ -9,8 +9,8 @@ import java.util.List;
 
 public interface FeedManager {
 
-	/** Returns the unique ID of the client. */
-	ClientId getClientId();
+	/** The unique ID of the RSS feed client. */
+	ClientId CLIENT_ID = new ClientId("org.briarproject.briar.feed");
 
 	/** Adds a RSS feed. */
 	void addFeed(String url, GroupId g) throws DbException, IOException;
diff --git a/briar-api/src/org/briarproject/api/forum/ForumManager.java b/briar-api/src/org/briarproject/api/forum/ForumManager.java
index 51af10a1c3c4e669374ac93457541d09b39b4d16..37aadb723b7798d4429d5feee69214fc1da0728b 100644
--- a/briar-api/src/org/briarproject/api/forum/ForumManager.java
+++ b/briar-api/src/org/briarproject/api/forum/ForumManager.java
@@ -14,8 +14,8 @@ import java.util.Collection;
 
 public interface ForumManager extends MessageTracker {
 
-	/** Returns the unique ID of the forum client. */
-	ClientId getClientId();
+	/** The unique ID of the forum client. */
+	ClientId CLIENT_ID = new ClientId("org.briarproject.briar.forum");
 
 	/** Subscribes to a forum. */
 	Forum addForum(String name) throws DbException;
diff --git a/briar-api/src/org/briarproject/api/forum/ForumSharingManager.java b/briar-api/src/org/briarproject/api/forum/ForumSharingManager.java
index ec0135c75f71e14659082fe955e828cdbd8f2ae5..b2f99acf6186b881d4e1d9a5b8bc2c46c96fa94a 100644
--- a/briar-api/src/org/briarproject/api/forum/ForumSharingManager.java
+++ b/briar-api/src/org/briarproject/api/forum/ForumSharingManager.java
@@ -1,7 +1,10 @@
 package org.briarproject.api.forum;
 
 import org.briarproject.api.sharing.SharingManager;
+import org.briarproject.api.sync.ClientId;
 
 public interface ForumSharingManager extends SharingManager<Forum> {
 
+	ClientId CLIENT_ID = new ClientId("org.briarproject.briar.forum.sharing");
+
 }
diff --git a/briar-api/src/org/briarproject/api/introduction/IntroductionManager.java b/briar-api/src/org/briarproject/api/introduction/IntroductionManager.java
index 3f2fcea12fa3aec8833df878598f8a170e0ee7fe..6914318d833b95d2b213bc2e2cb34e107cf94819 100644
--- a/briar-api/src/org/briarproject/api/introduction/IntroductionManager.java
+++ b/briar-api/src/org/briarproject/api/introduction/IntroductionManager.java
@@ -12,8 +12,8 @@ import java.util.Collection;
 
 public interface IntroductionManager extends MessageTracker {
 
-	/** Returns the unique ID of the introduction client. */
-	ClientId getClientId();
+	/** The unique ID of the introduction client. */
+	ClientId CLIENT_ID = new ClientId("org.briarproject.briar.introduction");
 
 	/**
 	 * sends two initial introduction messages
diff --git a/briar-api/src/org/briarproject/api/messaging/MessagingManager.java b/briar-api/src/org/briarproject/api/messaging/MessagingManager.java
index bf03e188c252b48cb57117e7dddad195c717d4bb..c6de1772f1dded122d3249a3ed00f802e3041552 100644
--- a/briar-api/src/org/briarproject/api/messaging/MessagingManager.java
+++ b/briar-api/src/org/briarproject/api/messaging/MessagingManager.java
@@ -11,8 +11,8 @@ import java.util.Collection;
 
 public interface MessagingManager extends MessageTracker {
 
-	/** Returns the unique ID of the messaging client. */
-	ClientId getClientId();
+	/** The unique ID of the messaging client. */
+	ClientId CLIENT_ID = new ClientId("org.briarproject.briar.messaging");
 
 	/** Stores a local private message. */
 	void addLocalMessage(PrivateMessage m) throws DbException;
diff --git a/briar-api/src/org/briarproject/api/privategroup/PrivateGroupManager.java b/briar-api/src/org/briarproject/api/privategroup/PrivateGroupManager.java
index d0ed0d7500d2d39de7dcadf91102af61db609f9b..85b190452ffd875010d07b2f1a416f12e11ed46f 100644
--- a/briar-api/src/org/briarproject/api/privategroup/PrivateGroupManager.java
+++ b/briar-api/src/org/briarproject/api/privategroup/PrivateGroupManager.java
@@ -14,8 +14,8 @@ import java.util.Collection;
 @NotNullByDefault
 public interface PrivateGroupManager extends MessageTracker {
 
-	/** Returns the unique ID of the private group client. */
-	ClientId getClientId();
+	/** The unique ID of the private group client. */
+	ClientId CLIENT_ID = new ClientId("org.briarproject.briar.privategroup");
 
 	/**
 	 * Adds a new private group and joins it.
diff --git a/briar-api/src/org/briarproject/api/privategroup/invitation/GroupInvitationManager.java b/briar-api/src/org/briarproject/api/privategroup/invitation/GroupInvitationManager.java
index a5ca33dae143336d889b38e657f3c10ca6090a3b..745b69fc8cc5a34872391628e7044c051064ad54 100644
--- a/briar-api/src/org/briarproject/api/privategroup/invitation/GroupInvitationManager.java
+++ b/briar-api/src/org/briarproject/api/privategroup/invitation/GroupInvitationManager.java
@@ -14,8 +14,9 @@ import java.util.Collection;
 
 public interface GroupInvitationManager extends MessageTracker {
 
-	/** Returns the unique ID of the private group invitation client. */
-	ClientId getClientId();
+	/** The unique ID of the private group invitation client. */
+	ClientId CLIENT_ID =
+			new ClientId("org.briarproject.briar.privategroup.invitation");
 
 	/**
 	 * Sends an invitation to share the given forum with the given contact
diff --git a/briar-api/src/org/briarproject/api/properties/TransportPropertyManager.java b/briar-api/src/org/briarproject/api/properties/TransportPropertyManager.java
index 38fedd9fb76d9c19083296134fb391ef2f90e86e..b7da722fdbc85be496987afcddae7dc7cfd3383f 100644
--- a/briar-api/src/org/briarproject/api/properties/TransportPropertyManager.java
+++ b/briar-api/src/org/briarproject/api/properties/TransportPropertyManager.java
@@ -4,11 +4,15 @@ import org.briarproject.api.TransportId;
 import org.briarproject.api.contact.ContactId;
 import org.briarproject.api.db.DbException;
 import org.briarproject.api.db.Transaction;
+import org.briarproject.api.sync.ClientId;
 
 import java.util.Map;
 
 public interface TransportPropertyManager {
 
+	/** The unique ID of the transport property client. */
+	ClientId CLIENT_ID = new ClientId("org.briarproject.briar.properties");
+
 	/**
 	 * Stores the given properties received while adding a contact - they will
 	 * be superseded by any properties synced from the contact.
diff --git a/briar-api/src/org/briarproject/api/sharing/SharingManager.java b/briar-api/src/org/briarproject/api/sharing/SharingManager.java
index c7b1c8004954c5af181b8a1cb092beb8f16adb84..934818f955ccd9af4f370c13d5a914e245f5eef2 100644
--- a/briar-api/src/org/briarproject/api/sharing/SharingManager.java
+++ b/briar-api/src/org/briarproject/api/sharing/SharingManager.java
@@ -5,18 +5,12 @@ import org.briarproject.api.clients.SessionId;
 import org.briarproject.api.contact.Contact;
 import org.briarproject.api.contact.ContactId;
 import org.briarproject.api.db.DbException;
-import org.briarproject.api.sync.ClientId;
 import org.briarproject.api.sync.GroupId;
 
 import java.util.Collection;
 
 public interface SharingManager<S extends Shareable> extends MessageTracker {
 
-	/**
-	 * Returns the unique ID of the group sharing client.
-	 */
-	ClientId getClientId();
-
 	/**
 	 * Sends an invitation to share the given group with the given contact
 	 * and sends an optional message along with it.
diff --git a/briar-api/src/org/briarproject/api/sync/ClientId.java b/briar-api/src/org/briarproject/api/sync/ClientId.java
index 7fd5456c1c075dc6f56b336b435dfe4447542d90..7101b31069e3424d0f7a495a4e29f53a86536e4e 100644
--- a/briar-api/src/org/briarproject/api/sync/ClientId.java
+++ b/briar-api/src/org/briarproject/api/sync/ClientId.java
@@ -1,18 +1,39 @@
 package org.briarproject.api.sync;
 
-import org.briarproject.api.UniqueId;
+import org.briarproject.api.nullsafety.NotNullByDefault;
+
+import javax.annotation.concurrent.Immutable;
 
 /**
- * Type-safe wrapper for a byte array that uniquely identifies a sync client.
+ * Wrapper for a name-spaced string that uniquely identifies a sync client.
  */
-public class ClientId extends UniqueId {
+@Immutable
+@NotNullByDefault
+public class ClientId implements Comparable<ClientId> {
+
+	private final String id;
+
+	public ClientId(String id) {
+		this.id = id;
+	}
 
-	public ClientId(byte[] id) {
-		super(id);
+	public String getString() {
+		return id;
+	}
+
+	@Override
+	public int compareTo(ClientId clientId) {
+		return id.compareTo(clientId.getString());
 	}
 
 	@Override
 	public boolean equals(Object o) {
-		return o instanceof ClientId && super.equals(o);
+		return o instanceof ClientId && id.equals(((ClientId) o).id);
 	}
+
+	@Override
+	public int hashCode() {
+		return id.hashCode();
+	}
+
 }
diff --git a/briar-core/src/org/briarproject/blogs/BlogManagerImpl.java b/briar-core/src/org/briarproject/blogs/BlogManagerImpl.java
index 455e17c2ff892bf44dcdc8386cfe5db36aa8cc09..e591fd2d2b986726f57effd25a7293209d6110eb 100644
--- a/briar-core/src/org/briarproject/blogs/BlogManagerImpl.java
+++ b/briar-core/src/org/briarproject/blogs/BlogManagerImpl.java
@@ -27,13 +27,11 @@ import org.briarproject.api.identity.Author.Status;
 import org.briarproject.api.identity.AuthorId;
 import org.briarproject.api.identity.IdentityManager;
 import org.briarproject.api.identity.LocalAuthor;
-import org.briarproject.api.sync.ClientId;
 import org.briarproject.api.sync.Group;
 import org.briarproject.api.sync.GroupId;
 import org.briarproject.api.sync.Message;
 import org.briarproject.api.sync.MessageId;
 import org.briarproject.clients.BdfIncomingMessageHook;
-import org.briarproject.util.StringUtils;
 import org.jetbrains.annotations.Nullable;
 
 import java.security.GeneralSecurityException;
@@ -74,10 +72,6 @@ import static org.briarproject.blogs.BlogPostValidator.authorToBdfDictionary;
 class BlogManagerImpl extends BdfIncomingMessageHook implements BlogManager,
 		AddContactHook, RemoveContactHook, Client {
 
-	static final ClientId CLIENT_ID = new ClientId(StringUtils.fromHexString(
-			"dafbe56f0c8971365cea4bb5f08ec9a6" +
-					"1d686e058b943997b6ff259ba423f613"));
-
 	private final IdentityManager identityManager;
 	private final ContactManager contactManager;
 	private final BlogFactory blogFactory;
@@ -98,11 +92,6 @@ class BlogManagerImpl extends BdfIncomingMessageHook implements BlogManager,
 		removeHooks = new CopyOnWriteArrayList<RemoveBlogHook>();
 	}
 
-	@Override
-	public ClientId getClientId() {
-		return CLIENT_ID;
-	}
-
 	@Override
 	public void createLocalState(Transaction txn) throws DbException {
 		// Ensure that the local identity has its own personal blog
diff --git a/briar-core/src/org/briarproject/db/JdbcDatabase.java b/briar-core/src/org/briarproject/db/JdbcDatabase.java
index 913add501941d0760b2ce2de292a174047302550..3ee7fadd6fe9c336d5dd31c6663c3793b26c6e30 100644
--- a/briar-core/src/org/briarproject/db/JdbcDatabase.java
+++ b/briar-core/src/org/briarproject/db/JdbcDatabase.java
@@ -67,8 +67,8 @@ import static org.briarproject.db.ExponentialBackoff.calculateExpiry;
  */
 abstract class JdbcDatabase implements Database<Connection> {
 
-	private static final int SCHEMA_VERSION = 27;
-	private static final int MIN_SCHEMA_VERSION = 27;
+	private static final int SCHEMA_VERSION = 28;
+	private static final int MIN_SCHEMA_VERSION = 28;
 
 	private static final String CREATE_SETTINGS =
 			"CREATE TABLE settings"
@@ -103,7 +103,7 @@ abstract class JdbcDatabase implements Database<Connection> {
 	private static final String CREATE_GROUPS =
 			"CREATE TABLE groups"
 					+ " (groupId HASH NOT NULL,"
-					+ " clientId HASH NOT NULL,"
+					+ " clientId VARCHAR NOT NULL,"
 					+ " descriptor BINARY NOT NULL,"
 					+ " PRIMARY KEY (groupId))";
 
@@ -504,7 +504,7 @@ abstract class JdbcDatabase implements Database<Connection> {
 					+ " VALUES (?, ?, ?)";
 			ps = txn.prepareStatement(sql);
 			ps.setBytes(1, g.getId().getBytes());
-			ps.setBytes(2, g.getClientId().getBytes());
+			ps.setString(2, g.getClientId().getString());
 			ps.setBytes(3, g.getDescriptor());
 			int affected = ps.executeUpdate();
 			if (affected != 1) throw new DbStateException();
@@ -1091,7 +1091,7 @@ abstract class JdbcDatabase implements Database<Connection> {
 			ps.setBytes(1, g.getBytes());
 			rs = ps.executeQuery();
 			if (!rs.next()) throw new DbStateException();
-			ClientId clientId = new ClientId(rs.getBytes(1));
+			ClientId clientId = new ClientId(rs.getString(1));
 			byte[] descriptor = rs.getBytes(2);
 			rs.close();
 			ps.close();
@@ -1111,7 +1111,7 @@ abstract class JdbcDatabase implements Database<Connection> {
 			String sql = "SELECT groupId, descriptor FROM groups"
 					+ " WHERE clientId = ?";
 			ps = txn.prepareStatement(sql);
-			ps.setBytes(1, c.getBytes());
+			ps.setString(1, c.getString());
 			rs = ps.executeQuery();
 			List<Group> groups = new ArrayList<Group>();
 			while (rs.next()) {
@@ -1678,7 +1678,7 @@ abstract class JdbcDatabase implements Database<Connection> {
 					+ " WHERE state = ? AND clientId = ? AND raw IS NOT NULL";
 			ps = txn.prepareStatement(sql);
 			ps.setInt(1, state.getValue());
-			ps.setBytes(2, c.getBytes());
+			ps.setString(2, c.getString());
 			rs = ps.executeQuery();
 			List<MessageId> ids = new ArrayList<MessageId>();
 			while (rs.next()) ids.add(new MessageId(rs.getBytes(1)));
@@ -1707,7 +1707,7 @@ abstract class JdbcDatabase implements Database<Connection> {
 					+ " WHERE m.shared = FALSE AND m1.shared = TRUE"
 					+ " AND g.clientId = ?";
 			ps = txn.prepareStatement(sql);
-			ps.setBytes(1, c.getBytes());
+			ps.setString(1, c.getString());
 			rs = ps.executeQuery();
 			List<MessageId> ids = new ArrayList<MessageId>();
 			while (rs.next()) ids.add(new MessageId(rs.getBytes(1)));
diff --git a/briar-core/src/org/briarproject/feed/FeedManagerImpl.java b/briar-core/src/org/briarproject/feed/FeedManagerImpl.java
index 11e98eeacde28e5b64573015a08920390d5a047b..b2229a60cd930f42fd3a2ad264834ba0d67636dd 100644
--- a/briar-core/src/org/briarproject/feed/FeedManagerImpl.java
+++ b/briar-core/src/org/briarproject/feed/FeedManagerImpl.java
@@ -30,7 +30,6 @@ import org.briarproject.api.identity.IdentityManager;
 import org.briarproject.api.identity.LocalAuthor;
 import org.briarproject.api.lifecycle.IoExecutor;
 import org.briarproject.api.plugins.TorConstants;
-import org.briarproject.api.sync.ClientId;
 import org.briarproject.api.sync.Group;
 import org.briarproject.api.sync.GroupId;
 import org.briarproject.api.system.Clock;
@@ -73,11 +72,6 @@ class FeedManagerImpl implements FeedManager, Client, EventListener {
 	private static final Logger LOG =
 			Logger.getLogger(FeedManagerImpl.class.getName());
 
-	private static final ClientId CLIENT_ID =
-			new ClientId(StringUtils.fromHexString(
-					"466565644d616e6167657202fb797097"
-							+ "255af837abbf8c16e250b3c2ccc286eb"));
-
 	private static final int CONNECT_TIMEOUT = 60 * 1000; // Milliseconds
 
 	private final ScheduledExecutorService feedExecutor;
@@ -114,11 +108,6 @@ class FeedManagerImpl implements FeedManager, Client, EventListener {
 		this.torSocketFactory = torSocketFactory;
 	}
 
-	@Override
-	public ClientId getClientId() {
-		return CLIENT_ID;
-	}
-
 	@Override
 	public void eventOccurred(Event e) {
 		if (e instanceof TransportEnabledEvent) {
@@ -510,7 +499,7 @@ class FeedManagerImpl implements FeedManager, Client, EventListener {
 	}
 
 	private Group getLocalGroup() {
-		return contactGroupFactory.createLocalGroup(getClientId());
+		return contactGroupFactory.createLocalGroup(CLIENT_ID);
 	}
 
 }
diff --git a/briar-core/src/org/briarproject/forum/ForumManagerImpl.java b/briar-core/src/org/briarproject/forum/ForumManagerImpl.java
index 8cd1d9f0eee072d0bb8c59a65d02eee21609e6a5..db82d71c123545e7a3549825f7f921e5a54f87cb 100644
--- a/briar-core/src/org/briarproject/forum/ForumManagerImpl.java
+++ b/briar-core/src/org/briarproject/forum/ForumManagerImpl.java
@@ -20,13 +20,11 @@ import org.briarproject.api.identity.Author.Status;
 import org.briarproject.api.identity.AuthorId;
 import org.briarproject.api.identity.IdentityManager;
 import org.briarproject.api.identity.LocalAuthor;
-import org.briarproject.api.sync.ClientId;
 import org.briarproject.api.sync.Group;
 import org.briarproject.api.sync.GroupId;
 import org.briarproject.api.sync.Message;
 import org.briarproject.api.sync.MessageId;
 import org.briarproject.clients.BdfIncomingMessageHook;
-import org.briarproject.util.StringUtils;
 import org.jetbrains.annotations.Nullable;
 
 import java.security.GeneralSecurityException;
@@ -56,10 +54,6 @@ import static org.briarproject.clients.BdfConstants.MSG_KEY_READ;
 
 class ForumManagerImpl extends BdfIncomingMessageHook implements ForumManager {
 
-	static final ClientId CLIENT_ID = new ClientId(StringUtils.fromHexString(
-			"859a7be50dca035b64bd6902fb797097"
-					+ "795af837abbf8c16d750b3c2ccc186ea"));
-
 	private final IdentityManager identityManager;
 	private final ForumFactory forumFactory;
 	private final ForumPostFactory forumPostFactory;
@@ -92,11 +86,6 @@ class ForumManagerImpl extends BdfIncomingMessageHook implements ForumManager {
 		return true;
 	}
 
-	@Override
-	public ClientId getClientId() {
-		return CLIENT_ID;
-	}
-
 	@Override
 	public Forum addForum(String name) throws DbException {
 		Forum f = forumFactory.createForum(name);
diff --git a/briar-core/src/org/briarproject/forum/ForumModule.java b/briar-core/src/org/briarproject/forum/ForumModule.java
index 4a2e6a79830a0b61ce93731354f651d968a2ba17..0cc501d0af7ac43f4609ff4829985773ec12ed7b 100644
--- a/briar-core/src/org/briarproject/forum/ForumModule.java
+++ b/briar-core/src/org/briarproject/forum/ForumModule.java
@@ -32,9 +32,8 @@ public class ForumModule {
 	ForumManager provideForumManager(ForumManagerImpl forumManager,
 			ValidationManager validationManager) {
 
-		validationManager
-				.registerIncomingMessageHook(forumManager.getClientId(),
-						forumManager);
+		validationManager.registerIncomingMessageHook(ForumManager.CLIENT_ID,
+				forumManager);
 
 		return forumManager;
 	}
diff --git a/briar-core/src/org/briarproject/introduction/IntroductionManagerImpl.java b/briar-core/src/org/briarproject/introduction/IntroductionManagerImpl.java
index 7c3e2361f58ca3e4559cc975c298fa0420ca1af7..30cae32f45b85f3ed3cbc83141edb65afbffd042 100644
--- a/briar-core/src/org/briarproject/introduction/IntroductionManagerImpl.java
+++ b/briar-core/src/org/briarproject/introduction/IntroductionManagerImpl.java
@@ -23,14 +23,12 @@ import org.briarproject.api.introduction.IntroductionManager;
 import org.briarproject.api.introduction.IntroductionMessage;
 import org.briarproject.api.introduction.IntroductionRequest;
 import org.briarproject.api.introduction.IntroductionResponse;
-import org.briarproject.api.sync.ClientId;
 import org.briarproject.api.sync.Group;
 import org.briarproject.api.sync.GroupId;
 import org.briarproject.api.sync.Message;
 import org.briarproject.api.sync.MessageId;
 import org.briarproject.api.sync.MessageStatus;
 import org.briarproject.clients.ConversationClientImpl;
-import org.briarproject.util.StringUtils;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -79,10 +77,6 @@ class IntroductionManagerImpl extends ConversationClientImpl
 		implements IntroductionManager, Client, AddContactHook,
 		RemoveContactHook {
 
-	static final ClientId CLIENT_ID = new ClientId(StringUtils.fromHexString(
-			"23b1897c198a90ae75b976ac023d0f32"
-					+ "80ca67b12f2346b2c23a34f34e2434c3"));
-
 	private static final Logger LOG =
 			Logger.getLogger(IntroductionManagerImpl.class.getName());
 
@@ -102,11 +96,6 @@ class IntroductionManagerImpl extends ConversationClientImpl
 		this.introductionGroupFactory = introductionGroupFactory;
 	}
 
-	@Override
-	public ClientId getClientId() {
-		return CLIENT_ID;
-	}
-
 	@Override
 	public void createLocalState(Transaction txn) throws DbException {
 		db.addGroup(txn, introductionGroupFactory.createLocalGroup());
diff --git a/briar-core/src/org/briarproject/introduction/IntroductionModule.java b/briar-core/src/org/briarproject/introduction/IntroductionModule.java
index 989100ff8b2266f5435def18051b36bdb111dfdc..14a92654ef7e64c2e32b23f02cb30b2901473ec3 100644
--- a/briar-core/src/org/briarproject/introduction/IntroductionModule.java
+++ b/briar-core/src/org/briarproject/introduction/IntroductionModule.java
@@ -15,6 +15,7 @@ import javax.inject.Singleton;
 import dagger.Module;
 import dagger.Provides;
 
+import static org.briarproject.api.introduction.IntroductionManager.CLIENT_ID;
 import static org.briarproject.api.sync.ValidationManager.MessageValidator;
 
 @Module
@@ -28,16 +29,14 @@ public class IntroductionModule {
 	@Provides
 	@Singleton
 	MessageValidator provideValidator(MessageQueueManager messageQueueManager,
-			IntroductionManager introductionManager,
 			MetadataEncoder metadataEncoder, ClientHelper clientHelper,
 			Clock clock) {
 
 		IntroductionValidator introductionValidator = new IntroductionValidator(
 				clientHelper, metadataEncoder, clock);
 
-		messageQueueManager.registerMessageValidator(
-				introductionManager.getClientId(),
-				introductionValidator);
+		messageQueueManager
+				.registerMessageValidator(CLIENT_ID, introductionValidator);
 
 		return introductionValidator;
 	}
@@ -54,9 +53,8 @@ public class IntroductionModule {
 		lifecycleManager.registerClient(introductionManager);
 		contactManager.registerAddContactHook(introductionManager);
 		contactManager.registerRemoveContactHook(introductionManager);
-		messageQueueManager.registerIncomingMessageHook(
-				introductionManager.getClientId(),
-				introductionManager);
+		messageQueueManager
+				.registerIncomingMessageHook(CLIENT_ID, introductionManager);
 		conversationManager.registerConversationClient(introductionManager);
 
 		return introductionManager;
diff --git a/briar-core/src/org/briarproject/messaging/MessagingManagerImpl.java b/briar-core/src/org/briarproject/messaging/MessagingManagerImpl.java
index bf18252996d3f83dede281e5d8275e5923870509..624bf1b74486e81b08f5829fee342316a29a9bc7 100644
--- a/briar-core/src/org/briarproject/messaging/MessagingManagerImpl.java
+++ b/briar-core/src/org/briarproject/messaging/MessagingManagerImpl.java
@@ -18,14 +18,12 @@ import org.briarproject.api.event.PrivateMessageReceivedEvent;
 import org.briarproject.api.messaging.MessagingManager;
 import org.briarproject.api.messaging.PrivateMessage;
 import org.briarproject.api.messaging.PrivateMessageHeader;
-import org.briarproject.api.sync.ClientId;
 import org.briarproject.api.sync.Group;
 import org.briarproject.api.sync.GroupId;
 import org.briarproject.api.sync.Message;
 import org.briarproject.api.sync.MessageId;
 import org.briarproject.api.sync.MessageStatus;
 import org.briarproject.clients.ConversationClientImpl;
-import org.briarproject.util.StringUtils;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -38,10 +36,6 @@ import static org.briarproject.clients.BdfConstants.MSG_KEY_READ;
 class MessagingManagerImpl extends ConversationClientImpl
 		implements MessagingManager, Client, AddContactHook, RemoveContactHook {
 
-	static final ClientId CLIENT_ID = new ClientId(StringUtils.fromHexString(
-			"6bcdc006c0910b0f44e40644c3b31f1a"
-					+ "8bf9a6d6021d40d219c86b731b903070"));
-
 	private final ContactGroupFactory contactGroupFactory;
 
 	@Inject
@@ -87,11 +81,6 @@ class MessagingManagerImpl extends ConversationClientImpl
 		db.removeGroup(txn, getContactGroup(c));
 	}
 
-	@Override
-	public ClientId getClientId() {
-		return CLIENT_ID;
-	}
-
 	@Override
 	protected boolean incomingMessage(Transaction txn, Message m, BdfList body,
 			BdfDictionary meta) throws DbException, FormatException {
diff --git a/briar-core/src/org/briarproject/privategroup/GroupMessageValidator.java b/briar-core/src/org/briarproject/privategroup/GroupMessageValidator.java
index e71624317524ab0404ed6967197a510f54977c73..e1613b04562ee4a6d94387ffc32438abe0f98369 100644
--- a/briar-core/src/org/briarproject/privategroup/GroupMessageValidator.java
+++ b/briar-core/src/org/briarproject/privategroup/GroupMessageValidator.java
@@ -12,7 +12,6 @@ import org.briarproject.api.identity.AuthorFactory;
 import org.briarproject.api.privategroup.MessageType;
 import org.briarproject.api.privategroup.PrivateGroup;
 import org.briarproject.api.privategroup.PrivateGroupFactory;
-import org.briarproject.api.privategroup.invitation.GroupInvitationManager;
 import org.briarproject.api.sync.Group;
 import org.briarproject.api.sync.InvalidMessageException;
 import org.briarproject.api.sync.Message;
@@ -30,6 +29,7 @@ import static org.briarproject.api.identity.AuthorConstants.MAX_SIGNATURE_LENGTH
 import static org.briarproject.api.privategroup.MessageType.JOIN;
 import static org.briarproject.api.privategroup.MessageType.POST;
 import static org.briarproject.api.privategroup.PrivateGroupConstants.MAX_GROUP_POST_BODY_LENGTH;
+import static org.briarproject.api.privategroup.invitation.GroupInvitationManager.CLIENT_ID;
 import static org.briarproject.privategroup.Constants.KEY_MEMBER_ID;
 import static org.briarproject.privategroup.Constants.KEY_MEMBER_NAME;
 import static org.briarproject.privategroup.Constants.KEY_MEMBER_PUBLIC_KEY;
@@ -44,18 +44,15 @@ class GroupMessageValidator extends BdfMessageValidator {
 	private final ContactGroupFactory contactGroupFactory;
 	private final PrivateGroupFactory groupFactory;
 	private final AuthorFactory authorFactory;
-	private final GroupInvitationManager groupInvitationManager; // TODO remove
 
 	GroupMessageValidator(ContactGroupFactory contactGroupFactory,
 			PrivateGroupFactory groupFactory,
 			ClientHelper clientHelper, MetadataEncoder metadataEncoder,
-			Clock clock, AuthorFactory authorFactory,
-			GroupInvitationManager groupInvitationManager) {
+			Clock clock, AuthorFactory authorFactory) {
 		super(clientHelper, metadataEncoder, clock);
 		this.contactGroupFactory = contactGroupFactory;
 		this.groupFactory = groupFactory;
 		this.authorFactory = authorFactory;
-		this.groupInvitationManager = groupInvitationManager;
 	}
 
 	@Override
@@ -125,8 +122,8 @@ class GroupMessageValidator extends BdfMessageValidator {
 
 			// derive invitation group
 			Group invitationGroup = contactGroupFactory
-					.createContactGroup(groupInvitationManager.getClientId(),
-							pg.getAuthor().getId(), member.getId());
+					.createContactGroup(CLIENT_ID, pg.getAuthor().getId(),
+							member.getId());
 
 			// signature with the creator's private key
 			// over a list with four elements:
diff --git a/briar-core/src/org/briarproject/privategroup/PrivateGroupManagerImpl.java b/briar-core/src/org/briarproject/privategroup/PrivateGroupManagerImpl.java
index 4b2ab02666881033dd666eb1d6b491d39f204277..49b5bc2f12feeecf01d656353edd59778a5102ca 100644
--- a/briar-core/src/org/briarproject/privategroup/PrivateGroupManagerImpl.java
+++ b/briar-core/src/org/briarproject/privategroup/PrivateGroupManagerImpl.java
@@ -23,13 +23,11 @@ import org.briarproject.api.privategroup.MessageType;
 import org.briarproject.api.privategroup.PrivateGroup;
 import org.briarproject.api.privategroup.PrivateGroupFactory;
 import org.briarproject.api.privategroup.PrivateGroupManager;
-import org.briarproject.api.sync.ClientId;
 import org.briarproject.api.sync.Group;
 import org.briarproject.api.sync.GroupId;
 import org.briarproject.api.sync.Message;
 import org.briarproject.api.sync.MessageId;
 import org.briarproject.clients.BdfIncomingMessageHook;
-import org.briarproject.util.StringUtils;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -64,10 +62,6 @@ import static org.briarproject.privategroup.Constants.KEY_TYPE;
 public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements
 		PrivateGroupManager {
 
-	static final ClientId CLIENT_ID = new ClientId(
-			StringUtils.fromHexString("5072697661746547726f75704d616e61"
-					+ "67657220627920546f727374656e2047"));
-
 	private final PrivateGroupFactory privateGroupFactory;
 	private final IdentityManager identityManager;
 	private final List<PrivateGroupHook> hooks;
@@ -84,11 +78,6 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements
 		hooks = new CopyOnWriteArrayList<PrivateGroupHook>();
 	}
 
-	@Override
-	public ClientId getClientId() {
-		return CLIENT_ID;
-	}
-
 	@Override
 	public void addPrivateGroup(PrivateGroup group, GroupMessage joinMsg)
 			throws DbException {
@@ -251,7 +240,7 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements
 		Collection<Group> groups;
 		Transaction txn = db.startTransaction(true);
 		try {
-			groups = db.getGroups(txn, getClientId());
+			groups = db.getGroups(txn, CLIENT_ID);
 			db.commitTransaction(txn);
 		} finally {
 			db.endTransaction(txn);
diff --git a/briar-core/src/org/briarproject/privategroup/PrivateGroupModule.java b/briar-core/src/org/briarproject/privategroup/PrivateGroupModule.java
index 2c60d72073c52fa01445c4a14dc888f4c45f7498..b4c80cbabd410decd01958419c5a005f1700bcd4 100644
--- a/briar-core/src/org/briarproject/privategroup/PrivateGroupModule.java
+++ b/briar-core/src/org/briarproject/privategroup/PrivateGroupModule.java
@@ -38,7 +38,7 @@ public class PrivateGroupModule {
 			ValidationManager validationManager) {
 
 		validationManager
-				.registerIncomingMessageHook(groupManager.getClientId(),
+				.registerIncomingMessageHook(PrivateGroupManager.CLIENT_ID,
 						groupManager);
 
 		return groupManager;
@@ -68,9 +68,9 @@ public class PrivateGroupModule {
 
 		GroupMessageValidator validator = new GroupMessageValidator(
 				contactGroupFactory, groupFactory, clientHelper,
-				metadataEncoder, clock, authorFactory, groupInvitationManager);
+				metadataEncoder, clock, authorFactory);
 		validationManager.registerMessageValidator(
-				PrivateGroupManagerImpl.CLIENT_ID, validator);
+				PrivateGroupManager.CLIENT_ID, validator);
 
 		return validator;
 	}
@@ -84,7 +84,7 @@ public class PrivateGroupModule {
 			ValidationManager validationManager) {
 
 		validationManager.registerIncomingMessageHook(
-				groupInvitationManager.getClientId(), groupInvitationManager);
+				GroupInvitationManager.CLIENT_ID, groupInvitationManager);
 		lifecycleManager.registerClient(groupInvitationManager);
 		contactManager.registerAddContactHook(groupInvitationManager);
 		contactManager.registerRemoveContactHook(groupInvitationManager);
diff --git a/briar-core/src/org/briarproject/privategroup/invitation/GroupInvitationManagerImpl.java b/briar-core/src/org/briarproject/privategroup/invitation/GroupInvitationManagerImpl.java
index 12477ab20b994595192b2e53b2bef17944e0f9c2..f7dba6e1f1e7955c5514f7b0f0608da6399814e7 100644
--- a/briar-core/src/org/briarproject/privategroup/invitation/GroupInvitationManagerImpl.java
+++ b/briar-core/src/org/briarproject/privategroup/invitation/GroupInvitationManagerImpl.java
@@ -19,12 +19,10 @@ import org.briarproject.api.privategroup.PrivateGroup;
 import org.briarproject.api.privategroup.invitation.GroupInvitationItem;
 import org.briarproject.api.privategroup.invitation.GroupInvitationManager;
 import org.briarproject.api.sharing.InvitationMessage;
-import org.briarproject.api.sync.ClientId;
 import org.briarproject.api.sync.Group;
 import org.briarproject.api.sync.GroupId;
 import org.briarproject.api.sync.Message;
 import org.briarproject.clients.ConversationClientImpl;
-import org.briarproject.util.StringUtils;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -38,11 +36,6 @@ public class GroupInvitationManagerImpl extends ConversationClientImpl
 		ContactManager.AddContactHook, ContactManager.RemoveContactHook,
 		ConversationManager.ConversationClient {
 
-	private static final ClientId CLIENT_ID =
-			new ClientId(StringUtils.fromHexString(
-					"B55231ABFC4A10666CD93D649B1D7F4F"
-							+ "016E65B87BB4C04F4E35613713DBCD13"));
-
 	private final ContactGroupFactory contactGroupFactory;
 	private final Group localGroup;
 
@@ -52,12 +45,7 @@ public class GroupInvitationManagerImpl extends ConversationClientImpl
 			ContactGroupFactory contactGroupFactory) {
 		super(db, clientHelper, metadataParser);
 		this.contactGroupFactory = contactGroupFactory;
-		localGroup = contactGroupFactory.createLocalGroup(getClientId());
-	}
-
-	@Override
-	public ClientId getClientId() {
-		return CLIENT_ID;
+		localGroup = contactGroupFactory.createLocalGroup(CLIENT_ID);
 	}
 
 	@Override
@@ -94,7 +82,7 @@ public class GroupInvitationManagerImpl extends ConversationClientImpl
 
 	@Override
 	protected Group getContactGroup(Contact c) {
-		return contactGroupFactory.createContactGroup(getClientId(), c);
+		return contactGroupFactory.createContactGroup(CLIENT_ID, c);
 	}
 
 	@Override
diff --git a/briar-core/src/org/briarproject/properties/TransportPropertyManagerImpl.java b/briar-core/src/org/briarproject/properties/TransportPropertyManagerImpl.java
index cabfe6d056168032c818db8271890982ff2de716..b0900795e1204a754139f0ae9cd26fd115e28cf7 100644
--- a/briar-core/src/org/briarproject/properties/TransportPropertyManagerImpl.java
+++ b/briar-core/src/org/briarproject/properties/TransportPropertyManagerImpl.java
@@ -16,13 +16,11 @@ import org.briarproject.api.db.DbException;
 import org.briarproject.api.db.Transaction;
 import org.briarproject.api.properties.TransportProperties;
 import org.briarproject.api.properties.TransportPropertyManager;
-import org.briarproject.api.sync.ClientId;
 import org.briarproject.api.sync.Group;
 import org.briarproject.api.sync.GroupId;
 import org.briarproject.api.sync.Message;
 import org.briarproject.api.sync.MessageId;
 import org.briarproject.api.system.Clock;
-import org.briarproject.util.StringUtils;
 
 import java.util.Collections;
 import java.util.HashMap;
@@ -34,10 +32,6 @@ import javax.inject.Inject;
 class TransportPropertyManagerImpl implements TransportPropertyManager,
 		Client, AddContactHook, RemoveContactHook {
 
-	static final ClientId CLIENT_ID = new ClientId(StringUtils.fromHexString(
-			"673ea091673561e28f70122f6a8ea8f4"
-					+ "97c3624b86fa07f785bb15f09fb87b4b"));
-
 	private final DatabaseComponent db;
 	private final ClientHelper clientHelper;
 	private final ContactGroupFactory contactGroupFactory;
diff --git a/briar-core/src/org/briarproject/sharing/BlogSharingManagerImpl.java b/briar-core/src/org/briarproject/sharing/BlogSharingManagerImpl.java
index 5429ef96dfa92f130471ca2e0bb71568fe8ca4a4..39533d7d936a12ddc57d2c4ee6a852fb1eb0a7d9 100644
--- a/briar-core/src/org/briarproject/sharing/BlogSharingManagerImpl.java
+++ b/briar-core/src/org/briarproject/sharing/BlogSharingManagerImpl.java
@@ -33,7 +33,6 @@ import org.briarproject.api.sync.ClientId;
 import org.briarproject.api.sync.GroupId;
 import org.briarproject.api.sync.MessageId;
 import org.briarproject.api.system.Clock;
-import org.briarproject.util.StringUtils;
 
 import java.security.SecureRandom;
 
@@ -48,10 +47,6 @@ class BlogSharingManagerImpl extends
 		SharingManagerImpl<Blog, BlogInvitation, BlogInviteeSessionState, BlogSharerSessionState, BlogInvitationReceivedEvent, BlogInvitationResponseReceivedEvent>
 		implements BlogSharingManager, RemoveBlogHook {
 
-	static final ClientId CLIENT_ID = new ClientId(StringUtils.fromHexString(
-			"bee438b5de0b3a685badc4e49d76e72d"
-					+ "21e01c4b569a775112756bdae267a028"));
-
 	private final IdentityManager identityManager;
 	private final BlogManager blogManager;
 
@@ -84,7 +79,7 @@ class BlogSharingManagerImpl extends
 	}
 
 	@Override
-	public ClientId getClientId() {
+	protected ClientId getClientId() {
 		return CLIENT_ID;
 	}
 
diff --git a/briar-core/src/org/briarproject/sharing/ForumSharingManagerImpl.java b/briar-core/src/org/briarproject/sharing/ForumSharingManagerImpl.java
index 092cf96f58edee95ab989df89d01e0b34c8fe18c..d4c04971a0e4a3961cfe2e05b2b3bc5a5fced674 100644
--- a/briar-core/src/org/briarproject/sharing/ForumSharingManagerImpl.java
+++ b/briar-core/src/org/briarproject/sharing/ForumSharingManagerImpl.java
@@ -27,7 +27,6 @@ import org.briarproject.api.sync.ClientId;
 import org.briarproject.api.sync.GroupId;
 import org.briarproject.api.sync.MessageId;
 import org.briarproject.api.system.Clock;
-import org.briarproject.util.StringUtils;
 
 import java.security.SecureRandom;
 
@@ -42,10 +41,6 @@ class ForumSharingManagerImpl extends
 		SharingManagerImpl<Forum, ForumInvitation, ForumInviteeSessionState, ForumSharerSessionState, ForumInvitationReceivedEvent, ForumInvitationResponseReceivedEvent>
 		implements ForumSharingManager, ForumManager.RemoveForumHook {
 
-	static final ClientId CLIENT_ID = new ClientId(StringUtils.fromHexString(
-			"cd11a5d04dccd9e2931d6fc3df456313"
-					+ "63bb3e9d9d0e9405fccdb051f41f5449"));
-
 	private final SFactory sFactory;
 	private final IFactory iFactory;
 	private final ISFactory isFactory;
@@ -75,7 +70,7 @@ class ForumSharingManagerImpl extends
 	}
 
 	@Override
-	public ClientId getClientId() {
+	protected ClientId getClientId() {
 		return CLIENT_ID;
 	}
 
diff --git a/briar-core/src/org/briarproject/sharing/SharingManagerImpl.java b/briar-core/src/org/briarproject/sharing/SharingManagerImpl.java
index 32591209f4531e125fdda0bfc71b31e7bfcafdd1..cd525096c8543ea428cf05b71c0163a2deabc1f1 100644
--- a/briar-core/src/org/briarproject/sharing/SharingManagerImpl.java
+++ b/briar-core/src/org/briarproject/sharing/SharingManagerImpl.java
@@ -25,10 +25,11 @@ import org.briarproject.api.event.Event;
 import org.briarproject.api.event.InvitationRequestReceivedEvent;
 import org.briarproject.api.event.InvitationResponseReceivedEvent;
 import org.briarproject.api.identity.LocalAuthor;
-import org.briarproject.api.sharing.SharingInvitationItem;
 import org.briarproject.api.sharing.InvitationMessage;
 import org.briarproject.api.sharing.Shareable;
+import org.briarproject.api.sharing.SharingInvitationItem;
 import org.briarproject.api.sharing.SharingManager;
+import org.briarproject.api.sync.ClientId;
 import org.briarproject.api.sync.Group;
 import org.briarproject.api.sync.GroupId;
 import org.briarproject.api.sync.Message;
@@ -115,6 +116,8 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS
 		localGroup = contactGroupFactory.createLocalGroup(getClientId());
 	}
 
+	protected abstract ClientId getClientId();
+
 	protected abstract InvitationMessage createInvitationRequest(MessageId id,
 			I msg, ContactId contactId, boolean available, long time,
 			boolean local, boolean sent, boolean seen, boolean read);
diff --git a/briar-core/src/org/briarproject/sync/GroupFactoryImpl.java b/briar-core/src/org/briarproject/sync/GroupFactoryImpl.java
index 9c00b15cb6bdfe15fc8d17e66b280e2f92b0a67f..e5ee94a2d34a885e55a45c57e984e256a26c9bd0 100644
--- a/briar-core/src/org/briarproject/sync/GroupFactoryImpl.java
+++ b/briar-core/src/org/briarproject/sync/GroupFactoryImpl.java
@@ -5,6 +5,7 @@ import org.briarproject.api.sync.ClientId;
 import org.briarproject.api.sync.Group;
 import org.briarproject.api.sync.GroupFactory;
 import org.briarproject.api.sync.GroupId;
+import org.briarproject.util.StringUtils;
 
 import javax.inject.Inject;
 
@@ -18,7 +19,9 @@ class GroupFactoryImpl implements GroupFactory {
 	}
 
 	public Group createGroup(ClientId c, byte[] descriptor) {
-		byte[] hash = crypto.hash(GroupId.LABEL, c.getBytes(), descriptor);
+		byte[] hash =
+				crypto.hash(GroupId.LABEL, StringUtils.toUtf8(c.getString()),
+						descriptor);
 		return new Group(new GroupId(hash), c, descriptor);
 	}
 }
diff --git a/briar-tests/src/org/briarproject/blogs/BlogManagerImplTest.java b/briar-tests/src/org/briarproject/blogs/BlogManagerImplTest.java
index 0e97c4c2f219e94085d076935f8aa5a53808ed87..552ebaf37bc8c9901bd2c5c6681cae394cb708e8 100644
--- a/briar-tests/src/org/briarproject/blogs/BlogManagerImplTest.java
+++ b/briar-tests/src/org/briarproject/blogs/BlogManagerImplTest.java
@@ -85,11 +85,6 @@ public class BlogManagerImplTest extends BriarTestCase {
 		message = new Message(messageId, blog1.getId(), 42, getRandomBytes(42));
 	}
 
-	@Test
-	public void testClientId() {
-		assertEquals(CLIENT_ID, blogManager.getClientId());
-	}
-
 	@Test
 	public void testCreateLocalState() throws DbException {
 		final Transaction txn = new Transaction(null, false);
diff --git a/briar-tests/src/org/briarproject/clients/MessageQueueManagerImplTest.java b/briar-tests/src/org/briarproject/clients/MessageQueueManagerImplTest.java
index 797251a1de031fdf4f12565c9c506311c873d8bf..39a166f4e76e0626d8539c6ecc209f78a8a26f00 100644
--- a/briar-tests/src/org/briarproject/clients/MessageQueueManagerImplTest.java
+++ b/briar-tests/src/org/briarproject/clients/MessageQueueManagerImplTest.java
@@ -43,7 +43,8 @@ import static org.junit.Assert.assertSame;
 public class MessageQueueManagerImplTest extends BriarTestCase {
 
 	private final GroupId groupId = new GroupId(TestUtils.getRandomId());
-	private final ClientId clientId = new ClientId(TestUtils.getRandomId());
+	private final ClientId clientId =
+			new ClientId(TestUtils.getRandomString(5));
 	private final byte[] descriptor = new byte[0];
 	private final Group group = new Group(groupId, clientId, descriptor);
 	private final long timestamp = System.currentTimeMillis();
diff --git a/briar-tests/src/org/briarproject/db/DatabaseComponentImplTest.java b/briar-tests/src/org/briarproject/db/DatabaseComponentImplTest.java
index f2be5bb18a30f389e147d5e4e173a964bed6315d..44c62675cb207a2352b6cfd9fb8bd4e30f0f90b5 100644
--- a/briar-tests/src/org/briarproject/db/DatabaseComponentImplTest.java
+++ b/briar-tests/src/org/briarproject/db/DatabaseComponentImplTest.java
@@ -90,7 +90,7 @@ public class DatabaseComponentImplTest extends BriarTestCase {
 	private final Contact contact;
 
 	public DatabaseComponentImplTest() {
-		clientId = new ClientId(TestUtils.getRandomId());
+		clientId = new ClientId(TestUtils.getRandomString(5));
 		groupId = new GroupId(TestUtils.getRandomId());
 		byte[] descriptor = new byte[0];
 		group = new Group(groupId, clientId, descriptor);
diff --git a/briar-tests/src/org/briarproject/db/H2DatabaseTest.java b/briar-tests/src/org/briarproject/db/H2DatabaseTest.java
index 473aac8050854257a368f9ef4ffa175f826529b6..e5f368a7c28b9ccb62ebe75487199175847f245e 100644
--- a/briar-tests/src/org/briarproject/db/H2DatabaseTest.java
+++ b/briar-tests/src/org/briarproject/db/H2DatabaseTest.java
@@ -81,7 +81,7 @@ public class H2DatabaseTest extends BriarTestCase {
 
 	public H2DatabaseTest() throws Exception {
 		groupId = new GroupId(TestUtils.getRandomId());
-		clientId = new ClientId(TestUtils.getRandomId());
+		clientId = new ClientId(TestUtils.getRandomString(5));
 		byte[] descriptor = new byte[0];
 		group = new Group(groupId, clientId, descriptor);
 		AuthorId authorId = new AuthorId(TestUtils.getRandomId());
@@ -601,7 +601,7 @@ public class H2DatabaseTest extends BriarTestCase {
 		List<Group> groups = new ArrayList<>();
 		for (int i = 0; i < 100; i++) {
 			GroupId id = new GroupId(TestUtils.getRandomId());
-			ClientId clientId = new ClientId(TestUtils.getRandomId());
+			ClientId clientId = new ClientId(TestUtils.getRandomString(5));
 			byte[] descriptor = new byte[0];
 			groups.add(new Group(id, clientId, descriptor));
 		}
diff --git a/briar-tests/src/org/briarproject/introduction/IntroductionManagerImplTest.java b/briar-tests/src/org/briarproject/introduction/IntroductionManagerImplTest.java
index 8bb138be366f7bb0d5344c64ff8f2dcc68dae856..e3c7d2ea5aee81a354f7870d9bee1f7c79bd075e 100644
--- a/briar-tests/src/org/briarproject/introduction/IntroductionManagerImplTest.java
+++ b/briar-tests/src/org/briarproject/introduction/IntroductionManagerImplTest.java
@@ -82,7 +82,7 @@ public class IntroductionManagerImplTest extends BriarTestCase {
 		introducee2 =
 				new Contact(contactId2, author2, localAuthorId2, true, true);
 
-		ClientId clientId = new ClientId(TestUtils.getRandomId());
+		ClientId clientId = new ClientId(TestUtils.getRandomString(5));
 		introductionGroup1 = new Group(new GroupId(TestUtils.getRandomId()),
 				clientId, new byte[0]);
 		introductionGroup2 = new Group(new GroupId(TestUtils.getRandomId()),
diff --git a/briar-tests/src/org/briarproject/introduction/IntroductionValidatorTest.java b/briar-tests/src/org/briarproject/introduction/IntroductionValidatorTest.java
index 19ea3b62b07613bd96fb7d7330488857a2d02171..3c1be62abf21d0b5788901ef44b18821178e3819 100644
--- a/briar-tests/src/org/briarproject/introduction/IntroductionValidatorTest.java
+++ b/briar-tests/src/org/briarproject/introduction/IntroductionValidatorTest.java
@@ -59,7 +59,7 @@ public class IntroductionValidatorTest extends BriarTestCase {
 
 	public IntroductionValidatorTest() {
 		GroupId groupId = new GroupId(TestUtils.getRandomId());
-		ClientId clientId = new ClientId(TestUtils.getRandomId());
+		ClientId clientId = new ClientId(TestUtils.getRandomString(5));
 		byte[] descriptor = TestUtils.getRandomBytes(12);
 		group = new Group(groupId, clientId, descriptor);
 
diff --git a/briar-tests/src/org/briarproject/introduction/MessageSenderTest.java b/briar-tests/src/org/briarproject/introduction/MessageSenderTest.java
index bf3fdde3c51e3d31d34b91c536904e9c692cdf32..56415f41c99a5dd6c86d9027f4c189d938b72144 100644
--- a/briar-tests/src/org/briarproject/introduction/MessageSenderTest.java
+++ b/briar-tests/src/org/briarproject/introduction/MessageSenderTest.java
@@ -61,7 +61,8 @@ public class MessageSenderTest extends BriarTestCase {
 		final Transaction txn = new Transaction(null, false);
 		final Group privateGroup =
 				new Group(new GroupId(TestUtils.getRandomId()),
-						new ClientId(TestUtils.getRandomId()), new byte[0]);
+						new ClientId(TestUtils.getRandomString(5)),
+						new byte[0]);
 		final SessionId sessionId = new SessionId(TestUtils.getRandomId());
 		byte[] mac = TestUtils.getRandomBytes(42);
 		byte[] sig = TestUtils.getRandomBytes(MAX_SIGNATURE_LENGTH);
diff --git a/briar-tests/src/org/briarproject/properties/TransportPropertyValidatorTest.java b/briar-tests/src/org/briarproject/properties/TransportPropertyValidatorTest.java
index f719479f166422ae1466aa997f7a32a9479ef3a0..a7798148c2f1caf0ce1d4c5c7548b924c438ae83 100644
--- a/briar-tests/src/org/briarproject/properties/TransportPropertyValidatorTest.java
+++ b/briar-tests/src/org/briarproject/properties/TransportPropertyValidatorTest.java
@@ -36,7 +36,7 @@ public class TransportPropertyValidatorTest extends BriarTestCase {
 		bdfDictionary = new BdfDictionary();
 
 		GroupId groupId = new GroupId(TestUtils.getRandomId());
-		ClientId clientId = new ClientId(TestUtils.getRandomId());
+		ClientId clientId = new ClientId(TestUtils.getRandomString(5));
 		byte[] descriptor = TestUtils.getRandomBytes(12);
 		group = new Group(groupId, clientId, descriptor);
 
diff --git a/briar-tests/src/org/briarproject/sync/ValidationManagerImplTest.java b/briar-tests/src/org/briarproject/sync/ValidationManagerImplTest.java
index edfc7154847521626cf96da7c9899c5fbc98aa6c..373f94f808637c41a719d3b534a526b79c0687ad 100644
--- a/briar-tests/src/org/briarproject/sync/ValidationManagerImplTest.java
+++ b/briar-tests/src/org/briarproject/sync/ValidationManagerImplTest.java
@@ -39,7 +39,8 @@ import static org.briarproject.api.sync.ValidationManager.State.UNKNOWN;
 
 public class ValidationManagerImplTest extends BriarTestCase {
 
-	private final ClientId clientId = new ClientId(TestUtils.getRandomId());
+	private final ClientId clientId =
+			new ClientId(TestUtils.getRandomString(5));
 	private final MessageId messageId = new MessageId(TestUtils.getRandomId());
 	private final MessageId messageId1 = new MessageId(TestUtils.getRandomId());
 	private final MessageId messageId2 = new MessageId(TestUtils.getRandomId());