diff --git a/briar-api/src/org/briarproject/api/data/BdfDictionary.java b/briar-api/src/org/briarproject/api/data/BdfDictionary.java
index 54a20f6f51b71fffb9f63e5d6b4c1c8e5430d7b3..ed0d5b98f95492b6d77668183053afc6ab963096 100644
--- a/briar-api/src/org/briarproject/api/data/BdfDictionary.java
+++ b/briar-api/src/org/briarproject/api/data/BdfDictionary.java
@@ -1,13 +1,39 @@
 package org.briarproject.api.data;
 
+import org.briarproject.api.Bytes;
 import org.briarproject.api.FormatException;
 
 import java.util.Hashtable;
+import java.util.Map;
+import java.util.Map.Entry;
 
 public class BdfDictionary extends Hashtable<String, Object> {
 
 	public static final Object NULL_VALUE = new Object();
 
+	/**
+	 * Factory method for constructing dictionaries inline.
+	 * <pre>
+	 * BdfDictionary.of(
+	 *     new BdfEntry("foo", foo),
+	 *     new BdfEntry("bar", bar)
+	 * );
+	 * </pre>
+	 */
+	public static BdfDictionary of(Entry<String, Object>... entries) {
+		BdfDictionary d = new BdfDictionary();
+		for (Entry<String, Object> e : entries) d.put(e.getKey(), e.getValue());
+		return d;
+	}
+
+	public BdfDictionary() {
+		super();
+	}
+
+	public BdfDictionary(Map<String, Object> m) {
+		super(m);
+	}
+
 	public Boolean getBoolean(String key) throws FormatException {
 		Object o = get(key);
 		if (o instanceof Boolean) return (Boolean) o;
@@ -23,24 +49,32 @@ public class BdfDictionary extends Hashtable<String, Object> {
 	public Long getInteger(String key) throws FormatException {
 		Object o = get(key);
 		if (o instanceof Long) return (Long) o;
+		if (o instanceof Integer) return ((Integer) o).longValue();
+		if (o instanceof Short) return ((Short) o).longValue();
+		if (o instanceof Byte) return ((Byte) o).longValue();
 		throw new FormatException();
 	}
 
 	public Long getInteger(String key, Long defaultValue) {
 		Object o = get(key);
 		if (o instanceof Long) return (Long) o;
+		if (o instanceof Integer) return ((Integer) o).longValue();
+		if (o instanceof Short) return ((Short) o).longValue();
+		if (o instanceof Byte) return ((Byte) o).longValue();
 		return defaultValue;
 	}
 
 	public Double getFloat(String key) throws FormatException {
 		Object o = get(key);
 		if (o instanceof Double) return (Double) o;
+		if (o instanceof Float) return ((Float) o).doubleValue();
 		throw new FormatException();
 	}
 
 	public Double getFloat(String key, Double defaultValue) {
 		Object o = get(key);
 		if (o instanceof Double) return (Double) o;
+		if (o instanceof Float) return ((Float) o).doubleValue();
 		return defaultValue;
 	}
 
@@ -59,12 +93,14 @@ public class BdfDictionary extends Hashtable<String, Object> {
 	public byte[] getRaw(String key) throws FormatException {
 		Object o = get(key);
 		if (o instanceof byte[]) return (byte[]) o;
+		if (o instanceof Bytes) return ((Bytes) o).getBytes();
 		throw new FormatException();
 	}
 
 	public byte[] getRaw(String key, byte[] defaultValue) {
 		Object o = get(key);
 		if (o instanceof byte[]) return (byte[]) o;
+		if (o instanceof Bytes) return ((Bytes) o).getBytes();
 		return defaultValue;
 	}
 
diff --git a/briar-api/src/org/briarproject/api/data/BdfEntry.java b/briar-api/src/org/briarproject/api/data/BdfEntry.java
new file mode 100644
index 0000000000000000000000000000000000000000..0168d2a3c5672661b4896ea300ed587765b160bd
--- /dev/null
+++ b/briar-api/src/org/briarproject/api/data/BdfEntry.java
@@ -0,0 +1,32 @@
+package org.briarproject.api.data;
+
+import java.util.Map.Entry;
+
+// This class is not thread-safe
+public class BdfEntry implements Entry<String, Object> {
+
+	private final String key;
+	private Object value;
+
+	public BdfEntry(String key, Object value) {
+		this.key = key;
+		this.value = value;
+	}
+
+	@Override
+	public String getKey() {
+		return key;
+	}
+
+	@Override
+	public Object getValue() {
+		return value;
+	}
+
+	@Override
+	public Object setValue(Object value) {
+		Object oldValue = this.value;
+		this.value = value;
+		return oldValue;
+	}
+}
diff --git a/briar-api/src/org/briarproject/api/data/BdfList.java b/briar-api/src/org/briarproject/api/data/BdfList.java
index 2caa597ec65103c4da429867c878bfa82ca0ac16..2d58bcd388c0e33cc8f9b2b0c767efb8437bac04 100644
--- a/briar-api/src/org/briarproject/api/data/BdfList.java
+++ b/briar-api/src/org/briarproject/api/data/BdfList.java
@@ -1,11 +1,32 @@
 package org.briarproject.api.data;
 
+import org.briarproject.api.Bytes;
 import org.briarproject.api.FormatException;
 
+import java.util.Arrays;
+import java.util.List;
 import java.util.Vector;
 
 public class BdfList extends Vector<Object> {
 
+	/**
+	 * Factory method for constructing lists inline.
+	 * <pre>
+	 * BdfList.of(1, 2, 3);
+	 * </pre>
+	 */
+	public static BdfList of(Object... items) {
+		return new BdfList(Arrays.asList(items));
+	}
+
+	public BdfList() {
+		super();
+	}
+
+	public BdfList(List<Object> items) {
+		super(items);
+	}
+
 	public Boolean getBoolean(int index) throws FormatException {
 		Object o = get(index);
 		if (o instanceof Boolean) return (Boolean) o;
@@ -21,24 +42,32 @@ public class BdfList extends Vector<Object> {
 	public Long getInteger(int index) throws FormatException {
 		Object o = get(index);
 		if (o instanceof Long) return (Long) o;
+		if (o instanceof Integer) return ((Integer) o).longValue();
+		if (o instanceof Short) return ((Short) o).longValue();
+		if (o instanceof Byte) return ((Byte) o).longValue();
 		throw new FormatException();
 	}
 
 	public Long getInteger(int index, Long defaultValue) {
 		Object o = get(index);
 		if (o instanceof Long) return (Long) o;
+		if (o instanceof Integer) return ((Integer) o).longValue();
+		if (o instanceof Short) return ((Short) o).longValue();
+		if (o instanceof Byte) return ((Byte) o).longValue();
 		return defaultValue;
 	}
 
 	public Double getFloat(int index) throws FormatException {
 		Object o = get(index);
 		if (o instanceof Double) return (Double) o;
+		if (o instanceof Float) return ((Float) o).doubleValue();
 		throw new FormatException();
 	}
 
 	public Double getFloat(int index, Double defaultValue) {
 		Object o = get(index);
 		if (o instanceof Double) return (Double) o;
+		if (o instanceof Float) return ((Float) o).doubleValue();
 		return defaultValue;
 	}
 
@@ -57,12 +86,14 @@ public class BdfList extends Vector<Object> {
 	public byte[] getRaw(int index) throws FormatException {
 		Object o = get(index);
 		if (o instanceof byte[]) return (byte[]) o;
+		if (o instanceof Bytes) return ((Bytes) o).getBytes();
 		throw new FormatException();
 	}
 
 	public byte[] getRaw(int index, byte[] defaultValue) {
 		Object o = get(index);
 		if (o instanceof byte[]) return (byte[]) o;
+		if (o instanceof Bytes) return ((Bytes) o).getBytes();
 		return defaultValue;
 	}
 
diff --git a/briar-core/src/org/briarproject/data/MetadataEncoderImpl.java b/briar-core/src/org/briarproject/data/MetadataEncoderImpl.java
index e70070391bdbcad505ac24eaf7b640e55890fca9..1de4c8ef62e41cb0c538e0ffcb0c58b08cd0eefb 100644
--- a/briar-core/src/org/briarproject/data/MetadataEncoderImpl.java
+++ b/briar-core/src/org/briarproject/data/MetadataEncoderImpl.java
@@ -1,5 +1,6 @@
 package org.briarproject.data;
 
+import org.briarproject.api.Bytes;
 import org.briarproject.api.FormatException;
 import org.briarproject.api.data.BdfDictionary;
 import org.briarproject.api.data.MetadataEncoder;
@@ -62,6 +63,7 @@ class MetadataEncoderImpl implements MetadataEncoder {
 		else if (o instanceof Double) encodeFloat(out, (Double) o);
 		else if (o instanceof String) encodeString(out, (String) o);
 		else if (o instanceof byte[]) encodeRaw(out, (byte[]) o);
+		else if (o instanceof Bytes) encodeRaw(out, ((Bytes) o).getBytes());
 		else if (o instanceof List) encodeList(out, (List) o);
 		else if (o instanceof Map) encodeDictionary(out, (Map) o);
 		else throw new FormatException();
diff --git a/briar-tests/src/org/briarproject/data/BdfDictionaryTest.java b/briar-tests/src/org/briarproject/data/BdfDictionaryTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..0e2c9d8dfae2e9315b74c8e18a29e0a98ad9e501
--- /dev/null
+++ b/briar-tests/src/org/briarproject/data/BdfDictionaryTest.java
@@ -0,0 +1,65 @@
+package org.briarproject.data;
+
+import org.briarproject.BriarTestCase;
+import org.briarproject.api.Bytes;
+import org.briarproject.api.data.BdfDictionary;
+import org.briarproject.api.data.BdfEntry;
+import org.junit.Test;
+
+import java.util.Collections;
+
+import static org.briarproject.api.data.BdfDictionary.NULL_VALUE;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+
+public class BdfDictionaryTest extends BriarTestCase {
+
+	@Test
+	public void testConstructors() {
+		assertEquals(Collections.emptyMap(), new BdfDictionary());
+		assertEquals(Collections.singletonMap("foo", NULL_VALUE),
+				new BdfDictionary(Collections.singletonMap("foo", NULL_VALUE)));
+	}
+
+	@Test
+	public void testFactoryMethod() {
+		assertEquals(Collections.emptyMap(), BdfDictionary.of());
+		assertEquals(Collections.singletonMap("foo", NULL_VALUE),
+				BdfDictionary.of(new BdfEntry("foo", NULL_VALUE)));
+	}
+
+	@Test
+	public void testIntegerPromotion() throws Exception {
+		BdfDictionary d = new BdfDictionary();
+		d.put("foo", (byte) 1);
+		d.put("bar", (short) 2);
+		d.put("baz", 3);
+		d.put("bam", 4L);
+		assertEquals(Long.valueOf(1), d.getInteger("foo"));
+		assertEquals(Long.valueOf(2), d.getInteger("bar"));
+		assertEquals(Long.valueOf(3), d.getInteger("baz"));
+		assertEquals(Long.valueOf(4), d.getInteger("bam"));
+	}
+
+	@Test
+	public void testFloatPromotion() throws Exception {
+		BdfDictionary d = new BdfDictionary();
+		d.put("foo", 1F);
+		d.put("bar", 2D);
+		assertEquals(Double.valueOf(1), d.getFloat("foo"));
+		assertEquals(Double.valueOf(2), d.getFloat("bar"));
+	}
+
+	@Test
+	public void testByteArrayUnwrapping() throws Exception {
+		BdfDictionary d = new BdfDictionary();
+		d.put("foo", new byte[123]);
+		d.put("bar", new Bytes(new byte[123]));
+		byte[] foo = d.getRaw("foo");
+		assertEquals(123, foo.length);
+		assertArrayEquals(new byte[123], foo);
+		byte[] bar = d.getRaw("bar");
+		assertEquals(123, bar.length);
+		assertArrayEquals(new byte[123], bar);
+	}
+}
diff --git a/briar-tests/src/org/briarproject/data/BdfListTest.java b/briar-tests/src/org/briarproject/data/BdfListTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..b1954e8164aa61ff17b2543617b7d23a0f0056d5
--- /dev/null
+++ b/briar-tests/src/org/briarproject/data/BdfListTest.java
@@ -0,0 +1,65 @@
+package org.briarproject.data;
+
+import org.briarproject.BriarTestCase;
+import org.briarproject.api.Bytes;
+import org.briarproject.api.data.BdfList;
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+import static org.briarproject.api.data.BdfDictionary.NULL_VALUE;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+
+public class BdfListTest extends BriarTestCase {
+
+	@Test
+	public void testConstructors() {
+		assertEquals(Collections.emptyList(), new BdfList());
+		assertEquals(Arrays.asList(1, 2, NULL_VALUE),
+				new BdfList(Arrays.asList(1, 2, NULL_VALUE)));
+	}
+
+	@Test
+	public void testFactoryMethod() {
+		assertEquals(Collections.emptyList(), BdfList.of());
+		assertEquals(Arrays.asList(1, 2, NULL_VALUE),
+				BdfList.of(1, 2, NULL_VALUE));
+	}
+
+	@Test
+	public void testIntegerPromotion() throws Exception {
+		BdfList list = new BdfList();
+		list.add((byte) 1);
+		list.add((short) 2);
+		list.add(3);
+		list.add(4L);
+		assertEquals(Long.valueOf(1), list.getInteger(0));
+		assertEquals(Long.valueOf(2), list.getInteger(1));
+		assertEquals(Long.valueOf(3), list.getInteger(2));
+		assertEquals(Long.valueOf(4), list.getInteger(3));
+	}
+
+	@Test
+	public void testFloatPromotion() throws Exception {
+		BdfList list = new BdfList();
+		list.add(1F);
+		list.add(2D);
+		assertEquals(Double.valueOf(1), list.getFloat(0));
+		assertEquals(Double.valueOf(2), list.getFloat(1));
+	}
+
+	@Test
+	public void testByteArrayUnwrapping() throws Exception {
+		BdfList list = new BdfList();
+		list.add(new byte[123]);
+		list.add(new Bytes(new byte[123]));
+		byte[] first = list.getRaw(0);
+		assertEquals(123, first.length);
+		assertArrayEquals(new byte[123], first);
+		byte[] second = list.getRaw(1);
+		assertEquals(123, second.length);
+		assertArrayEquals(new byte[123], second);
+	}
+}