diff --git a/.classpath b/.classpath
index 2f247967a057d62c42661a794154f6712ca18a5f..210b0bbcfa843271085ea0222dc8e29beb7ef4e5 100644
--- a/.classpath
+++ b/.classpath
@@ -16,5 +16,6 @@
 	<classpathentry kind="lib" path="lib/commons-io-2.0.1.jar"/>
 	<classpathentry kind="lib" path="lib/h2small-1.3.157.jar"/>
 	<classpathentry kind="lib" path="lib/test/junit-4.9b3.jar"/>
+	<classpathentry kind="lib" path="lib/bcprov-jdk15-146.jar"/>
 	<classpathentry kind="output" path="bin"/>
 </classpath>
diff --git a/api/net/sf/briar/api/crypto/CryptoComponent.java b/api/net/sf/briar/api/crypto/CryptoComponent.java
new file mode 100644
index 0000000000000000000000000000000000000000..3399127bc69b6f6582a8ef3cbaab2b9fa5eea1c9
--- /dev/null
+++ b/api/net/sf/briar/api/crypto/CryptoComponent.java
@@ -0,0 +1,17 @@
+package net.sf.briar.api.crypto;
+
+import java.security.KeyPair;
+import java.security.MessageDigest;
+import java.security.Signature;
+
+
+public interface CryptoComponent {
+
+	KeyPair generateKeyPair();
+
+	KeyParser getKeyParser();
+
+	MessageDigest getMessageDigest();
+
+	Signature getSignature();
+}
diff --git a/components/net/sf/briar/crypto/CryptoComponentImpl.java b/components/net/sf/briar/crypto/CryptoComponentImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..ab0458e969ca345da3bac16a51b9bd25cbe302ee
--- /dev/null
+++ b/components/net/sf/briar/crypto/CryptoComponentImpl.java
@@ -0,0 +1,66 @@
+package net.sf.briar.crypto;
+
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Security;
+import java.security.Signature;
+
+import net.sf.briar.api.crypto.CryptoComponent;
+import net.sf.briar.api.crypto.KeyParser;
+
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+
+public class CryptoComponentImpl implements CryptoComponent {
+
+	private static final String PROVIDER = "BC";
+	private static final String DIGEST_ALGO = "SHA-256";
+	private static final String KEY_PAIR_ALGO = "RSA";
+	private static final String SIGNATURE_ALGO = "SHA256withRSA";
+
+	private final KeyParser keyParser;
+	private final KeyPairGenerator keyPairGenerator;
+
+	CryptoComponentImpl() {
+		Security.addProvider(new BouncyCastleProvider());
+		try {
+			keyParser = new KeyParserImpl(KEY_PAIR_ALGO, PROVIDER);
+			keyPairGenerator = KeyPairGenerator.getInstance(KEY_PAIR_ALGO,
+					PROVIDER);
+		} catch(NoSuchAlgorithmException impossible) {
+			throw new RuntimeException(impossible);
+		} catch(NoSuchProviderException impossible) {
+			throw new RuntimeException(impossible);
+		}
+	}
+
+	public KeyPair generateKeyPair() {
+		return keyPairGenerator.generateKeyPair();
+	}
+
+	public KeyParser getKeyParser() {
+		return keyParser;
+	}
+
+	public MessageDigest getMessageDigest() {
+		try {
+			return MessageDigest.getInstance(DIGEST_ALGO, PROVIDER);
+		} catch(NoSuchAlgorithmException impossible) {
+			throw new RuntimeException(impossible);
+		} catch(NoSuchProviderException impossible) {
+			throw new RuntimeException(impossible);
+		}
+	}
+
+	public Signature getSignature() {
+		try {
+			return Signature.getInstance(SIGNATURE_ALGO, PROVIDER);
+		} catch(NoSuchAlgorithmException impossible) {
+			throw new RuntimeException(impossible);
+		} catch(NoSuchProviderException impossible) {
+			throw new RuntimeException(impossible);
+		}
+	}
+}
diff --git a/components/net/sf/briar/crypto/CryptoModule.java b/components/net/sf/briar/crypto/CryptoModule.java
index 93240a4839b21abcd9ee60f8464a6cca91085165..1f6546a8cb2b91e72b899814875b2098a4f6a905 100644
--- a/components/net/sf/briar/crypto/CryptoModule.java
+++ b/components/net/sf/briar/crypto/CryptoModule.java
@@ -1,60 +1,14 @@
 package net.sf.briar.crypto;
 
