diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/client/ContactGroupFactory.java b/bramble-api/src/main/java/org/briarproject/bramble/api/client/ContactGroupFactory.java
index d68f115fdc454f85013b8daecd5fd670145880cc..6b4ba6b4c23d022475c6f436050316c48ca996c7 100644
--- a/bramble-api/src/main/java/org/briarproject/bramble/api/client/ContactGroupFactory.java
+++ b/bramble-api/src/main/java/org/briarproject/bramble/api/client/ContactGroupFactory.java
@@ -12,18 +12,19 @@ public interface ContactGroupFactory {
 	/**
 	 * Creates a group that is not shared with any contacts.
 	 */
-	Group createLocalGroup(ClientId clientId);
+	Group createLocalGroup(ClientId clientId, int clientVersion);
 
 	/**
 	 * Creates a group for the given client to share with the given contact.
 	 */
-	Group createContactGroup(ClientId clientId, Contact contact);
+	Group createContactGroup(ClientId clientId, int clientVersion,
+			Contact contact);
 
 	/**
 	 * Creates a group for the given client to share between the given authors
 	 * identified by their AuthorIds.
 	 */
-	Group createContactGroup(ClientId clientId, AuthorId authorId1,
-			AuthorId authorId2);
+	Group createContactGroup(ClientId clientId, int clientVersion,
+			AuthorId authorId1, AuthorId authorId2);
 
 }
diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/contact/ContactExchangeTask.java b/bramble-api/src/main/java/org/briarproject/bramble/api/contact/ContactExchangeTask.java
index 5750c0e3b4d203a5bf6d829619383f8e89fdd0a4..f07fe3ea5a18d15fc4a64a48c5907197f36160ae 100644
--- a/bramble-api/src/main/java/org/briarproject/bramble/api/contact/ContactExchangeTask.java
+++ b/bramble-api/src/main/java/org/briarproject/bramble/api/contact/ContactExchangeTask.java
@@ -12,6 +12,11 @@ import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
 @NotNullByDefault
 public interface ContactExchangeTask {
 
+	/**
+	 * The current version of the contact exchange protocol
+	 */
+	int PROTOCOL_VERSION = 0;
+
 	/**
 	 * Label for deriving Alice's header key from the master secret.
 	 */
diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/crypto/CryptoComponent.java b/bramble-api/src/main/java/org/briarproject/bramble/api/crypto/CryptoComponent.java
index 3a2be304a6fbc9d2e1529eebf72fc7f8794c1832..c104f61d1310111389eb053b81dcaf6257a93e08 100644
--- a/bramble-api/src/main/java/org/briarproject/bramble/api/crypto/CryptoComponent.java
+++ b/bramble-api/src/main/java/org/briarproject/bramble/api/crypto/CryptoComponent.java
@@ -41,11 +41,11 @@ public interface CryptoComponent {
 	 * secret derived for another purpose
 	 * @param theirPublicKey the public key of the remote party
 	 * @param ourKeyPair the key pair of the local party
-	 * @param alice true if the local party is Alice
 	 * @return the shared secret
 	 */
 	SecretKey deriveSharedSecret(String label, PublicKey theirPublicKey,
-			KeyPair ourKeyPair, boolean alice) throws GeneralSecurityException;
+			KeyPair ourKeyPair, byte[]... inputs)
+			throws GeneralSecurityException;
 
 	/**
 	 * Signs the given byte[] with the given ECDSA private key.
diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/properties/TransportPropertyManager.java b/bramble-api/src/main/java/org/briarproject/bramble/api/properties/TransportPropertyManager.java
index 8a219c0c69e047878b7e6b4be70c709c5e3ae965..fe33328a358b9feda1c21fe4eda9f9411cb8e791 100644
--- a/bramble-api/src/main/java/org/briarproject/bramble/api/properties/TransportPropertyManager.java
+++ b/bramble-api/src/main/java/org/briarproject/bramble/api/properties/TransportPropertyManager.java
@@ -17,6 +17,11 @@ public interface TransportPropertyManager {
 	 */
 	ClientId CLIENT_ID = new ClientId("org.briarproject.briar.properties");
 
+	/**
+	 * The current version of the transport property client.
+	 */
+	int CLIENT_VERSION = 0;
+
 	/**
 	 * Stores the given properties received while adding a contact - they will
 	 * be superseded by any properties synced from the contact.
diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/sync/GroupFactory.java b/bramble-api/src/main/java/org/briarproject/bramble/api/sync/GroupFactory.java
index 999e1f93666933c124d492dcacd7dad1f352532a..844ded0e14863172165246aa13d534433c91df87 100644
--- a/bramble-api/src/main/java/org/briarproject/bramble/api/sync/GroupFactory.java
+++ b/bramble-api/src/main/java/org/briarproject/bramble/api/sync/GroupFactory.java
@@ -6,7 +6,7 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
 public interface GroupFactory {
 
 	/**
-	 * Creates a group with the given client ID and descriptor.
+	 * Creates a group with the given client ID, client version and descriptor.
 	 */
-	Group createGroup(ClientId c, byte[] descriptor);
+	Group createGroup(ClientId c, int clientVersion, byte[] descriptor);
 }
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/client/ContactGroupFactoryImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/client/ContactGroupFactoryImpl.java
index 0690553479ff74cfc67c95264c193115714152a8..fba2aa745a72fca908df892714ee9305df9ef02b 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/client/ContactGroupFactoryImpl.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/client/ContactGroupFactoryImpl.java
@@ -32,23 +32,25 @@ class ContactGroupFactoryImpl implements ContactGroupFactory {
 	}
 
 	@Override
