diff --git a/components/net/sf/briar/transport/Frame.java b/components/net/sf/briar/transport/Frame.java
index f9d3ca2d1ba346941847556dee5e8a08f9049bcf..64c8eeda9a94cf71b7752bde3c0498f3395742de 100644
--- a/components/net/sf/briar/transport/Frame.java
+++ b/components/net/sf/briar/transport/Frame.java
@@ -4,10 +4,18 @@ import static net.sf.briar.api.transport.TransportConstants.MAX_FRAME_LENGTH;
 
 class Frame {
 
-	private final byte[] buf = new byte[MAX_FRAME_LENGTH];
+	private final byte[] buf;
 
 	private int length = -1;
 
+	Frame() {
+		this(MAX_FRAME_LENGTH);
+	}
+
+	Frame(int length) {
+		buf = new byte[length];
+	}
+
 	public byte[] getBuffer() {
 		return buf;
 	}
diff --git a/components/net/sf/briar/transport/XorErasureDecoder.java b/components/net/sf/briar/transport/XorErasureDecoder.java
index 47093034edd670874fa4211cd6f83008194b9245..685aab252e74842a5fb87cf89e463e40de05e2ad 100644
--- a/components/net/sf/briar/transport/XorErasureDecoder.java
+++ b/components/net/sf/briar/transport/XorErasureDecoder.java
@@ -36,27 +36,31 @@ class XorErasureDecoder implements ErasureDecoder {
 			// We don't need no stinkin' parity segment
 			for(int i = 0; i < n - 1; i++) {
 				byte[] src = set[i].getBuffer();
-				System.arraycopy(src, 0, dest, offset, length);
+				int copyLength = Math.min(length, dest.length - offset);
+				System.arraycopy(src, 0, dest, offset, copyLength);
 				offset += length;
 			}
 		} else {
 			// Reconstruct the missing segment
 			byte[] parity = new byte[length];
 			int missingOffset = -1;
-			for(int i = 0; i < n; i++) {
+			for(int i = 0; i < n - 1; i++) {
 				if(set[i] == null) {
 					missingOffset = offset;
 				} else {
 					byte[] src = set[i].getBuffer();
-					System.arraycopy(src, 0, dest, offset, length);
 					for(int j = 0; j < length; j++) parity[j] ^= src[j];
+					int copyLength = Math.min(length, dest.length - offset);
+					System.arraycopy(src, 0, dest, offset, copyLength);
 				}
 				offset += length;
 			}
+			byte[] src = set[n - 1].getBuffer();
+			for(int i = 0; i < length; i++) parity[i] ^= src[i];
 			assert missingOffset != -1;
-			System.arraycopy(parity, 0, dest, missingOffset, length);
+			int copyLength = Math.min(length, dest.length - missingOffset);
+			System.arraycopy(parity, 0, dest, missingOffset, copyLength);
 		}
-		assert offset == length * (n - 1);
 		// The frame length may not be an exact multiple of the segment length
 		int payload = HeaderEncoder.getPayloadLength(dest);
 		int padding = HeaderEncoder.getPaddingLength(dest);
diff --git a/components/net/sf/briar/transport/XorErasureEncoder.java b/components/net/sf/briar/transport/XorErasureEncoder.java
index b0a529b6473c538d6069c6f1e8e0b348e0f48029..220f679e38b92968cb902a5a709944430a05402b 100644
--- a/components/net/sf/briar/transport/XorErasureEncoder.java
+++ b/components/net/sf/briar/transport/XorErasureEncoder.java
@@ -21,8 +21,9 @@ class XorErasureEncoder implements ErasureEncoder {
 		byte[] src = f.getBuffer(), parity = set[n - 1].getBuffer();
 		int offset = 0;
 		for(int i = 0; i < n - 1; i++) {
-			System.arraycopy(src, offset, set[i].getBuffer(), 0, length);
-			for(int j = 0; j < length; j++) parity[j] ^= src[offset + j];
+			int copyLength = Math.min(length, src.length - offset);
+			System.arraycopy(src, offset, set[i].getBuffer(), 0, copyLength);
+			for(int j = 0; j < copyLength; j++) parity[j] ^= src[offset + j];
 			offset += length;
 		}
 		return set;
diff --git a/test/build.xml b/test/build.xml
index 2f41b5e64e9f118f1c81d9ce4481405acb5fab46..c2b2dd641e8c53764d2e97334b80dc86c7653a24 100644
--- a/test/build.xml
+++ b/test/build.xml
@@ -61,6 +61,7 @@
 			<test name='net.sf.briar.transport.IncomingSegmentedEncryptionLayerTest'/>
 			<test name='net.sf.briar.transport.OutgoingEncryptionLayerImplTest'/>
 			<test name='net.sf.briar.transport.OutgoingSegmentedEncryptionLayerTest'/>
+			<test name='net.sf.briar.transport.XorErasureCodeTest'/>
 			<test name='net.sf.briar.transport.XorErasureDecoderTest'/>
 			<test name='net.sf.briar.transport.XorErasureEncoderTest'/>
 			<test name='net.sf.briar.util.ByteUtilsTest'/>
diff --git a/test/net/sf/briar/transport/XorErasureCodeTest.java b/test/net/sf/briar/transport/XorErasureCodeTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..b361cc2d83371fbaceb9fc4d39a83a0c14dca175
--- /dev/null
+++ b/test/net/sf/briar/transport/XorErasureCodeTest.java
@@ -0,0 +1,50 @@
+package net.sf.briar.transport;
+
+import static net.sf.briar.api.transport.TransportConstants.FRAME_HEADER_LENGTH;
+import static net.sf.briar.api.transport.TransportConstants.MAC_LENGTH;
+
+import java.util.Random;
+
+import net.sf.briar.BriarTestCase;
+import net.sf.briar.api.transport.Segment;
+
+import static org.junit.Assert.assertArrayEquals;
+import org.junit.Test;
+
+public class XorErasureCodeTest extends BriarTestCase {
+
+	@Test
+	public void testEncodingAndDecodingWithAllSegments() throws Exception {
+		XorErasureEncoder e = new XorErasureEncoder(5);
+		XorErasureDecoder d = new XorErasureDecoder(5);
+		Frame f = new Frame(1234);
+		new Random().nextBytes(f.getBuffer());
+		int payload = 1234 - FRAME_HEADER_LENGTH - MAC_LENGTH;
+		HeaderEncoder.encodeHeader(f.getBuffer(), 0L, payload, 0);
+		f.setLength(1234);
+		Segment[] set = e.encodeFrame(f);
+		assertEquals(5, set.length);
+		Frame f1 = new Frame(1234);
+		assertTrue(d.decodeFrame(f1, set));
+		assertArrayEquals(f.getBuffer(), f1.getBuffer());
+	}
+
+	@Test
+	public void testEncodingAndDecodingWithMissingSegment() throws Exception {
+		XorErasureEncoder e = new XorErasureEncoder(5);
+		XorErasureDecoder d = new XorErasureDecoder(5);
+		Frame f = new Frame(1234);
+		new Random().nextBytes(f.getBuffer());
+		int payload = 1234 - FRAME_HEADER_LENGTH - MAC_LENGTH;
+		HeaderEncoder.encodeHeader(f.getBuffer(), 0L, payload, 0);
+		f.setLength(1234);
+		for(int i = 0; i < 5; i++) {
+			Segment[] set = e.encodeFrame(f);
+			assertEquals(5, set.length);
+			set[i] = null;
+			Frame f1 = new Frame(1234);
+			assertTrue(d.decodeFrame(f1, set));
+			assertArrayEquals(f.getBuffer(), f1.getBuffer());
+		}
+	}
+}
diff --git a/test/net/sf/briar/transport/XorErasureDecoderTest.java b/test/net/sf/briar/transport/XorErasureDecoderTest.java
index 3b78f755b497a1a4dd0c2f19794f94dda368eb8f..944610fcbeae3700f9ef429410095d0a8efa4480 100644
--- a/test/net/sf/briar/transport/XorErasureDecoderTest.java
+++ b/test/net/sf/briar/transport/XorErasureDecoderTest.java
@@ -14,24 +14,15 @@ public class XorErasureDecoderTest extends BriarTestCase {
 
 	@Test
 	public void testMaximumLength() throws Exception {
+		XorErasureDecoder d = new XorErasureDecoder(5);
 		// A frame of the maximum length should be decoded successfully
 		Segment[] set = encodeEmptyFrame(MAX_FRAME_LENGTH / 4, 5);
-		XorErasureDecoder d = new XorErasureDecoder(5);
 		Frame f = new Frame();
 		assertTrue(d.decodeFrame(f, set));
-		// Check the header
-		byte[] b = f.getBuffer();
-		assertEquals(0L, HeaderEncoder.getFrameNumber(b));
-		int payload = MAX_FRAME_LENGTH - FRAME_HEADER_LENGTH - MAC_LENGTH;
-		assertEquals(payload, HeaderEncoder.getPayloadLength(b));
-		assertEquals(0, HeaderEncoder.getPaddingLength(b));
-		// Check the body
-		assertEquals(MAX_FRAME_LENGTH, f.getLength());
-		for(int i = FRAME_HEADER_LENGTH; i < MAX_FRAME_LENGTH; i++) {
-			assertEquals(0, b[i]);
-		}
+		checkFrame(f, MAX_FRAME_LENGTH);
 		// A frame larger than the maximum length should not be decoded
 		set = encodeEmptyFrame(MAX_FRAME_LENGTH / 4 + 1, 5);
+		f = new Frame();
 		try {
 			d.decodeFrame(f, set);
 		} catch(FormatException expected) {}
@@ -47,12 +38,35 @@ public class XorErasureDecoderTest extends BriarTestCase {
 		set[1].setLength(251);
 		// The frame should be decoded successfully
 		XorErasureDecoder d = new XorErasureDecoder(4);
-		Frame f = new Frame();
+		Frame f = new Frame(750);
 		assertTrue(d.decodeFrame(f, set));
 		// The minimum of the segments' lengths should have been used
 		assertEquals(750, f.getLength());
 	}
 
+	@Test
+	public void testDecodingWithMissingSegment() throws Exception {
+		XorErasureDecoder d = new XorErasureDecoder(4);
+		for(int i = 0; i < 4; i++) {
+			Segment[] set = encodeEmptyFrame(250, 4);
+			set[i] = null;
+			// The frame should be decoded successfully
+			Frame f = new Frame(750);
+			assertTrue(d.decodeFrame(f, set));
+			checkFrame(f, 750);
+		}
+	}
+
+	@Test
+	public void testDecodingWithTwoMissingSegments() throws Exception {
+		XorErasureDecoder d = new XorErasureDecoder(4);
+		Segment[] set = encodeEmptyFrame(250, 4);
+		set[0] = null;
+		set[1] = null;
+		Frame f = new Frame(750);
+		assertFalse(d.decodeFrame(f, set));
+	}
+
 	private Segment[] encodeEmptyFrame(int length, int n) {
 		Segment[] set = new Segment[n];
 		for(int i = 0; i < n; i++) {
@@ -64,4 +78,17 @@ public class XorErasureDecoderTest extends BriarTestCase {
 		HeaderEncoder.encodeHeader(set[n - 1].getBuffer(), 0L, payload, 0);
 		return set;
 	}
+
+	private void checkFrame(Frame f, int length) {
+		byte[] b = f.getBuffer();
+		assertEquals(0L, HeaderEncoder.getFrameNumber(b));
+		int payload = length - FRAME_HEADER_LENGTH - MAC_LENGTH;
+		assertEquals(payload, HeaderEncoder.getPayloadLength(b));
+		assertEquals(0, HeaderEncoder.getPaddingLength(b));
+		// Check the body
+		assertEquals(length, f.getLength());
+		for(int i = FRAME_HEADER_LENGTH; i < length; i++) {
+			assertEquals("" + i, 0, b[i]);
+		}
+	}
 }