diff --git a/api/net/sf/briar/api/crypto/CryptoComponent.java b/api/net/sf/briar/api/crypto/CryptoComponent.java
index 504ed97055b130202be2d8a65c781512757276ad..6997072e54f7cad5c056a2e03dedafbf64d50d61 100644
--- a/api/net/sf/briar/api/crypto/CryptoComponent.java
+++ b/api/net/sf/briar/api/crypto/CryptoComponent.java
@@ -10,31 +10,31 @@ import javax.crypto.SecretKey;
 
 public interface CryptoComponent {
 
-	SecretKey deriveIncomingMacKey(byte[] secret);
-
 	SecretKey deriveIncomingFrameKey(byte[] secret);
 
-	SecretKey deriveIncomingTagKey(byte[] secret);
+	SecretKey deriveIncomingIvKey(byte[] secret);
 
-	SecretKey deriveOutgoingMacKey(byte[] secret);
+	SecretKey deriveIncomingMacKey(byte[] secret);
 
 	SecretKey deriveOutgoingFrameKey(byte[] secret);
 
-	SecretKey deriveOutgoingTagKey(byte[] secret);
+	SecretKey deriveOutgoingIvKey(byte[] secret);
+
+	SecretKey deriveOutgoingMacKey(byte[] secret);
 
 	KeyPair generateKeyPair();
 
 	SecretKey generateSecretKey();
 
+	Cipher getFrameCipher();
+
+	Cipher getIvCipher();
+
 	KeyParser getKeyParser();
 
 	Mac getMac();
 
 	MessageDigest getMessageDigest();
 
-	Cipher getFrameCipher();
-
 	Signature getSignature();
-
-	Cipher getTagCipher();
 }
diff --git a/api/net/sf/briar/api/transport/ConnectionRecogniser.java b/api/net/sf/briar/api/transport/ConnectionRecogniser.java
index 511f65cf573191d3cf77fcc5059d7b987d318236..b57af58d4beda85ddfb54fc41058e5a32f4484e5 100644
--- a/api/net/sf/briar/api/transport/ConnectionRecogniser.java
+++ b/api/net/sf/briar/api/transport/ConnectionRecogniser.java
@@ -10,8 +10,9 @@ import net.sf.briar.api.db.DbException;
 public interface ConnectionRecogniser {
 
 	/**
-	 * Returns the ID of the contact who created the tag if the connection
-	 * should be accepted, or null if the connection should be rejected.
+	 * Returns the ID of the contact who created the encrypted IV if the
+	 * connection should be accepted, or null if the connection should be
+	 * rejected.
 	 */
-	ContactId acceptConnection(byte[] tag) throws DbException;
+	ContactId acceptConnection(byte[] encryptedIv) throws DbException;
 }
diff --git a/api/net/sf/briar/api/transport/TransportConstants.java b/api/net/sf/briar/api/transport/TransportConstants.java
index 2746a8c0dfd9e6e1f8cea917928eebf8a8239da5..0aa0c01afa9cd143928e12bfc78db5314ffeefc6 100644
--- a/api/net/sf/briar/api/transport/TransportConstants.java
+++ b/api/net/sf/briar/api/transport/TransportConstants.java
@@ -7,6 +7,9 @@ public interface TransportConstants {
 	 */
 	static final int MAX_FRAME_LENGTH = 65536; // 2^16
 
-	/** The length in bytes of the tag that uniquely identifies a connection. */
-	static final int TAG_LENGTH = 16;
+	/**
+	 * The length in bytes of the encrypted IV that uniquely identifies a
+	 * connection.
+	 */
+	static final int IV_LENGTH = 16;
 }
diff --git a/components/net/sf/briar/crypto/CryptoComponentImpl.java b/components/net/sf/briar/crypto/CryptoComponentImpl.java
index f8816a1859a95bf1f4ffc977fa44b2ea9992d176..57ac876e5835953910d87ef7ebe02845bd0e8a01 100644
--- a/components/net/sf/briar/crypto/CryptoComponentImpl.java
+++ b/components/net/sf/briar/crypto/CryptoComponentImpl.java
@@ -37,12 +37,12 @@ class CryptoComponentImpl implements CryptoComponent {
 	private static final String KEY_PAIR_ALGO = "ECDSA";
 	private static final int KEY_PAIR_BITS = 256;
 	private static final String SECRET_STORAGE_ALGO = "AES/CTR/NoPadding";
-	private static final String MAC_ALGO = "HMacSHA256";
-	private static final String PACKET_CIPHER_ALGO = "AES/CTR/NoPadding";
+	private static final String FRAME_CIPHER_ALGO = "AES/CTR/NoPadding";
 	private static final String SECRET_KEY_ALGO = "AES";
 	private static final int SECRET_KEY_BITS = 256;
+	private static final String IV_CIPHER_ALGO = "AES/ECB/NoPadding";
+	private static final String MAC_ALGO = "HMacSHA256";
 	private static final String SIGNATURE_ALGO = "ECDSA";
-	private static final String TAG_CIPHER_ALGO = "AES/ECB/NoPadding";
 
 	private final SecretKey secretStorageKey;
 	private final KeyParser keyParser;
@@ -68,14 +68,14 @@ class CryptoComponentImpl implements CryptoComponent {
 		}
 	}
 