-	public Group createLocalGroup(ClientId clientId) {
-		return groupFactory.createGroup(clientId, LOCAL_GROUP_DESCRIPTOR);
+	public Group createLocalGroup(ClientId clientId, int clientVersion) {
+		return groupFactory.createGroup(clientId, clientVersion,
+				LOCAL_GROUP_DESCRIPTOR);
 	}
 
 	@Override
-	public Group createContactGroup(ClientId clientId, Contact contact) {
+	public Group createContactGroup(ClientId clientId, int clientVersion,
+			Contact contact) {
 		AuthorId local = contact.getLocalAuthorId();
 		AuthorId remote = contact.getAuthor().getId();
 		byte[] descriptor = createGroupDescriptor(local, remote);
-		return groupFactory.createGroup(clientId, descriptor);
+		return groupFactory.createGroup(clientId, clientVersion, descriptor);
 	}
 
 	@Override
-	public Group createContactGroup(ClientId clientId, AuthorId authorId1,
-			AuthorId authorId2) {
+	public Group createContactGroup(ClientId clientId, int clientVersion,
+			AuthorId authorId1, AuthorId authorId2) {
 		byte[] descriptor = createGroupDescriptor(authorId1, authorId2);
-		return groupFactory.createGroup(clientId, descriptor);
+		return groupFactory.createGroup(clientId, clientVersion, descriptor);
 	}
 
 	private byte[] createGroupDescriptor(AuthorId local, AuthorId remote) {
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/contact/ContactExchangeTaskImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/contact/ContactExchangeTaskImpl.java
index 50a4f841cba5c01c95113c3c52bdb4eba537784c..773fa1aab72e4bdb044e0830f6ffc486fc789603 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/contact/ContactExchangeTaskImpl.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/contact/ContactExchangeTaskImpl.java
@@ -142,8 +142,9 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
 
 		// Derive the header keys for the transport streams
 		SecretKey aliceHeaderKey = crypto.deriveKey(ALICE_KEY_LABEL,
-				masterSecret);
-		SecretKey bobHeaderKey = crypto.deriveKey(BOB_KEY_LABEL, masterSecret);
+				masterSecret, new byte[] {PROTOCOL_VERSION});
+		SecretKey bobHeaderKey = crypto.deriveKey(BOB_KEY_LABEL, masterSecret,
+				new byte[] {PROTOCOL_VERSION});
 
 		// Create the readers
 		InputStream streamReader =
@@ -157,8 +158,10 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
 		BdfWriter w = bdfWriterFactory.createWriter(streamWriter);
 
 		// Derive the nonces to be signed
-		byte[] aliceNonce = crypto.mac(ALICE_NONCE_LABEL, masterSecret);
-		byte[] bobNonce = crypto.mac(BOB_NONCE_LABEL, masterSecret);
+		byte[] aliceNonce = crypto.mac(ALICE_NONCE_LABEL, masterSecret,
+				new byte[] {PROTOCOL_VERSION});
+		byte[] bobNonce = crypto.mac(BOB_NONCE_LABEL, masterSecret,
+				new byte[] {PROTOCOL_VERSION});
 
 		// Exchange pseudonyms, signed nonces, and timestamps
 		long localTimestamp = clock.currentTimeMillis();
@@ -197,8 +200,8 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
 
 		try {
 			// Add the contact
-			ContactId contactId = addContact(remoteAuthor, masterSecret,
-					timestamp, alice, remoteProperties);
+			ContactId contactId = addContact(remoteAuthor, timestamp,
+					remoteProperties);
 			// Reuse the connection as a transport connection
 			connectionManager.manageOutgoingConnection(contactId, transportId,
 					conn);
@@ -295,15 +298,15 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
 		return remote;
 	}
 
-	private ContactId addContact(Author remoteAuthor, SecretKey master,
-			long timestamp, boolean alice,
+	private ContactId addContact(Author remoteAuthor, long timestamp,
 			Map<TransportId, TransportProperties> remoteProperties)
 			throws DbException {
 		ContactId contactId;
 		Transaction txn = db.startTransaction(false);
 		try {
 			contactId = contactManager.addContact(txn, remoteAuthor,
-					localAuthor.getId(), master, timestamp, alice, true, true);
+					localAuthor.getId(), masterSecret, timestamp, alice,
+					true, true);
 			transportPropertyManager.addRemoteProperties(txn, contactId,
 					remoteProperties);
 			db.commitTransaction(txn);
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/crypto/CryptoComponentImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/crypto/CryptoComponentImpl.java
index 37af381df94e92420b5437bb5fc334d1521cc7ec..7eed7b5b7fd4e542e5f3766bc3ce2fdab81c48d6 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/crypto/CryptoComponentImpl.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/crypto/CryptoComponentImpl.java
@@ -227,18 +227,15 @@ class CryptoComponentImpl implements CryptoComponent {
 
 	@Override
 	public SecretKey deriveSharedSecret(String label, PublicKey theirPublicKey,
-			KeyPair ourKeyPair, boolean alice) throws GeneralSecurityException {
+			KeyPair ourKeyPair, byte[]... inputs)
+			throws GeneralSecurityException {
 		PrivateKey ourPriv = ourKeyPair.getPrivate();
-		byte[] raw = performRawKeyAgreement(ourPriv, theirPublicKey);
-		byte[] alicePub, bobPub;
-		if (alice) {
-			alicePub = ourKeyPair.getPublic().getEncoded();
-			bobPub = theirPublicKey.getEncoded();
-		} else {
-			alicePub = theirPublicKey.getEncoded();
-			bobPub = ourKeyPair.getPublic().getEncoded();
-		}
-		return new SecretKey(hash(label, raw, alicePub, bobPub));
+		byte[][] hashInputs = new byte[inputs.length + 1][];
+		hashInputs[0] = performRawKeyAgreement(ourPriv, theirPublicKey);
+		System.arraycopy(inputs, 0, hashInputs, 1, inputs.length);
+		byte[] hash = hash(label, hashInputs);
+		if (hash.length != SecretKey.LENGTH) throw new IllegalStateException();
+		return new SecretKey(hash);
 	}
 
 	@Override
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/keyagreement/KeyAgreementProtocol.java b/bramble-core/src/main/java/org/briarproject/bramble/keyagreement/KeyAgreementProtocol.java
index a5c24c6e4231101717ba2fc892f98875196b666c..ab5ea4f921ea361774d3b65395a8cc4f90503480 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/keyagreement/KeyAgreementProtocol.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/keyagreement/KeyAgreementProtocol.java
@@ -15,6 +15,7 @@ import java.security.GeneralSecurityException;
 import java.util.Arrays;
 
 import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.MASTER_SECRET_LABEL;
+import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.PROTOCOL_VERSION;
 import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.SHARED_SECRET_LABEL;
 
 /**
@@ -142,8 +143,15 @@ class KeyAgreementProtocol {
 	private SecretKey deriveSharedSecret(PublicKey theirPublicKey)
 			throws AbortException {
 		try {
+			byte[] ourPublicKeyBytes = ourKeyPair.getPublic().getEncoded();
+			byte[] theirPublicKeyBytes = theirPublicKey.getEncoded();
+			byte[][] inputs = {
+					new byte[] {PROTOCOL_VERSION},
+					alice ? ourPublicKeyBytes : theirPublicKeyBytes,
+					alice ? theirPublicKeyBytes : ourPublicKeyBytes
+			};
 			return crypto.deriveSharedSecret(SHARED_SECRET_LABEL,
-					theirPublicKey, ourKeyPair, alice);
+					theirPublicKey, ourKeyPair, inputs);
 		} catch (GeneralSecurityException e) {
 			throw new AbortException(e);
 		}
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/properties/TransportPropertyManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/properties/TransportPropertyManagerImpl.java
index 26ab19c330eaf756b87a1af7abf496efff2fc490..9f4a5bb528cb55d8c79777507199068879264788 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/properties/TransportPropertyManagerImpl.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/properties/TransportPropertyManagerImpl.java
@@ -58,7 +58,8 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
 		this.metadataParser = metadataParser;
 		this.contactGroupFactory = contactGroupFactory;
 		this.clock = clock;
-		localGroup = contactGroupFactory.createLocalGroup(CLIENT_ID);
+		localGroup = contactGroupFactory.createLocalGroup(CLIENT_ID,
+				CLIENT_VERSION);
 	}
 
 	@Override
@@ -287,7 +288,8 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
 	}
 
 	private Group getContactGroup(Contact c) {
-		return contactGroupFactory.createContactGroup(CLIENT_ID, c);
+		return contactGroupFactory.createContactGroup(CLIENT_ID,
+				CLIENT_VERSION, c);
 	}
 
 	private void storeMessage(Transaction txn, GroupId g, TransportId t,
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/sync/GroupFactoryImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/sync/GroupFactoryImpl.java
index 18065fc104976d888cbfdc1bf82b04ad92bb7d60..a28592bdce4338fe51939a39555d3cdcfecdd8a1 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/sync/GroupFactoryImpl.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/sync/GroupFactoryImpl.java
@@ -6,11 +6,16 @@ import org.briarproject.bramble.api.sync.ClientId;
 import org.briarproject.bramble.api.sync.Group;
 import org.briarproject.bramble.api.sync.GroupFactory;
 import org.briarproject.bramble.api.sync.GroupId;
+import org.briarproject.bramble.util.ByteUtils;
 import org.briarproject.bramble.util.StringUtils;
 
 import javax.annotation.concurrent.Immutable;
 import javax.inject.Inject;
 
+import static org.briarproject.bramble.api.sync.GroupId.LABEL;
+import static org.briarproject.bramble.api.sync.SyncConstants.PROTOCOL_VERSION;
+import static org.briarproject.bramble.util.ByteUtils.INT_32_BYTES;
+
 @Immutable
 @NotNullByDefault
 class GroupFactoryImpl implements GroupFactory {
@@ -23,9 +28,12 @@ class GroupFactoryImpl implements GroupFactory {
 	}
 
 	@Override
-	public Group createGroup(ClientId c, byte[] descriptor) {
-		byte[] hash = crypto.hash(GroupId.LABEL,
-				StringUtils.toUtf8(c.getString()), descriptor);
+	public Group createGroup(ClientId c, int clientVersion, byte[] descriptor) {
+		byte[] clientVersionBytes = new byte[INT_32_BYTES];
+		ByteUtils.writeUint32(clientVersion, clientVersionBytes, 0);
+		byte[] hash = crypto.hash(LABEL, new byte[] {PROTOCOL_VERSION},
+				StringUtils.toUtf8(c.getString()), clientVersionBytes,
+				descriptor);
 		return new Group(new GroupId(hash), c, descriptor);
 	}
 }
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/sync/MessageFactoryImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/sync/MessageFactoryImpl.java
index 7ca6824a3d2f6ecc0628dc1d392864c84bb341a1..e7a68d7d8a50d0328473b72bed38c9b92e341c2d 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/sync/MessageFactoryImpl.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/sync/MessageFactoryImpl.java
@@ -12,8 +12,10 @@ import org.briarproject.bramble.util.ByteUtils;
 import javax.annotation.concurrent.Immutable;
 import javax.inject.Inject;
 
+import static org.briarproject.bramble.api.sync.MessageId.LABEL;
 import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH;
 import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
+import static org.briarproject.bramble.api.sync.SyncConstants.PROTOCOL_VERSION;
 
 @Immutable
 @NotNullByDefault
@@ -32,9 +34,9 @@ class MessageFactoryImpl implements MessageFactory {
 			throw new IllegalArgumentException();
 		byte[] timeBytes = new byte[ByteUtils.INT_64_BYTES];
 		ByteUtils.writeUint64(timestamp, timeBytes, 0);
-		byte[] idHash =
-				crypto.hash(MessageId.LABEL, g.getBytes(), timeBytes, body);
-		MessageId id = new MessageId(idHash);
+		byte[] hash = crypto.hash(LABEL, new byte[] {PROTOCOL_VERSION},
+				g.getBytes(), timeBytes, body);
+		MessageId id = new MessageId(hash);
 		byte[] raw = new byte[MESSAGE_HEADER_LENGTH + body.length];
 		System.arraycopy(g.getBytes(), 0, raw, 0, UniqueId.LENGTH);
 		ByteUtils.writeUint64(timestamp, raw, UniqueId.LENGTH);
diff --git a/bramble-core/src/test/java/org/briarproject/bramble/crypto/KeyAgreementTest.java b/bramble-core/src/test/java/org/briarproject/bramble/crypto/KeyAgreementTest.java
index 1aec3b78fe14e7f5a5c9923a4698de8edf59f50f..5a3568631ca95d7846ae58df0ae5e3c1015d4285 100644
--- a/bramble-core/src/test/java/org/briarproject/bramble/crypto/KeyAgreementTest.java
+++ b/bramble-core/src/test/java/org/briarproject/bramble/crypto/KeyAgreementTest.java
@@ -7,7 +7,10 @@ import org.briarproject.bramble.test.BrambleTestCase;
 import org.briarproject.bramble.test.TestSecureRandomProvider;
 import org.junit.Test;
 
+import java.util.Random;
+
 import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.SHARED_SECRET_LABEL;
+import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
 import static org.junit.Assert.assertArrayEquals;
 
 public class KeyAgreementTest extends BrambleTestCase {
@@ -18,10 +21,14 @@ public class KeyAgreementTest extends BrambleTestCase {
 				new CryptoComponentImpl(new TestSecureRandomProvider());
 		KeyPair aPair = crypto.generateAgreementKeyPair();
 		KeyPair bPair = crypto.generateAgreementKeyPair();
+		Random random = new Random();
+		byte[][] inputs = new byte[random.nextInt(10) + 1][];
+		for (int i = 0; i < inputs.length; i++)
+			inputs[i] = getRandomBytes(random.nextInt(256));
 		SecretKey aShared = crypto.deriveSharedSecret(SHARED_SECRET_LABEL,
-				bPair.getPublic(), aPair, true);
+				bPair.getPublic(), aPair, inputs);
 		SecretKey bShared = crypto.deriveSharedSecret(SHARED_SECRET_LABEL,
-				aPair.getPublic(), bPair, false);
+				aPair.getPublic(), bPair, inputs);
 		assertArrayEquals(aShared.getBytes(), bShared.getBytes());
 	}
 }
diff --git a/bramble-core/src/test/java/org/briarproject/bramble/keyagreement/KeyAgreementProtocolTest.java b/bramble-core/src/test/java/org/briarproject/bramble/keyagreement/KeyAgreementProtocolTest.java
index c6c55ce0407b765f9832aa3c88eaa59ef3aaf64f..e070db6a9401d60c2470cf416518149b65f1cac7 100644
--- a/bramble-core/src/test/java/org/briarproject/bramble/keyagreement/KeyAgreementProtocolTest.java
+++ b/bramble-core/src/test/java/org/briarproject/bramble/keyagreement/KeyAgreementProtocolTest.java
@@ -18,6 +18,7 @@ import org.junit.Test;
 
 import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.COMMIT_LENGTH;
 import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.MASTER_SECRET_LABEL;
+import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.PROTOCOL_VERSION;
 import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.SHARED_SECRET_LABEL;
 import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
 import static org.briarproject.bramble.test.TestUtils.getSecretKey;
@@ -90,6 +91,10 @@ public class KeyAgreementProtocolTest extends BrambleTestCase {
 			will(returnValue(alicePubKeyBytes));
 			allowing(crypto).getAgreementKeyParser();
 			will(returnValue(keyParser));
+			allowing(alicePubKey).getEncoded();
+			will(returnValue(alicePubKeyBytes));
+			allowing(bobPubKey).getEncoded();
+			will(returnValue(bobPubKeyBytes));
 
 			// Alice sends her public key
 			oneOf(transport).sendKey(alicePubKeyBytes);
@@ -108,7 +113,8 @@ public class KeyAgreementProtocolTest extends BrambleTestCase {
 
 			// Alice computes shared secret
 			oneOf(crypto).deriveSharedSecret(SHARED_SECRET_LABEL, bobPubKey,
-					ourKeyPair, true);
+					ourKeyPair, new byte[] {PROTOCOL_VERSION},
+					alicePubKeyBytes, bobPubKeyBytes);
 			will(returnValue(sharedSecret));
 
 			// Alice sends her confirmation record
@@ -161,6 +167,10 @@ public class KeyAgreementProtocolTest extends BrambleTestCase {
 			will(returnValue(bobPubKeyBytes));
 			allowing(crypto).getAgreementKeyParser();
 			will(returnValue(keyParser));
+			allowing(alicePubKey).getEncoded();
+			will(returnValue(alicePubKeyBytes));
+			allowing(bobPubKey).getEncoded();
+			will(returnValue(bobPubKeyBytes));
 
 			// Bob receives Alice's public key
 			oneOf(transport).receiveKey();
@@ -178,7 +188,8 @@ public class KeyAgreementProtocolTest extends BrambleTestCase {
 
 			// Bob computes shared secret
 			oneOf(crypto).deriveSharedSecret(SHARED_SECRET_LABEL, alicePubKey,
-					ourKeyPair, false);
+					ourKeyPair, new byte[] {PROTOCOL_VERSION},
+					alicePubKeyBytes, bobPubKeyBytes);
 			will(returnValue(sharedSecret));
 
 			// Bob receives Alices's confirmation record
@@ -246,7 +257,8 @@ public class KeyAgreementProtocolTest extends BrambleTestCase {
 
 			// Alice never computes shared secret
 			never(crypto).deriveSharedSecret(SHARED_SECRET_LABEL, badPubKey,
-					ourKeyPair, true);
+					ourKeyPair, new byte[] {PROTOCOL_VERSION},
+					alicePubKeyBytes, bobPubKeyBytes);
 		}});
 
 		// execute
@@ -317,6 +329,8 @@ public class KeyAgreementProtocolTest extends BrambleTestCase {
 			will(returnValue(alicePubKeyBytes));
 			allowing(crypto).getAgreementKeyParser();
 			will(returnValue(keyParser));
+			allowing(bobPubKey).getEncoded();
+			will(returnValue(bobPubKeyBytes));
 
 			// Alice sends her public key
 			oneOf(transport).sendKey(alicePubKeyBytes);
@@ -335,7 +349,8 @@ public class KeyAgreementProtocolTest extends BrambleTestCase {
 
 			// Alice computes shared secret
 			oneOf(crypto).deriveSharedSecret(SHARED_SECRET_LABEL, bobPubKey,
-					ourKeyPair, true);
+					ourKeyPair, new byte[] {PROTOCOL_VERSION},
+					alicePubKeyBytes, bobPubKeyBytes);
 			will(returnValue(sharedSecret));
 
 			// Alice sends her confirmation record
@@ -389,6 +404,8 @@ public class KeyAgreementProtocolTest extends BrambleTestCase {
 			will(returnValue(bobPubKeyBytes));
 			allowing(crypto).getAgreementKeyParser();
 			will(returnValue(keyParser));
+			allowing(alicePubKey).getEncoded();
+			will(returnValue(alicePubKeyBytes));
 
 			// Bob receives Alice's public key
 			oneOf(transport).receiveKey();
@@ -406,7 +423,8 @@ public class KeyAgreementProtocolTest extends BrambleTestCase {
 
 			// Bob computes shared secret
 			oneOf(crypto).deriveSharedSecret(SHARED_SECRET_LABEL, alicePubKey,
-					ourKeyPair, false);
+					ourKeyPair, new byte[] {PROTOCOL_VERSION},
+					alicePubKeyBytes, bobPubKeyBytes);
 			will(returnValue(sharedSecret));
 
 			// Bob receives a bad confirmation record
diff --git a/bramble-core/src/test/java/org/briarproject/bramble/properties/TransportPropertyManagerImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/properties/TransportPropertyManagerImplTest.java
index c2f8dc044ce634be1e760c7ece3f841a6e243717..33a738557cca792f904540098d9f2c64c4743932 100644
--- a/bramble-core/src/test/java/org/briarproject/bramble/properties/TransportPropertyManagerImplTest.java
+++ b/bramble-core/src/test/java/org/briarproject/bramble/properties/TransportPropertyManagerImplTest.java
@@ -34,6 +34,7 @@ import java.util.Map;
 import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
 import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
 import static org.briarproject.bramble.api.properties.TransportPropertyManager.CLIENT_ID;
+import static org.briarproject.bramble.api.properties.TransportPropertyManager.CLIENT_VERSION;
 import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
 import static org.briarproject.bramble.api.sync.SyncConstants.MAX_GROUP_DESCRIPTOR_LENGTH;
 import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH;
@@ -78,7 +79,8 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
 
 	private TransportPropertyManagerImpl createInstance() {
 		context.checking(new Expectations() {{
-			oneOf(contactGroupFactory).createLocalGroup(CLIENT_ID);
+			oneOf(contactGroupFactory).createLocalGroup(CLIENT_ID,
+					CLIENT_VERSION);
 			will(returnValue(localGroup));
 		}});
 		return new TransportPropertyManagerImpl(db, clientHelper,
@@ -98,12 +100,14 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
 			oneOf(db).getContacts(txn);
 			will(returnValue(contacts));
 			// The first contact's group has already been set up
-			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact1);
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
+					CLIENT_VERSION, contact1);
 			will(returnValue(contactGroup1));
 			oneOf(db).containsGroup(txn, contactGroup1.getId());
 			will(returnValue(true));
 			// The second contact's group hasn't been set up
-			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact2);
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
+					CLIENT_VERSION, contact2);
 			will(returnValue(contactGroup2));
 			oneOf(db).containsGroup(txn, contactGroup2.getId());
 			will(returnValue(false));
@@ -130,7 +134,8 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
 
 		context.checking(new Expectations() {{
 			// Create the group and share it with the contact
-			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact);
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
+					CLIENT_VERSION, contact);
 			will(returnValue(contactGroup));
 			oneOf(db).containsGroup(txn, contactGroup.getId());
 			will(returnValue(false));
@@ -156,7 +161,8 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
 		Group contactGroup = getGroup();
 
 		context.checking(new Expectations() {{
-			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact);
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
+					CLIENT_VERSION, contact);
 			will(returnValue(contactGroup));
 			oneOf(db).removeGroup(txn, contactGroup);
 		}});
@@ -297,7 +303,8 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
 		context.checking(new Expectations() {{
 			oneOf(db).getContact(txn, contact.getId());
 			will(returnValue(contact));
-			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact);
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
+					CLIENT_VERSION, contact);
 			will(returnValue(contactGroup));
 		}});
 		expectStoreMessage(txn, contactGroup.getId(), "foo", fooPropertiesDict,
@@ -431,13 +438,15 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
 			will(returnValue(contacts));
 			// First contact: skipped because not active
 			// Second contact: no updates
-			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact2);
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
+					CLIENT_VERSION, contact2);
 			will(returnValue(contactGroup2));
 			oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
 					contactGroup2.getId());
 			will(returnValue(Collections.emptyMap()));
 			// Third contact: returns an update
-			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact3);
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
+					CLIENT_VERSION, contact3);
 			will(returnValue(contactGroup3));
 			oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
 					contactGroup3.getId());
@@ -507,7 +516,8 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
 			// Store the new properties in each contact's group, version 1
 			oneOf(db).getContacts(txn);
 			will(returnValue(Collections.singletonList(contact)));
-			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact);
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
+					CLIENT_VERSION, contact);
 			will(returnValue(contactGroup));
 			oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
 					contactGroup.getId());
@@ -559,7 +569,8 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
 			// Store the merged properties in each contact's group, version 2
 			oneOf(db).getContacts(txn);
 			will(returnValue(Collections.singletonList(contact)));
-			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact);
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
+					CLIENT_VERSION, contact);
 			will(returnValue(contactGroup));
 			oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
 					contactGroup.getId());
diff --git a/bramble-core/src/test/java/org/briarproject/bramble/sync/SyncIntegrationTest.java b/bramble-core/src/test/java/org/briarproject/bramble/sync/SyncIntegrationTest.java
index 7bb53e8435c05d56a0eec01b4eb944c4ab6a1cff..c5f3136129864c45040cfbce9bf63f5e7c5ffb88 100644
--- a/bramble-core/src/test/java/org/briarproject/bramble/sync/SyncIntegrationTest.java
+++ b/bramble-core/src/test/java/org/briarproject/bramble/sync/SyncIntegrationTest.java
@@ -22,7 +22,6 @@ import org.briarproject.bramble.api.transport.StreamReaderFactory;
 import org.briarproject.bramble.api.transport.StreamWriterFactory;
 import org.briarproject.bramble.test.BrambleTestCase;
 import org.briarproject.bramble.test.TestUtils;
-import org.briarproject.bramble.util.StringUtils;
 import org.junit.Test;
 
 import java.io.ByteArrayInputStream;
@@ -37,6 +36,7 @@ import javax.inject.Inject;
 import static org.briarproject.bramble.api.sync.SyncConstants.MAX_GROUP_DESCRIPTOR_LENGTH;
 import static org.briarproject.bramble.api.transport.TransportConstants.PROTOCOL_VERSION;
 import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH;
+import static org.briarproject.bramble.util.StringUtils.getRandomString;
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -79,9 +79,11 @@ public class SyncIntegrationTest extends BrambleTestCase {
 		headerKey = TestUtils.getSecretKey();
 		streamNumber = 123;
 		// Create a group
-		ClientId clientId = new ClientId(StringUtils.getRandomString(5));
+		ClientId clientId = new ClientId(getRandomString(123));
+		int clientVersion = 1234567890;
 		byte[] descriptor = new byte[MAX_GROUP_DESCRIPTOR_LENGTH];
-		Group group = groupFactory.createGroup(clientId, descriptor);
+		Group group = groupFactory.createGroup(clientId, clientVersion,
+				descriptor);
 		// Add two messages to the group
 		long timestamp = System.currentTimeMillis();
 		byte[] body = "Hello world".getBytes("UTF-8");
diff --git a/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogManager.java b/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogManager.java
index 4ad7e99eb7d4058271b74c147a7c19f1974aedc1..bbf1da0944381d3d290a682a29c7405285cd4525 100644
--- a/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogManager.java
+++ b/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogManager.java
@@ -17,10 +17,15 @@ import javax.annotation.Nullable;
 public interface BlogManager {
 
 	/**
-	 * Unique ID of the blog client.
+	 * The unique ID of the blog client.
 	 */
 	ClientId CLIENT_ID = new ClientId("org.briarproject.briar.blog");
 
+	/**
+	 * The current version of the blog client.
+	 */
+	int CLIENT_VERSION = 0;
+
 	/**
 	 * Adds the given {@link Blog).}
 	 */
diff --git a/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogSharingManager.java b/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogSharingManager.java
index 87f669bef0099f4f255b8a45fde8fbe60b78059c..e4b68bd6b42cf4576414e4f01ace74aacc66cde8 100644
--- a/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogSharingManager.java
+++ b/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogSharingManager.java
@@ -5,6 +5,13 @@ import org.briarproject.briar.api.sharing.SharingManager;
 
 public interface BlogSharingManager extends SharingManager<Blog> {
 
+	/**
+	 * The unique ID of the blog sharing client.
+	 */
 	ClientId CLIENT_ID = new ClientId("org.briarproject.briar.blog.sharing");
 
+	/**
+	 * The current version of the blog sharing client.
+	 */
+	int CLIENT_VERSION = 0;
 }
diff --git a/briar-api/src/main/java/org/briarproject/briar/api/feed/FeedManager.java b/briar-api/src/main/java/org/briarproject/briar/api/feed/FeedManager.java
index 7d83b22c151d70e37e69e7d04272001464b10a3b..50f67963a5e2d0bdc9367e068df28d05ed39d92e 100644
--- a/briar-api/src/main/java/org/briarproject/briar/api/feed/FeedManager.java
+++ b/briar-api/src/main/java/org/briarproject/briar/api/feed/FeedManager.java
@@ -15,6 +15,11 @@ public interface FeedManager {
 	 */
 	ClientId CLIENT_ID = new ClientId("org.briarproject.briar.feed");
 
+	/**
+	 * The current version of the RSS feed client.
+	 */
+	int CLIENT_VERSION = 0;
+
 	/**
 	 * Adds an RSS feed as a new dedicated blog.
 	 */
diff --git a/briar-api/src/main/java/org/briarproject/briar/api/forum/ForumManager.java b/briar-api/src/main/java/org/briarproject/briar/api/forum/ForumManager.java
index c861b4e63d72eb84c5dcae9f02e5a02353344826..8eb7eb1ad3504f31b38ccae8228873250574cfe8 100644
--- a/briar-api/src/main/java/org/briarproject/briar/api/forum/ForumManager.java
+++ b/briar-api/src/main/java/org/briarproject/briar/api/forum/ForumManager.java
@@ -22,6 +22,11 @@ public interface ForumManager {
 	 */
 	ClientId CLIENT_ID = new ClientId("org.briarproject.briar.forum");
 
+	/**
+	 * The current version of the forum client.
+	 */
+	int CLIENT_VERSION = 0;
+
 	/**
 	 * Subscribes to a forum.
 	 */
diff --git a/briar-api/src/main/java/org/briarproject/briar/api/forum/ForumSharingManager.java b/briar-api/src/main/java/org/briarproject/briar/api/forum/ForumSharingManager.java
index 85bdf53da858e17ccecba833e23c2655f7c6ea47..5620e024c11f99af1886f0fe51be03ae3a58138a 100644
--- a/briar-api/src/main/java/org/briarproject/briar/api/forum/ForumSharingManager.java
+++ b/briar-api/src/main/java/org/briarproject/briar/api/forum/ForumSharingManager.java
@@ -5,6 +5,13 @@ import org.briarproject.briar.api.sharing.SharingManager;
 
 public interface ForumSharingManager extends SharingManager<Forum> {
 
+	/**
+	 * The unique ID of the forum sharing client.
+	 */
 	ClientId CLIENT_ID = new ClientId("org.briarproject.briar.forum.sharing");
 
+	/**
+	 * The current version of the forum sharing client.
+	 */
+	int CLIENT_VERSION = 0;
 }
diff --git a/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionManager.java b/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionManager.java
index a9b8660813a247413c3e8f8a6e9b2186cb428382..ce9d067277fabd9aed94a254f3c86f2b47ee3775 100644
--- a/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionManager.java
+++ b/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionManager.java
@@ -21,6 +21,11 @@ public interface IntroductionManager extends ConversationClient {
 	 */
 	ClientId CLIENT_ID = new ClientId("org.briarproject.briar.introduction");
 
+	/**
+	 * The current version of the introduction client.
+	 */
+	int CLIENT_VERSION = 0;
+
 	/**
 	 * Sends two initial introduction messages.
 	 */
diff --git a/briar-api/src/main/java/org/briarproject/briar/api/messaging/MessagingManager.java b/briar-api/src/main/java/org/briarproject/briar/api/messaging/MessagingManager.java
index c2b80fc4625b4c87159f9c6aec881c72b239a74a..65f406a6faa8bb9274110ee54af624136982fff4 100644
--- a/briar-api/src/main/java/org/briarproject/briar/api/messaging/MessagingManager.java
+++ b/briar-api/src/main/java/org/briarproject/briar/api/messaging/MessagingManager.java
@@ -18,6 +18,11 @@ public interface MessagingManager extends ConversationClient {
 	 */
 	ClientId CLIENT_ID = new ClientId("org.briarproject.briar.messaging");
 
+	/**
+	 * The current version of the messaging client.
+	 */
+	int CLIENT_VERSION = 0;
+
 	/**
 	 * Stores a local private message.
 	 */
diff --git a/briar-api/src/main/java/org/briarproject/briar/api/privategroup/PrivateGroupManager.java b/briar-api/src/main/java/org/briarproject/briar/api/privategroup/PrivateGroupManager.java
index aa4b7d45828d2a3d6e279a66f87801a940a5036c..7d08ae016dfd8e6be85c03eafe7cd35dbb9f6017 100644
--- a/briar-api/src/main/java/org/briarproject/briar/api/privategroup/PrivateGroupManager.java
+++ b/briar-api/src/main/java/org/briarproject/briar/api/privategroup/PrivateGroupManager.java
@@ -21,6 +21,11 @@ public interface PrivateGroupManager {
 	 */
 	ClientId CLIENT_ID = new ClientId("org.briarproject.briar.privategroup");
 
+	/**
+	 * The current version of the private group client.
+	 */
+	int CLIENT_VERSION = 0;
+
 	/**
 	 * Adds a new private group and joins it.
 	 *
diff --git a/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationManager.java b/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationManager.java
index 6fc4c57e440e0210515b106fbd5fa9897d5fb090..fc3ca339f30ba6f9c9822dcc9944c6728e3493bf 100644
--- a/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationManager.java
+++ b/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationManager.java
@@ -25,6 +25,11 @@ public interface GroupInvitationManager extends ConversationClient {
 	ClientId CLIENT_ID =
 			new ClientId("org.briarproject.briar.privategroup.invitation");
 
+	/**
+	 * The current version of the private group invitation client.
+	 */
+	int CLIENT_VERSION = 0;
+
 	/**
 	 * Sends an invitation to share the given private group with the given
 	 * contact, including an optional message.
diff --git a/briar-core/src/main/java/org/briarproject/briar/blog/BlogFactoryImpl.java b/briar-core/src/main/java/org/briarproject/briar/blog/BlogFactoryImpl.java
index 6410d69bcd03fbb2ce42704777a8d983894508bd..8cf9d024a295d93fc424dbf87cb7a1a6950dc898 100644
--- a/briar-core/src/main/java/org/briarproject/briar/blog/BlogFactoryImpl.java
+++ b/briar-core/src/main/java/org/briarproject/briar/blog/BlogFactoryImpl.java
@@ -16,6 +16,8 @@ import javax.inject.Inject;
 
 import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
 import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
+import static org.briarproject.briar.api.blog.BlogManager.CLIENT_ID;
+import static org.briarproject.briar.api.blog.BlogManager.CLIENT_VERSION;
 
 @Immutable
 @NotNullByDefault
@@ -52,8 +54,8 @@ class BlogFactoryImpl implements BlogFactory {
 					rssFeed
 			);
 			byte[] descriptor = clientHelper.toByteArray(blog);
-			Group g = groupFactory
-					.createGroup(BlogManagerImpl.CLIENT_ID, descriptor);
+			Group g = groupFactory.createGroup(CLIENT_ID, CLIENT_VERSION,
+					descriptor);
 			return new Blog(g, a, rssFeed);
 		} catch (FormatException e) {
 			throw new RuntimeException(e);
diff --git a/briar-core/src/main/java/org/briarproject/briar/blog/BlogPostValidator.java b/briar-core/src/main/java/org/briarproject/briar/blog/BlogPostValidator.java
index 6fa9be04f19f36a8aaa31cccbd628dd9c357547b..84c5877c20699bbb979460f8017181a16799f123 100644
--- a/briar-core/src/main/java/org/briarproject/briar/blog/BlogPostValidator.java
+++ b/briar-core/src/main/java/org/briarproject/briar/blog/BlogPostValidator.java
@@ -45,6 +45,8 @@ import static org.briarproject.briar.api.blog.BlogConstants.KEY_TIME_RECEIVED;
 import static org.briarproject.briar.api.blog.BlogConstants.KEY_TYPE;
 import static org.briarproject.briar.api.blog.BlogConstants.MAX_BLOG_COMMENT_LENGTH;
 import static org.briarproject.briar.api.blog.BlogConstants.MAX_BLOG_POST_BODY_LENGTH;
+import static org.briarproject.briar.api.blog.BlogManager.CLIENT_ID;
+import static org.briarproject.briar.api.blog.BlogManager.CLIENT_VERSION;
 import static org.briarproject.briar.api.blog.BlogPostFactory.SIGNING_LABEL_COMMENT;
 import static org.briarproject.briar.api.blog.BlogPostFactory.SIGNING_LABEL_POST;
 import static org.briarproject.briar.api.blog.MessageType.COMMENT;
@@ -199,8 +201,8 @@ class BlogPostValidator extends BdfMessageValidator {
 		checkLength(signature, 1, MAX_SIGNATURE_LENGTH);
 
 		// Get and Validate the Wrapped Message
-		Group wGroup = groupFactory
-				.createGroup(BlogManagerImpl.CLIENT_ID, descriptor);
+		Group wGroup = groupFactory.createGroup(CLIENT_ID, CLIENT_VERSION,
+				descriptor);
 		Blog wBlog = blogFactory.parseBlog(wGroup);
 		BdfList wBodyList = BdfList.of(POST.getInt(), content, signature);
 		byte[] wBody = clientHelper.toByteArray(wBodyList);
@@ -262,8 +264,8 @@ class BlogPostValidator extends BdfMessageValidator {
 		MessageId parentId = new MessageId(parentIdBytes);
 
 		// Get and Validate the Wrapped Comment
-		Group wGroup = groupFactory
-				.createGroup(BlogManagerImpl.CLIENT_ID, descriptor);
+		Group wGroup = groupFactory.createGroup(CLIENT_ID, CLIENT_VERSION,
+				descriptor);
 		BdfList wBodyList = BdfList.of(COMMENT.getInt(), comment, pOriginalId,
 				oldId, signature);
 		byte[] wBody = clientHelper.toByteArray(wBodyList);
diff --git a/briar-core/src/main/java/org/briarproject/briar/client/QueueMessageFactoryImpl.java b/briar-core/src/main/java/org/briarproject/briar/client/QueueMessageFactoryImpl.java
index 4dcc471ada1f6b79ef7b98081f98393f8a8cb38d..da8cb1426e996a2daa75c1503afce11c250e6baf 100644
--- a/briar-core/src/main/java/org/briarproject/briar/client/QueueMessageFactoryImpl.java
+++ b/briar-core/src/main/java/org/briarproject/briar/client/QueueMessageFactoryImpl.java
@@ -12,8 +12,10 @@ import org.briarproject.briar.api.client.QueueMessageFactory;
 import javax.annotation.concurrent.Immutable;
 import javax.inject.Inject;
 
+import static org.briarproject.bramble.api.sync.MessageId.LABEL;
 import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_LENGTH;
 import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
+import static org.briarproject.bramble.api.sync.SyncConstants.PROTOCOL_VERSION;
 import static org.briarproject.bramble.util.ByteUtils.INT_64_BYTES;
 import static org.briarproject.briar.api.client.QueueMessage.MAX_QUEUE_MESSAGE_BODY_LENGTH;
 import static org.briarproject.briar.api.client.QueueMessage.QUEUE_MESSAGE_HEADER_LENGTH;
@@ -45,9 +47,9 @@ class QueueMessageFactoryImpl implements QueueMessageFactory {
 		byte[] bodyBytes = new byte[body.length + INT_64_BYTES];
 		System.arraycopy(raw, MESSAGE_HEADER_LENGTH, bodyBytes, 0,
 				body.length + INT_64_BYTES);
-		MessageId id = new MessageId(
-				crypto.hash(MessageId.LABEL, groupId.getBytes(), timeBytes,
-						bodyBytes));
+		byte[] hash = crypto.hash(LABEL, new byte[] {PROTOCOL_VERSION},
+				groupId.getBytes(), timeBytes, bodyBytes);
+		MessageId id = new MessageId(hash);
 		return new QueueMessage(id, groupId, timestamp, queuePosition, raw);
 	}
 
diff --git a/briar-core/src/main/java/org/briarproject/briar/feed/FeedManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/feed/FeedManagerImpl.java
index 3857f1fb5572cc5eb78f74474d503ff1603b8e8e..f4d94413d9634fd6861b5799a77e849682c55d99 100644
--- a/briar-core/src/main/java/org/briarproject/briar/feed/FeedManagerImpl.java
+++ b/briar-core/src/main/java/org/briarproject/briar/feed/FeedManagerImpl.java
@@ -496,7 +496,7 @@ class FeedManagerImpl implements FeedManager, Client, EventListener,
 	}
 
 	private Group getLocalGroup() {
-		return contactGroupFactory.createLocalGroup(CLIENT_ID);
+		return contactGroupFactory.createLocalGroup(CLIENT_ID, CLIENT_VERSION);
 	}
 
 }
diff --git a/briar-core/src/main/java/org/briarproject/briar/forum/ForumFactoryImpl.java b/briar-core/src/main/java/org/briarproject/briar/forum/ForumFactoryImpl.java
index 5570d52542fcc8eed76d7bd51bbb8ae973dd32a7..d540661ec65a10b3b69efbe01bfb40e01f036fb6 100644
--- a/briar-core/src/main/java/org/briarproject/briar/forum/ForumFactoryImpl.java
+++ b/briar-core/src/main/java/org/briarproject/briar/forum/ForumFactoryImpl.java
@@ -18,6 +18,7 @@ import javax.inject.Inject;
 import static org.briarproject.briar.api.forum.ForumConstants.FORUM_SALT_LENGTH;
 import static org.briarproject.briar.api.forum.ForumConstants.MAX_FORUM_NAME_LENGTH;
 import static org.briarproject.briar.api.forum.ForumManager.CLIENT_ID;
+import static org.briarproject.briar.api.forum.ForumManager.CLIENT_VERSION;
 
 @Immutable
 @NotNullByDefault
@@ -52,7 +53,8 @@ class ForumFactoryImpl implements ForumFactory {
 		try {
 			BdfList forum = BdfList.of(name, salt);
 			byte[] descriptor = clientHelper.toByteArray(forum);
-			Group g = groupFactory.createGroup(CLIENT_ID, descriptor);
+			Group g = groupFactory.createGroup(CLIENT_ID, CLIENT_VERSION,
+					descriptor);
 			return new Forum(g, name, salt);
 		} catch (FormatException e) {
 			throw new AssertionError(e);
diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeManager.java b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeManager.java
index 6ecfcef49cfa0b54d7ef7c305a7eedf66153f352..1bf8ea37a82c7ea00c276632813a88d47fe78063 100644
--- a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeManager.java
+++ b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeManager.java
@@ -96,6 +96,7 @@ import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE
 import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_ABORT;
 import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_ACK;
 import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_RESPONSE;
+import static org.briarproject.briar.api.introduction.IntroductionManager.CLIENT_VERSION;
 
 @Immutable
 @NotNullByDefault
@@ -433,8 +434,13 @@ class IntroduceeManager {
 
 		// The shared secret is derived from the local ephemeral key pair
 		// and the remote ephemeral public key
+		byte[][] inputs = {
+				new byte[] {CLIENT_VERSION},
+				alice ? ourPublicKeyBytes : theirPublicKeyBytes,
+				alice ? theirPublicKeyBytes : ourPublicKeyBytes
+		};
 		return cryptoComponent.deriveSharedSecret(SHARED_SECRET_LABEL,
-				theirPublicKey, ourKeyPair, alice);
+				theirPublicKey, ourKeyPair, inputs);
 	}
 
 	/**
diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionGroupFactory.java b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionGroupFactory.java
index 8aadc03d72eb4016826986fe36b0248ab36e7914..050d2b9f4430bcf38f950ea6c3dd941d0ac44cd2 100644
--- a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionGroupFactory.java
+++ b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionGroupFactory.java
@@ -7,6 +7,7 @@ import org.briarproject.bramble.api.sync.Group;
 import javax.inject.Inject;
 
 import static org.briarproject.briar.api.introduction.IntroductionManager.CLIENT_ID;
+import static org.briarproject.briar.api.introduction.IntroductionManager.CLIENT_VERSION;
 
 class IntroductionGroupFactory {
 
@@ -16,14 +17,16 @@ class IntroductionGroupFactory {
 	@Inject
 	IntroductionGroupFactory(ContactGroupFactory contactGroupFactory) {
 		this.contactGroupFactory = contactGroupFactory;
-		localGroup = contactGroupFactory.createLocalGroup(CLIENT_ID);
+		localGroup = contactGroupFactory.createLocalGroup(CLIENT_ID,
+				CLIENT_VERSION);
 	}
 
 	Group createIntroductionGroup(Contact c) {
-		return contactGroupFactory.createContactGroup(CLIENT_ID, c);
+		return contactGroupFactory.createContactGroup(CLIENT_ID,
+				CLIENT_VERSION, c);
 	}
 
-	public Group createLocalGroup() {
+	Group createLocalGroup() {
 		return localGroup;
 	}
 
diff --git a/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingManagerImpl.java
index 2305dd47bed4b5c0e251add9fad57a5fd7acb519..c67d5913568770b3d45cf6b0e6d163a86073fbac 100644
--- a/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingManagerImpl.java
+++ b/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingManagerImpl.java
@@ -79,7 +79,8 @@ class MessagingManagerImpl extends ConversationClientImpl
 
 	@Override
 	public Group getContactGroup(Contact c) {
-		return contactGroupFactory.createContactGroup(CLIENT_ID, c);
+		return contactGroupFactory.createContactGroup(CLIENT_ID,
+				CLIENT_VERSION, c);
 	}
 
 	@Override
diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/PrivateGroupFactoryImpl.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/PrivateGroupFactoryImpl.java
index 4a19e68ebbe127840874063cc135a902953e5f80..bcf7846d62188ae676433a6ce6defa14d2cf1b30 100644
--- a/briar-core/src/main/java/org/briarproject/briar/privategroup/PrivateGroupFactoryImpl.java
+++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/PrivateGroupFactoryImpl.java
@@ -20,6 +20,7 @@ import javax.inject.Inject;
 import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.GROUP_SALT_LENGTH;
 import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.MAX_GROUP_NAME_LENGTH;
 import static org.briarproject.briar.api.privategroup.PrivateGroupManager.CLIENT_ID;
+import static org.briarproject.briar.api.privategroup.PrivateGroupManager.CLIENT_VERSION;
 
 @Immutable
 @NotNullByDefault
@@ -64,7 +65,8 @@ class PrivateGroupFactoryImpl implements PrivateGroupFactory {
 					salt
 			);
 			byte[] descriptor = clientHelper.toByteArray(group);
-			Group g = groupFactory.createGroup(CLIENT_ID, descriptor);
+			Group g = groupFactory.createGroup(CLIENT_ID, CLIENT_VERSION,
+					descriptor);
 			return new PrivateGroup(g, name, author, salt);
 		} catch (FormatException e) {
 			throw new RuntimeException(e);
diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationFactoryImpl.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationFactoryImpl.java
index d527674737daa3f52466a8cb5c51b58e9d7fcee5..29ca211f6debe399d920fe954aebc30be956fef1 100644
--- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationFactoryImpl.java
+++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationFactoryImpl.java
@@ -17,6 +17,7 @@ import javax.annotation.concurrent.Immutable;
 import javax.inject.Inject;
 
 import static org.briarproject.briar.api.privategroup.invitation.GroupInvitationManager.CLIENT_ID;
+import static org.briarproject.briar.api.privategroup.invitation.GroupInvitationManager.CLIENT_VERSION;
 
 @Immutable
 @NotNullByDefault
@@ -52,7 +53,7 @@ class GroupInvitationFactoryImpl implements GroupInvitationFactory {
 	public BdfList createInviteToken(AuthorId creatorId, AuthorId memberId,
 			GroupId privateGroupId, long timestamp) {
 		Group contactGroup = contactGroupFactory.createContactGroup(CLIENT_ID,
-				creatorId, memberId);
+				CLIENT_VERSION, creatorId, memberId);
 		return BdfList.of(
 				timestamp,
 				contactGroup.getId(),
diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImpl.java
index 1ae598c837aa6796dde6257e50a8baa561f33a48..0125b5e53ea5c3dead9346f5fa24a22948068535 100644
--- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImpl.java
+++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImpl.java
@@ -132,7 +132,8 @@ class GroupInvitationManagerImpl extends ConversationClientImpl
 
 	@Override
 	public Group getContactGroup(Contact c) {
-		return contactGroupFactory.createContactGroup(CLIENT_ID, c);
+		return contactGroupFactory.createContactGroup(CLIENT_ID,
+				CLIENT_VERSION, c);
 	}
 
 	@Override
diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/BlogSharingManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/sharing/BlogSharingManagerImpl.java
index f095aba4664968cffa4150e7e969c7a868d6d676..4c7863cd5b631bbaf9cd10dd1ee9d53d5417a4e1 100644
--- a/briar-core/src/main/java/org/briarproject/briar/sharing/BlogSharingManagerImpl.java
+++ b/briar-core/src/main/java/org/briarproject/briar/sharing/BlogSharingManagerImpl.java
@@ -51,6 +51,11 @@ class BlogSharingManagerImpl extends SharingManagerImpl<Blog>
 		return CLIENT_ID;
 	}
 
+	@Override
+	protected int getClientVersion() {
+		return CLIENT_VERSION;
+	}
+
 	/**
 	 * This is called during each startup for each existing Contact.
 	 */
diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/ForumSharingManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/sharing/ForumSharingManagerImpl.java
index c91fac76e6b687d0ee892de225620bf24dfb844b..528743b9cc6ba65d939f8db3c27ab7014d8e3b36 100644
--- a/briar-core/src/main/java/org/briarproject/briar/sharing/ForumSharingManagerImpl.java
+++ b/briar-core/src/main/java/org/briarproject/briar/sharing/ForumSharingManagerImpl.java
@@ -38,6 +38,11 @@ class ForumSharingManagerImpl extends SharingManagerImpl<Forum>
 		return CLIENT_ID;
 	}
 
+	@Override
+	protected int getClientVersion() {
+		return CLIENT_VERSION;
+	}
+
 	@Override
 	public void removingForum(Transaction txn, Forum f) throws DbException {
 		removingShareable(txn, f);
diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/SharingManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/sharing/SharingManagerImpl.java
index 75ab728ff85b16f00b0a8989b6ef58f611c674b8..b70fb74eaf3939733355483a232c8fcd50f9fbd0 100644
--- a/briar-core/src/main/java/org/briarproject/briar/sharing/SharingManagerImpl.java
+++ b/briar-core/src/main/java/org/briarproject/briar/sharing/SharingManagerImpl.java
@@ -80,6 +80,8 @@ abstract class SharingManagerImpl<S extends Shareable>
 
 	protected abstract ClientId getClientId();
 
+	protected abstract int getClientVersion();
+
 	@Override
 	public void createLocalState(Transaction txn) throws DbException {
 		// Ensure we've set things up for any pre-existing contacts
@@ -113,7 +115,8 @@ abstract class SharingManagerImpl<S extends Shareable>
 
 	@Override
 	public Group getContactGroup(Contact c) {
-		return contactGroupFactory.createContactGroup(getClientId(), c);
+		return contactGroupFactory.createContactGroup(getClientId(),
+				getClientVersion(), c);
 	}
 
 	@Override
diff --git a/briar-core/src/test/java/org/briarproject/briar/blog/BlogPostValidatorTest.java b/briar-core/src/test/java/org/briarproject/briar/blog/BlogPostValidatorTest.java
index 988e3d48b932b19f8aa14ac7e9f17902e1531b64..3a7877a7802f23db87e6bc8797ee25364bf8efbf 100644
--- a/briar-core/src/test/java/org/briarproject/briar/blog/BlogPostValidatorTest.java
+++ b/briar-core/src/test/java/org/briarproject/briar/blog/BlogPostValidatorTest.java
@@ -8,7 +8,6 @@ import org.briarproject.bramble.api.data.BdfList;
 import org.briarproject.bramble.api.data.MetadataEncoder;
 import org.briarproject.bramble.api.identity.Author;
 import org.briarproject.bramble.api.identity.AuthorId;
-import org.briarproject.bramble.api.sync.ClientId;
 import org.briarproject.bramble.api.sync.Group;
 import org.briarproject.bramble.api.sync.GroupFactory;
 import org.briarproject.bramble.api.sync.GroupId;
@@ -40,6 +39,8 @@ import static org.briarproject.briar.api.blog.BlogConstants.KEY_PARENT_MSG_ID;
 import static org.briarproject.briar.api.blog.BlogConstants.KEY_PUBLIC_KEY;
 import static org.briarproject.briar.api.blog.BlogConstants.KEY_READ;
 import static org.briarproject.briar.api.blog.BlogConstants.KEY_RSS_FEED;
+import static org.briarproject.briar.api.blog.BlogManager.CLIENT_ID;
+import static org.briarproject.briar.api.blog.BlogManager.CLIENT_VERSION;
 import static org.briarproject.briar.api.blog.BlogPostFactory.SIGNING_LABEL_COMMENT;
 import static org.briarproject.briar.api.blog.BlogPostFactory.SIGNING_LABEL_POST;
 import static org.briarproject.briar.api.blog.MessageType.COMMENT;
@@ -54,7 +55,6 @@ public class BlogPostValidatorTest extends BriarTestCase {
 	private final Mockery context = new Mockery();
 	private final Blog blog, rssBlog;
 	private final BdfDictionary authorDict;
-	private final ClientId clientId;
 	private final byte[] descriptor;
 	private final Group group;
 	private final Message message;
@@ -69,9 +69,8 @@ public class BlogPostValidatorTest extends BriarTestCase {
 
 	public BlogPostValidatorTest() {
 		GroupId groupId = new GroupId(TestUtils.getRandomId());
-		clientId = BlogManagerImpl.CLIENT_ID;
 		descriptor = TestUtils.getRandomBytes(42);
-		group = new Group(groupId, clientId, descriptor);
+		group = new Group(groupId, CLIENT_ID, descriptor);
 		AuthorId authorId =
 				new AuthorId(TestUtils.getRandomBytes(AuthorId.LENGTH));
 		byte[] publicKey = TestUtils.getRandomBytes(MAX_PUBLIC_KEY_LENGTH);
@@ -215,7 +214,8 @@ public class BlogPostValidatorTest extends BriarTestCase {
 		byte[] originalBody = TestUtils.getRandomBytes(42);
 
 		context.checking(new Expectations() {{
-			oneOf(groupFactory).createGroup(clientId, descriptor);
+			oneOf(groupFactory).createGroup(CLIENT_ID, CLIENT_VERSION,
+					descriptor);
 			will(returnValue(b.getGroup()));
 			oneOf(blogFactory).parseBlog(b.getGroup());
 			will(returnValue(b));
@@ -258,7 +258,8 @@ public class BlogPostValidatorTest extends BriarTestCase {
 		byte[] originalBody = TestUtils.getRandomBytes(42);
 
 		context.checking(new Expectations() {{
-			oneOf(groupFactory).createGroup(clientId, descriptor);
+			oneOf(groupFactory).createGroup(CLIENT_ID, CLIENT_VERSION,
+					descriptor);
 			will(returnValue(blog.getGroup()));
 			oneOf(clientHelper).toByteArray(originalList);
 			will(returnValue(originalBody));
diff --git a/briar-core/src/test/java/org/briarproject/briar/feed/FeedManagerImplTest.java b/briar-core/src/test/java/org/briarproject/briar/feed/FeedManagerImplTest.java
index e8e914dc88924ec6af7936ac70af442dcf88c5ac..2f7953311f1fdb0aba6934210aa2a990c011df9a 100644
--- a/briar-core/src/test/java/org/briarproject/briar/feed/FeedManagerImplTest.java
+++ b/briar-core/src/test/java/org/briarproject/briar/feed/FeedManagerImplTest.java
@@ -42,6 +42,7 @@ import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
 import static org.briarproject.bramble.test.TestUtils.getRandomId;
 import static org.briarproject.briar.api.feed.FeedConstants.KEY_FEEDS;
 import static org.briarproject.briar.api.feed.FeedManager.CLIENT_ID;
+import static org.briarproject.briar.api.feed.FeedManager.CLIENT_VERSION;
 
 public class FeedManagerImplTest extends BrambleMockTestCase {
 
@@ -133,7 +134,8 @@ public class FeedManagerImplTest extends BrambleMockTestCase {
 
 	private void expectGetLocalGroup() {
 		context.checking(new Expectations() {{
-			oneOf(contactGroupFactory).createLocalGroup(CLIENT_ID);
+			oneOf(contactGroupFactory).createLocalGroup(CLIENT_ID,
+					CLIENT_VERSION);
 			will(returnValue(localGroup));
 		}});
 	}
diff --git a/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionIntegrationTest.java
index b6b088f9d5293f86e3a29ed9e630ca0cf54fb268..896bdc2a31bec4946f57b39732c61f1dd4d81321 100644
--- a/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionIntegrationTest.java
+++ b/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionIntegrationTest.java
@@ -75,6 +75,7 @@ import static org.briarproject.briar.api.introduction.IntroductionConstants.TRAN
 import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE;
 import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_REQUEST;
 import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_RESPONSE;
+import static org.briarproject.briar.api.introduction.IntroductionManager.CLIENT_VERSION;
 import static org.briarproject.briar.test.BriarTestUtils.assertGroupCount;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -753,8 +754,13 @@ public class IntroductionIntegrationTest
 		KeyPair eKeyPair2 = crypto.generateAgreementKeyPair();
 
 		// Nonce 1
+		byte[][] inputs = {
+				new byte[] {CLIENT_VERSION},
+				eKeyPair1.getPublic().getEncoded(),
+				eKeyPair2.getPublic().getEncoded()
+		};
 		SecretKey sharedSecret = crypto.deriveSharedSecret(SHARED_SECRET_LABEL,
-				eKeyPair2.getPublic(), eKeyPair1, true);
+				eKeyPair2.getPublic(), eKeyPair1, inputs);
 		byte[] nonce1 = crypto.mac(ALICE_NONCE_LABEL, sharedSecret);
 
 		// Signature 1
@@ -787,20 +793,24 @@ public class IntroductionIntegrationTest
 
 		// replace ephemeral key pair and recalculate matching keys and nonce
 		KeyPair eKeyPair1f = crypto.generateAgreementKeyPair();
-		byte[] ePublicKeyBytes1f = eKeyPair1f.getPublic().getEncoded();
+		byte[][] fakeInputs = {
+				new byte[] {CLIENT_VERSION},
+				eKeyPair1f.getPublic().getEncoded(),
+				eKeyPair2.getPublic().getEncoded()
+		};
 		sharedSecret = crypto.deriveSharedSecret(SHARED_SECRET_LABEL,
-				eKeyPair2.getPublic(), eKeyPair1f, true);
+				eKeyPair2.getPublic(), eKeyPair1f, fakeInputs);
 		nonce1 = crypto.mac(ALICE_NONCE_LABEL, sharedSecret);
 
 		// recalculate MAC
 		macKey1 = crypto.deriveKey(ALICE_MAC_KEY_LABEL, sharedSecret);
 		toMacList = BdfList.of(keyPair1.getPublic().getEncoded(),
-				ePublicKeyBytes1f, tp1, time1);
+				eKeyPair1f.getPublic().getEncoded(), tp1, time1);
 		toMac = clientHelper.toByteArray(toMacList);
 		mac1 = crypto.mac(MAC_LABEL, macKey1, toMac);
 
 		// update state with faked information
-		state.put(E_PUBLIC_KEY, ePublicKeyBytes1f);
+		state.put(E_PUBLIC_KEY, eKeyPair1f.getPublic().getEncoded());
 		state.put(MAC, mac1);
 		state.put(MAC_KEY, macKey1.getBytes());
 		state.put(NONCE, nonce1);
diff --git a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImplTest.java b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImplTest.java
index 50167d6e27636a48e1b005bb1809e536e3ccf994..c0e3b116b4c15ae5ffbc5c14fbc024aa879754e5 100644
--- a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImplTest.java
+++ b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImplTest.java
@@ -52,6 +52,7 @@ import static org.briarproject.bramble.util.StringUtils.getRandomString;
 import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.GROUP_SALT_LENGTH;
 import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.MAX_GROUP_NAME_LENGTH;
 import static org.briarproject.briar.api.privategroup.invitation.GroupInvitationManager.CLIENT_ID;
+import static org.briarproject.briar.api.privategroup.invitation.GroupInvitationManager.CLIENT_VERSION;
 import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.GROUP_KEY_CONTACT_ID;
 import static org.briarproject.briar.privategroup.invitation.MessageType.ABORT;
 import static org.briarproject.briar.privategroup.invitation.MessageType.INVITE;
@@ -162,7 +163,8 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
 	private void expectAddingContact(Contact c, boolean contactExists)
 			throws Exception {
 		context.checking(new Expectations() {{
-			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, c);
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
+					CLIENT_VERSION, c);
 			will(returnValue(contactGroup));
 			oneOf(db).containsGroup(txn, contactGroup.getId());
 			will(returnValue(contactExists));
@@ -188,7 +190,8 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
 
 	private void expectAddingMember(GroupId g, Contact c) throws Exception {
 		context.checking(new Expectations() {{
-			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, c);
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
+					CLIENT_VERSION, c);
 			will(returnValue(contactGroup));
 		}});
 		expectGetSession(noResults, new SessionId(g.getBytes()),
@@ -243,7 +246,8 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
 	@Test
 	public void testRemovingContact() throws Exception {
 		context.checking(new Expectations() {{
-			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact);
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
+					CLIENT_VERSION, contact);
 			will(returnValue(contactGroup));
 			oneOf(db).removeGroup(txn, contactGroup);
 		}});
@@ -457,7 +461,8 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
 			will(returnValue(txn));
 			oneOf(db).getContact(txn, contactId);
 			will(returnValue(contact));
-			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact);
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
+					CLIENT_VERSION, contact);
 			will(returnValue(contactGroup));
 		}});
 		expectCreateStorageId();
@@ -488,7 +493,8 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
 			will(returnValue(txn));
 			oneOf(db).getContact(txn, contactId);
 			will(returnValue(contact));
-			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact);
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
+					CLIENT_VERSION, contact);
 			will(returnValue(contactGroup));
 			oneOf(sessionParser)
 					.parseCreatorSession(contactGroup.getId(), bdfSession);
@@ -516,7 +522,8 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
 			will(returnValue(txn));
 			oneOf(db).getContact(txn, contactId);
 			will(returnValue(contact));
-			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact);
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
+					CLIENT_VERSION, contact);
 			will(returnValue(contactGroup));
 			oneOf(db).endTransaction(txn);
 		}});
@@ -567,7 +574,8 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
 			will(returnValue(txn));
 			oneOf(db).getContact(txn, contactId);
 			will(returnValue(contact));
-			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact);
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
+					CLIENT_VERSION, contact);
 			will(returnValue(contactGroup));
 			oneOf(sessionParser)
 					.parseInviteeSession(contactGroup.getId(), bdfSession);
@@ -588,7 +596,8 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
 			will(returnValue(txn));
 			oneOf(db).getContact(txn, contactId);
 			will(returnValue(contact));
-			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact);
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
+					CLIENT_VERSION, contact);
 			will(returnValue(contactGroup));
 			oneOf(sessionParser)
 					.parsePeerSession(contactGroup.getId(), bdfSession);
@@ -612,7 +621,8 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
 			will(returnValue(txn));
 			oneOf(db).getContact(txn, contactId);
 			will(returnValue(contact));
-			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact);
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
+					CLIENT_VERSION, contact);
 			will(returnValue(contactGroup));
 			oneOf(db).endTransaction(txn);
 		}});
@@ -650,7 +660,8 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
 			will(returnValue(txn));
 			oneOf(db).getContact(txn, contactId);
 			will(returnValue(contact));
-			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact);
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
+					CLIENT_VERSION, contact);
 			will(returnValue(contactGroup));
 			oneOf(messageParser).getMessagesVisibleInUiQuery();
 			will(returnValue(query));