-import java.security.KeyPair;
-import java.security.KeyPairGenerator;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.security.Signature;
-
-import net.sf.briar.api.crypto.KeyParser;
+import net.sf.briar.api.crypto.CryptoComponent;
 
 import com.google.inject.AbstractModule;
-import com.google.inject.Provides;
+import com.google.inject.Singleton;
 
 public class CryptoModule extends AbstractModule {
 
-	private static final String DIGEST_ALGO = "SHA-256";
-	private static final String KEY_PAIR_ALGO = "RSA";
-	private static final String SIGNATURE_ALGO = "SHA256withRSA";
-
 	@Override
 	protected void configure() {
-		try {
-			bind(KeyParser.class).toInstance(new KeyParserImpl(KEY_PAIR_ALGO));
-		} catch(NoSuchAlgorithmException e) {
-			// FIXME: Can modules throw?
-			throw new RuntimeException(e);
-		}
-	}
-
-	@Provides
-	MessageDigest getMessageDigest() {
-		try {
-			return MessageDigest.getInstance(DIGEST_ALGO);
-		} catch(NoSuchAlgorithmException e) {
-			// FIXME: Providers should not throw
-			throw new RuntimeException(e);
-		}
-	}
-
-	@Provides
-	Signature getSignature() {
-		try {
-			return Signature.getInstance(SIGNATURE_ALGO);
-		} catch(NoSuchAlgorithmException e) {
-			// FIXME: Providers should not throw
-			throw new RuntimeException(e);
-		}
-	}
-
-	@Provides
-	KeyPair generateKeyPair() {
-		try {
-			KeyPairGenerator gen = KeyPairGenerator.getInstance(KEY_PAIR_ALGO);
-			return gen.generateKeyPair();
-		} catch(NoSuchAlgorithmException e) {
-			// FIXME: Providers should not throw
-			throw new RuntimeException(e);
-		}
+		bind(CryptoComponent.class).to(CryptoComponentImpl.class).in(Singleton.class);
 	}
 }
diff --git a/components/net/sf/briar/crypto/KeyParserImpl.java b/components/net/sf/briar/crypto/KeyParserImpl.java
index 13ae3ee5f97ca0d52b4c9ed0a3cab19ee47eff9b..ec875f60d498db185f79b7757806cb8802630cb1 100644
--- a/components/net/sf/briar/crypto/KeyParserImpl.java
+++ b/components/net/sf/briar/crypto/KeyParserImpl.java
@@ -2,6 +2,7 @@ package net.sf.briar.crypto;
 
 import java.security.KeyFactory;
 import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
 import java.security.PublicKey;
 import java.security.spec.EncodedKeySpec;
 import java.security.spec.InvalidKeySpecException;