-	public SecretKey deriveIncomingMacKey(byte[] secret) {
+	public SecretKey deriveIncomingFrameKey(byte[] secret) {
 		SharedSecret s = new SharedSecret(secret);
-		return deriveMacKey(s, !s.getAlice());
+		return deriveFrameKey(s, !s.getAlice());
 	}
 
-	private SecretKey deriveMacKey(SharedSecret s, boolean alice) {
-		if(alice) return deriveKey("MACA", s.getIv(), s.getCiphertext());
-		else return deriveKey("MACB", s.getIv(), s.getCiphertext());
+	private SecretKey deriveFrameKey(SharedSecret s, boolean alice) {
+		if(alice) return deriveKey("F_A", s.getIv(), s.getCiphertext());
+		else return deriveKey("F_B", s.getIv(), s.getCiphertext());
 	}
 
 	private SecretKey deriveKey(String name, IvParameterSpec iv,
@@ -114,39 +114,39 @@ class CryptoComponentImpl implements CryptoComponent {
 		}
 	}
 
-	public SecretKey deriveIncomingFrameKey(byte[] secret) {
+	public SecretKey deriveIncomingIvKey(byte[] secret) {
 		SharedSecret s = new SharedSecret(secret);
-		return deriveFrameKey(s, !s.getAlice());
+		return deriveIvKey(s, !s.getAlice());
 	}
 
-	private SecretKey deriveFrameKey(SharedSecret s, boolean alice) {
-		if(alice) return deriveKey("PKTA", s.getIv(), s.getCiphertext());
-		else return deriveKey("PKTB", s.getIv(), s.getCiphertext());
+	private SecretKey deriveIvKey(SharedSecret s, boolean alice) {
+		if(alice) return deriveKey("I_A", s.getIv(), s.getCiphertext());
+		else return deriveKey("I_B", s.getIv(), s.getCiphertext());
 	}
 
-	public SecretKey deriveIncomingTagKey(byte[] secret) {
+	public SecretKey deriveIncomingMacKey(byte[] secret) {
 		SharedSecret s = new SharedSecret(secret);
-		return deriveTagKey(s, !s.getAlice());
+		return deriveMacKey(s, !s.getAlice());
 	}
 
-	private SecretKey deriveTagKey(SharedSecret s, boolean alice) {
-		if(alice) return deriveKey("TAGA", s.getIv(), s.getCiphertext());
-		else return deriveKey("TAGB", s.getIv(), s.getCiphertext());
+	private SecretKey deriveMacKey(SharedSecret s, boolean alice) {
+		if(alice) return deriveKey("M_A", s.getIv(), s.getCiphertext());
+		else return deriveKey("M_B", s.getIv(), s.getCiphertext());
 	}
 
-	public SecretKey deriveOutgoingMacKey(byte[] secret) {
+	public SecretKey deriveOutgoingFrameKey(byte[] secret) {
 		SharedSecret s = new SharedSecret(secret);
-		return deriveMacKey(s, s.getAlice());
+		return deriveFrameKey(s, s.getAlice());
 	}
 
-	public SecretKey deriveOutgoingFrameKey(byte[] secret) {
+	public SecretKey deriveOutgoingIvKey(byte[] secret) {
 		SharedSecret s = new SharedSecret(secret);
-		return deriveFrameKey(s, s.getAlice());
+		return deriveIvKey(s, s.getAlice());
 	}
 
-	public SecretKey deriveOutgoingTagKey(byte[] secret) {
+	public SecretKey deriveOutgoingMacKey(byte[] secret) {
 		SharedSecret s = new SharedSecret(secret);
-		return deriveTagKey(s, s.getAlice());
+		return deriveMacKey(s, s.getAlice());
 	}
 
 	public KeyPair generateKeyPair() {
@@ -157,45 +157,47 @@ class CryptoComponentImpl implements CryptoComponent {
 		return keyGenerator.generateKey();
 	}
 
-	public KeyParser getKeyParser() {
-		return keyParser;
-	}
-
-	public Mac getMac() {
+	public Cipher getFrameCipher() {
 		try {
-			return Mac.getInstance(MAC_ALGO, PROVIDER);
+			return Cipher.getInstance(FRAME_CIPHER_ALGO, PROVIDER);
 		} catch(NoSuchAlgorithmException e) {
 			throw new RuntimeException(e);
+		} catch(NoSuchPaddingException e) {
+			throw new RuntimeException(e);
 		} catch(NoSuchProviderException e) {
 			throw new RuntimeException(e);
 		}
 	}
 
-	public MessageDigest getMessageDigest() {
+	public Cipher getIvCipher() {
 		try {
-			return MessageDigest.getInstance(DIGEST_ALGO, PROVIDER);
+			return Cipher.getInstance(IV_CIPHER_ALGO, PROVIDER);
 		} catch(NoSuchAlgorithmException e) {
 			throw new RuntimeException(e);
+		} catch(NoSuchPaddingException e) {
+			throw new RuntimeException(e);
 		} catch(NoSuchProviderException e) {
 			throw new RuntimeException(e);
 		}
 	}
 
-	public Cipher getFrameCipher() {
+	public KeyParser getKeyParser() {
+		return keyParser;
+	}
+
+	public Mac getMac() {
 		try {
-			return Cipher.getInstance(PACKET_CIPHER_ALGO, PROVIDER);
+			return Mac.getInstance(MAC_ALGO, PROVIDER);
 		} catch(NoSuchAlgorithmException e) {
 			throw new RuntimeException(e);
-		} catch(NoSuchPaddingException e) {
-			throw new RuntimeException(e);
 		} catch(NoSuchProviderException e) {
 			throw new RuntimeException(e);
 		}
 	}
 
-	public Signature getSignature() {
+	public MessageDigest getMessageDigest() {
 		try {
-			return Signature.getInstance(SIGNATURE_ALGO, PROVIDER);
+			return MessageDigest.getInstance(DIGEST_ALGO, PROVIDER);
 		} catch(NoSuchAlgorithmException e) {
 			throw new RuntimeException(e);
 		} catch(NoSuchProviderException e) {
@@ -203,13 +205,11 @@ class CryptoComponentImpl implements CryptoComponent {
 		}
 	}
 
-	public Cipher getTagCipher() {
+	public Signature getSignature() {
 		try {
-			return Cipher.getInstance(TAG_CIPHER_ALGO, PROVIDER);
+			return Signature.getInstance(SIGNATURE_ALGO, PROVIDER);
 		} catch(NoSuchAlgorithmException e) {
 			throw new RuntimeException(e);
-		} catch(NoSuchPaddingException e) {
-			throw new RuntimeException(e);
 		} catch(NoSuchProviderException e) {
 			throw new RuntimeException(e);
 		}
diff --git a/components/net/sf/briar/transport/ConnectionDecrypterImpl.java b/components/net/sf/briar/transport/ConnectionDecrypterImpl.java
index 4ab3b618d76caf95b496475cad15fc084d119025..9e74fe792b33ca71317c892c3421ad1a362b2603 100644
--- a/components/net/sf/briar/transport/ConnectionDecrypterImpl.java
+++ b/components/net/sf/briar/transport/ConnectionDecrypterImpl.java
@@ -1,6 +1,6 @@
 package net.sf.briar.transport;
 
-import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
+import static net.sf.briar.api.transport.TransportConstants.IV_LENGTH;
 import static net.sf.briar.util.ByteUtils.MAX_32_BIT_UNSIGNED;
 
 import java.io.EOFException;
@@ -24,7 +24,7 @@ implements ConnectionDecrypter {
 	private final long connection;
 	private final Cipher frameCipher;
 	private final SecretKey frameKey;
-	private final byte[] buf, tag;
+	private final byte[] buf, iv;
 
 	private int bufOff = 0, bufLen = 0;
 	private long frame = 0L;
@@ -37,8 +37,8 @@ implements ConnectionDecrypter {
 		this.connection = connection;
 		this.frameCipher = frameCipher;
 		this.frameKey = frameKey;
-		buf = new byte[TAG_LENGTH];
-		tag = new byte[TAG_LENGTH];
+		buf = new byte[IV_LENGTH];
+		iv = new byte[IV_LENGTH];
 	}
 
 	public InputStream getInputStream() {
@@ -132,11 +132,11 @@ implements ConnectionDecrypter {
 	private void initialiseCipher() {
 		assert betweenFrames;
 		if(frame > MAX_32_BIT_UNSIGNED) throw new IllegalStateException();
-		TagEncoder.encodeTag(tag, transportId, connection, frame);
-		// Use the plaintext tag to initialise the packet cipher
-		IvParameterSpec iv = new IvParameterSpec(tag);
+		IvEncoder.encodeIv(iv, transportId, connection, frame);
+		// Use the plaintext IV to initialise the frame cipher
+		IvParameterSpec ivSpec = new IvParameterSpec(iv);
 		try {
-			frameCipher.init(Cipher.DECRYPT_MODE, frameKey, iv);
+			frameCipher.init(Cipher.DECRYPT_MODE, frameKey, ivSpec);
 		} catch(InvalidAlgorithmParameterException badIv) {
 			throw new RuntimeException(badIv);
 		} catch(InvalidKeyException badKey) {
diff --git a/components/net/sf/briar/transport/ConnectionEncrypterImpl.java b/components/net/sf/briar/transport/ConnectionEncrypterImpl.java
index 0fccc905f9cf23abd14f8c980078a31cd4d5eef8..ad1d2d72859043f460087493357f3fed5f674382 100644
--- a/components/net/sf/briar/transport/ConnectionEncrypterImpl.java
+++ b/components/net/sf/briar/transport/ConnectionEncrypterImpl.java
@@ -1,6 +1,6 @@
 package net.sf.briar.transport;
 
-import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
+import static net.sf.briar.api.transport.TransportConstants.IV_LENGTH;
 import static net.sf.briar.util.ByteUtils.MAX_32_BIT_UNSIGNED;
 
 import java.io.FilterOutputStream;
@@ -20,29 +20,29 @@ implements ConnectionEncrypter {
 
 	private final int transportId;
 	private final long connection;
-	private final Cipher tagCipher, frameCipher;
+	private final Cipher ivCipher, frameCipher;
 	private final SecretKey frameKey;
-	private final byte[] tag;
+	private final byte[] iv;
 
 	private long frame = 0L;
 	private boolean started = false, betweenFrames = false;
 
 	ConnectionEncrypterImpl(OutputStream out, int transportId,
-			long connection, Cipher tagCipher, Cipher frameCipher,
-			SecretKey tagKey, SecretKey frameKey) {
+			long connection, Cipher ivCipher, Cipher frameCipher,
+			SecretKey ivKey, SecretKey frameKey) {
 		super(out);
 		this.transportId = transportId;
 		this.connection = connection;
-		this.tagCipher = tagCipher;
+		this.ivCipher = ivCipher;
 		this.frameCipher = frameCipher;
 		this.frameKey = frameKey;
-		tag = new byte[TAG_LENGTH];
+		iv = new byte[IV_LENGTH];
 		try {
-			tagCipher.init(Cipher.ENCRYPT_MODE, tagKey);
+			ivCipher.init(Cipher.ENCRYPT_MODE, ivKey);
 		} catch(InvalidKeyException badKey) {
 			throw new IllegalArgumentException(badKey);
 		}
-		if(tagCipher.getOutputSize(TAG_LENGTH) != TAG_LENGTH)
+		if(ivCipher.getOutputSize(IV_LENGTH) != IV_LENGTH)
 			throw new IllegalArgumentException();
 	}
 
@@ -64,7 +64,7 @@ implements ConnectionEncrypter {
 
 	@Override
 	public void write(int b) throws IOException {
-		if(!started) writeTag();
+		if(!started) writeIv();
 		if(betweenFrames) initialiseCipher();
 		byte[] ciphertext = frameCipher.update(new byte[] {(byte) b});
 		if(ciphertext != null) out.write(ciphertext);
@@ -77,18 +77,18 @@ implements ConnectionEncrypter {
 
 	@Override
 	public void write(byte[] b, int off, int len) throws IOException {
-		if(!started) writeTag();
+		if(!started) writeIv();
 		if(betweenFrames) initialiseCipher();
 		byte[] ciphertext = frameCipher.update(b, off, len);
 		if(ciphertext != null) out.write(ciphertext);
 	}
 
-	private void writeTag() throws IOException {
+	private void writeIv() throws IOException {
 		assert !started;
 		assert !betweenFrames;
-		TagEncoder.encodeTag(tag, transportId, connection, 0L);
+		IvEncoder.encodeIv(iv, transportId, connection, 0L);
 		try {
-			out.write(tagCipher.doFinal(tag));
+			out.write(ivCipher.doFinal(iv));
 		} catch(BadPaddingException badCipher) {
 			throw new IOException(badCipher);
 		} catch(IllegalBlockSizeException badCipher) {
@@ -102,10 +102,10 @@ implements ConnectionEncrypter {
 		assert started;
 		assert betweenFrames;
 		if(frame > MAX_32_BIT_UNSIGNED) throw new IllegalStateException();
-		TagEncoder.encodeTag(tag, transportId, connection, frame);
-		IvParameterSpec iv = new IvParameterSpec(tag);
+		IvEncoder.encodeIv(iv, transportId, connection, frame);
+		IvParameterSpec ivSpec = new IvParameterSpec(iv);
 		try {
-			frameCipher.init(Cipher.ENCRYPT_MODE, frameKey, iv);
+			frameCipher.init(Cipher.ENCRYPT_MODE, frameKey, ivSpec);
 		} catch(InvalidAlgorithmParameterException badIv) {
 			throw new RuntimeException(badIv);
 		} catch(InvalidKeyException badKey) {
diff --git a/components/net/sf/briar/transport/ConnectionRecogniserImpl.java b/components/net/sf/briar/transport/ConnectionRecogniserImpl.java
index 5f662503c0b5c4f55360cc1828c56b24b075f35d..7915ecf7189bb648894947f35270a1b6d4637d63 100644
--- a/components/net/sf/briar/transport/ConnectionRecogniserImpl.java
+++ b/components/net/sf/briar/transport/ConnectionRecogniserImpl.java
@@ -1,6 +1,6 @@
 package net.sf.briar.transport;
 
-import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
+import static net.sf.briar.api.transport.TransportConstants.IV_LENGTH;
 
 import java.security.InvalidKeyException;
 import java.util.HashMap;
@@ -27,9 +27,9 @@ DatabaseListener {
 	private final int transportId;
 	private final CryptoComponent crypto;
 	private final DatabaseComponent db;
-	private final Map<Bytes, ContactId> tagToContact;
-	private final Map<Bytes, Long> tagToConnectionNumber;
-	private final Map<ContactId, Map<Long, Bytes>> contactToTags;
+	private final Map<Bytes, ContactId> ivToContact;
+	private final Map<Bytes, Long> ivToConnectionNumber;
+	private final Map<ContactId, Map<Long, Bytes>> contactToIvs;
 	private final Map<ContactId, Cipher> contactToCipher;
 	private final Map<ContactId, ConnectionWindow> contactToWindow;
 	private boolean initialised = false;
@@ -40,9 +40,9 @@ DatabaseListener {
 		this.crypto = crypto;
 		this.db = db;
 		// FIXME: There's probably a tidier way of maintaining all this state
-		tagToContact = new HashMap<Bytes, ContactId>();
-		tagToConnectionNumber = new HashMap<Bytes, Long>();
-		contactToTags = new HashMap<ContactId, Map<Long, Bytes>>();
+		ivToContact = new HashMap<Bytes, ContactId>();
+		ivToConnectionNumber = new HashMap<Bytes, Long>();
+		contactToIvs = new HashMap<ContactId, Map<Long, Bytes>>();
 		contactToCipher = new HashMap<ContactId, Cipher>();
 		contactToWindow = new HashMap<ContactId, ConnectionWindow>();
 		db.addListener(this);
@@ -51,26 +51,26 @@ DatabaseListener {
 	private synchronized void initialise() throws DbException {
 		for(ContactId c : db.getContacts()) {
 			try {
-				// Initialise and store the contact's tag cipher
+				// Initialise and store the contact's IV cipher
 				byte[] secret = db.getSharedSecret(c);
-				SecretKey tagKey = crypto.deriveIncomingTagKey(secret);
-				Cipher cipher = crypto.getTagCipher();
+				SecretKey ivKey = crypto.deriveIncomingIvKey(secret);
+				Cipher cipher = crypto.getIvCipher();
 				try {
-					cipher.init(Cipher.ENCRYPT_MODE, tagKey);
+					cipher.init(Cipher.ENCRYPT_MODE, ivKey);
 				} catch(InvalidKeyException badKey) {
 					throw new RuntimeException(badKey);
 				}
 				contactToCipher.put(c, cipher);
-				// Calculate the tags for the contact's connection window
+				// Calculate the IVs for the contact's connection window
 				ConnectionWindow w = db.getConnectionWindow(c, transportId);
-				Map<Long, Bytes> tags = new HashMap<Long, Bytes>();
+				Map<Long, Bytes> ivs = new HashMap<Long, Bytes>();
 				for(Long unseen : w.getUnseenConnectionNumbers()) {
-					Bytes expectedTag = new Bytes(calculateTag(c, unseen));
-					tagToContact.put(expectedTag, c);
-					tagToConnectionNumber.put(expectedTag, unseen);
-					tags.put(unseen, expectedTag);
+					Bytes expectedIv = new Bytes(encryptIv(c, unseen));
+					ivToContact.put(expectedIv, c);
+					ivToConnectionNumber.put(expectedIv, unseen);
+					ivs.put(unseen, expectedIv);
 				}
-				contactToTags.put(c, tags);
+				contactToIvs.put(c, ivs);
 				contactToWindow.put(c, w);
 			} catch(NoSuchContactException e) {
 				// The contact was removed after the call to getContacts()
@@ -80,12 +80,12 @@ DatabaseListener {
 		initialised = true;
 	}
 
-	private synchronized byte[] calculateTag(ContactId c, long connection) {
-		byte[] tag = TagEncoder.encodeTag(transportId, connection);
+	private synchronized byte[] encryptIv(ContactId c, long connection) {
+		byte[] iv = IvEncoder.encodeIv(transportId, connection);
 		Cipher cipher = contactToCipher.get(c);
 		assert cipher != null;
 		try {
-			return cipher.doFinal(tag);
+			return cipher.doFinal(iv);
 		} catch(BadPaddingException badCipher) {
 			throw new RuntimeException(badCipher);
 		} catch(IllegalBlockSizeException badCipher) {
@@ -93,36 +93,36 @@ DatabaseListener {
 		}
 	}
 
-	public synchronized ContactId acceptConnection(byte[] tag)
+	public synchronized ContactId acceptConnection(byte[] encryptedIv)
 	throws DbException {
-		if(tag.length != TAG_LENGTH)
+		if(encryptedIv.length != IV_LENGTH)
 			throw new IllegalArgumentException();
 		if(!initialised) initialise();
-		Bytes b = new Bytes(tag);
-		ContactId contactId = tagToContact.remove(b);
-		Long connection = tagToConnectionNumber.remove(b);
+		Bytes b = new Bytes(encryptedIv);
+		ContactId contactId = ivToContact.remove(b);
+		Long connection = ivToConnectionNumber.remove(b);
 		assert (contactId == null) == (connection == null);
 		if(contactId == null) return null;
-		// The tag was expected - update and save the connection window
+		// The IV was expected - update and save the connection window
 		ConnectionWindow w = contactToWindow.get(contactId);
 		assert w != null;
 		w.setSeen(connection);
 		db.setConnectionWindow(contactId, transportId, w);
-		// Update the set of expected tags
-		Map<Long, Bytes> oldTags = contactToTags.remove(contactId);
-		assert oldTags != null;
-		assert oldTags.containsKey(connection);
-		Map<Long, Bytes> newTags = new HashMap<Long, Bytes>();
+		// Update the set of expected IVs
+		Map<Long, Bytes> oldIvs = contactToIvs.remove(contactId);
+		assert oldIvs != null;
+		assert oldIvs.containsKey(connection);
+		Map<Long, Bytes> newIvs = new HashMap<Long, Bytes>();
 		for(Long unseen : w.getUnseenConnectionNumbers()) {
-			Bytes expectedTag = oldTags.get(unseen);
-			if(expectedTag == null) {
-				expectedTag = new Bytes(calculateTag(contactId, unseen));
-				tagToContact.put(expectedTag, contactId);
-				tagToConnectionNumber.put(expectedTag, connection);
+			Bytes expectedIv = oldIvs.get(unseen);
+			if(expectedIv == null) {
+				expectedIv = new Bytes(encryptIv(contactId, unseen));
+				ivToContact.put(expectedIv, contactId);
+				ivToConnectionNumber.put(expectedIv, connection);
 			}
-			newTags.put(unseen, expectedTag);
+			newIvs.put(unseen, expectedIv);
 		}
-		contactToTags.put(contactId, newTags);
+		contactToIvs.put(contactId, newIvs);
 		return contactId;
 	}
 
diff --git a/components/net/sf/briar/transport/ConnectionWriterFactoryImpl.java b/components/net/sf/briar/transport/ConnectionWriterFactoryImpl.java
index ae12ef4b1c4384ce4fb3fd6440f8a4e2dc3cc835..9d0768c03c78164aab7e26af713c38de264fb7e6 100644
--- a/components/net/sf/briar/transport/ConnectionWriterFactoryImpl.java
+++ b/components/net/sf/briar/transport/ConnectionWriterFactoryImpl.java
@@ -25,9 +25,9 @@ class ConnectionWriterFactoryImpl implements ConnectionWriterFactory {
 	public ConnectionWriter createConnectionWriter(OutputStream out,
 			int transportId, long connection, byte[] secret) {
 		SecretKey macKey = crypto.deriveOutgoingMacKey(secret);
-		SecretKey tagKey = crypto.deriveOutgoingTagKey(secret);
+		SecretKey ivKey = crypto.deriveOutgoingIvKey(secret);
 		SecretKey frameKey = crypto.deriveOutgoingFrameKey(secret);
-		Cipher tagCipher = crypto.getTagCipher();
+		Cipher ivCipher = crypto.getIvCipher();
 		Cipher frameCipher = crypto.getFrameCipher();
 		Mac mac = crypto.getMac();
 		try {
@@ -36,7 +36,7 @@ class ConnectionWriterFactoryImpl implements ConnectionWriterFactory {
 			throw new IllegalArgumentException(badKey);
 		}
 		ConnectionEncrypter encrypter = new ConnectionEncrypterImpl(out,
-				transportId, connection, tagCipher, frameCipher, tagKey,
+				transportId, connection, ivCipher, frameCipher, ivKey,
 				frameKey);
 		return new ConnectionWriterImpl(encrypter, mac);
 	}
diff --git a/components/net/sf/briar/transport/IvEncoder.java b/components/net/sf/briar/transport/IvEncoder.java
new file mode 100644
index 0000000000000000000000000000000000000000..481f0304a59226d303661c58b02817e528505d26
--- /dev/null
+++ b/components/net/sf/briar/transport/IvEncoder.java
@@ -0,0 +1,33 @@
+package net.sf.briar.transport;
+
+import static net.sf.briar.api.transport.TransportConstants.IV_LENGTH;
+import net.sf.briar.util.ByteUtils;
+
+class IvEncoder {
+
+	static byte[] encodeIv(int transportId, long connection) {
+		byte[] iv = new byte[IV_LENGTH];
+		// Encode the transport identifier as an unsigned 16-bit integer
+		ByteUtils.writeUint16(transportId, iv, 4);
+		// Encode the connection number as an unsigned 32-bit integer
+		ByteUtils.writeUint32(connection, iv, 6);
+		return iv;
+	}
+
+	static void encodeIv(byte[] iv, int transportId, long connection,
+			long frame) {
+		if(iv.length != IV_LENGTH) throw new IllegalArgumentException();
+		// The first 16 bits of the IV must be zero (reserved)
+		iv[0] = 0;
+		iv[1] = 0;
+		// Encode the transport identifier as an unsigned 16-bit integer
+		ByteUtils.writeUint16(transportId, iv, 4);
+		// Encode the connection number as an unsigned 32-bit integer
+		ByteUtils.writeUint32(connection, iv, 6);
+		// Encode the frame number as an unsigned 32-bit integer
+		ByteUtils.writeUint32(frame, iv, 10);
+		// The last 16 bits of the IV must be zero (block number)
+		iv[14] = 0;
+		iv[15] = 0;
+	}
+}
diff --git a/components/net/sf/briar/transport/TagDecoder.java b/components/net/sf/briar/transport/TagDecoder.java
deleted file mode 100644
index a83be3d847f5b68e77c387d44b7c840c0c4727d0..0000000000000000000000000000000000000000
--- a/components/net/sf/briar/transport/TagDecoder.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package net.sf.briar.transport;
-
-import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
-import net.sf.briar.util.ByteUtils;
-
-class TagDecoder {
-
-	static boolean decodeTag(byte[] tag, int transportId, long connection) {
-		if(tag.length != TAG_LENGTH) return false;
-		// First 32 bits must be zero (reserved)
-		for(int i = 0; i < 4; i++) if(tag[i] != 0) return false;
-		// Transport identifier is encoded as an unsigned 16-bit integer
-		if(ByteUtils.readUint16(tag, 4) != transportId) return false;
-		// Connection number is encoded as an unsigned 32-bit integer
-		if(ByteUtils.readUint32(tag, 6) != connection) return false;
-		// Last 48 bits must be zero (frame number and block number)
-		for(int i = 10; i < 16; i++) if(tag[i] != 0) return false;
-		return true;
-	}
-}
diff --git a/components/net/sf/briar/transport/TagEncoder.java b/components/net/sf/briar/transport/TagEncoder.java
deleted file mode 100644
index dbde2fa50538021ad218f4ff86d2b653a55ad209..0000000000000000000000000000000000000000
--- a/components/net/sf/briar/transport/TagEncoder.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package net.sf.briar.transport;
-
-import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
-import net.sf.briar.util.ByteUtils;
-
-class TagEncoder {
-
-	static byte[] encodeTag(int transportId, long connection) {
-		byte[] tag = new byte[TAG_LENGTH];
-		// Encode the transport identifier as an unsigned 16-bit integer
-		ByteUtils.writeUint16(transportId, tag, 4);
-		// Encode the connection number as an unsigned 32-bit integer
-		ByteUtils.writeUint32(connection, tag, 6);
-		return tag;
-	}
-
-	static void encodeTag(byte[] tag, int transportId, long connection,
-			long frame) {
-		if(tag.length != TAG_LENGTH) throw new IllegalArgumentException();
-		// The first 16 bits of the tag must be zero (reserved)
-		ByteUtils.writeUint16(0, tag, 0);
-		// Encode the transport identifier as an unsigned 16-bit integer
-		ByteUtils.writeUint16(transportId, tag, 4);
-		// Encode the connection number as an unsigned 32-bit integer
-		ByteUtils.writeUint32(connection, tag, 6);
-		// Encode the frame number as an unsigned 32-bit integer
-		ByteUtils.writeUint32(frame, tag, 10);
-		// The last 16 bits of the tag must be zero (block number)
-		ByteUtils.writeUint16(0, tag, 14);
-	}
-}
diff --git a/test/net/sf/briar/FileReadWriteTest.java b/test/net/sf/briar/FileReadWriteTest.java
index e7a6c86c9b5cd2b56808ef875d4f0243c8b8617a..a831946ca58668bed06feab6a227c0eaba9d7471 100644
--- a/test/net/sf/briar/FileReadWriteTest.java
+++ b/test/net/sf/briar/FileReadWriteTest.java
@@ -185,10 +185,10 @@ public class FileReadWriteTest extends TestCase {
 		testWriteFile();
 
 		InputStream in = new FileInputStream(file);
-		byte[] firstTag = new byte[16];
+		byte[] iv = new byte[16];
 		int offset = 0;
 		while(offset < 16) {
-			int read = in.read(firstTag, offset, firstTag.length - offset);
+			int read = in.read(iv, offset, iv.length - offset);
 			if(read == -1) break;
 			offset += read;
 		}
diff --git a/test/net/sf/briar/crypto/CryptoComponentTest.java b/test/net/sf/briar/crypto/CryptoComponentTest.java
index b8ea8ade6a8a36e136374a323035a58bb791c7e8..8e64765e2f81fd3b7c22b5a2cf17e43f0b7ff2a0 100644
--- a/test/net/sf/briar/crypto/CryptoComponentTest.java
+++ b/test/net/sf/briar/crypto/CryptoComponentTest.java
@@ -29,21 +29,21 @@ public class CryptoComponentTest extends TestCase {
 				crypto.deriveOutgoingMacKey(bobSecret));
 		assertEquals(crypto.deriveIncomingFrameKey(aliceSecret),
 				crypto.deriveOutgoingFrameKey(bobSecret));
-		assertEquals(crypto.deriveIncomingTagKey(aliceSecret),
-				crypto.deriveOutgoingTagKey(bobSecret));
+		assertEquals(crypto.deriveIncomingIvKey(aliceSecret),
+				crypto.deriveOutgoingIvKey(bobSecret));
 		// Check that Alice's outgoing keys match Bob's incoming keys
 		assertEquals(crypto.deriveOutgoingMacKey(aliceSecret),
 				crypto.deriveIncomingMacKey(bobSecret));
 		assertEquals(crypto.deriveOutgoingFrameKey(aliceSecret),
 				crypto.deriveIncomingFrameKey(bobSecret));
-		assertEquals(crypto.deriveOutgoingTagKey(aliceSecret),
-				crypto.deriveIncomingTagKey(bobSecret));
+		assertEquals(crypto.deriveOutgoingIvKey(aliceSecret),
+				crypto.deriveIncomingIvKey(bobSecret));
 		// Check that Alice's incoming and outgoing keys are different
 		assertFalse(crypto.deriveIncomingMacKey(aliceSecret).equals(
 				crypto.deriveOutgoingMacKey(aliceSecret)));
 		assertFalse(crypto.deriveIncomingFrameKey(aliceSecret).equals(
 				crypto.deriveOutgoingFrameKey(aliceSecret)));
-		assertFalse(crypto.deriveIncomingTagKey(aliceSecret).equals(
-				crypto.deriveOutgoingTagKey(aliceSecret)));
+		assertFalse(crypto.deriveIncomingIvKey(aliceSecret).equals(
+				crypto.deriveOutgoingIvKey(aliceSecret)));
 	}
 }
diff --git a/test/net/sf/briar/transport/ConnectionDecrypterImplTest.java b/test/net/sf/briar/transport/ConnectionDecrypterImplTest.java
index 9bf306fd844dc7470d0a80e28c5b1fc75e876e87..17870334683262853391d3b1dd8cceeaffb6eaa2 100644
--- a/test/net/sf/briar/transport/ConnectionDecrypterImplTest.java
+++ b/test/net/sf/briar/transport/ConnectionDecrypterImplTest.java
@@ -1,6 +1,6 @@
 package net.sf.briar.transport;
 
-import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
+import static net.sf.briar.api.transport.TransportConstants.IV_LENGTH;
 
 import java.io.ByteArrayInputStream;
 import java.util.Arrays;
@@ -54,16 +54,16 @@ public class ConnectionDecrypterImplTest extends TestCase {
 	public void testDecryption() throws Exception {
 		// Calculate the expected plaintext for the first frame
 		byte[] ciphertext = new byte[123];
-		byte[] ivBytes = new byte[TAG_LENGTH];
-		TagEncoder.encodeTag(ivBytes, transportId, connection, 0L);
-		IvParameterSpec iv = new IvParameterSpec(ivBytes);
-		frameCipher.init(Cipher.DECRYPT_MODE, frameKey, iv);
+		byte[] iv = new byte[IV_LENGTH];
+		IvEncoder.encodeIv(iv, transportId, connection, 0L);
+		IvParameterSpec ivSpec = new IvParameterSpec(iv);
+		frameCipher.init(Cipher.DECRYPT_MODE, frameKey, ivSpec);
 		byte[] plaintext = frameCipher.doFinal(ciphertext);
 		// Calculate the expected plaintext for the second frame
 		byte[] ciphertext1 = new byte[1234];
-		TagEncoder.encodeTag(ivBytes, transportId, connection, 1L);
-		iv = new IvParameterSpec(ivBytes);
-		frameCipher.init(Cipher.DECRYPT_MODE, frameKey, iv);
+		IvEncoder.encodeIv(iv, transportId, connection, 1L);
+		ivSpec = new IvParameterSpec(iv);
+		frameCipher.init(Cipher.DECRYPT_MODE, frameKey, ivSpec);
 		byte[] plaintext1 = frameCipher.doFinal(ciphertext1);
 		assertEquals(ciphertext1.length, plaintext1.length);
 		// Concatenate the ciphertexts
diff --git a/test/net/sf/briar/transport/ConnectionEncrypterImplTest.java b/test/net/sf/briar/transport/ConnectionEncrypterImplTest.java
index 3b3a9145d2d3811e0fb18ab6eec23dc68d3acb64..59624159ddd541970e6f03aa7c659bc33b941e87 100644
--- a/test/net/sf/briar/transport/ConnectionEncrypterImplTest.java
+++ b/test/net/sf/briar/transport/ConnectionEncrypterImplTest.java
@@ -1,6 +1,6 @@
 package net.sf.briar.transport;
 
-import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
+import static net.sf.briar.api.transport.TransportConstants.IV_LENGTH;
 
 import java.io.ByteArrayOutputStream;
 import java.util.Arrays;
@@ -22,8 +22,8 @@ public class ConnectionEncrypterImplTest extends TestCase {
 
 	private static final int MAC_LENGTH = 32;
 
-	private final Cipher tagCipher, frameCipher;
-	private final SecretKey tagKey, frameKey;
+	private final Cipher ivCipher, frameCipher;
+	private final SecretKey ivKey, frameKey;
 	private final int transportId = 1234;
 	private final long connection = 12345L;
 
@@ -31,9 +31,9 @@ public class ConnectionEncrypterImplTest extends TestCase {
 		super();
 		Injector i = Guice.createInjector(new CryptoModule());
 		CryptoComponent crypto = i.getInstance(CryptoComponent.class);
-		tagCipher = crypto.getTagCipher();
+		ivCipher = crypto.getIvCipher();
 		frameCipher = crypto.getFrameCipher();
-		tagKey = crypto.generateSecretKey();
+		ivKey = crypto.generateSecretKey();
 		frameKey = crypto.generateSecretKey();
 	}
 
@@ -41,27 +41,26 @@ public class ConnectionEncrypterImplTest extends TestCase {
 	public void testSingleByteFrame() throws Exception {
 		ByteArrayOutputStream out = new ByteArrayOutputStream();
 		ConnectionEncrypter e = new ConnectionEncrypterImpl(out, transportId,
-				connection, tagCipher, frameCipher, tagKey, frameKey);
+				connection, ivCipher, frameCipher, ivKey, frameKey);
 		e.getOutputStream().write((byte) 0);
 		e.writeMac(new byte[MAC_LENGTH]);
-		assertEquals(TAG_LENGTH + 1 + MAC_LENGTH, out.toByteArray().length);
+		assertEquals(IV_LENGTH + 1 + MAC_LENGTH, out.toByteArray().length);
 	}
 
 	@Test
 	public void testEncryption() throws Exception {
-		// Calculate the expected ciphertext for the tag
-		byte[] plaintextTag = TagEncoder.encodeTag(transportId, connection);
-		assertEquals(TAG_LENGTH, plaintextTag.length);
-		tagCipher.init(Cipher.ENCRYPT_MODE, tagKey);
-		byte[] tag = tagCipher.doFinal(plaintextTag);
-		assertEquals(TAG_LENGTH, tag.length);
+		// Calculate the expected ciphertext for the IV
+		byte[] iv = IvEncoder.encodeIv(transportId, connection);
+		assertEquals(IV_LENGTH, iv.length);
+		ivCipher.init(Cipher.ENCRYPT_MODE, ivKey);
+		byte[] encryptedIv = ivCipher.doFinal(iv);
+		assertEquals(IV_LENGTH, encryptedIv.length);
 		// Calculate the expected ciphertext for the first frame
 		byte[] plaintext = new byte[123];
 		byte[] plaintextMac = new byte[MAC_LENGTH];
-		byte[] ivBytes = new byte[TAG_LENGTH];
-		TagEncoder.encodeTag(ivBytes, transportId, connection, 0L);
-		IvParameterSpec iv = new IvParameterSpec(ivBytes);
-		frameCipher.init(Cipher.ENCRYPT_MODE, frameKey, iv);
+		IvEncoder.encodeIv(iv, transportId, connection, 0L);
+		IvParameterSpec ivSpec = new IvParameterSpec(iv);
+		frameCipher.init(Cipher.ENCRYPT_MODE, frameKey, ivSpec);
 		byte[] ciphertext = new byte[plaintext.length + plaintextMac.length];
 		int offset = frameCipher.update(plaintext, 0, plaintext.length,
 				ciphertext);
@@ -69,9 +68,9 @@ public class ConnectionEncrypterImplTest extends TestCase {
 				offset);
 		// Calculate the expected ciphertext for the second frame
 		byte[] plaintext1 = new byte[1234];
-		TagEncoder.encodeTag(ivBytes, transportId, connection, 1L);
-		iv = new IvParameterSpec(ivBytes);
-		frameCipher.init(Cipher.ENCRYPT_MODE, frameKey, iv);
+		IvEncoder.encodeIv(iv, transportId, connection, 1L);
+		ivSpec = new IvParameterSpec(iv);
+		frameCipher.init(Cipher.ENCRYPT_MODE, frameKey, ivSpec);
 		byte[] ciphertext1 = new byte[plaintext1.length + plaintextMac.length];
 		offset = frameCipher.update(plaintext1, 0, plaintext1.length,
 				ciphertext1);
@@ -79,14 +78,14 @@ public class ConnectionEncrypterImplTest extends TestCase {
 				offset);
 		// Concatenate the ciphertexts
 		ByteArrayOutputStream out = new ByteArrayOutputStream();
-		out.write(tag);
+		out.write(encryptedIv);
 		out.write(ciphertext);
 		out.write(ciphertext1);
 		byte[] expected = out.toByteArray();
 		// Use a ConnectionEncrypter to encrypt the plaintext
 		out.reset();
 		ConnectionEncrypter e = new ConnectionEncrypterImpl(out, transportId,
-				connection, tagCipher, frameCipher, tagKey, frameKey);
+				connection, ivCipher, frameCipher, ivKey, frameKey);
 		e.getOutputStream().write(plaintext);
 		e.writeMac(plaintextMac);
 		e.getOutputStream().write(plaintext1);
diff --git a/test/net/sf/briar/transport/ConnectionReaderImplTest.java b/test/net/sf/briar/transport/ConnectionReaderImplTest.java
index d73e43676e82a382dbfdd90fa3886447da9cf719..1e8fe8a5681b39b142731de4508ea6f0b370dcf8 100644
--- a/test/net/sf/briar/transport/ConnectionReaderImplTest.java
+++ b/test/net/sf/briar/transport/ConnectionReaderImplTest.java
@@ -33,6 +33,8 @@ public class ConnectionReaderImplTest extends TestCase {
 		mac.init(crypto.generateSecretKey());
 	}
 
+	// FIXME: Test corner cases and corrupt frames
+
 	@Test
 	public void testSingleByteFrame() throws Exception {
 		// Six bytes for the header, one for the payload
diff --git a/test/net/sf/briar/transport/ConnectionRecogniserImplTest.java b/test/net/sf/briar/transport/ConnectionRecogniserImplTest.java
index c94b242a8a57c9538276596b77517afc7604316b..4d8af92f52989c03dc952024933d046e8456daf9 100644
--- a/test/net/sf/briar/transport/ConnectionRecogniserImplTest.java
+++ b/test/net/sf/briar/transport/ConnectionRecogniserImplTest.java
@@ -1,6 +1,6 @@
 package net.sf.briar.transport;
 
-import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
+import static net.sf.briar.api.transport.TransportConstants.IV_LENGTH;
 
 import java.util.Collection;
 import java.util.Collections;
@@ -41,7 +41,7 @@ public class ConnectionRecogniserImplTest extends TestCase {
 	}
 
 	@Test
-	public void testUnexpectedTag() throws Exception {
+	public void testUnexpectedIv() throws Exception {
 		Mockery context = new Mockery();
 		final DatabaseComponent db = context.mock(DatabaseComponent.class);
 		context.checking(new Expectations() {{
@@ -55,18 +55,18 @@ public class ConnectionRecogniserImplTest extends TestCase {
 		}});
 		final ConnectionRecogniserImpl c =
 			new ConnectionRecogniserImpl(transportId, crypto, db);
-		assertNull(c.acceptConnection(new byte[TAG_LENGTH]));
+		assertNull(c.acceptConnection(new byte[IV_LENGTH]));
 		context.assertIsSatisfied();
 	}
 
 	@Test
-	public void testExpectedTag() throws Exception {
-		// Calculate the expected tag for connection number 3
-		SecretKey tagKey = crypto.deriveIncomingTagKey(secret);
-		Cipher tagCipher = crypto.getTagCipher();
-		tagCipher.init(Cipher.ENCRYPT_MODE, tagKey);
-		byte[] tag = TagEncoder.encodeTag(transportId, 3L);
-		byte[] encryptedTag = tagCipher.doFinal(tag);
+	public void testExpectedIv() throws Exception {
+		// Calculate the expected IV for connection number 3
+		SecretKey ivKey = crypto.deriveIncomingIvKey(secret);
+		Cipher ivCipher = crypto.getIvCipher();
+		ivCipher.init(Cipher.ENCRYPT_MODE, ivKey);
+		byte[] iv = IvEncoder.encodeIv(transportId, 3L);
+		byte[] encryptedIv = ivCipher.doFinal(iv);
 
 		Mockery context = new Mockery();
 		final DatabaseComponent db = context.mock(DatabaseComponent.class);
@@ -83,10 +83,10 @@ public class ConnectionRecogniserImplTest extends TestCase {
 		}});
 		final ConnectionRecogniserImpl c =
 			new ConnectionRecogniserImpl(transportId, crypto, db);
-		// First time - the tag should be expected
-		assertEquals(contactId, c.acceptConnection(encryptedTag));
-		// Second time - the tag should no longer be expected
-		assertNull(c.acceptConnection(encryptedTag));
+		// First time - the IV should be expected
+		assertEquals(contactId, c.acceptConnection(encryptedIv));
+		// Second time - the IV should no longer be expected
+		assertNull(c.acceptConnection(encryptedIv));
 		// The window should have advanced
 		assertEquals(4L, connectionWindow.getCentre());
 		Collection<Long> unseen = connectionWindow.getUnseenConnectionNumbers();
diff --git a/test/net/sf/briar/transport/ConnectionWriterImplTest.java b/test/net/sf/briar/transport/ConnectionWriterImplTest.java
index 4892d58c9724296d8e9c08ecf37b14534d3c9f50..134b58ab69c9dae97f70f312a550a1036440e2a2 100644
--- a/test/net/sf/briar/transport/ConnectionWriterImplTest.java
+++ b/test/net/sf/briar/transport/ConnectionWriterImplTest.java
@@ -30,6 +30,8 @@ public class ConnectionWriterImplTest extends TestCase {
 		mac.init(crypto.generateSecretKey());
 	}
 
+	// FIXME: Test corner cases
+
 	@Test
 	public void testSingleByteFrame() throws Exception {
 		// Six bytes for the header, one for the payload
diff --git a/test/net/sf/briar/transport/FrameReadWriteTest.java b/test/net/sf/briar/transport/FrameReadWriteTest.java
index 7fb8ef717728d91e14b14aa7a2e4bceb4fbe4187..d7c98f09a7ba3725fe56b6160741cf5c1752af64 100644
--- a/test/net/sf/briar/transport/FrameReadWriteTest.java
+++ b/test/net/sf/briar/transport/FrameReadWriteTest.java
@@ -1,6 +1,6 @@
 package net.sf.briar.transport;
 
-import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
+import static net.sf.briar.api.transport.TransportConstants.IV_LENGTH;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
@@ -27,8 +27,8 @@ import com.google.inject.Injector;
 public class FrameReadWriteTest extends TestCase {
 
 	private final CryptoComponent crypto;
-	private final Cipher tagCipher, frameCipher;
-	private final SecretKey macKey, tagKey, frameKey;
+	private final Cipher ivCipher, frameCipher;
+	private final SecretKey ivKey, frameKey, macKey;
 	private final Mac mac;
 	private final Random random;
 	private final byte[] secret = new byte[100];
@@ -39,24 +39,24 @@ public class FrameReadWriteTest extends TestCase {
 		super();
 		Injector i = Guice.createInjector(new CryptoModule());
 		crypto = i.getInstance(CryptoComponent.class);
-		tagCipher = crypto.getTagCipher();
+		ivCipher = crypto.getIvCipher();
 		frameCipher = crypto.getFrameCipher();
-		// Since we're sending packets to ourselves, we only need outgoing keys
-		macKey = crypto.deriveOutgoingMacKey(secret);
-		tagKey = crypto.deriveOutgoingTagKey(secret);
+		// Since we're sending frames to ourselves, we only need outgoing keys
+		ivKey = crypto.deriveOutgoingIvKey(secret);
 		frameKey = crypto.deriveOutgoingFrameKey(secret);
+		macKey = crypto.deriveOutgoingMacKey(secret);
 		mac = crypto.getMac();
 		random = new Random();
 	}
 
 	@Test
 	public void testWriteAndRead() throws Exception {
-		// Calculate the expected ciphertext for the tag
-		byte[] plaintextTag = TagEncoder.encodeTag(transportId, connection);
-		assertEquals(TAG_LENGTH, plaintextTag.length);
-		tagCipher.init(Cipher.ENCRYPT_MODE, tagKey);
-		byte[] tag = tagCipher.doFinal(plaintextTag);
-		assertEquals(TAG_LENGTH, tag.length);
+		// Calculate the expected ciphertext for the IV
+		byte[] iv = IvEncoder.encodeIv(transportId, connection);
+		assertEquals(IV_LENGTH, iv.length);
+		ivCipher.init(Cipher.ENCRYPT_MODE, ivKey);
+		byte[] encryptedIv = ivCipher.doFinal(iv);
+		assertEquals(IV_LENGTH, encryptedIv.length);
 		// Generate two random frames
 		byte[] frame = new byte[12345];
 		random.nextBytes(frame);
@@ -65,7 +65,7 @@ public class FrameReadWriteTest extends TestCase {
 		// Write the frames
 		ByteArrayOutputStream out = new ByteArrayOutputStream();
 		ConnectionEncrypter encrypter = new ConnectionEncrypterImpl(out,
-				transportId, connection, tagCipher, frameCipher, tagKey,
+				transportId, connection, ivCipher, frameCipher, ivKey,
 				frameKey);
 		mac.init(macKey);
 		ConnectionWriter writer = new ConnectionWriterImpl(encrypter, mac);
@@ -76,9 +76,9 @@ public class FrameReadWriteTest extends TestCase {
 		out1.flush();
 		// Read the frames back
 		ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
-		byte[] recoveredTag = new byte[TAG_LENGTH];
-		assertEquals(TAG_LENGTH, in.read(recoveredTag));
-		assertTrue(Arrays.equals(tag, recoveredTag));
+		byte[] recoveredIv = new byte[IV_LENGTH];
+		assertEquals(IV_LENGTH, in.read(recoveredIv));
+		assertTrue(Arrays.equals(encryptedIv, recoveredIv));
 		ConnectionDecrypter decrypter = new ConnectionDecrypterImpl(in,
 				transportId, connection, frameCipher, frameKey);
 		ConnectionReader reader = new ConnectionReaderImpl(decrypter, mac);