@@ -726,7 +737,8 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
 			will(returnValue(txn));
 			oneOf(db).getContacts(txn);
 			will(returnValue(Collections.singletonList(contact)));
-			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact);
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
+					CLIENT_VERSION, contact);
 			will(returnValue(contactGroup));
 			oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
 					contactGroup.getId(), query);
@@ -793,7 +805,8 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
 			throws Exception {
 		expectGetSession(oneResult, sessionId, contactGroup.getId());
 		context.checking(new Expectations() {{
-			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact);
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
+					CLIENT_VERSION, contact);
 			will(returnValue(contactGroup));
 			oneOf(db).startTransaction(true);
 			will(returnValue(txn));
@@ -847,11 +860,14 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
 		context.checking(new Expectations() {{
 			oneOf(db).getContacts(txn);
 			will(returnValue(contacts));
-			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact);
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
+					CLIENT_VERSION, contact);
 			will(returnValue(contactGroup));
-			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact2);
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
+					CLIENT_VERSION, contact2);
 			will(returnValue(contactGroup2));
-			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact3);
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
+					CLIENT_VERSION, contact3);
 			will(returnValue(contactGroup3));
 			// session 1
 			oneOf(sessionParser).getRole(bdfSession);
diff --git a/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingIntegrationTest.java
index 8a7a974a817a66ccbc27f28bc12a44ffbdb82b26..37bbe16e19261f980bee6d036b07a0f50254e2c6 100644
--- a/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingIntegrationTest.java
+++ b/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingIntegrationTest.java
@@ -32,6 +32,7 @@ import java.util.Collection;
 import java.util.List;
 
 import static org.briarproject.briar.api.blog.BlogSharingManager.CLIENT_ID;