@@ -13,8 +14,9 @@ class KeyParserImpl implements KeyParser {
 
 	private final KeyFactory keyFactory;
 
-	KeyParserImpl(String algorithm) throws NoSuchAlgorithmException {
-		keyFactory = KeyFactory.getInstance(algorithm);
+	KeyParserImpl(String algorithm, String provider)
+	throws NoSuchAlgorithmException, NoSuchProviderException {
+		keyFactory = KeyFactory.getInstance(algorithm, provider);
 	}
 
 	public PublicKey parsePublicKey(byte[] encodedKey)
diff --git a/components/net/sf/briar/protocol/GroupFactoryImpl.java b/components/net/sf/briar/protocol/GroupFactoryImpl.java
index b76028565f9307379eae4ee4dc1902d6debc2973..f704a31e3011a3202bbaa8f2a5ece02245192727 100644
--- a/components/net/sf/briar/protocol/GroupFactoryImpl.java
+++ b/components/net/sf/briar/protocol/GroupFactoryImpl.java
@@ -3,6 +3,7 @@ package net.sf.briar.protocol;
 import java.security.PublicKey;
 import java.security.spec.InvalidKeySpecException;
 
+import net.sf.briar.api.crypto.CryptoComponent;
 import net.sf.briar.api.crypto.KeyParser;
 import net.sf.briar.api.protocol.Group;
 import net.sf.briar.api.protocol.GroupFactory;
@@ -15,8 +16,8 @@ class GroupFactoryImpl implements GroupFactory {
 	private final KeyParser keyParser;
 
 	@Inject
-	GroupFactoryImpl(KeyParser keyParser) {
-		this.keyParser = keyParser;
+	GroupFactoryImpl(CryptoComponent crypto) {
+		keyParser = crypto.getKeyParser();
 	}
 
 	public Group createGroup(GroupId id, String name, boolean restricted,
diff --git a/components/net/sf/briar/protocol/MessageEncoderImpl.java b/components/net/sf/briar/protocol/MessageEncoderImpl.java
index 102f552e960dd6b44fa4c361dc53af6ace0d38b4..ef1107baee4e0471b914e8d2bc2f4c069d49f27d 100644
--- a/components/net/sf/briar/protocol/MessageEncoderImpl.java
+++ b/components/net/sf/briar/protocol/MessageEncoderImpl.java
@@ -7,6 +7,7 @@ import java.security.KeyPair;
 import java.security.MessageDigest;
 import java.security.Signature;
 
+import net.sf.briar.api.crypto.CryptoComponent;
 import net.sf.briar.api.protocol.AuthorId;
 import net.sf.briar.api.protocol.GroupId;
 import net.sf.briar.api.protocol.Message;
@@ -25,10 +26,9 @@ class MessageEncoderImpl implements MessageEncoder {
 	private final WriterFactory writerFactory;
 
 	@Inject
-	MessageEncoderImpl(Signature signature, MessageDigest messageDigest,
-			WriterFactory writerFactory) {
-		this.signature = signature;
-		this.messageDigest = messageDigest;
+	MessageEncoderImpl(CryptoComponent crypto, WriterFactory writerFactory) {
+		signature = crypto.getSignature();
+		messageDigest = crypto.getMessageDigest();
 		this.writerFactory = writerFactory;
 	}
 
diff --git a/components/net/sf/briar/protocol/writers/PacketWriterFactoryImpl.java b/components/net/sf/briar/protocol/writers/PacketWriterFactoryImpl.java
index 97294daa51a1c8c4397f445a237ae5f95cb816f5..7d0959db5460ecee61f651e1ff25f90eafe9bf3b 100644
--- a/components/net/sf/briar/protocol/writers/PacketWriterFactoryImpl.java
+++ b/components/net/sf/briar/protocol/writers/PacketWriterFactoryImpl.java
@@ -3,6 +3,7 @@ package net.sf.briar.protocol.writers;
 import java.io.OutputStream;
 import java.security.MessageDigest;
 
+import net.sf.briar.api.crypto.CryptoComponent;
 import net.sf.briar.api.protocol.writers.AckWriter;
 import net.sf.briar.api.protocol.writers.BatchWriter;
 import net.sf.briar.api.protocol.writers.PacketWriterFactory;
@@ -18,9 +19,9 @@ class PacketWriterFactoryImpl implements PacketWriterFactory {
 	private final WriterFactory writerFactory;
 
 	@Inject
-	PacketWriterFactoryImpl(MessageDigest messageDigest,
+	PacketWriterFactoryImpl(CryptoComponent crypto,
 			WriterFactory writerFactory) {
-		this.messageDigest = messageDigest;
+		messageDigest = crypto.getMessageDigest();
 		this.writerFactory = writerFactory;
 	}
 
diff --git a/lib/bcprov-jdk15-146.jar b/lib/bcprov-jdk15-146.jar
new file mode 100644
index 0000000000000000000000000000000000000000..daa0b54cc0fdc4d68bdeea96175b6c46f03daf46
Binary files /dev/null and b/lib/bcprov-jdk15-146.jar differ
diff --git a/test/net/sf/briar/protocol/BatchReaderTest.java b/test/net/sf/briar/protocol/BatchReaderTest.java
index 7e58b5c264f5a02f1be00bf34fda98493c5cc1c1..54bb5042cfef6d68c37165f0e31ade61e39c371e 100644
--- a/test/net/sf/briar/protocol/BatchReaderTest.java
+++ b/test/net/sf/briar/protocol/BatchReaderTest.java
@@ -7,6 +7,7 @@ import java.security.MessageDigest;
 import java.util.Collections;
 
 import junit.framework.TestCase;
+import net.sf.briar.api.crypto.CryptoComponent;
 import net.sf.briar.api.protocol.Batch;
 import net.sf.briar.api.protocol.BatchId;
 import net.sf.briar.api.protocol.Message;
@@ -42,7 +43,7 @@ public class BatchReaderTest extends TestCase {
 				new CryptoModule());
 		readerFactory = i.getInstance(ReaderFactory.class);
 		writerFactory = i.getInstance(WriterFactory.class);
-		messageDigest = i.getInstance(MessageDigest.class);
+		messageDigest = i.getInstance(CryptoComponent.class).getMessageDigest();
 		context = new Mockery();
 		message = context.mock(Message.class);
 	}
diff --git a/test/net/sf/briar/protocol/ConsumersTest.java b/test/net/sf/briar/protocol/ConsumersTest.java
index c2d16bf84f06f0dc6864b3097310c0660d3f5358..22c290830914f7b528b7bebbbf338addef31e2a8 100644
--- a/test/net/sf/briar/protocol/ConsumersTest.java
+++ b/test/net/sf/briar/protocol/ConsumersTest.java
@@ -7,6 +7,7 @@ import java.util.Arrays;
 import java.util.Random;
 
 import junit.framework.TestCase;
+import net.sf.briar.api.crypto.CryptoComponent;
 import net.sf.briar.api.serial.FormatException;
 import net.sf.briar.crypto.CryptoModule;
 
@@ -18,20 +19,18 @@ import com.google.inject.Injector;
 
 public class ConsumersTest extends TestCase {
 
-	private Signature signature = null;
-	private KeyPair keyPair = null;
-	private MessageDigest messageDigest = null;
+	private CryptoComponent crypto = null;
 
 	@Before
 	public void setUp() {
 		Injector i = Guice.createInjector(new CryptoModule());
-		signature = i.getInstance(Signature.class);
-		keyPair = i.getInstance(KeyPair.class);
-		messageDigest = i.getInstance(MessageDigest.class);
+		crypto = i.getInstance(CryptoComponent.class);
 	}
 		
 	@Test
 	public void testSigningConsumer() throws Exception {
+		Signature signature = crypto.getSignature();
+		KeyPair keyPair = crypto.generateKeyPair();
 		byte[] data = new byte[1234];
 		// Generate some random data and sign it
 		new Random().nextBytes(data);
@@ -50,6 +49,7 @@ public class ConsumersTest extends TestCase {
 
 	@Test
 	public void testDigestingConsumer() throws Exception {
+		MessageDigest messageDigest = crypto.getMessageDigest();
 		byte[] data = new byte[1234];
 		// Generate some random data and digest it
 		new Random().nextBytes(data);
diff --git a/test/net/sf/briar/protocol/FileReadWriteTest.java b/test/net/sf/briar/protocol/FileReadWriteTest.java
index 27a180459dcebd8cc35382e1b9fc5e88d861931e..62ad02a7f4bb555bcf18132ed118447cc2366fab 100644
--- a/test/net/sf/briar/protocol/FileReadWriteTest.java
+++ b/test/net/sf/briar/protocol/FileReadWriteTest.java
@@ -13,6 +13,7 @@ import java.util.Iterator;
 
 import junit.framework.TestCase;
 import net.sf.briar.TestUtils;
+import net.sf.briar.api.crypto.CryptoComponent;
 import net.sf.briar.api.crypto.KeyParser;
 import net.sf.briar.api.protocol.Ack;
 import net.sf.briar.api.protocol.Batch;
@@ -63,6 +64,7 @@ public class FileReadWriteTest extends TestCase {
 	private final ReaderFactory readerFactory;
 	private final WriterFactory writerFactory;
 	private final PacketWriterFactory packetWriterFactory;
+	private final CryptoComponent crypto;
 	private final Signature signature;
 	private final MessageDigest messageDigest, batchDigest;
 	private final KeyParser keyParser;
@@ -77,15 +79,16 @@ public class FileReadWriteTest extends TestCase {
 		readerFactory = i.getInstance(ReaderFactory.class);
 		writerFactory = i.getInstance(WriterFactory.class);
 		packetWriterFactory = i.getInstance(PacketWriterFactory.class);
-		keyParser = i.getInstance(KeyParser.class);
-		signature = i.getInstance(Signature.class);
-		messageDigest = i.getInstance(MessageDigest.class);
-		batchDigest = i.getInstance(MessageDigest.class);
+		crypto = i.getInstance(CryptoComponent.class);
+		keyParser = crypto.getKeyParser();
+		signature = crypto.getSignature();
+		messageDigest = crypto.getMessageDigest();
+		batchDigest = crypto.getMessageDigest();
 		assertEquals(messageDigest.getDigestLength(), UniqueId.LENGTH);
 		assertEquals(batchDigest.getDigestLength(), UniqueId.LENGTH);
 		// Create and encode a test message
 		MessageEncoder messageEncoder = i.getInstance(MessageEncoder.class);
-		KeyPair keyPair = i.getInstance(KeyPair.class);
+		KeyPair keyPair = crypto.generateKeyPair();
 		message = messageEncoder.encodeMessage(MessageId.NONE, sub, nick,
 				keyPair, messageBody.getBytes("UTF-8"));
 		// Create a test group, then write and read it to calculate its ID
@@ -144,7 +147,7 @@ public class FileReadWriteTest extends TestCase {
 		ObjectReader<Batch> batchReader = new BatchReader(batchDigest,
 				messageReader, new BatchFactoryImpl());
 		ObjectReader<Group> groupReader = new GroupReader(batchDigest,
-				new GroupFactoryImpl(keyParser));
+				new GroupFactoryImpl(crypto));
 		ObjectReader<Subscriptions> subscriptionReader =
 			new SubscriptionReader(groupReader, new SubscriptionFactoryImpl());
 		ObjectReader<Transports> transportReader =
diff --git a/test/net/sf/briar/protocol/SigningDigestingOutputStreamTest.java b/test/net/sf/briar/protocol/SigningDigestingOutputStreamTest.java
index a82f75e982b0067ae44b4cef445ac180081af5bf..cf58b29fcb4ef1058b0b37379665253e6341fbbb 100644
--- a/test/net/sf/briar/protocol/SigningDigestingOutputStreamTest.java
+++ b/test/net/sf/briar/protocol/SigningDigestingOutputStreamTest.java
@@ -9,6 +9,7 @@ import java.util.Arrays;
 import java.util.Random;
 
 import junit.framework.TestCase;
+import net.sf.briar.api.crypto.CryptoComponent;
 import net.sf.briar.crypto.CryptoModule;
 
 import org.junit.Before;
@@ -19,20 +20,19 @@ import com.google.inject.Injector;
 
 public class SigningDigestingOutputStreamTest extends TestCase {
 
-	private Signature signature = null;
-	private KeyPair keyPair = null;
-	private MessageDigest messageDigest = null;
+	private CryptoComponent crypto = null;
 
 	@Before
 	public void setUp() throws Exception {
 		Injector i = Guice.createInjector(new CryptoModule());
-		signature = i.getInstance(Signature.class);
-		keyPair = i.getInstance(KeyPair.class);
-		messageDigest = i.getInstance(MessageDigest.class);
+		crypto = i.getInstance(CryptoComponent.class);
 	}
 
 	@Test
 	public void testStopAndStart() throws Exception {
+		Signature signature = crypto.getSignature();
+		KeyPair keyPair = crypto.generateKeyPair();
+		MessageDigest messageDigest = crypto.getMessageDigest();
 		byte[] input = new byte[1024];
 		new Random().nextBytes(input);
 		ByteArrayOutputStream out = new ByteArrayOutputStream(input.length);
@@ -69,6 +69,8 @@ public class SigningDigestingOutputStreamTest extends TestCase {
 
 	@Test
 	public void testSignatureExceptionThrowsIOException() throws Exception {
+		Signature signature = crypto.getSignature();
+		MessageDigest messageDigest = crypto.getMessageDigest();
 		ByteArrayOutputStream out = new ByteArrayOutputStream();
 		SigningDigestingOutputStream s =
 			new SigningDigestingOutputStream(out, signature, messageDigest);