diff --git a/briar-android/src/org/briarproject/android/invitation/AddContactActivity.java b/briar-android/src/org/briarproject/android/invitation/AddContactActivity.java index 011f7d38d0f6ded2ee0005e8e0f617d956d77359..7d2ab13417b4e5b3407fdbf549942c99e1154afe 100644 --- a/briar-android/src/org/briarproject/android/invitation/AddContactActivity.java +++ b/briar-android/src/org/briarproject/android/invitation/AddContactActivity.java @@ -55,12 +55,12 @@ implements InvitationListener { private boolean localCompared = false, remoteCompared = false; private boolean localMatched = false, remoteMatched = false; private String contactName = null; - private boolean bluetoothWasEnabled = false; // Fields that are accessed from background threads must be volatile @Inject private volatile DatabaseComponent db; @Inject private volatile IdentityManager identityManager; - private volatile boolean leaveBluetoothEnabled = true; + private volatile boolean bluetoothWasEnabled = false; + private volatile boolean leaveBluetoothEnabled = false; @Override public void onCreate(Bundle state) { @@ -173,7 +173,8 @@ implements InvitationListener { long duration = System.currentTimeMillis() - now; if (LOG.isLoggable(INFO)) LOG.info("Loading setting took " + duration + " ms"); - leaveBluetoothEnabled = c.getBoolean("enable", false); + leaveBluetoothEnabled = bluetoothWasEnabled + || c.getBoolean("enable", false); } catch (DbException e) { if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); @@ -328,7 +329,7 @@ implements InvitationListener { } public void disableBluetooth() { - if (!bluetoothWasEnabled && !leaveBluetoothEnabled) { + if (!leaveBluetoothEnabled) { if (LOG.isLoggable(INFO)) LOG.info("Turning off Bluetooth again"); BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); diff --git a/briar-api/src/org/briarproject/api/transport/TransportConstants.java b/briar-api/src/org/briarproject/api/transport/TransportConstants.java index 219f5d481461cb499635be23d59e8baba074a7d4..ae3a6c3daf9af55555e07023020a8a3ac0932629 100644 --- a/briar-api/src/org/briarproject/api/transport/TransportConstants.java +++ b/briar-api/src/org/briarproject/api/transport/TransportConstants.java @@ -19,7 +19,7 @@ public interface TransportConstants { + MAC_LENGTH; /** The length of the frame initalisation vector (IV) in bytes. */ - int FRAME_IV_LENGTH = 12; + int FRAME_IV_LENGTH = 24; /** The length of the frame header in bytes. */ int FRAME_HEADER_LENGTH = 4 + MAC_LENGTH; diff --git a/briar-core/src/org/briarproject/crypto/AuthenticatedCipher.java b/briar-core/src/org/briarproject/crypto/AuthenticatedCipher.java index 5ee21e3e4ca1047f67f40a2b427d1e37ae7005ce..fe4f8bee006711dfd0ad12ec5d1298eaf5e4508d 100644 --- a/briar-core/src/org/briarproject/crypto/AuthenticatedCipher.java +++ b/briar-core/src/org/briarproject/crypto/AuthenticatedCipher.java @@ -26,14 +26,14 @@ interface AuthenticatedCipher { * including the MAC. * @param inputOff the offset into the input array where the data to be * processed starts. - * @param len the number of bytes to be processed. If decrypting, includes - * the MAC length. - * @param output the output buffer the processed bytes go into. If - * encrypting, the ciphertext including the MAC. If - * decrypting, the plaintext. - * @param outputOff the offset into the output byte array the processed - * data starts at. - * @return the number of bytes processed. + * @param len the length of the input. If decrypting, includes the MAC + * length. + * @param output the output byte array. If encrypting, the ciphertext + * including the MAC. If decrypting, the plaintext. + * @param outputOff the offset into the output byte array where the + * processed data starts. + * @return the length of the output. If encrypting, includes the MAC + * length. * @throws GeneralSecurityException on invalid input. */ int process(byte[] input, int inputOff, int len, byte[] output, diff --git a/briar-core/src/org/briarproject/crypto/AuthenticatedCipherImpl.java b/briar-core/src/org/briarproject/crypto/AuthenticatedCipherImpl.java deleted file mode 100644 index c21213287369da998b5b91fc8b5e268816ca5358..0000000000000000000000000000000000000000 --- a/briar-core/src/org/briarproject/crypto/AuthenticatedCipherImpl.java +++ /dev/null @@ -1,57 +0,0 @@ -package org.briarproject.crypto; - -import static org.briarproject.api.transport.TransportConstants.MAC_LENGTH; - -import java.security.GeneralSecurityException; - -import org.briarproject.api.crypto.SecretKey; -import org.spongycastle.crypto.DataLengthException; -import org.spongycastle.crypto.InvalidCipherTextException; -import org.spongycastle.crypto.engines.AESLightEngine; -import org.spongycastle.crypto.modes.AEADBlockCipher; -import org.spongycastle.crypto.modes.GCMBlockCipher; -import org.spongycastle.crypto.modes.gcm.BasicGCMMultiplier; -import org.spongycastle.crypto.params.AEADParameters; -import org.spongycastle.crypto.params.KeyParameter; - -class AuthenticatedCipherImpl implements AuthenticatedCipher { - - private final AEADBlockCipher cipher; - - AuthenticatedCipherImpl() { - cipher = new GCMBlockCipher(new AESLightEngine(), - new BasicGCMMultiplier()); - } - - public int process(byte[] input, int inputOff, int len, byte[] output, - int outputOff) throws GeneralSecurityException { - int processed = 0; - if (len != 0) { - processed = cipher.processBytes(input, inputOff, len, output, - outputOff); - } - try { - return processed + cipher.doFinal(output, outputOff + processed); - } catch (DataLengthException e) { - throw new GeneralSecurityException(e.getMessage()); - } catch (InvalidCipherTextException e) { - throw new GeneralSecurityException(e.getMessage()); - } - } - - public void init(boolean encrypt, SecretKey key, byte[] iv) - throws GeneralSecurityException { - KeyParameter k = new KeyParameter(key.getBytes()); - // Authenticate the IV by passing it as additional authenticated data - AEADParameters params = new AEADParameters(k, MAC_LENGTH * 8, iv, iv); - try { - cipher.init(encrypt, params); - } catch (IllegalArgumentException e) { - throw new GeneralSecurityException(e.getMessage()); - } - } - - public int getMacBytes() { - return MAC_LENGTH; - } -} diff --git a/briar-core/src/org/briarproject/crypto/CryptoComponentImpl.java b/briar-core/src/org/briarproject/crypto/CryptoComponentImpl.java index 5827a03b8cb393f32672a42c1b689aaab58f59fa..e88e42ea36380d1728d67ab4026be97f411dde2d 100644 --- a/briar-core/src/org/briarproject/crypto/CryptoComponentImpl.java +++ b/briar-core/src/org/briarproject/crypto/CryptoComponentImpl.java @@ -55,8 +55,8 @@ class CryptoComponentImpl implements CryptoComponent { private static final int AGREEMENT_KEY_PAIR_BITS = 256; private static final int SIGNATURE_KEY_PAIR_BITS = 256; - private static final int STORAGE_IV_BYTES = 16; // 128 bits - private static final int PBKDF_SALT_BYTES = 16; // 128 bits + private static final int STORAGE_IV_BYTES = 24; // 196 bits + private static final int PBKDF_SALT_BYTES = 32; // 256 bits private static final int PBKDF_TARGET_MILLIS = 500; private static final int PBKDF_SAMPLES = 30; @@ -94,16 +94,16 @@ class CryptoComponentImpl implements CryptoComponent { private final KeyParser agreementKeyParser, signatureKeyParser; @Inject - CryptoComponentImpl(SeedProvider r) { + CryptoComponentImpl(SeedProvider seedProvider) { if (!FortunaSecureRandom.selfTest()) throw new RuntimeException(); - SecureRandom secureRandom1 = new SecureRandom(); + SecureRandom platformSecureRandom = new SecureRandom(); if (LOG.isLoggable(INFO)) { - String provider = secureRandom1.getProvider().getName(); - String algorithm = secureRandom1.getAlgorithm(); + String provider = platformSecureRandom.getProvider().getName(); + String algorithm = platformSecureRandom.getAlgorithm(); LOG.info("Default SecureRandom: " + provider + " " + algorithm); } - SecureRandom secureRandom2 = new FortunaSecureRandom(r.getSeed()); - secureRandom = new CombinedSecureRandom(secureRandom1, secureRandom2); + SecureRandom fortuna = new FortunaSecureRandom(seedProvider.getSeed()); + secureRandom = new CombinedSecureRandom(platformSecureRandom, fortuna); ECKeyGenerationParameters params = new ECKeyGenerationParameters( PARAMETERS, secureRandom); agreementKeyPairGenerator = new ECKeyPairGenerator(); @@ -325,7 +325,7 @@ class CryptoComponentImpl implements CryptoComponent { } public byte[] encryptWithPassword(byte[] input, String password) { - AuthenticatedCipher cipher = new AuthenticatedCipherImpl(); + AuthenticatedCipher cipher = new XSalsa20Poly1305AuthenticatedCipher(); int macBytes = cipher.getMacBytes(); // Generate a random salt byte[] salt = new byte[PBKDF_SALT_BYTES]; @@ -355,7 +355,7 @@ class CryptoComponentImpl implements CryptoComponent { } public byte[] decryptWithPassword(byte[] input, String password) { - AuthenticatedCipher cipher = new AuthenticatedCipherImpl(); + AuthenticatedCipher cipher = new XSalsa20Poly1305AuthenticatedCipher(); int macBytes = cipher.getMacBytes(); // The input contains the salt, iterations, IV, ciphertext and MAC if (input.length < PBKDF_SALT_BYTES + 4 + STORAGE_IV_BYTES + macBytes) diff --git a/briar-core/src/org/briarproject/crypto/CryptoModule.java b/briar-core/src/org/briarproject/crypto/CryptoModule.java index 3cdaf74041683bae608eb3cfcdf890939daeeb4c..35a4b0136035e8951fa0475e3b64b7ee444c7932 100644 --- a/briar-core/src/org/briarproject/crypto/CryptoModule.java +++ b/briar-core/src/org/briarproject/crypto/CryptoModule.java @@ -1,6 +1,14 @@ package org.briarproject.crypto; -import static java.util.concurrent.TimeUnit.SECONDS; +import com.google.inject.AbstractModule; +import com.google.inject.Provides; + +import org.briarproject.api.crypto.CryptoComponent; +import org.briarproject.api.crypto.CryptoExecutor; +import org.briarproject.api.crypto.PasswordStrengthEstimator; +import org.briarproject.api.crypto.StreamDecrypterFactory; +import org.briarproject.api.crypto.StreamEncrypterFactory; +import org.briarproject.api.lifecycle.LifecycleManager; import java.util.concurrent.BlockingQueue; import java.util.concurrent.Executor; @@ -11,15 +19,7 @@ import java.util.concurrent.ThreadPoolExecutor; import javax.inject.Singleton; -import org.briarproject.api.crypto.CryptoComponent; -import org.briarproject.api.crypto.CryptoExecutor; -import org.briarproject.api.crypto.PasswordStrengthEstimator; -import org.briarproject.api.crypto.StreamDecrypterFactory; -import org.briarproject.api.crypto.StreamEncrypterFactory; -import org.briarproject.api.lifecycle.LifecycleManager; - -import com.google.inject.AbstractModule; -import com.google.inject.Provides; +import static java.util.concurrent.TimeUnit.SECONDS; public class CryptoModule extends AbstractModule { @@ -42,7 +42,8 @@ public class CryptoModule extends AbstractModule { @Override protected void configure() { - bind(AuthenticatedCipher.class).to(AuthenticatedCipherImpl.class); + bind(AuthenticatedCipher.class).to( + XSalsa20Poly1305AuthenticatedCipher.class); bind(CryptoComponent.class).to( CryptoComponentImpl.class).in(Singleton.class); bind(PasswordStrengthEstimator.class).to( diff --git a/briar-core/src/org/briarproject/crypto/XSalsa20Poly1305AC.java b/briar-core/src/org/briarproject/crypto/XSalsa20Poly1305AuthenticatedCipher.java similarity index 90% rename from briar-core/src/org/briarproject/crypto/XSalsa20Poly1305AC.java rename to briar-core/src/org/briarproject/crypto/XSalsa20Poly1305AuthenticatedCipher.java index 7a4a39d90b6133b321cf7bcf222a92a7426bddf9..8143b696ad334c6447c48f34d2eba35eb8f737c1 100644 --- a/briar-core/src/org/briarproject/crypto/XSalsa20Poly1305AC.java +++ b/briar-core/src/org/briarproject/crypto/XSalsa20Poly1305AuthenticatedCipher.java @@ -24,7 +24,8 @@ import static org.briarproject.api.transport.TransportConstants.MAC_LENGTH; * <li>http://cr.yp.to/highspeed/naclcrypto-20090310.pdf</li> * </ul> */ -public class XSalsa20Poly1305AC implements AuthenticatedCipher { +public class XSalsa20Poly1305AuthenticatedCipher + implements AuthenticatedCipher { /** Length of the padding to be used to generate the Poly1305 key */ private static final int SUBKEY_LENGTH = 32; @@ -34,13 +35,14 @@ public class XSalsa20Poly1305AC implements AuthenticatedCipher { private boolean encrypting; - XSalsa20Poly1305AC() { + XSalsa20Poly1305AuthenticatedCipher() { xSalsa20Engine = new XSalsa20Engine(); poly1305 = new Poly1305(); } @Override - public void init(boolean encrypt, SecretKey key, byte[] iv) throws GeneralSecurityException { + public void init(boolean encrypt, SecretKey key, byte[] iv) + throws GeneralSecurityException { encrypting = encrypt; KeyParameter k = new KeyParameter(key.getBytes()); ParametersWithIV params = new ParametersWithIV(k, iv); @@ -52,12 +54,10 @@ public class XSalsa20Poly1305AC implements AuthenticatedCipher { } @Override - public int process(byte[] input, int inputOff, int len, byte[] output, int outputOff) throws GeneralSecurityException { - if (len == 0) - return 0; - else if (!encrypting && len < MAC_LENGTH) + public int process(byte[] input, int inputOff, int len, byte[] output, + int outputOff) throws GeneralSecurityException { + if (!encrypting && len < MAC_LENGTH) throw new GeneralSecurityException("Invalid MAC"); - try { // Generate the Poly1305 subkey from an empty array byte[] zero = new byte[SUBKEY_LENGTH]; @@ -100,7 +100,7 @@ public class XSalsa20Poly1305AC implements AuthenticatedCipher { throw new GeneralSecurityException("Invalid MAC"); } - // Invert the stream encryption + // Apply or invert the stream encryption int processed = xSalsa20Engine.processBytes( input, encrypting ? inputOff : inputOff + MAC_LENGTH, encrypting ? len : len - MAC_LENGTH, @@ -112,7 +112,7 @@ public class XSalsa20Poly1305AC implements AuthenticatedCipher { poly1305.doFinal(output, outputOff); } - return processed; + return encrypting ? processed + MAC_LENGTH : processed; } catch (DataLengthException e) { throw new GeneralSecurityException(e.getMessage()); } diff --git a/briar-tests/src/org/briarproject/crypto/XSalsa20Poly1305ACTest.java b/briar-tests/src/org/briarproject/crypto/XSalsa20Poly1305AuthenticatedCipherTest.java similarity index 70% rename from briar-tests/src/org/briarproject/crypto/XSalsa20Poly1305ACTest.java rename to briar-tests/src/org/briarproject/crypto/XSalsa20Poly1305AuthenticatedCipherTest.java index 723d7984add90ede9644b3bcd5e8f7f43286a9a0..6d45fc975769459c7cd45207260ac5538fa81f21 100644 --- a/briar-tests/src/org/briarproject/crypto/XSalsa20Poly1305ACTest.java +++ b/briar-tests/src/org/briarproject/crypto/XSalsa20Poly1305AuthenticatedCipherTest.java @@ -6,10 +6,12 @@ import org.briarproject.util.StringUtils; import org.junit.Test; import java.security.GeneralSecurityException; +import java.util.Random; import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; -public class XSalsa20Poly1305ACTest extends BriarTestCase { +public class XSalsa20Poly1305AuthenticatedCipherTest extends BriarTestCase { // Test vectors from the NaCl paper // http://cr.yp.to/highspeed/naclcrypto-20090310.pdf @@ -47,43 +49,45 @@ public class XSalsa20Poly1305ACTest extends BriarTestCase { @Test public void testEncrypt() throws Exception { SecretKey k = new SecretKey(TEST_KEY); - AuthenticatedCipher cipher = new XSalsa20Poly1305AC(); + AuthenticatedCipher cipher = new XSalsa20Poly1305AuthenticatedCipher(); cipher.init(true, k, TEST_IV); - byte[] output = new byte[TEST_PLAINTEXT.length + cipher.getMacBytes()]; - cipher.process(TEST_PLAINTEXT, 0, TEST_PLAINTEXT.length, output, 0); + byte[] output = new byte[TEST_CIPHERTEXT.length]; + assertEquals(TEST_CIPHERTEXT.length, cipher.process(TEST_PLAINTEXT, 0, + TEST_PLAINTEXT.length, output, 0)); assertArrayEquals(TEST_CIPHERTEXT, output); } @Test public void testDecrypt() throws Exception { SecretKey k = new SecretKey(TEST_KEY); - AuthenticatedCipher cipher = new XSalsa20Poly1305AC(); + AuthenticatedCipher cipher = new XSalsa20Poly1305AuthenticatedCipher(); cipher.init(false, k, TEST_IV); - byte[] output = new byte[TEST_CIPHERTEXT.length - cipher.getMacBytes()]; - cipher.process(TEST_CIPHERTEXT, 0, TEST_CIPHERTEXT.length, output, 0); + byte[] output = new byte[TEST_PLAINTEXT.length]; + assertEquals(TEST_PLAINTEXT.length, cipher.process(TEST_CIPHERTEXT, 0, + TEST_CIPHERTEXT.length, output, 0)); assertArrayEquals(TEST_PLAINTEXT, output); } @Test(expected = GeneralSecurityException.class) public void testDecryptFailsWithShortInput() throws Exception { SecretKey k = new SecretKey(TEST_KEY); - AuthenticatedCipher cipher = new XSalsa20Poly1305AC(); + AuthenticatedCipher cipher = new XSalsa20Poly1305AuthenticatedCipher(); cipher.init(false, k, TEST_IV); - byte[] input = new byte[8]; - System.arraycopy(TEST_CIPHERTEXT, 0, input, 0, 8); - byte[] output = new byte[TEST_CIPHERTEXT.length - cipher.getMacBytes()]; + byte[] input = new byte[cipher.getMacBytes() - 1]; + System.arraycopy(TEST_CIPHERTEXT, 0, input, 0, input.length); + byte[] output = new byte[TEST_PLAINTEXT.length]; cipher.process(input, 0, input.length, output, 0); } @Test(expected = GeneralSecurityException.class) public void testDecryptFailsWithAlteredCiphertext() throws Exception { SecretKey k = new SecretKey(TEST_KEY); - AuthenticatedCipher cipher = new XSalsa20Poly1305AC(); + AuthenticatedCipher cipher = new XSalsa20Poly1305AuthenticatedCipher(); cipher.init(false, k, TEST_IV); byte[] input = new byte[TEST_CIPHERTEXT.length]; System.arraycopy(TEST_CIPHERTEXT, 0, input, 0, TEST_CIPHERTEXT.length); - input[TEST_CIPHERTEXT.length - cipher.getMacBytes()] = 42; - byte[] output = new byte[TEST_CIPHERTEXT.length - cipher.getMacBytes()]; + input[new Random().nextInt(TEST_CIPHERTEXT.length)] ^= 0xFF; + byte[] output = new byte[TEST_PLAINTEXT.length]; cipher.process(input, 0, input.length, output, 0); } }