+import static org.briarproject.briar.api.blog.BlogSharingManager.CLIENT_VERSION;
 import static org.briarproject.briar.test.BriarTestUtils.assertGroupCount;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -125,7 +126,7 @@ public class BlogSharingIntegrationTest
 
 		// get sharing group and assert group message count
 		GroupId g = contactGroupFactory.createContactGroup(CLIENT_ID,
-				contact1From0).getId();
+				CLIENT_VERSION, contact1From0).getId();
 		assertGroupCount(messageTracker0, g, 1, 0);
 
 		// sync first request message
@@ -200,7 +201,7 @@ public class BlogSharingIntegrationTest
 
 		// get sharing group and assert group message count
 		GroupId g = contactGroupFactory.createContactGroup(CLIENT_ID,
-				contact1From0).getId();
+				CLIENT_VERSION, contact1From0).getId();
 		assertGroupCount(messageTracker0, g, 1, 0);
 
 		// sync first request message
diff --git a/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingManagerImplTest.java b/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingManagerImplTest.java
index a7c76401723561a33efdd7dec370bfbcf5b697a9..22e9bbf6198502557237954f6d9a427354a2827f 100644
--- a/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingManagerImplTest.java
+++ b/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingManagerImplTest.java
@@ -39,6 +39,7 @@ import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
 import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
 import static org.briarproject.bramble.test.TestUtils.getRandomId;
 import static org.briarproject.briar.api.blog.BlogSharingManager.CLIENT_ID;
