diff --git a/briar-android/src/org/briarproject/android/AppModule.java b/briar-android/src/org/briarproject/android/AppModule.java index e412c9b5bca509ad11613f15fd22a24c25ca1bc8..22d59c206cced7be93fcdc15a98c8519cf0b7b11 100644 --- a/briar-android/src/org/briarproject/android/AppModule.java +++ b/briar-android/src/org/briarproject/android/AppModule.java @@ -4,6 +4,8 @@ import android.app.Application; import org.briarproject.android.api.AndroidNotificationManager; import org.briarproject.android.api.ReferenceManager; +import org.briarproject.api.crypto.CryptoComponent; +import org.briarproject.api.crypto.PublicKey; import org.briarproject.api.crypto.SecretKey; import org.briarproject.api.db.DatabaseConfig; import org.briarproject.api.event.EventBus; @@ -13,6 +15,7 @@ import org.briarproject.api.ui.UiCallback; import org.briarproject.util.StringUtils; import java.io.File; +import java.security.GeneralSecurityException; import javax.inject.Inject; import javax.inject.Singleton; @@ -94,16 +97,25 @@ public class AppModule { @Provides @Singleton - public DevConfig provideDevConfig() { + public DevConfig provideDevConfig(CryptoComponent crypto) { + final PublicKey pub; + try { + // TODO fill in + pub = crypto.getMessageKeyParser() + .parsePublicKey(StringUtils.fromHexString("")); + } catch (GeneralSecurityException e) { + throw new RuntimeException(e); + } + return new DevConfig() { + private final PublicKey DEV_PUB_KEY = pub; // TODO fill in - private final byte[] DEV_PUB_KEY = StringUtils.fromHexString(""); private final String DEV_ONION = ""; private final int DEV_REPORT_PORT = 8080; @Override - public byte[] getDevPublicKey() { + public PublicKey getDevPublicKey() { return DEV_PUB_KEY; } diff --git a/briar-api/src/org/briarproject/api/crypto/CryptoComponent.java b/briar-api/src/org/briarproject/api/crypto/CryptoComponent.java index 5f72ae3120a1a5cdc00ea0845fa449d74c466a6c..dedcafbff7896a3a1b8c957c3e73643d2eef04c6 100644 --- a/briar-api/src/org/briarproject/api/crypto/CryptoComponent.java +++ b/briar-api/src/org/briarproject/api/crypto/CryptoComponent.java @@ -27,6 +27,8 @@ public interface CryptoComponent { KeyParser getSignatureKeyParser(); + KeyParser getMessageKeyParser(); + /** Generates a random invitation code. */ int generateBTInvitationCode(); @@ -161,5 +163,5 @@ public interface CryptoComponent { /** * Encrypts the given plaintext to the given public key. */ - String encryptToKey(byte[] publicKey, byte[] plaintext); + String encryptToKey(PublicKey publicKey, byte[] plaintext); } diff --git a/briar-api/src/org/briarproject/api/reporting/DevConfig.java b/briar-api/src/org/briarproject/api/reporting/DevConfig.java index 4152cd927724a3d049d72d58ecc199f17d8522fd..f82e8131804943dbdd00fdada5360eef1bad2166 100644 --- a/briar-api/src/org/briarproject/api/reporting/DevConfig.java +++ b/briar-api/src/org/briarproject/api/reporting/DevConfig.java @@ -1,8 +1,10 @@ package org.briarproject.api.reporting; +import org.briarproject.api.crypto.PublicKey; + public interface DevConfig { - byte[] getDevPublicKey(); + PublicKey getDevPublicKey(); String getDevOnionAddress(); diff --git a/briar-core/src/org/briarproject/crypto/CryptoComponentImpl.java b/briar-core/src/org/briarproject/crypto/CryptoComponentImpl.java index 87a65ef649042ab83a83d4b1bb91d8490590add4..2411e51989c57386115b767025eec02f3e4068b3 100644 --- a/briar-core/src/org/briarproject/crypto/CryptoComponentImpl.java +++ b/briar-core/src/org/briarproject/crypto/CryptoComponentImpl.java @@ -29,7 +29,6 @@ import org.spongycastle.crypto.params.ECPrivateKeyParameters; import org.spongycastle.crypto.params.ECPublicKeyParameters; import org.spongycastle.crypto.params.KeyParameter; -import java.io.IOException; import java.nio.charset.Charset; import java.security.GeneralSecurityException; import java.security.SecureRandom; @@ -95,6 +94,7 @@ class CryptoComponentImpl implements CryptoComponent { private final ECKeyPairGenerator agreementKeyPairGenerator; private final ECKeyPairGenerator signatureKeyPairGenerator; private final KeyParser agreementKeyParser, signatureKeyParser; + private final MessageEncrypter messageEncrypter; @Inject CryptoComponentImpl(SeedProvider seedProvider) { @@ -117,6 +117,7 @@ class CryptoComponentImpl implements CryptoComponent { AGREEMENT_KEY_PAIR_BITS); signatureKeyParser = new Sec1KeyParser(PARAMETERS, SIGNATURE_KEY_PAIR_BITS); + messageEncrypter = new MessageEncrypter(secureRandom); } public SecretKey generateSecretKey() { @@ -198,6 +199,10 @@ class CryptoComponentImpl implements CryptoComponent { return signatureKeyParser; } + public KeyParser getMessageKeyParser() { + return messageEncrypter.getKeyParser(); + } + public int generateBTInvitationCode() { int codeBytes = (CODE_BITS + 7) / 8; byte[] random = new byte[codeBytes]; @@ -440,13 +445,10 @@ class CryptoComponentImpl implements CryptoComponent { } } - public String encryptToKey(byte[] publicKey, byte[] plaintext) { - MessageEncrypter encrypter = new MessageEncrypter(secureRandom); + public String encryptToKey(PublicKey publicKey, byte[] plaintext) { try { - byte[] ciphertext = encrypter.encrypt(publicKey, plaintext); + byte[] ciphertext = messageEncrypter.encrypt(publicKey, plaintext); return AsciiArmour.wrap(ciphertext, 70); - } catch (IOException e) { - throw new RuntimeException(e); } catch (CryptoException e) { throw new RuntimeException(e); } diff --git a/briar-core/src/org/briarproject/crypto/MessageEncrypter.java b/briar-core/src/org/briarproject/crypto/MessageEncrypter.java index 5453bcd2f6f3ddcb0a5c79a677e5e77b41756c22..bbef555e9acd51a282bc5ab0fe35fc2cd29174ed 100644 --- a/briar-core/src/org/briarproject/crypto/MessageEncrypter.java +++ b/briar-core/src/org/briarproject/crypto/MessageEncrypter.java @@ -1,5 +1,9 @@ package org.briarproject.crypto; +import org.briarproject.api.crypto.KeyPair; +import org.briarproject.api.crypto.KeyParser; +import org.briarproject.api.crypto.PrivateKey; +import org.briarproject.api.crypto.PublicKey; import org.briarproject.util.StringUtils; import org.spongycastle.asn1.teletrust.TeleTrusTNamedCurves; import org.spongycastle.asn1.x9.X9ECParameters; @@ -10,7 +14,6 @@ import org.spongycastle.crypto.CipherParameters; import org.spongycastle.crypto.CryptoException; import org.spongycastle.crypto.DerivationFunction; import org.spongycastle.crypto.KeyEncoder; -import org.spongycastle.crypto.KeyParser; import org.spongycastle.crypto.Mac; import org.spongycastle.crypto.agreement.ECDHCBasicAgreement; import org.spongycastle.crypto.digests.SHA256Digest; @@ -30,13 +33,11 @@ import org.spongycastle.crypto.params.ECPublicKeyParameters; import org.spongycastle.crypto.params.IESWithCipherParameters; import org.spongycastle.crypto.parsers.ECIESPublicKeyParser; -import java.io.ByteArrayInputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.PrintStream; -import java.math.BigInteger; import java.nio.charset.Charset; import java.security.SecureRandom; import java.util.Scanner; @@ -44,6 +45,7 @@ import java.util.Scanner; public class MessageEncrypter { private static final ECDomainParameters PARAMETERS; + private static final int MESSAGE_KEY_BITS = 512; private static final int MAC_KEY_BITS = 256; private static final int CIPHER_KEY_BITS = 256; private static final int LINE_LENGTH = 70; @@ -55,40 +57,52 @@ public class MessageEncrypter { } private final ECKeyPairGenerator generator; - private final EphemeralKeyPairGenerator ephemeralGenerator; private final KeyParser parser; + private final EphemeralKeyPairGenerator ephemeralGenerator; + private final PublicKeyParser ephemeralParser; MessageEncrypter(SecureRandom random) { generator = new ECKeyPairGenerator(); generator.init(new ECKeyGenerationParameters(PARAMETERS, random)); + parser = new Sec1KeyParser(PARAMETERS, MESSAGE_KEY_BITS); KeyEncoder encoder = new PublicKeyEncoder(); ephemeralGenerator = new EphemeralKeyPairGenerator(generator, encoder); - parser = new PublicKeyParser(PARAMETERS); + ephemeralParser = new PublicKeyParser(PARAMETERS); } - AsymmetricCipherKeyPair generateKeyPair() { - return generator.generateKeyPair(); + KeyPair generateKeyPair() { + AsymmetricCipherKeyPair keyPair = generator.generateKeyPair(); + // Return a wrapper that uses the SEC 1 encoding + ECPublicKeyParameters ecPublicKey = + (ECPublicKeyParameters) keyPair.getPublic(); + PublicKey publicKey = new Sec1PublicKey(ecPublicKey); + ECPrivateKeyParameters ecPrivateKey = + (ECPrivateKeyParameters) keyPair.getPrivate(); + PrivateKey privateKey = + new Sec1PrivateKey(ecPrivateKey, MESSAGE_KEY_BITS); + return new KeyPair(publicKey, privateKey); } - byte[] encrypt(byte[] keyBytes, byte[] plaintext) - throws IOException, CryptoException { - InputStream in = new ByteArrayInputStream(keyBytes); - ECPublicKeyParameters publicKey = - (ECPublicKeyParameters) parser.readKey(in); - return encrypt(publicKey, plaintext); + KeyParser getKeyParser() { + return parser; } - byte[] encrypt(ECPublicKeyParameters pubKey, byte[] plaintext) - throws CryptoException { + byte[] encrypt(PublicKey pub, byte[] plaintext) throws CryptoException { + if (!(pub instanceof Sec1PublicKey)) + throw new IllegalArgumentException(); IESEngine engine = getEngine(); - engine.init(pubKey, getCipherParameters(), ephemeralGenerator); + engine.init(((Sec1PublicKey) pub).getKey(), getCipherParameters(), + ephemeralGenerator); return engine.processBlock(plaintext, 0, plaintext.length); } - byte[] decrypt(ECPrivateKeyParameters privKey, byte[] ciphertext) + byte[] decrypt(PrivateKey priv, byte[] ciphertext) throws CryptoException { + if (!(priv instanceof Sec1PrivateKey)) + throw new IllegalArgumentException(); IESEngine engine = getEngine(); - engine.init(privKey, getCipherParameters(), parser); + engine.init(((Sec1PrivateKey) priv).getKey(), getCipherParameters(), + ephemeralParser); return engine.processBlock(ciphertext, 0, ciphertext.length); } @@ -146,18 +160,15 @@ public class MessageEncrypter { return; } // Generate a key pair - AsymmetricCipherKeyPair keyPair = encrypter.generateKeyPair(); - ECPublicKeyParameters publicKey = - (ECPublicKeyParameters) keyPair.getPublic(); - byte[] publicKeyBytes = publicKey.getQ().getEncoded(false); + KeyPair keyPair = encrypter.generateKeyPair(); PrintStream out = new PrintStream(new FileOutputStream(args[1])); - out.print(StringUtils.toHexString(publicKeyBytes)); + out.print( + StringUtils.toHexString(keyPair.getPublic().getEncoded())); out.flush(); out.close(); - ECPrivateKeyParameters privateKey = - (ECPrivateKeyParameters) keyPair.getPrivate(); out = new PrintStream(new FileOutputStream(args[2])); - out.print(privateKey.getD().toString(16).toUpperCase()); + out.print( + StringUtils.toHexString(keyPair.getPrivate().getEncoded())); out.flush(); out.close(); } else if (args[0].equals("encrypt")) { @@ -167,7 +178,9 @@ public class MessageEncrypter { } // Encrypt a decrypted message InputStream in = new FileInputStream(args[1]); - byte[] publicKey = StringUtils.fromHexString(readFully(in).trim()); + byte[] keyBytes = StringUtils.fromHexString(readFully(in).trim()); + PublicKey publicKey = + encrypter.getKeyParser().parsePublicKey(keyBytes); String message = readFully(System.in); byte[] plaintext = message.getBytes(Charset.forName("UTF-8")); byte[] ciphertext = encrypter.encrypt(publicKey, plaintext); @@ -179,10 +192,9 @@ public class MessageEncrypter { } // Decrypt an encrypted message InputStream in = new FileInputStream(args[1]); - byte[] b = StringUtils.fromHexString(readFully(in).trim()); - BigInteger d = new BigInteger(1, b); - ECPrivateKeyParameters privateKey = new ECPrivateKeyParameters(d, - PARAMETERS); + byte[] keyBytes = StringUtils.fromHexString(readFully(in).trim()); + PrivateKey privateKey = + encrypter.getKeyParser().parsePrivateKey(keyBytes); byte[] ciphertext = AsciiArmour.unwrap(readFully(System.in)); byte[] plaintext = encrypter.decrypt(privateKey, ciphertext); System.out.println(new String(plaintext, Charset.forName("UTF-8"))); @@ -193,7 +205,8 @@ public class MessageEncrypter { private static void printUsage() { System.err.println("Usage:"); - System.err.println("MessageEncrypter generate <public_key_file> <private_key_file>"); + System.err.println( + "MessageEncrypter generate <public_key_file> <private_key_file>"); System.err.println("MessageEncrypter encrypt <public_key_file>"); System.err.println("MessageEncrypter decrypt <private_key_file>"); } diff --git a/briar-tests/src/org/briarproject/crypto/MessageEncrypterTest.java b/briar-tests/src/org/briarproject/crypto/MessageEncrypterTest.java index 29c07984e5b5d3e66b059cc4f6a7940c80d88d26..351fa48af43aff0e0d6841419d469d8d7fc5e218 100644 --- a/briar-tests/src/org/briarproject/crypto/MessageEncrypterTest.java +++ b/briar-tests/src/org/briarproject/crypto/MessageEncrypterTest.java @@ -1,6 +1,9 @@ package org.briarproject.crypto; import org.briarproject.BriarTestCase; +import org.briarproject.api.crypto.KeyPair; +import org.briarproject.api.crypto.PrivateKey; +import org.briarproject.api.crypto.PublicKey; import org.junit.Test; import org.spongycastle.crypto.AsymmetricCipherKeyPair; import org.spongycastle.crypto.CryptoException; @@ -18,9 +21,9 @@ public class MessageEncrypterTest extends BriarTestCase { @Test public void testEncryptionAndDecryption() throws Exception { MessageEncrypter m = new MessageEncrypter(random); - AsymmetricCipherKeyPair kp = m.generateKeyPair(); - ECPublicKeyParameters pub = (ECPublicKeyParameters) kp.getPublic(); - ECPrivateKeyParameters priv = (ECPrivateKeyParameters) kp.getPrivate(); + KeyPair kp = m.generateKeyPair(); + PublicKey pub = kp.getPublic(); + PrivateKey priv = kp.getPrivate(); byte[] plaintext = new byte[123]; random.nextBytes(plaintext); byte[] ciphertext = m.encrypt(pub, plaintext); @@ -31,9 +34,9 @@ public class MessageEncrypterTest extends BriarTestCase { @Test(expected = CryptoException.class) public void testDecryptionFailsWithAlteredCiphertext() throws Exception { MessageEncrypter m = new MessageEncrypter(random); - AsymmetricCipherKeyPair kp = m.generateKeyPair(); - ECPublicKeyParameters pub = (ECPublicKeyParameters) kp.getPublic(); - ECPrivateKeyParameters priv = (ECPrivateKeyParameters) kp.getPrivate(); + KeyPair kp = m.generateKeyPair(); + PublicKey pub = kp.getPublic(); + PrivateKey priv = kp.getPrivate(); byte[] ciphertext = m.encrypt(pub, new byte[123]); ciphertext[random.nextInt(ciphertext.length)] ^= 0xFF; m.decrypt(priv, ciphertext);