+import static org.briarproject.briar.api.blog.BlogSharingManager.CLIENT_VERSION;
 import static org.briarproject.briar.sharing.SharingConstants.GROUP_KEY_CONTACT_ID;
 
 public class BlogSharingManagerImplTest extends BrambleMockTestCase {
@@ -152,7 +153,8 @@ public class BlogSharingManagerImplTest extends BrambleMockTestCase {
 		context.checking(new Expectations() {{
 			oneOf(db).getContacts(txn);
 			will(returnValue(contacts));
-			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact);
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
+					CLIENT_VERSION, contact);
 			will(returnValue(contactGroup));
 			oneOf(db).containsGroup(txn, contactGroup.getId());
 			will(returnValue(false));
@@ -185,8 +187,8 @@ public class BlogSharingManagerImplTest extends BrambleMockTestCase {
 				new Message(new MessageId(getRandomId()), contactGroup.getId(),
 						42L, getRandomBytes(1337));
 		context.checking(new Expectations() {{
-			oneOf(contactGroupFactory)
-					.createContactGroup(CLIENT_ID, contact);
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
+					CLIENT_VERSION, contact);
 			will(returnValue(contactGroup));
 			oneOf(sessionParser)
 					.getSessionQuery(new SessionId(blog.getId().getBytes()));
@@ -220,7 +222,8 @@ public class BlogSharingManagerImplTest extends BrambleMockTestCase {
 		context.checking(new Expectations() {{
 			oneOf(db).getContacts(txn);
 			will(returnValue(contacts));
-			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact);
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
+					CLIENT_VERSION, contact);
 			will(returnValue(contactGroup));
 			oneOf(sessionParser)
 					.getSessionQuery(new SessionId(blog.getId().getBytes()));
diff --git a/briar-core/src/test/java/org/briarproject/briar/sharing/ForumSharingIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/sharing/ForumSharingIntegrationTest.java
index 01cd70589fb3f01b3c9102cf2711faf404dc599c..bbc83660a006de207252894a6088eb52cd373308 100644
--- a/briar-core/src/test/java/org/briarproject/briar/sharing/ForumSharingIntegrationTest.java
+++ b/briar-core/src/test/java/org/briarproject/briar/sharing/ForumSharingIntegrationTest.java
@@ -38,6 +38,8 @@ import java.util.List;
 
 import static junit.framework.Assert.assertNotNull;
 import static org.briarproject.bramble.util.StringUtils.getRandomString;
+import static org.briarproject.briar.api.forum.ForumSharingManager.CLIENT_ID;
+import static org.briarproject.briar.api.forum.ForumSharingManager.CLIENT_VERSION;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
@@ -399,9 +401,8 @@ public class ForumSharingIntegrationTest
 		assertTrue(listener0.responseReceived);
 
 		// response and invitation got tracked
-		Group group = contactGroupFactory
-				.createContactGroup(ForumSharingManager.CLIENT_ID,
-						contact0From1);
+		Group group = contactGroupFactory.createContactGroup(CLIENT_ID,
+				CLIENT_VERSION, contact0From1);
 		assertEquals(2, c1.getMessageTracker().getGroupCount(group.getId())
 				.getMsgCount());
 
@@ -432,9 +433,8 @@ public class ForumSharingIntegrationTest
 		assertEquals(1, forumSharingManager1.getInvitations().size());
 
 		// assert that the invitation arrived
-		Group group = contactGroupFactory
-				.createContactGroup(ForumSharingManager.CLIENT_ID,
-						contact0From1);
+		Group group = contactGroupFactory.createContactGroup(CLIENT_ID,
+				CLIENT_VERSION, contact0From1);
 		assertEquals(1, c1.getMessageTracker().getGroupCount(group.getId())
 				.getMsgCount());