From d4fa656dbb89e011bc35f5cb10db7ff654232d94 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Sat, 13 Dec 2014 12:00:40 +0000 Subject: [PATCH 01/10] Application layer keepalives to detect dead TCP connections. DuplexOutgoingSession flushes its output stream if it's idle for a transport-defined interval, causing an empty frame to be sent. The TCP and Tor plugins use a socket timeout equal to twice the idle interval to detect dead connections. See bugs #27, #46 and #60. --- .../plugins/droidtooth/DroidtoothPlugin.java | 6 ++++++ .../plugins/tcp/AndroidLanTcpPlugin.java | 4 ++-- .../plugins/tcp/AndroidLanTcpPluginFactory.java | 3 ++- .../org/briarproject/plugins/tor/TorPlugin.java | 17 ++++++++++++++--- .../plugins/tor/TorPluginFactory.java | 3 ++- .../api/plugins/duplex/DuplexPlugin.java | 3 +++ .../messaging/DuplexOutgoingSession.java | 9 ++++++++- .../briarproject/plugins/tcp/LanTcpPlugin.java | 5 +++-- .../plugins/tcp/LanTcpPluginFactory.java | 3 ++- .../org/briarproject/plugins/tcp/TcpPlugin.java | 17 ++++++++++++++--- .../briarproject/plugins/tcp/WanTcpPlugin.java | 6 +++--- .../plugins/tcp/WanTcpPluginFactory.java | 3 ++- .../transport/StreamWriterImpl.java | 2 +- .../plugins/bluetooth/BluetoothPlugin.java | 5 +++++ .../briarproject/plugins/modem/ModemPlugin.java | 5 +++++ .../plugins/tcp/LanTcpClientTest.java | 10 ++++++++-- .../plugins/tcp/LanTcpPluginTest.java | 6 +++--- .../plugins/tcp/LanTcpServerTest.java | 8 +++++++- .../transport/StreamWriterImplTest.java | 6 +++++- 19 files changed, 95 insertions(+), 26 deletions(-) diff --git a/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothPlugin.java b/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothPlugin.java index 1b65e45c8..e7cd834df 100644 --- a/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothPlugin.java +++ b/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothPlugin.java @@ -107,6 +107,11 @@ class DroidtoothPlugin implements DuplexPlugin { return maxLatency; } + public long getMaxIdleTime() { + // Bluetooth detects dead connections so we don't need keepalives + return Long.MAX_VALUE; + } + public boolean start() throws IOException { // BluetoothAdapter.getDefaultAdapter() must be called on a thread // with a message queue, so submit it to the AndroidExecutor @@ -361,6 +366,7 @@ class DroidtoothPlugin implements DuplexPlugin { private class BluetoothStateReceiver extends BroadcastReceiver { + @Override public void onReceive(Context ctx, Intent intent) { int state = intent.getIntExtra(EXTRA_STATE, 0); if(state == STATE_ON) { diff --git a/briar-android/src/org/briarproject/plugins/tcp/AndroidLanTcpPlugin.java b/briar-android/src/org/briarproject/plugins/tcp/AndroidLanTcpPlugin.java index eaec50c41..25a9fbc54 100644 --- a/briar-android/src/org/briarproject/plugins/tcp/AndroidLanTcpPlugin.java +++ b/briar-android/src/org/briarproject/plugins/tcp/AndroidLanTcpPlugin.java @@ -27,8 +27,8 @@ class AndroidLanTcpPlugin extends LanTcpPlugin { AndroidLanTcpPlugin(Executor ioExecutor, Context appContext, DuplexPluginCallback callback, int maxFrameLength, long maxLatency, - long pollingInterval) { - super(ioExecutor, callback, maxFrameLength, maxLatency, + long maxIdleTime, long pollingInterval) { + super(ioExecutor, callback, maxFrameLength, maxLatency, maxIdleTime, pollingInterval); this.appContext = appContext; } diff --git a/briar-android/src/org/briarproject/plugins/tcp/AndroidLanTcpPluginFactory.java b/briar-android/src/org/briarproject/plugins/tcp/AndroidLanTcpPluginFactory.java index a51326e55..8160ac969 100644 --- a/briar-android/src/org/briarproject/plugins/tcp/AndroidLanTcpPluginFactory.java +++ b/briar-android/src/org/briarproject/plugins/tcp/AndroidLanTcpPluginFactory.java @@ -13,6 +13,7 @@ public class AndroidLanTcpPluginFactory implements DuplexPluginFactory { private static final int MAX_FRAME_LENGTH = 1024; private static final long MAX_LATENCY = 60 * 1000; // 1 minute + private static final long MAX_IDLE_TIME = 30 * 1000; // 30 seconds private static final long POLLING_INTERVAL = 60 * 1000; // 1 minute private final Executor ioExecutor; @@ -29,6 +30,6 @@ public class AndroidLanTcpPluginFactory implements DuplexPluginFactory { public DuplexPlugin createPlugin(DuplexPluginCallback callback) { return new AndroidLanTcpPlugin(ioExecutor, appContext, callback, - MAX_FRAME_LENGTH, MAX_LATENCY, POLLING_INTERVAL); + MAX_FRAME_LENGTH, MAX_LATENCY, MAX_IDLE_TIME, POLLING_INTERVAL); } } diff --git a/briar-android/src/org/briarproject/plugins/tor/TorPlugin.java b/briar-android/src/org/briarproject/plugins/tor/TorPlugin.java index 905040b5c..bd59adda5 100644 --- a/briar-android/src/org/briarproject/plugins/tor/TorPlugin.java +++ b/briar-android/src/org/briarproject/plugins/tor/TorPlugin.java @@ -75,8 +75,8 @@ class TorPlugin implements DuplexPlugin, EventHandler { private final Context appContext; private final LocationUtils locationUtils; private final DuplexPluginCallback callback; - private final int maxFrameLength; - private final long maxLatency, pollingInterval; + private final int maxFrameLength, socketTimeout; + private final long maxLatency, maxIdleTime, pollingInterval; private final File torDirectory, torFile, geoIpFile, configFile, doneFile; private final File cookieFile, hostnameFile; private final AtomicBoolean circuitBuilt; @@ -90,14 +90,19 @@ class TorPlugin implements DuplexPlugin, EventHandler { TorPlugin(Executor ioExecutor, Context appContext, LocationUtils locationUtils, DuplexPluginCallback callback, - int maxFrameLength, long maxLatency, long pollingInterval) { + int maxFrameLength, long maxLatency, long maxIdleTime, + long pollingInterval) { this.ioExecutor = ioExecutor; this.appContext = appContext; this.locationUtils = locationUtils; this.callback = callback; this.maxFrameLength = maxFrameLength; this.maxLatency = maxLatency; + this.maxIdleTime = maxIdleTime; this.pollingInterval = pollingInterval; + if(2 * maxIdleTime > Integer.MAX_VALUE) + socketTimeout = Integer.MAX_VALUE; + else socketTimeout = (int) (2 * maxIdleTime); torDirectory = appContext.getDir("tor", MODE_PRIVATE); torFile = new File(torDirectory, "tor"); geoIpFile = new File(torDirectory, "geoip"); @@ -120,6 +125,10 @@ class TorPlugin implements DuplexPlugin, EventHandler { return maxLatency; } + public long getMaxIdleTime() { + return maxIdleTime; + } + public boolean start() throws IOException { // Try to connect to an existing Tor process if there is one boolean startProcess = false; @@ -446,6 +455,7 @@ class TorPlugin implements DuplexPlugin, EventHandler { Socket s; try { s = ss.accept(); + s.setSoTimeout(socketTimeout); } catch(IOException e) { // This is expected when the socket is closed if(LOG.isLoggable(INFO)) LOG.info(e.toString()); @@ -529,6 +539,7 @@ class TorPlugin implements DuplexPlugin, EventHandler { Socks5Proxy proxy = new Socks5Proxy("127.0.0.1", SOCKS_PORT); proxy.resolveAddrLocally(false); Socket s = new SocksSocket(proxy, onion, 80); + s.setSoTimeout(socketTimeout); if(LOG.isLoggable(INFO)) LOG.info("Connected to " + onion); return new TorTransportConnection(this, s); } catch(IOException e) { diff --git a/briar-android/src/org/briarproject/plugins/tor/TorPluginFactory.java b/briar-android/src/org/briarproject/plugins/tor/TorPluginFactory.java index b7c08b225..1260648c3 100644 --- a/briar-android/src/org/briarproject/plugins/tor/TorPluginFactory.java +++ b/briar-android/src/org/briarproject/plugins/tor/TorPluginFactory.java @@ -19,6 +19,7 @@ public class TorPluginFactory implements DuplexPluginFactory { private static final int MAX_FRAME_LENGTH = 1024; private static final long MAX_LATENCY = 60 * 1000; // 1 minute + private static final long MAX_IDLE_TIME = 30 * 1000; // 30 seconds private static final long POLLING_INTERVAL = 3 * 60 * 1000; // 3 minutes private final Executor ioExecutor; @@ -43,6 +44,6 @@ public class TorPluginFactory implements DuplexPluginFactory { return null; } return new TorPlugin(ioExecutor,appContext, locationUtils, callback, - MAX_FRAME_LENGTH, MAX_LATENCY, POLLING_INTERVAL); + MAX_FRAME_LENGTH, MAX_LATENCY, MAX_IDLE_TIME, POLLING_INTERVAL); } } diff --git a/briar-api/src/org/briarproject/api/plugins/duplex/DuplexPlugin.java b/briar-api/src/org/briarproject/api/plugins/duplex/DuplexPlugin.java index 8712d7b79..43fcb3c82 100644 --- a/briar-api/src/org/briarproject/api/plugins/duplex/DuplexPlugin.java +++ b/briar-api/src/org/briarproject/api/plugins/duplex/DuplexPlugin.java @@ -7,6 +7,9 @@ import org.briarproject.api.plugins.Plugin; /** An interface for transport plugins that support duplex communication. */ public interface DuplexPlugin extends Plugin { + /** Returns the transport's maximum idle time in milliseconds. */ + long getMaxIdleTime(); + /** * Attempts to create and return a connection to the given contact using * the current transport and configuration properties. Returns null if a diff --git a/briar-core/src/org/briarproject/messaging/DuplexOutgoingSession.java b/briar-core/src/org/briarproject/messaging/DuplexOutgoingSession.java index a656c9458..9a1ac406d 100644 --- a/briar-core/src/org/briarproject/messaging/DuplexOutgoingSession.java +++ b/briar-core/src/org/briarproject/messaging/DuplexOutgoingSession.java @@ -1,5 +1,6 @@ package org.briarproject.messaging; +import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.logging.Level.INFO; import static java.util.logging.Level.WARNING; import static org.briarproject.api.messaging.MessagingConstants.MAX_PACKET_LENGTH; @@ -54,6 +55,7 @@ import org.briarproject.api.messaging.TransportUpdate; */ class DuplexOutgoingSession implements MessagingSession, EventListener { + private static final int MAX_IDLE_TIME = 30 * 1000; // Milliseconds private static final Logger LOG = Logger.getLogger(DuplexOutgoingSession.class.getName()); @@ -108,7 +110,12 @@ class DuplexOutgoingSession implements MessagingSession, EventListener { while(!interrupted) { // Flush the stream if it's going to be idle if(writerTasks.isEmpty()) out.flush(); - ThrowingRunnable task = writerTasks.take(); + ThrowingRunnable task = writerTasks.poll( + MAX_IDLE_TIME, MILLISECONDS); + if(task == null) { + LOG.info("Idle timeout"); + continue; // Flush and wait again + } if(task == CLOSE) break; task.run(); } diff --git a/briar-core/src/org/briarproject/plugins/tcp/LanTcpPlugin.java b/briar-core/src/org/briarproject/plugins/tcp/LanTcpPlugin.java index 39e4b9418..d585fa83e 100644 --- a/briar-core/src/org/briarproject/plugins/tcp/LanTcpPlugin.java +++ b/briar-core/src/org/briarproject/plugins/tcp/LanTcpPlugin.java @@ -17,8 +17,9 @@ class LanTcpPlugin extends TcpPlugin { static final TransportId ID = new TransportId("lan"); LanTcpPlugin(Executor ioExecutor, DuplexPluginCallback callback, - int maxFrameLength, long maxLatency, long pollingInterval) { - super(ioExecutor, callback, maxFrameLength, maxLatency, + int maxFrameLength, long maxLatency, long maxIdleTime, + long pollingInterval) { + super(ioExecutor, callback, maxFrameLength, maxLatency, maxIdleTime, pollingInterval); } diff --git a/briar-core/src/org/briarproject/plugins/tcp/LanTcpPluginFactory.java b/briar-core/src/org/briarproject/plugins/tcp/LanTcpPluginFactory.java index 02b53eab9..0d7aef843 100644 --- a/briar-core/src/org/briarproject/plugins/tcp/LanTcpPluginFactory.java +++ b/briar-core/src/org/briarproject/plugins/tcp/LanTcpPluginFactory.java @@ -11,6 +11,7 @@ public class LanTcpPluginFactory implements DuplexPluginFactory { private static final int MAX_FRAME_LENGTH = 1024; private static final long MAX_LATENCY = 60 * 1000; // 1 minute + private static final long MAX_IDLE_TIME = 30 * 1000; // 30 seconds private static final long POLLING_INTERVAL = 60 * 1000; // 1 minute private final Executor ioExecutor; @@ -25,6 +26,6 @@ public class LanTcpPluginFactory implements DuplexPluginFactory { public DuplexPlugin createPlugin(DuplexPluginCallback callback) { return new LanTcpPlugin(ioExecutor, callback, MAX_FRAME_LENGTH, - MAX_LATENCY, POLLING_INTERVAL); + MAX_LATENCY, MAX_IDLE_TIME, POLLING_INTERVAL); } } diff --git a/briar-core/src/org/briarproject/plugins/tcp/TcpPlugin.java b/briar-core/src/org/briarproject/plugins/tcp/TcpPlugin.java index a8d3e8dde..d8dd77be6 100644 --- a/briar-core/src/org/briarproject/plugins/tcp/TcpPlugin.java +++ b/briar-core/src/org/briarproject/plugins/tcp/TcpPlugin.java @@ -37,8 +37,8 @@ abstract class TcpPlugin implements DuplexPlugin { protected final Executor ioExecutor; protected final DuplexPluginCallback callback; - protected final int maxFrameLength; - protected final long maxLatency, pollingInterval; + protected final int maxFrameLength, socketTimeout; + protected final long maxLatency, maxIdleTime, pollingInterval; protected volatile boolean running = false; protected volatile ServerSocket socket = null; @@ -53,12 +53,17 @@ abstract class TcpPlugin implements DuplexPlugin { protected abstract boolean isConnectable(InetSocketAddress remote); protected TcpPlugin(Executor ioExecutor, DuplexPluginCallback callback, - int maxFrameLength, long maxLatency, long pollingInterval) { + int maxFrameLength, long maxLatency, long maxIdleTime, + long pollingInterval) { this.ioExecutor = ioExecutor; this.callback = callback; this.maxFrameLength = maxFrameLength; this.maxLatency = maxLatency; + this.maxIdleTime = maxIdleTime; this.pollingInterval = pollingInterval; + if(2 * maxIdleTime > Integer.MAX_VALUE) + socketTimeout = Integer.MAX_VALUE; + else socketTimeout = (int) (2 * maxIdleTime); } public int getMaxFrameLength() { @@ -69,6 +74,10 @@ abstract class TcpPlugin implements DuplexPlugin { return maxLatency; } + public long getMaxIdleTime() { + return maxIdleTime; + } + public boolean start() { running = true; bind(); @@ -136,6 +145,7 @@ abstract class TcpPlugin implements DuplexPlugin { Socket s; try { s = socket.accept(); + s.setSoTimeout(socketTimeout); } catch(IOException e) { // This is expected when the socket is closed if(LOG.isLoggable(INFO)) LOG.info(e.toString()); @@ -195,6 +205,7 @@ abstract class TcpPlugin implements DuplexPlugin { try { if(LOG.isLoggable(INFO)) LOG.info("Connecting to " + remote); s.connect(remote); + s.setSoTimeout(socketTimeout); if(LOG.isLoggable(INFO)) LOG.info("Connected to " + remote); return new TcpTransportConnection(this, s); } catch(IOException e) { diff --git a/briar-core/src/org/briarproject/plugins/tcp/WanTcpPlugin.java b/briar-core/src/org/briarproject/plugins/tcp/WanTcpPlugin.java index 6e2e3e754..8bc290c93 100644 --- a/briar-core/src/org/briarproject/plugins/tcp/WanTcpPlugin.java +++ b/briar-core/src/org/briarproject/plugins/tcp/WanTcpPlugin.java @@ -21,9 +21,9 @@ class WanTcpPlugin extends TcpPlugin { private volatile MappingResult mappingResult; WanTcpPlugin(Executor ioExecutor, DuplexPluginCallback callback, - int maxFrameLength, long maxLatency, long pollingInterval, - PortMapper portMapper) { - super(ioExecutor, callback, maxFrameLength, maxLatency, + int maxFrameLength, long maxLatency, long maxIdleTime, + long pollingInterval, PortMapper portMapper) { + super(ioExecutor, callback, maxFrameLength, maxLatency, maxIdleTime, pollingInterval); this.portMapper = portMapper; } diff --git a/briar-core/src/org/briarproject/plugins/tcp/WanTcpPluginFactory.java b/briar-core/src/org/briarproject/plugins/tcp/WanTcpPluginFactory.java index f478bbc29..c7381b125 100644 --- a/briar-core/src/org/briarproject/plugins/tcp/WanTcpPluginFactory.java +++ b/briar-core/src/org/briarproject/plugins/tcp/WanTcpPluginFactory.java @@ -12,6 +12,7 @@ public class WanTcpPluginFactory implements DuplexPluginFactory { private static final int MAX_FRAME_LENGTH = 1024; private static final long MAX_LATENCY = 60 * 1000; // 1 minute + private static final long MAX_IDLE_TIME = 30 * 1000; // 30 seconds private static final long POLLING_INTERVAL = 5 * 60 * 1000; // 5 minutes private final Executor ioExecutor; @@ -29,7 +30,7 @@ public class WanTcpPluginFactory implements DuplexPluginFactory { public DuplexPlugin createPlugin(DuplexPluginCallback callback) { return new WanTcpPlugin(ioExecutor, callback, MAX_FRAME_LENGTH, - MAX_LATENCY, POLLING_INTERVAL, + MAX_LATENCY, MAX_IDLE_TIME, POLLING_INTERVAL, new PortMapperImpl(shutdownManager)); } } diff --git a/briar-core/src/org/briarproject/transport/StreamWriterImpl.java b/briar-core/src/org/briarproject/transport/StreamWriterImpl.java index 7a65a1219..7e38809a8 100644 --- a/briar-core/src/org/briarproject/transport/StreamWriterImpl.java +++ b/briar-core/src/org/briarproject/transport/StreamWriterImpl.java @@ -42,7 +42,7 @@ class StreamWriterImpl extends OutputStream implements StreamWriter { @Override public void flush() throws IOException { - if(length > 0) writeFrame(false); + writeFrame(false); out.flush(); } diff --git a/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothPlugin.java b/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothPlugin.java index 82f69bee2..4a90f76ba 100644 --- a/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothPlugin.java +++ b/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothPlugin.java @@ -78,6 +78,11 @@ class BluetoothPlugin implements DuplexPlugin { return maxLatency; } + public long getMaxIdleTime() { + // Bluetooth detects dead connections so we don't need keepalives + return Long.MAX_VALUE; + } + public boolean start() throws IOException { // Initialise the Bluetooth stack try { diff --git a/briar-desktop/src/org/briarproject/plugins/modem/ModemPlugin.java b/briar-desktop/src/org/briarproject/plugins/modem/ModemPlugin.java index 686f1c540..825fc3681 100644 --- a/briar-desktop/src/org/briarproject/plugins/modem/ModemPlugin.java +++ b/briar-desktop/src/org/briarproject/plugins/modem/ModemPlugin.java @@ -61,6 +61,11 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback { return maxLatency; } + public long getMaxIdleTime() { + // FIXME: Do we need keepalives for this transport? + return Long.MAX_VALUE; + } + public boolean start() { for(String portName : serialPortList.getPortNames()) { if(LOG.isLoggable(INFO)) diff --git a/briar-tests/src/org/briarproject/plugins/tcp/LanTcpClientTest.java b/briar-tests/src/org/briarproject/plugins/tcp/LanTcpClientTest.java index 8991467a9..3bf190ee8 100644 --- a/briar-tests/src/org/briarproject/plugins/tcp/LanTcpClientTest.java +++ b/briar-tests/src/org/briarproject/plugins/tcp/LanTcpClientTest.java @@ -15,6 +15,11 @@ import org.briarproject.plugins.DuplexClientTest; // is running on another machine public class LanTcpClientTest extends DuplexClientTest { + private static final int MAX_FRAME_LENGTH = 1024; + private static final int MAX_LATENCY = 60 * 1000; + private static final int MAX_IDLE_TIME = 30 * 1000; + private static final int POLLING_INTERVAL = 60 * 1000; + private LanTcpClientTest(Executor executor, String serverAddress, String serverPort) { // Store the server's internal address and port @@ -22,11 +27,12 @@ public class LanTcpClientTest extends DuplexClientTest { p.put("address", serverAddress); p.put("port", serverPort); Map remote = - Collections.singletonMap(contactId, p); + Collections.singletonMap(contactId, p); // Create the plugin callback = new ClientCallback(new TransportConfig(), new TransportProperties(), remote); - plugin = new LanTcpPlugin(executor, callback, 0, 0, 0); + plugin = new LanTcpPlugin(executor, callback, MAX_FRAME_LENGTH, + MAX_LATENCY, MAX_IDLE_TIME, POLLING_INTERVAL); } public static void main(String[] args) throws Exception { diff --git a/briar-tests/src/org/briarproject/plugins/tcp/LanTcpPluginTest.java b/briar-tests/src/org/briarproject/plugins/tcp/LanTcpPluginTest.java index f3a321bbc..c65fe2f96 100644 --- a/briar-tests/src/org/briarproject/plugins/tcp/LanTcpPluginTest.java +++ b/briar-tests/src/org/briarproject/plugins/tcp/LanTcpPluginTest.java @@ -32,7 +32,7 @@ public class LanTcpPluginTest extends BriarTestCase { @Test public void testAddressesAreOnSameLan() { - LanTcpPlugin plugin = new LanTcpPlugin(null, null, 0, 0, 0); + LanTcpPlugin plugin = new LanTcpPlugin(null, null, 0, 0, 0, 0); // Local and remote in 10.0.0.0/8 should return true assertTrue(plugin.addressesAreOnSameLan(makeAddress(10, 0, 0, 0), makeAddress(10, 255, 255, 255))); @@ -81,7 +81,7 @@ public class LanTcpPluginTest extends BriarTestCase { } Callback callback = new Callback(); Executor executor = Executors.newCachedThreadPool(); - DuplexPlugin plugin = new LanTcpPlugin(executor, callback, 0, 0, 0); + DuplexPlugin plugin = new LanTcpPlugin(executor, callback, 0, 0, 0, 0); plugin.start(); // The plugin should have bound a socket and stored the port number assertTrue(callback.propertiesLatch.await(5, SECONDS)); @@ -113,7 +113,7 @@ public class LanTcpPluginTest extends BriarTestCase { } Callback callback = new Callback(); Executor executor = Executors.newCachedThreadPool(); - DuplexPlugin plugin = new LanTcpPlugin(executor, callback, 0, 0, 0); + DuplexPlugin plugin = new LanTcpPlugin(executor, callback, 0, 0, 0, 0); plugin.start(); // The plugin should have bound a socket and stored the port number assertTrue(callback.propertiesLatch.await(5, SECONDS)); diff --git a/briar-tests/src/org/briarproject/plugins/tcp/LanTcpServerTest.java b/briar-tests/src/org/briarproject/plugins/tcp/LanTcpServerTest.java index ff96ae16d..198489c00 100644 --- a/briar-tests/src/org/briarproject/plugins/tcp/LanTcpServerTest.java +++ b/briar-tests/src/org/briarproject/plugins/tcp/LanTcpServerTest.java @@ -13,11 +13,17 @@ import org.briarproject.plugins.DuplexServerTest; // is running on another machine public class LanTcpServerTest extends DuplexServerTest { + private static final int MAX_FRAME_LENGTH = 1024; + private static final int MAX_LATENCY = 60 * 1000; + private static final int MAX_IDLE_TIME = 30 * 1000; + private static final int POLLING_INTERVAL = 60 * 1000; + private LanTcpServerTest(Executor executor) { callback = new ServerCallback(new TransportConfig(), new TransportProperties(), Collections.singletonMap(contactId, new TransportProperties())); - plugin = new LanTcpPlugin(executor, callback, 0, 0, 0); + plugin = new LanTcpPlugin(executor, callback, MAX_FRAME_LENGTH, + MAX_LATENCY, MAX_IDLE_TIME, POLLING_INTERVAL); } public static void main(String[] args) throws Exception { diff --git a/briar-tests/src/org/briarproject/transport/StreamWriterImplTest.java b/briar-tests/src/org/briarproject/transport/StreamWriterImplTest.java index e55e9092d..708769b2c 100644 --- a/briar-tests/src/org/briarproject/transport/StreamWriterImplTest.java +++ b/briar-tests/src/org/briarproject/transport/StreamWriterImplTest.java @@ -31,11 +31,15 @@ public class StreamWriterImplTest extends BriarTestCase { } @Test - public void testFlushWithoutBufferedDataOnlyFlushes() throws Exception { + public void testFlushWithoutBufferedDataWritesFrameAndFlushes() + throws Exception { Mockery context = new Mockery(); final FrameWriter writer = context.mock(FrameWriter.class); StreamWriterImpl w = new StreamWriterImpl(writer, FRAME_LENGTH); context.checking(new Expectations() {{ + // Write a non-final frame with an empty payload + oneOf(writer).writeFrame(with(any(byte[].class)), with(0), + with(false)); // Flush the stream oneOf(writer).flush(); }}); From 29a6596ee3084d15a32dfbf7d7631fa4e6cf6c34 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Sun, 14 Dec 2014 15:18:39 +0000 Subject: [PATCH 02/10] Use the transport's idle timeout, not a hardcoded value. --- .../DroidtoothTransportConnection.java | 4 +++ .../plugins/tor/TorTransportConnection.java | 4 +++ .../messaging/MessagingSessionFactory.java | 7 +++-- .../org/briarproject/api/plugins/Plugin.java | 3 +++ .../plugins/TransportConnectionWriter.java | 3 +++ .../api/plugins/duplex/DuplexPlugin.java | 3 --- .../messaging/DuplexOutgoingSession.java | 10 +++---- .../MessagingSessionFactoryImpl.java | 15 +++++++---- .../plugins/ConnectionManagerImpl.java | 27 ++++++++++++++----- .../briarproject/plugins/file/FilePlugin.java | 4 +++ .../plugins/file/FileTransportWriter.java | 4 +++ .../plugins/tcp/TcpTransportConnection.java | 4 +++ .../BluetoothTransportConnection.java | 4 +++ .../plugins/file/RemovableDrivePlugin.java | 3 +-- .../plugins/modem/ModemPlugin.java | 8 ++++-- 15 files changed, 77 insertions(+), 26 deletions(-) diff --git a/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothTransportConnection.java b/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothTransportConnection.java index d34965073..68ff547a1 100644 --- a/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothTransportConnection.java +++ b/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothTransportConnection.java @@ -68,6 +68,10 @@ class DroidtoothTransportConnection implements DuplexTransportConnection { return plugin.getMaxLatency(); } + public long getMaxIdleTime() { + return plugin.getMaxIdleTime(); + } + public long getCapacity() { return Long.MAX_VALUE; } diff --git a/briar-android/src/org/briarproject/plugins/tor/TorTransportConnection.java b/briar-android/src/org/briarproject/plugins/tor/TorTransportConnection.java index ab0969eae..081bba120 100644 --- a/briar-android/src/org/briarproject/plugins/tor/TorTransportConnection.java +++ b/briar-android/src/org/briarproject/plugins/tor/TorTransportConnection.java @@ -67,6 +67,10 @@ class TorTransportConnection implements DuplexTransportConnection { return plugin.getMaxLatency(); } + public long getMaxIdleTime() { + return plugin.getMaxIdleTime(); + } + public long getCapacity() { return Long.MAX_VALUE; } diff --git a/briar-api/src/org/briarproject/api/messaging/MessagingSessionFactory.java b/briar-api/src/org/briarproject/api/messaging/MessagingSessionFactory.java index c5ceca842..d59b8ae9a 100644 --- a/briar-api/src/org/briarproject/api/messaging/MessagingSessionFactory.java +++ b/briar-api/src/org/briarproject/api/messaging/MessagingSessionFactory.java @@ -11,6 +11,9 @@ public interface MessagingSessionFactory { MessagingSession createIncomingSession(ContactId c, TransportId t, InputStream in); - MessagingSession createOutgoingSession(ContactId c, TransportId t, - long maxLatency, boolean duplex, OutputStream out); + MessagingSession createSimplexOutgoingSession(ContactId c, TransportId t, + long maxLatency, OutputStream out); + + MessagingSession createDuplexOutgoingSession(ContactId c, TransportId t, + long maxLatency, long maxIdleTime, OutputStream out); } diff --git a/briar-api/src/org/briarproject/api/plugins/Plugin.java b/briar-api/src/org/briarproject/api/plugins/Plugin.java index 3389a7357..1048f04cf 100644 --- a/briar-api/src/org/briarproject/api/plugins/Plugin.java +++ b/briar-api/src/org/briarproject/api/plugins/Plugin.java @@ -17,6 +17,9 @@ public interface Plugin { /** Returns the transport's maximum latency in milliseconds. */ long getMaxLatency(); + /** Returns the transport's maximum idle time in milliseconds. */ + long getMaxIdleTime(); + /** Starts the plugin and returns true if it started successfully. */ boolean start() throws IOException; diff --git a/briar-api/src/org/briarproject/api/plugins/TransportConnectionWriter.java b/briar-api/src/org/briarproject/api/plugins/TransportConnectionWriter.java index 554e5de8a..4613f0e76 100644 --- a/briar-api/src/org/briarproject/api/plugins/TransportConnectionWriter.java +++ b/briar-api/src/org/briarproject/api/plugins/TransportConnectionWriter.java @@ -15,6 +15,9 @@ public interface TransportConnectionWriter { /** Returns the maximum latency of the transport in milliseconds. */ long getMaxLatency(); + /** Returns the maximum idle time of the transport in milliseconds. */ + long getMaxIdleTime(); + /** Returns the capacity of the transport connection in bytes. */ long getCapacity(); diff --git a/briar-api/src/org/briarproject/api/plugins/duplex/DuplexPlugin.java b/briar-api/src/org/briarproject/api/plugins/duplex/DuplexPlugin.java index 43fcb3c82..8712d7b79 100644 --- a/briar-api/src/org/briarproject/api/plugins/duplex/DuplexPlugin.java +++ b/briar-api/src/org/briarproject/api/plugins/duplex/DuplexPlugin.java @@ -7,9 +7,6 @@ import org.briarproject.api.plugins.Plugin; /** An interface for transport plugins that support duplex communication. */ public interface DuplexPlugin extends Plugin { - /** Returns the transport's maximum idle time in milliseconds. */ - long getMaxIdleTime(); - /** * Attempts to create and return a connection to the given contact using * the current transport and configuration properties. Returns null if a diff --git a/briar-core/src/org/briarproject/messaging/DuplexOutgoingSession.java b/briar-core/src/org/briarproject/messaging/DuplexOutgoingSession.java index 9a1ac406d..13e839554 100644 --- a/briar-core/src/org/briarproject/messaging/DuplexOutgoingSession.java +++ b/briar-core/src/org/briarproject/messaging/DuplexOutgoingSession.java @@ -55,7 +55,6 @@ import org.briarproject.api.messaging.TransportUpdate; */ class DuplexOutgoingSession implements MessagingSession, EventListener { - private static final int MAX_IDLE_TIME = 30 * 1000; // Milliseconds private static final Logger LOG = Logger.getLogger(DuplexOutgoingSession.class.getName()); @@ -69,7 +68,7 @@ class DuplexOutgoingSession implements MessagingSession, EventListener { private final EventBus eventBus; private final ContactId contactId; private final TransportId transportId; - private final long maxLatency; + private final long maxLatency, maxIdleTime; private final OutputStream out; private final PacketWriter packetWriter; private final BlockingQueue> writerTasks; @@ -79,13 +78,14 @@ class DuplexOutgoingSession implements MessagingSession, EventListener { DuplexOutgoingSession(DatabaseComponent db, Executor dbExecutor, EventBus eventBus, PacketWriterFactory packetWriterFactory, ContactId contactId, TransportId transportId, long maxLatency, - OutputStream out) { + long maxIdleTime, OutputStream out) { this.db = db; this.dbExecutor = dbExecutor; this.eventBus = eventBus; this.contactId = contactId; this.transportId = transportId; this.maxLatency = maxLatency; + this.maxIdleTime = maxIdleTime; this.out = out; packetWriter = packetWriterFactory.createPacketWriter(out); writerTasks = new LinkedBlockingQueue>(); @@ -110,8 +110,8 @@ class DuplexOutgoingSession implements MessagingSession, EventListener { while(!interrupted) { // Flush the stream if it's going to be idle if(writerTasks.isEmpty()) out.flush(); - ThrowingRunnable task = writerTasks.poll( - MAX_IDLE_TIME, MILLISECONDS); + ThrowingRunnable task = + writerTasks.poll(maxIdleTime, MILLISECONDS); if(task == null) { LOG.info("Idle timeout"); continue; // Flush and wait again diff --git a/briar-core/src/org/briarproject/messaging/MessagingSessionFactoryImpl.java b/briar-core/src/org/briarproject/messaging/MessagingSessionFactoryImpl.java index 04895580c..9ab638aa0 100644 --- a/briar-core/src/org/briarproject/messaging/MessagingSessionFactoryImpl.java +++ b/briar-core/src/org/briarproject/messaging/MessagingSessionFactoryImpl.java @@ -49,11 +49,16 @@ class MessagingSessionFactoryImpl implements MessagingSessionFactory { messageVerifier, packetReaderFactory, c, t, in); } - public MessagingSession createOutgoingSession(ContactId c, TransportId t, - long maxLatency, boolean duplex, OutputStream out) { - if(duplex) return new DuplexOutgoingSession(db, dbExecutor, eventBus, - packetWriterFactory, c, t, maxLatency, out); - else return new SimplexOutgoingSession(db, dbExecutor, eventBus, + public MessagingSession createSimplexOutgoingSession(ContactId c, + TransportId t, long maxLatency, OutputStream out) { + return new SimplexOutgoingSession(db, dbExecutor, eventBus, packetWriterFactory, c, t, maxLatency, out); } + + public MessagingSession createDuplexOutgoingSession(ContactId c, + TransportId t, long maxLatency, long maxIdleTime, + OutputStream out) { + return new DuplexOutgoingSession(db, dbExecutor, eventBus, + packetWriterFactory, c, t, maxLatency, maxIdleTime, out); + } } diff --git a/briar-core/src/org/briarproject/plugins/ConnectionManagerImpl.java b/briar-core/src/org/briarproject/plugins/ConnectionManagerImpl.java index d94e1f80e..9dad32f2e 100644 --- a/briar-core/src/org/briarproject/plugins/ConnectionManagerImpl.java +++ b/briar-core/src/org/briarproject/plugins/ConnectionManagerImpl.java @@ -107,14 +107,27 @@ class ConnectionManagerImpl implements ConnectionManager { } } - private MessagingSession createOutgoingSession(StreamContext ctx, - TransportConnectionWriter w, boolean duplex) throws IOException { + private MessagingSession createSimplexOutgoingSession(StreamContext ctx, + TransportConnectionWriter w) throws IOException { try { StreamWriter streamWriter = streamWriterFactory.createStreamWriter( w.getOutputStream(), w.getMaxFrameLength(), ctx); - return messagingSessionFactory.createOutgoingSession( + return messagingSessionFactory.createSimplexOutgoingSession( ctx.getContactId(), ctx.getTransportId(), w.getMaxLatency(), - duplex, streamWriter.getOutputStream()); + streamWriter.getOutputStream()); + } finally { + ByteUtils.erase(ctx.getSecret()); + } + } + + private MessagingSession createDuplexOutgoingSession(StreamContext ctx, + TransportConnectionWriter w) throws IOException { + try { + StreamWriter streamWriter = streamWriterFactory.createStreamWriter( + w.getOutputStream(), w.getMaxFrameLength(), ctx); + return messagingSessionFactory.createDuplexOutgoingSession( + ctx.getContactId(), ctx.getTransportId(), w.getMaxLatency(), + w.getMaxIdleTime(), streamWriter.getOutputStream()); } finally { ByteUtils.erase(ctx.getSecret()); } @@ -199,7 +212,7 @@ class ConnectionManagerImpl implements ConnectionManager { connectionRegistry.registerConnection(contactId, transportId); try { // Create and run the outgoing session - createOutgoingSession(ctx, writer, false).run(); + createSimplexOutgoingSession(ctx, writer).run(); disposeWriter(false); } catch(IOException e) { if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); @@ -287,7 +300,7 @@ class ConnectionManagerImpl implements ConnectionManager { } try { // Create and run the outgoing session - outgoingSession = createOutgoingSession(ctx, writer, true); + outgoingSession = createDuplexOutgoingSession(ctx, writer); outgoingSession.run(); disposeWriter(false); } catch(IOException e) { @@ -353,7 +366,7 @@ class ConnectionManagerImpl implements ConnectionManager { }); try { // Create and run the outgoing session - outgoingSession = createOutgoingSession(ctx, writer, true); + outgoingSession = createDuplexOutgoingSession(ctx, writer); outgoingSession.run(); disposeWriter(false); } catch(IOException e) { diff --git a/briar-core/src/org/briarproject/plugins/file/FilePlugin.java b/briar-core/src/org/briarproject/plugins/file/FilePlugin.java index 1af4215ba..9c298b023 100644 --- a/briar-core/src/org/briarproject/plugins/file/FilePlugin.java +++ b/briar-core/src/org/briarproject/plugins/file/FilePlugin.java @@ -56,6 +56,10 @@ public abstract class FilePlugin implements SimplexPlugin { return maxLatency; } + public long getMaxIdleTime() { + return Long.MAX_VALUE; // We don't need keepalives + } + public boolean isRunning() { return running; } diff --git a/briar-core/src/org/briarproject/plugins/file/FileTransportWriter.java b/briar-core/src/org/briarproject/plugins/file/FileTransportWriter.java index 2ca55593f..ecba989ff 100644 --- a/briar-core/src/org/briarproject/plugins/file/FileTransportWriter.java +++ b/briar-core/src/org/briarproject/plugins/file/FileTransportWriter.java @@ -35,6 +35,10 @@ class FileTransportWriter implements TransportConnectionWriter { return plugin.getMaxLatency(); } + public long getMaxIdleTime() { + return plugin.getMaxIdleTime(); + } + public long getCapacity() { return capacity; } diff --git a/briar-core/src/org/briarproject/plugins/tcp/TcpTransportConnection.java b/briar-core/src/org/briarproject/plugins/tcp/TcpTransportConnection.java index 83506a211..2df916265 100644 --- a/briar-core/src/org/briarproject/plugins/tcp/TcpTransportConnection.java +++ b/briar-core/src/org/briarproject/plugins/tcp/TcpTransportConnection.java @@ -67,6 +67,10 @@ class TcpTransportConnection implements DuplexTransportConnection { return plugin.getMaxLatency(); } + public long getMaxIdleTime() { + return plugin.getMaxIdleTime(); + } + public long getCapacity() { return Long.MAX_VALUE; } diff --git a/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothTransportConnection.java b/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothTransportConnection.java index 8a2c79672..3de6a6a10 100644 --- a/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothTransportConnection.java +++ b/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothTransportConnection.java @@ -68,6 +68,10 @@ class BluetoothTransportConnection implements DuplexTransportConnection { return plugin.getMaxLatency(); } + public long getMaxIdleTime() { + return plugin.getMaxIdleTime(); + } + public long getCapacity() { return Long.MAX_VALUE; } diff --git a/briar-desktop/src/org/briarproject/plugins/file/RemovableDrivePlugin.java b/briar-desktop/src/org/briarproject/plugins/file/RemovableDrivePlugin.java index 09ffd6f66..bdf9d84ef 100644 --- a/briar-desktop/src/org/briarproject/plugins/file/RemovableDrivePlugin.java +++ b/briar-desktop/src/org/briarproject/plugins/file/RemovableDrivePlugin.java @@ -29,8 +29,7 @@ implements RemovableDriveMonitor.Callback { RemovableDrivePlugin(Executor ioExecutor, FileUtils fileUtils, SimplexPluginCallback callback, RemovableDriveFinder finder, - RemovableDriveMonitor monitor, int maxFrameLength, - long maxLatency) { + RemovableDriveMonitor monitor, int maxFrameLength, long maxLatency) { super(ioExecutor, fileUtils, callback, maxFrameLength, maxLatency); this.finder = finder; this.monitor = monitor; diff --git a/briar-desktop/src/org/briarproject/plugins/modem/ModemPlugin.java b/briar-desktop/src/org/briarproject/plugins/modem/ModemPlugin.java index 825fc3681..983628497 100644 --- a/briar-desktop/src/org/briarproject/plugins/modem/ModemPlugin.java +++ b/briar-desktop/src/org/briarproject/plugins/modem/ModemPlugin.java @@ -223,11 +223,15 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback { private class Writer implements TransportConnectionWriter { public int getMaxFrameLength() { - return maxFrameLength; + return getMaxFrameLength(); } public long getMaxLatency() { - return maxLatency; + return getMaxLatency(); + } + + public long getMaxIdleTime() { + return getMaxIdleTime(); } public long getCapacity() { From 388b36b6be5f324fb07fd942940f1488caca1737 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Sun, 14 Dec 2014 20:26:41 +0000 Subject: [PATCH 03/10] Check periodically for retransmittable packets. Bug #46. --- .../plugins/droidtooth/DroidtoothPlugin.java | 15 ++- .../droidtooth/DroidtoothPluginFactory.java | 4 +- .../DroidtoothTransportConnection.java | 4 +- .../plugins/tcp/AndroidLanTcpPlugin.java | 4 +- .../tcp/AndroidLanTcpPluginFactory.java | 6 +- .../briarproject/plugins/tor/TorPlugin.java | 18 ++-- .../plugins/tor/TorPluginFactory.java | 6 +- .../plugins/tor/TorTransportConnection.java | 4 +- .../briarproject/api/crypto/KeyManager.java | 2 +- .../api/db/DatabaseComponent.java | 18 ++-- .../api/event/TransportAddedEvent.java | 6 +- .../messaging/MessagingSessionFactory.java | 4 +- .../api/messaging/PacketWriter.java | 2 + .../org/briarproject/api/plugins/Plugin.java | 6 +- .../plugins/TransportConnectionWriter.java | 4 +- .../src/org/briarproject/db/Database.java | 14 +-- .../db/DatabaseComponentImpl.java | 19 ++-- .../briarproject/db/ExponentialBackoff.java | 5 +- .../src/org/briarproject/db/JdbcDatabase.java | 23 ++--- .../briarproject/invitation/Connector.java | 4 +- .../messaging/DuplexOutgoingSession.java | 75 ++++++++++----- .../messaging/IncomingSession.java | 9 +- .../MessagingSessionFactoryImpl.java | 25 +++-- .../messaging/PacketWriterImpl.java | 4 + .../messaging/SimplexOutgoingSession.java | 15 +-- .../briarproject/plugins/file/FilePlugin.java | 11 +-- .../plugins/file/FileTransportWriter.java | 4 +- .../plugins/tcp/LanTcpPlugin.java | 4 +- .../plugins/tcp/LanTcpPluginFactory.java | 6 +- .../briarproject/plugins/tcp/TcpPlugin.java | 18 ++-- .../plugins/tcp/TcpTransportConnection.java | 4 +- .../plugins/tcp/WanTcpPlugin.java | 6 +- .../plugins/tcp/WanTcpPluginFactory.java | 12 +-- .../transport/KeyManagerImpl.java | 10 +- .../plugins/bluetooth/BluetoothPlugin.java | 15 ++- .../bluetooth/BluetoothPluginFactory.java | 4 +- .../BluetoothTransportConnection.java | 4 +- .../file/PollingRemovableDriveMonitor.java | 4 +- .../plugins/file/RemovableDrivePlugin.java | 4 +- .../file/RemovableDrivePluginFactory.java | 4 +- .../plugins/modem/ModemPlugin.java | 21 ++--- .../plugins/modem/ModemPluginFactory.java | 5 +- .../db/DatabaseComponentTest.java | 47 +++++----- .../db/ExponentialBackoffTest.java | 28 +++--- .../org/briarproject/db/H2DatabaseTest.java | 15 +-- .../SimplexMessagingIntegrationTest.java | 31 ++++--- .../messaging/SimplexOutgoingSessionTest.java | 91 ++++++++----------- .../plugins/PluginManagerImplTest.java | 6 +- .../plugins/modem/ModemPluginTest.java | 8 +- .../transport/KeyManagerImplTest.java | 14 +-- .../transport/KeyRotationIntegrationTest.java | 10 +- 51 files changed, 351 insertions(+), 331 deletions(-) diff --git a/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothPlugin.java b/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothPlugin.java index e7cd834df..1aff5ba37 100644 --- a/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothPlugin.java +++ b/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothPlugin.java @@ -69,8 +69,7 @@ class DroidtoothPlugin implements DuplexPlugin { private final SecureRandom secureRandom; private final Clock clock; private final DuplexPluginCallback callback; - private final int maxFrameLength; - private final long maxLatency, pollingInterval; + private final int maxFrameLength, maxLatency, pollingInterval; private volatile boolean running = false; private volatile boolean wasDisabled = false; @@ -82,8 +81,8 @@ class DroidtoothPlugin implements DuplexPlugin { DroidtoothPlugin(Executor ioExecutor, AndroidExecutor androidExecutor, Context appContext, SecureRandom secureRandom, Clock clock, - DuplexPluginCallback callback, int maxFrameLength, long maxLatency, - long pollingInterval) { + DuplexPluginCallback callback, int maxFrameLength, int maxLatency, + int pollingInterval) { this.ioExecutor = ioExecutor; this.androidExecutor = androidExecutor; this.appContext = appContext; @@ -103,13 +102,13 @@ class DroidtoothPlugin implements DuplexPlugin { return maxFrameLength; } - public long getMaxLatency() { + public int getMaxLatency() { return maxLatency; } - public long getMaxIdleTime() { + public int getMaxIdleTime() { // Bluetooth detects dead connections so we don't need keepalives - return Long.MAX_VALUE; + return Integer.MAX_VALUE; } public boolean start() throws IOException { @@ -245,7 +244,7 @@ class DroidtoothPlugin implements DuplexPlugin { return true; } - public long getPollingInterval() { + public int getPollingInterval() { return pollingInterval; } diff --git a/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothPluginFactory.java b/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothPluginFactory.java index b7bb20285..8cc21085d 100644 --- a/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothPluginFactory.java +++ b/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothPluginFactory.java @@ -16,8 +16,8 @@ import android.content.Context; public class DroidtoothPluginFactory implements DuplexPluginFactory { private static final int MAX_FRAME_LENGTH = 1024; - private static final long MAX_LATENCY = 60 * 1000; // 1 minute - private static final long POLLING_INTERVAL = 3 * 60 * 1000; // 3 minutes + private static final int MAX_LATENCY = 30 * 1000; // 30 seconds + private static final int POLLING_INTERVAL = 3 * 60 * 1000; // 3 minutes private final Executor ioExecutor; private final AndroidExecutor androidExecutor; diff --git a/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothTransportConnection.java b/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothTransportConnection.java index 68ff547a1..fa38875de 100644 --- a/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothTransportConnection.java +++ b/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothTransportConnection.java @@ -64,11 +64,11 @@ class DroidtoothTransportConnection implements DuplexTransportConnection { return plugin.getMaxFrameLength(); } - public long getMaxLatency() { + public int getMaxLatency() { return plugin.getMaxLatency(); } - public long getMaxIdleTime() { + public int getMaxIdleTime() { return plugin.getMaxIdleTime(); } diff --git a/briar-android/src/org/briarproject/plugins/tcp/AndroidLanTcpPlugin.java b/briar-android/src/org/briarproject/plugins/tcp/AndroidLanTcpPlugin.java index 25a9fbc54..6194e2ee8 100644 --- a/briar-android/src/org/briarproject/plugins/tcp/AndroidLanTcpPlugin.java +++ b/briar-android/src/org/briarproject/plugins/tcp/AndroidLanTcpPlugin.java @@ -26,8 +26,8 @@ class AndroidLanTcpPlugin extends LanTcpPlugin { private volatile BroadcastReceiver networkStateReceiver = null; AndroidLanTcpPlugin(Executor ioExecutor, Context appContext, - DuplexPluginCallback callback, int maxFrameLength, long maxLatency, - long maxIdleTime, long pollingInterval) { + DuplexPluginCallback callback, int maxFrameLength, int maxLatency, + int maxIdleTime, int pollingInterval) { super(ioExecutor, callback, maxFrameLength, maxLatency, maxIdleTime, pollingInterval); this.appContext = appContext; diff --git a/briar-android/src/org/briarproject/plugins/tcp/AndroidLanTcpPluginFactory.java b/briar-android/src/org/briarproject/plugins/tcp/AndroidLanTcpPluginFactory.java index 8160ac969..7e0a5469c 100644 --- a/briar-android/src/org/briarproject/plugins/tcp/AndroidLanTcpPluginFactory.java +++ b/briar-android/src/org/briarproject/plugins/tcp/AndroidLanTcpPluginFactory.java @@ -12,9 +12,9 @@ import android.content.Context; public class AndroidLanTcpPluginFactory implements DuplexPluginFactory { private static final int MAX_FRAME_LENGTH = 1024; - private static final long MAX_LATENCY = 60 * 1000; // 1 minute - private static final long MAX_IDLE_TIME = 30 * 1000; // 30 seconds - private static final long POLLING_INTERVAL = 60 * 1000; // 1 minute + private static final int MAX_LATENCY = 30 * 1000; // 30 seconds + private static final int MAX_IDLE_TIME = 30 * 1000; // 30 seconds + private static final int POLLING_INTERVAL = 3 * 60 * 1000; // 3 minutes private final Executor ioExecutor; private final Context appContext; diff --git a/briar-android/src/org/briarproject/plugins/tor/TorPlugin.java b/briar-android/src/org/briarproject/plugins/tor/TorPlugin.java index bd59adda5..4222da1ba 100644 --- a/briar-android/src/org/briarproject/plugins/tor/TorPlugin.java +++ b/briar-android/src/org/briarproject/plugins/tor/TorPlugin.java @@ -75,8 +75,8 @@ class TorPlugin implements DuplexPlugin, EventHandler { private final Context appContext; private final LocationUtils locationUtils; private final DuplexPluginCallback callback; - private final int maxFrameLength, socketTimeout; - private final long maxLatency, maxIdleTime, pollingInterval; + private final int maxFrameLength, maxLatency, maxIdleTime, pollingInterval; + private final int socketTimeout; private final File torDirectory, torFile, geoIpFile, configFile, doneFile; private final File cookieFile, hostnameFile; private final AtomicBoolean circuitBuilt; @@ -90,8 +90,8 @@ class TorPlugin implements DuplexPlugin, EventHandler { TorPlugin(Executor ioExecutor, Context appContext, LocationUtils locationUtils, DuplexPluginCallback callback, - int maxFrameLength, long maxLatency, long maxIdleTime, - long pollingInterval) { + int maxFrameLength, int maxLatency, int maxIdleTime, + int pollingInterval) { this.ioExecutor = ioExecutor; this.appContext = appContext; this.locationUtils = locationUtils; @@ -100,9 +100,9 @@ class TorPlugin implements DuplexPlugin, EventHandler { this.maxLatency = maxLatency; this.maxIdleTime = maxIdleTime; this.pollingInterval = pollingInterval; - if(2 * maxIdleTime > Integer.MAX_VALUE) + if(maxIdleTime > Integer.MAX_VALUE / 2) socketTimeout = Integer.MAX_VALUE; - else socketTimeout = (int) (2 * maxIdleTime); + else socketTimeout = maxIdleTime * 2; torDirectory = appContext.getDir("tor", MODE_PRIVATE); torFile = new File(torDirectory, "tor"); geoIpFile = new File(torDirectory, "geoip"); @@ -121,11 +121,11 @@ class TorPlugin implements DuplexPlugin, EventHandler { return maxFrameLength; } - public long getMaxLatency() { + public int getMaxLatency() { return maxLatency; } - public long getMaxIdleTime() { + public int getMaxIdleTime() { return maxIdleTime; } @@ -504,7 +504,7 @@ class TorPlugin implements DuplexPlugin, EventHandler { return true; } - public long getPollingInterval() { + public int getPollingInterval() { return pollingInterval; } diff --git a/briar-android/src/org/briarproject/plugins/tor/TorPluginFactory.java b/briar-android/src/org/briarproject/plugins/tor/TorPluginFactory.java index 1260648c3..bf44a3593 100644 --- a/briar-android/src/org/briarproject/plugins/tor/TorPluginFactory.java +++ b/briar-android/src/org/briarproject/plugins/tor/TorPluginFactory.java @@ -18,9 +18,9 @@ public class TorPluginFactory implements DuplexPluginFactory { Logger.getLogger(TorPluginFactory.class.getName()); private static final int MAX_FRAME_LENGTH = 1024; - private static final long MAX_LATENCY = 60 * 1000; // 1 minute - private static final long MAX_IDLE_TIME = 30 * 1000; // 30 seconds - private static final long POLLING_INTERVAL = 3 * 60 * 1000; // 3 minutes + private static final int MAX_LATENCY = 30 * 1000; // 30 seconds + private static final int MAX_IDLE_TIME = 30 * 1000; // 30 seconds + private static final int POLLING_INTERVAL = 3 * 60 * 1000; // 3 minutes private final Executor ioExecutor; private final Context appContext; diff --git a/briar-android/src/org/briarproject/plugins/tor/TorTransportConnection.java b/briar-android/src/org/briarproject/plugins/tor/TorTransportConnection.java index 081bba120..12880977f 100644 --- a/briar-android/src/org/briarproject/plugins/tor/TorTransportConnection.java +++ b/briar-android/src/org/briarproject/plugins/tor/TorTransportConnection.java @@ -63,11 +63,11 @@ class TorTransportConnection implements DuplexTransportConnection { return plugin.getMaxFrameLength(); } - public long getMaxLatency() { + public int getMaxLatency() { return plugin.getMaxLatency(); } - public long getMaxIdleTime() { + public int getMaxIdleTime() { return plugin.getMaxIdleTime(); } diff --git a/briar-api/src/org/briarproject/api/crypto/KeyManager.java b/briar-api/src/org/briarproject/api/crypto/KeyManager.java index 59e4d7af3..77c41132e 100644 --- a/briar-api/src/org/briarproject/api/crypto/KeyManager.java +++ b/briar-api/src/org/briarproject/api/crypto/KeyManager.java @@ -20,5 +20,5 @@ public interface KeyManager extends Service { * Called whenever an endpoint has been added. The initial secret is erased * before returning. */ - void endpointAdded(Endpoint ep, long maxLatency, byte[] initialSecret); + void endpointAdded(Endpoint ep, int maxLatency, byte[] initialSecret); } diff --git a/briar-api/src/org/briarproject/api/db/DatabaseComponent.java b/briar-api/src/org/briarproject/api/db/DatabaseComponent.java index e7b55dd6d..5159ac022 100644 --- a/briar-api/src/org/briarproject/api/db/DatabaseComponent.java +++ b/briar-api/src/org/briarproject/api/db/DatabaseComponent.java @@ -73,7 +73,7 @@ public interface DatabaseComponent { * Stores a transport and returns true if the transport was not previously * in the database. */ - boolean addTransport(TransportId t, long maxLatency) throws DbException; + boolean addTransport(TransportId t, int maxLatency) throws DbException; /** * Returns an acknowledgement for the given contact, or null if there are @@ -88,14 +88,14 @@ public interface DatabaseComponent { * sendable messages that fit in the given length. */ Collection generateBatch(ContactId c, int maxLength, - long maxLatency) throws DbException; + int maxLatency) throws DbException; /** * Returns an offer for the given contact for transmission over a * transport with the given maximum latency, or null if there are no * messages to offer. */ - Offer generateOffer(ContactId c, int maxMessages, long maxLatency) + Offer generateOffer(ContactId c, int maxMessages, int maxLatency) throws DbException; /** @@ -112,7 +112,7 @@ public interface DatabaseComponent { * sendable messages that fit in the given length. */ Collection generateRequestedBatch(ContactId c, int maxLength, - long maxLatency) throws DbException; + int maxLatency) throws DbException; /** * Returns a retention ack for the given contact, or null if no retention @@ -125,7 +125,7 @@ public interface DatabaseComponent { * over a transport with the given latency. Returns null if no update is * due. */ - RetentionUpdate generateRetentionUpdate(ContactId c, long maxLatency) + RetentionUpdate generateRetentionUpdate(ContactId c, int maxLatency) throws DbException; /** @@ -139,7 +139,7 @@ public interface DatabaseComponent { * over a transport with the given latency. Returns null if no update is * due. */ - SubscriptionUpdate generateSubscriptionUpdate(ContactId c, long maxLatency) + SubscriptionUpdate generateSubscriptionUpdate(ContactId c, int maxLatency) throws DbException; /** @@ -155,7 +155,7 @@ public interface DatabaseComponent { * updates are due. */ Collection generateTransportUpdates(ContactId c, - long maxLatency) throws DbException; + int maxLatency) throws DbException; /** * Returns the status of all groups to which the user subscribes or can @@ -227,8 +227,8 @@ public interface DatabaseComponent { /** Returns all contacts who subscribe to the given group. */ Collection getSubscribers(GroupId g) throws DbException; - /** Returns the maximum latencies of all local transports. */ - Map getTransportLatencies() throws DbException; + /** Returns the maximum latencies of all supported transports. */ + Map getTransportLatencies() throws DbException; /** Returns the number of unread messages in each subscribed group. */ Map getUnreadMessageCounts() throws DbException; diff --git a/briar-api/src/org/briarproject/api/event/TransportAddedEvent.java b/briar-api/src/org/briarproject/api/event/TransportAddedEvent.java index 7a1f599a6..b775ce6c9 100644 --- a/briar-api/src/org/briarproject/api/event/TransportAddedEvent.java +++ b/briar-api/src/org/briarproject/api/event/TransportAddedEvent.java @@ -6,9 +6,9 @@ import org.briarproject.api.TransportId; public class TransportAddedEvent extends Event { private final TransportId transportId; - private final long maxLatency; + private final int maxLatency; - public TransportAddedEvent(TransportId transportId, long maxLatency) { + public TransportAddedEvent(TransportId transportId, int maxLatency) { this.transportId = transportId; this.maxLatency = maxLatency; } @@ -17,7 +17,7 @@ public class TransportAddedEvent extends Event { return transportId; } - public long getMaxLatency() { + public int getMaxLatency() { return maxLatency; } } diff --git a/briar-api/src/org/briarproject/api/messaging/MessagingSessionFactory.java b/briar-api/src/org/briarproject/api/messaging/MessagingSessionFactory.java index d59b8ae9a..8764f3e25 100644 --- a/briar-api/src/org/briarproject/api/messaging/MessagingSessionFactory.java +++ b/briar-api/src/org/briarproject/api/messaging/MessagingSessionFactory.java @@ -12,8 +12,8 @@ public interface MessagingSessionFactory { InputStream in); MessagingSession createSimplexOutgoingSession(ContactId c, TransportId t, - long maxLatency, OutputStream out); + int maxLatency, OutputStream out); MessagingSession createDuplexOutgoingSession(ContactId c, TransportId t, - long maxLatency, long maxIdleTime, OutputStream out); + int maxLatency, int maxIdleTime, OutputStream out); } diff --git a/briar-api/src/org/briarproject/api/messaging/PacketWriter.java b/briar-api/src/org/briarproject/api/messaging/PacketWriter.java index bc7b4e1de..1300e84c5 100644 --- a/briar-api/src/org/briarproject/api/messaging/PacketWriter.java +++ b/briar-api/src/org/briarproject/api/messaging/PacketWriter.java @@ -29,4 +29,6 @@ public interface PacketWriter { void writeTransportAck(TransportAck a) throws IOException; void writeTransportUpdate(TransportUpdate u) throws IOException; + + void flush() throws IOException; } diff --git a/briar-api/src/org/briarproject/api/plugins/Plugin.java b/briar-api/src/org/briarproject/api/plugins/Plugin.java index 1048f04cf..eafb91007 100644 --- a/briar-api/src/org/briarproject/api/plugins/Plugin.java +++ b/briar-api/src/org/briarproject/api/plugins/Plugin.java @@ -15,10 +15,10 @@ public interface Plugin { int getMaxFrameLength(); /** Returns the transport's maximum latency in milliseconds. */ - long getMaxLatency(); + int getMaxLatency(); /** Returns the transport's maximum idle time in milliseconds. */ - long getMaxIdleTime(); + int getMaxIdleTime(); /** Starts the plugin and returns true if it started successfully. */ boolean start() throws IOException; @@ -39,7 +39,7 @@ public interface Plugin { * Returns the desired interval in milliseconds between calls to the * plugin's {@link #poll(Collection)} method. */ - long getPollingInterval(); + int getPollingInterval(); /** * Attempts to establish connections to contacts, passing any created diff --git a/briar-api/src/org/briarproject/api/plugins/TransportConnectionWriter.java b/briar-api/src/org/briarproject/api/plugins/TransportConnectionWriter.java index 4613f0e76..7f07411c6 100644 --- a/briar-api/src/org/briarproject/api/plugins/TransportConnectionWriter.java +++ b/briar-api/src/org/briarproject/api/plugins/TransportConnectionWriter.java @@ -13,10 +13,10 @@ public interface TransportConnectionWriter { int getMaxFrameLength(); /** Returns the maximum latency of the transport in milliseconds. */ - long getMaxLatency(); + int getMaxLatency(); /** Returns the maximum idle time of the transport in milliseconds. */ - long getMaxIdleTime(); + int getMaxIdleTime(); /** Returns the capacity of the transport connection in bytes. */ long getCapacity(); diff --git a/briar-core/src/org/briarproject/db/Database.java b/briar-core/src/org/briarproject/db/Database.java index 5bce51798..ba3c4ffaf 100644 --- a/briar-core/src/org/briarproject/db/Database.java +++ b/briar-core/src/org/briarproject/db/Database.java @@ -152,7 +152,7 @@ interface Database { *

* Locking: write. */ - boolean addTransport(T txn, TransportId t, long maxLatency) + boolean addTransport(T txn, TransportId t, int maxLatency) throws DbException; /** @@ -460,7 +460,7 @@ interface Database { *

* Locking: write. */ - RetentionUpdate getRetentionUpdate(T txn, ContactId c, long maxLatency) + RetentionUpdate getRetentionUpdate(T txn, ContactId c, int maxLatency) throws DbException; /** @@ -499,7 +499,7 @@ interface Database { * Locking: write. */ SubscriptionUpdate getSubscriptionUpdate(T txn, ContactId c, - long maxLatency) throws DbException; + int maxLatency) throws DbException; /** * Returns a collection of transport acks for the given contact, or null if @@ -511,11 +511,11 @@ interface Database { throws DbException; /** - * Returns the maximum latencies of all local transports. + * Returns the maximum latencies of all supported transports. *

* Locking: read. */ - Map getTransportLatencies(T txn) throws DbException; + Map getTransportLatencies(T txn) throws DbException; /** * Returns a collection of transport updates for the given contact and @@ -525,7 +525,7 @@ interface Database { * Locking: write. */ Collection getTransportUpdates(T txn, ContactId c, - long maxLatency) throws DbException; + int maxLatency) throws DbException; /** * Returns the number of unread messages in each subscribed group. @@ -798,6 +798,6 @@ interface Database { *

* Locking: write. */ - void updateExpiryTime(T txn, ContactId c, MessageId m, long maxLatency) + void updateExpiryTime(T txn, ContactId c, MessageId m, int maxLatency) throws DbException; } diff --git a/briar-core/src/org/briarproject/db/DatabaseComponentImpl.java b/briar-core/src/org/briarproject/db/DatabaseComponentImpl.java index c22643f0b..1c8bc564d 100644 --- a/briar-core/src/org/briarproject/db/DatabaseComponentImpl.java +++ b/briar-core/src/org/briarproject/db/DatabaseComponentImpl.java @@ -314,7 +314,7 @@ DatabaseCleaner.Callback { } } - public boolean addTransport(TransportId t, long maxLatency) + public boolean addTransport(TransportId t, int maxLatency) throws DbException { boolean added; lock.writeLock().lock(); @@ -357,7 +357,7 @@ DatabaseCleaner.Callback { } public Collection generateBatch(ContactId c, int maxLength, - long maxLatency) throws DbException { + int maxLatency) throws DbException { Collection ids; List messages = new ArrayList(); lock.writeLock().lock(); @@ -384,7 +384,7 @@ DatabaseCleaner.Callback { return Collections.unmodifiableList(messages); } - public Offer generateOffer(ContactId c, int maxMessages, long maxLatency) + public Offer generateOffer(ContactId c, int maxMessages, int maxLatency) throws DbException { Collection ids; lock.writeLock().lock(); @@ -432,7 +432,7 @@ DatabaseCleaner.Callback { } public Collection generateRequestedBatch(ContactId c, int maxLength, - long maxLatency) throws DbException { + int maxLatency) throws DbException { Collection ids; List messages = new ArrayList(); lock.writeLock().lock(); @@ -478,7 +478,7 @@ DatabaseCleaner.Callback { } } - public RetentionUpdate generateRetentionUpdate(ContactId c, long maxLatency) + public RetentionUpdate generateRetentionUpdate(ContactId c, int maxLatency) throws DbException { lock.writeLock().lock(); try { @@ -519,7 +519,7 @@ DatabaseCleaner.Callback { } public SubscriptionUpdate generateSubscriptionUpdate(ContactId c, - long maxLatency) throws DbException { + int maxLatency) throws DbException { lock.writeLock().lock(); try { T txn = db.startTransaction(); @@ -560,7 +560,7 @@ DatabaseCleaner.Callback { } public Collection generateTransportUpdates(ContactId c, - long maxLatency) throws DbException { + int maxLatency) throws DbException { lock.writeLock().lock(); try { T txn = db.startTransaction(); @@ -932,12 +932,13 @@ DatabaseCleaner.Callback { } } - public Map getTransportLatencies() throws DbException { + public Map getTransportLatencies() + throws DbException { lock.readLock().lock(); try { T txn = db.startTransaction(); try { - Map latencies = + Map latencies = db.getTransportLatencies(txn); db.commitTransaction(txn); return latencies; diff --git a/briar-core/src/org/briarproject/db/ExponentialBackoff.java b/briar-core/src/org/briarproject/db/ExponentialBackoff.java index 15444d11c..5248e8e50 100644 --- a/briar-core/src/org/briarproject/db/ExponentialBackoff.java +++ b/briar-core/src/org/briarproject/db/ExponentialBackoff.java @@ -11,13 +11,12 @@ class ExponentialBackoff { * transmissions increases exponentially. If the expiry time would * be greater than Long.MAX_VALUE, Long.MAX_VALUE is returned. */ - static long calculateExpiry(long now, long maxLatency, int txCount) { + static long calculateExpiry(long now, int maxLatency, int txCount) { if(now < 0) throw new IllegalArgumentException(); if(maxLatency <= 0) throw new IllegalArgumentException(); if(txCount < 0) throw new IllegalArgumentException(); // The maximum round-trip time is twice the maximum latency - long roundTrip = maxLatency * 2; - if(roundTrip < 0) return Long.MAX_VALUE; + long roundTrip = maxLatency * 2L; // The interval between transmissions is roundTrip * 2 ^ txCount for(int i = 0; i < txCount; i++) { roundTrip <<= 1; diff --git a/briar-core/src/org/briarproject/db/JdbcDatabase.java b/briar-core/src/org/briarproject/db/JdbcDatabase.java index fdeab4e54..d131b4a1d 100644 --- a/briar-core/src/org/briarproject/db/JdbcDatabase.java +++ b/briar-core/src/org/briarproject/db/JdbcDatabase.java @@ -62,8 +62,8 @@ import org.briarproject.api.transport.TemporarySecret; */ abstract class JdbcDatabase implements Database { - private static final int SCHEMA_VERSION = 6; - private static final int MIN_SCHEMA_VERSION = 5; + private static final int SCHEMA_VERSION = 7; + private static final int MIN_SCHEMA_VERSION = 7; private static final String CREATE_SETTINGS = "CREATE TABLE settings" @@ -213,7 +213,7 @@ abstract class JdbcDatabase implements Database { private static final String CREATE_TRANSPORTS = "CREATE TABLE transports" + " (transportId VARCHAR NOT NULL," - + " maxLatency BIGINT NOT NULL," + + " maxLatency INT NOT NULL," + " PRIMARY KEY (transportId))"; private static final String CREATE_TRANSPORT_CONFIGS = @@ -866,7 +866,7 @@ abstract class JdbcDatabase implements Database { } } - public boolean addTransport(Connection txn, TransportId t, long maxLatency) + public boolean addTransport(Connection txn, TransportId t, int maxLatency) throws DbException { PreparedStatement ps = null; ResultSet rs = null; @@ -2024,7 +2024,7 @@ abstract class JdbcDatabase implements Database { } public RetentionUpdate getRetentionUpdate(Connection txn, ContactId c, - long maxLatency) throws DbException { + int maxLatency) throws DbException { long now = clock.currentTimeMillis(); PreparedStatement ps = null; ResultSet rs = null; @@ -2202,7 +2202,7 @@ abstract class JdbcDatabase implements Database { } public SubscriptionUpdate getSubscriptionUpdate(Connection txn, ContactId c, - long maxLatency) throws DbException { + int maxLatency) throws DbException { long now = clock.currentTimeMillis(); PreparedStatement ps = null; ResultSet rs = null; @@ -2296,7 +2296,7 @@ abstract class JdbcDatabase implements Database { } } - public Map getTransportLatencies(Connection txn) + public Map getTransportLatencies(Connection txn) throws DbException { PreparedStatement ps = null; ResultSet rs = null; @@ -2304,10 +2304,11 @@ abstract class JdbcDatabase implements Database { String sql = "SELECT transportId, maxLatency FROM transports"; ps = txn.prepareStatement(sql); rs = ps.executeQuery(); - Map latencies = new HashMap(); + Map latencies = + new HashMap(); while(rs.next()){ TransportId id = new TransportId(rs.getString(1)); - latencies.put(id, rs.getLong(2)); + latencies.put(id, rs.getInt(2)); } rs.close(); ps.close(); @@ -2320,7 +2321,7 @@ abstract class JdbcDatabase implements Database { } public Collection getTransportUpdates(Connection txn, - ContactId c, long maxLatency) throws DbException { + ContactId c, int maxLatency) throws DbException { long now = clock.currentTimeMillis(); PreparedStatement ps = null; ResultSet rs = null; @@ -3301,7 +3302,7 @@ abstract class JdbcDatabase implements Database { } public void updateExpiryTime(Connection txn, ContactId c, MessageId m, - long maxLatency) throws DbException { + int maxLatency) throws DbException { PreparedStatement ps = null; ResultSet rs = null; try { diff --git a/briar-core/src/org/briarproject/invitation/Connector.java b/briar-core/src/org/briarproject/invitation/Connector.java index 9c0144620..1fa004012 100644 --- a/briar-core/src/org/briarproject/invitation/Connector.java +++ b/briar-core/src/org/briarproject/invitation/Connector.java @@ -285,7 +285,7 @@ abstract class Connector extends Thread { db.setRemoteProperties(contactId, remoteProps); // Create an endpoint for each transport shared with the contact List ids = new ArrayList(); - Map latencies = db.getTransportLatencies(); + Map latencies = db.getTransportLatencies(); for(TransportId id : localProps.keySet()) { if(latencies.containsKey(id) && remoteProps.containsKey(id)) ids.add(id); @@ -296,7 +296,7 @@ abstract class Connector extends Thread { for(int i = 0; i < size; i++) { TransportId id = ids.get(i); Endpoint ep = new Endpoint(contactId, id, epoch, alice); - long maxLatency = latencies.get(id); + int maxLatency = latencies.get(id); try { db.addEndpoint(ep); } catch(NoSuchTransportException e) { diff --git a/briar-core/src/org/briarproject/messaging/DuplexOutgoingSession.java b/briar-core/src/org/briarproject/messaging/DuplexOutgoingSession.java index 13e839554..23177097f 100644 --- a/briar-core/src/org/briarproject/messaging/DuplexOutgoingSession.java +++ b/briar-core/src/org/briarproject/messaging/DuplexOutgoingSession.java @@ -6,7 +6,6 @@ import static java.util.logging.Level.WARNING; import static org.briarproject.api.messaging.MessagingConstants.MAX_PACKET_LENGTH; import java.io.IOException; -import java.io.OutputStream; import java.util.Collection; import java.util.concurrent.BlockingQueue; import java.util.concurrent.Executor; @@ -37,7 +36,6 @@ import org.briarproject.api.messaging.Ack; import org.briarproject.api.messaging.MessagingSession; import org.briarproject.api.messaging.Offer; import org.briarproject.api.messaging.PacketWriter; -import org.briarproject.api.messaging.PacketWriterFactory; import org.briarproject.api.messaging.Request; import org.briarproject.api.messaging.RetentionAck; import org.briarproject.api.messaging.RetentionUpdate; @@ -45,16 +43,18 @@ import org.briarproject.api.messaging.SubscriptionAck; import org.briarproject.api.messaging.SubscriptionUpdate; import org.briarproject.api.messaging.TransportAck; import org.briarproject.api.messaging.TransportUpdate; +import org.briarproject.api.system.Clock; /** * An outgoing {@link org.briarproject.api.messaging.MessagingSession * MessagingSession} suitable for duplex transports. The session offers * messages before sending them, keeps its output stream open when there are no - * more packets to send, and reacts to events that make packets available to - * send. + * packets to send, and reacts to events that make packets available to send. */ class DuplexOutgoingSession implements MessagingSession, EventListener { + // Check for retransmittable packets once every 60 seconds + private static final int RETX_QUERY_INTERVAL = 60 * 1000; private static final Logger LOG = Logger.getLogger(DuplexOutgoingSession.class.getName()); @@ -66,28 +66,32 @@ class DuplexOutgoingSession implements MessagingSession, EventListener { private final DatabaseComponent db; private final Executor dbExecutor; private final EventBus eventBus; + private final Clock clock; private final ContactId contactId; private final TransportId transportId; - private final long maxLatency, maxIdleTime; - private final OutputStream out; + private final int maxLatency, maxIdleTime; private final PacketWriter packetWriter; private final BlockingQueue> writerTasks; + // The following must only be accessed on the writer thread + private long nextKeepalive = 0, nextRetxQuery = 0; + private boolean dataToFlush = true; + private volatile boolean interrupted = false; DuplexOutgoingSession(DatabaseComponent db, Executor dbExecutor, - EventBus eventBus, PacketWriterFactory packetWriterFactory, - ContactId contactId, TransportId transportId, long maxLatency, - long maxIdleTime, OutputStream out) { + EventBus eventBus, Clock clock, ContactId contactId, + TransportId transportId, int maxLatency, int maxIdleTime, + PacketWriter packetWriter) { this.db = db; this.dbExecutor = dbExecutor; this.eventBus = eventBus; + this.clock = clock; this.contactId = contactId; this.transportId = transportId; this.maxLatency = maxLatency; this.maxIdleTime = maxIdleTime; - this.out = out; - packetWriter = packetWriterFactory.createPacketWriter(out); + this.packetWriter = packetWriter; writerTasks = new LinkedBlockingQueue>(); } @@ -105,21 +109,50 @@ class DuplexOutgoingSession implements MessagingSession, EventListener { dbExecutor.execute(new GenerateBatch()); dbExecutor.execute(new GenerateOffer()); dbExecutor.execute(new GenerateRequest()); + long now = clock.currentTimeMillis(); + nextKeepalive = now + maxIdleTime; + nextRetxQuery = now + RETX_QUERY_INTERVAL; // Write packets until interrupted try { while(!interrupted) { - // Flush the stream if it's going to be idle - if(writerTasks.isEmpty()) out.flush(); - ThrowingRunnable task = - writerTasks.poll(maxIdleTime, MILLISECONDS); - if(task == null) { - LOG.info("Idle timeout"); - continue; // Flush and wait again + // Work out how long we should wait for a packet + now = clock.currentTimeMillis(); + long wait = Math.min(nextKeepalive, nextRetxQuery) - now; + if(wait < 0) wait = 0; + // Flush any unflushed data if we're going to wait + if(wait > 0 && dataToFlush && writerTasks.isEmpty()) { + packetWriter.flush(); + dataToFlush = false; + nextKeepalive = now + maxIdleTime; + } + // Wait for a packet + ThrowingRunnable task = writerTasks.poll(wait, + MILLISECONDS); + if(task == null) { + now = clock.currentTimeMillis(); + if(now >= nextRetxQuery) { + // Check for retransmittable packets + dbExecutor.execute(new GenerateTransportUpdates()); + dbExecutor.execute(new GenerateSubscriptionUpdate()); + dbExecutor.execute(new GenerateRetentionUpdate()); + dbExecutor.execute(new GenerateBatch()); + dbExecutor.execute(new GenerateOffer()); + nextRetxQuery = now + RETX_QUERY_INTERVAL; + } + if(now >= nextKeepalive) { + // Flush the stream to keep it alive + packetWriter.flush(); + dataToFlush = false; + nextKeepalive = now + maxIdleTime; + } + } else if(task == CLOSE) { + break; + } else { + task.run(); + dataToFlush = true; } - if(task == CLOSE) break; - task.run(); } - out.flush(); + if(dataToFlush) packetWriter.flush(); } catch(InterruptedException e) { LOG.info("Interrupted while waiting for a packet to write"); Thread.currentThread().interrupt(); diff --git a/briar-core/src/org/briarproject/messaging/IncomingSession.java b/briar-core/src/org/briarproject/messaging/IncomingSession.java index b85ccda0d..1bd8acd66 100644 --- a/briar-core/src/org/briarproject/messaging/IncomingSession.java +++ b/briar-core/src/org/briarproject/messaging/IncomingSession.java @@ -3,7 +3,6 @@ package org.briarproject.messaging; import static java.util.logging.Level.WARNING; import java.io.IOException; -import java.io.InputStream; import java.security.GeneralSecurityException; import java.util.concurrent.Executor; import java.util.logging.Logger; @@ -25,7 +24,6 @@ import org.briarproject.api.messaging.MessageVerifier; import org.briarproject.api.messaging.MessagingSession; import org.briarproject.api.messaging.Offer; import org.briarproject.api.messaging.PacketReader; -import org.briarproject.api.messaging.PacketReaderFactory; import org.briarproject.api.messaging.Request; import org.briarproject.api.messaging.RetentionAck; import org.briarproject.api.messaging.RetentionUpdate; @@ -56,9 +54,8 @@ class IncomingSession implements MessagingSession, EventListener { IncomingSession(DatabaseComponent db, Executor dbExecutor, Executor cryptoExecutor, EventBus eventBus, - MessageVerifier messageVerifier, - PacketReaderFactory packetReaderFactory, ContactId contactId, - TransportId transportId, InputStream in) { + MessageVerifier messageVerifier, ContactId contactId, + TransportId transportId, PacketReader packetReader) { this.db = db; this.dbExecutor = dbExecutor; this.cryptoExecutor = cryptoExecutor; @@ -66,7 +63,7 @@ class IncomingSession implements MessagingSession, EventListener { this.messageVerifier = messageVerifier; this.contactId = contactId; this.transportId = transportId; - packetReader = packetReaderFactory.createPacketReader(in); + this.packetReader = packetReader; } public void run() throws IOException { diff --git a/briar-core/src/org/briarproject/messaging/MessagingSessionFactoryImpl.java b/briar-core/src/org/briarproject/messaging/MessagingSessionFactoryImpl.java index 9ab638aa0..c7a31f609 100644 --- a/briar-core/src/org/briarproject/messaging/MessagingSessionFactoryImpl.java +++ b/briar-core/src/org/briarproject/messaging/MessagingSessionFactoryImpl.java @@ -15,8 +15,11 @@ import org.briarproject.api.event.EventBus; import org.briarproject.api.messaging.MessageVerifier; import org.briarproject.api.messaging.MessagingSession; import org.briarproject.api.messaging.MessagingSessionFactory; +import org.briarproject.api.messaging.PacketReader; import org.briarproject.api.messaging.PacketReaderFactory; +import org.briarproject.api.messaging.PacketWriter; import org.briarproject.api.messaging.PacketWriterFactory; +import org.briarproject.api.system.Clock; class MessagingSessionFactoryImpl implements MessagingSessionFactory { @@ -24,6 +27,7 @@ class MessagingSessionFactoryImpl implements MessagingSessionFactory { private final Executor dbExecutor, cryptoExecutor; private final MessageVerifier messageVerifier; private final EventBus eventBus; + private final Clock clock; private final PacketReaderFactory packetReaderFactory; private final PacketWriterFactory packetWriterFactory; @@ -31,7 +35,7 @@ class MessagingSessionFactoryImpl implements MessagingSessionFactory { MessagingSessionFactoryImpl(DatabaseComponent db, @DatabaseExecutor Executor dbExecutor, @CryptoExecutor Executor cryptoExecutor, - MessageVerifier messageVerifier, EventBus eventBus, + MessageVerifier messageVerifier, EventBus eventBus, Clock clock, PacketReaderFactory packetReaderFactory, PacketWriterFactory packetWriterFactory) { this.db = db; @@ -39,26 +43,29 @@ class MessagingSessionFactoryImpl implements MessagingSessionFactory { this.cryptoExecutor = cryptoExecutor; this.messageVerifier = messageVerifier; this.eventBus = eventBus; + this.clock = clock; this.packetReaderFactory = packetReaderFactory; this.packetWriterFactory = packetWriterFactory; } public MessagingSession createIncomingSession(ContactId c, TransportId t, InputStream in) { + PacketReader packetReader = packetReaderFactory.createPacketReader(in); return new IncomingSession(db, dbExecutor, cryptoExecutor, eventBus, - messageVerifier, packetReaderFactory, c, t, in); + messageVerifier, c, t, packetReader); } public MessagingSession createSimplexOutgoingSession(ContactId c, - TransportId t, long maxLatency, OutputStream out) { - return new SimplexOutgoingSession(db, dbExecutor, eventBus, - packetWriterFactory, c, t, maxLatency, out); + TransportId t, int maxLatency, OutputStream out) { + PacketWriter packetWriter = packetWriterFactory.createPacketWriter(out); + return new SimplexOutgoingSession(db, dbExecutor, eventBus, c, t, + maxLatency, packetWriter); } public MessagingSession createDuplexOutgoingSession(ContactId c, - TransportId t, long maxLatency, long maxIdleTime, - OutputStream out) { - return new DuplexOutgoingSession(db, dbExecutor, eventBus, - packetWriterFactory, c, t, maxLatency, maxIdleTime, out); + TransportId t, int maxLatency, int maxIdleTime, OutputStream out) { + PacketWriter packetWriter = packetWriterFactory.createPacketWriter(out); + return new DuplexOutgoingSession(db, dbExecutor, eventBus, clock, c, t, + maxLatency, maxIdleTime, packetWriter); } } diff --git a/briar-core/src/org/briarproject/messaging/PacketWriterImpl.java b/briar-core/src/org/briarproject/messaging/PacketWriterImpl.java index 4b0efd4a7..1ef8e348c 100644 --- a/briar-core/src/org/briarproject/messaging/PacketWriterImpl.java +++ b/briar-core/src/org/briarproject/messaging/PacketWriterImpl.java @@ -143,4 +143,8 @@ class PacketWriterImpl implements PacketWriter { w.writeInteger(u.getVersion()); w.writeStructEnd(); } + + public void flush() throws IOException { + out.flush(); + } } diff --git a/briar-core/src/org/briarproject/messaging/SimplexOutgoingSession.java b/briar-core/src/org/briarproject/messaging/SimplexOutgoingSession.java index 51ec4d81a..6d8dfabf1 100644 --- a/briar-core/src/org/briarproject/messaging/SimplexOutgoingSession.java +++ b/briar-core/src/org/briarproject/messaging/SimplexOutgoingSession.java @@ -5,7 +5,6 @@ import static java.util.logging.Level.WARNING; import static org.briarproject.api.messaging.MessagingConstants.MAX_PACKET_LENGTH; import java.io.IOException; -import java.io.OutputStream; import java.util.Collection; import java.util.concurrent.BlockingQueue; import java.util.concurrent.Executor; @@ -26,7 +25,6 @@ import org.briarproject.api.event.TransportRemovedEvent; import org.briarproject.api.messaging.Ack; import org.briarproject.api.messaging.MessagingSession; import org.briarproject.api.messaging.PacketWriter; -import org.briarproject.api.messaging.PacketWriterFactory; import org.briarproject.api.messaging.RetentionAck; import org.briarproject.api.messaging.RetentionUpdate; import org.briarproject.api.messaging.SubscriptionAck; @@ -55,8 +53,7 @@ class SimplexOutgoingSession implements MessagingSession, EventListener { private final EventBus eventBus; private final ContactId contactId; private final TransportId transportId; - private final long maxLatency; - private final OutputStream out; + private final int maxLatency; private final PacketWriter packetWriter; private final AtomicInteger outstandingQueries; private final BlockingQueue> writerTasks; @@ -64,17 +61,15 @@ class SimplexOutgoingSession implements MessagingSession, EventListener { private volatile boolean interrupted = false; SimplexOutgoingSession(DatabaseComponent db, Executor dbExecutor, - EventBus eventBus, PacketWriterFactory packetWriterFactory, - ContactId contactId, TransportId transportId, long maxLatency, - OutputStream out) { + EventBus eventBus, ContactId contactId, TransportId transportId, + int maxLatency, PacketWriter packetWriter) { this.db = db; this.dbExecutor = dbExecutor; this.eventBus = eventBus; this.contactId = contactId; this.transportId = transportId; this.maxLatency = maxLatency; - this.out = out; - packetWriter = packetWriterFactory.createPacketWriter(out); + this.packetWriter = packetWriter; outstandingQueries = new AtomicInteger(8); // One per type of packet writerTasks = new LinkedBlockingQueue>(); } @@ -98,7 +93,7 @@ class SimplexOutgoingSession implements MessagingSession, EventListener { if(task == CLOSE) break; task.run(); } - out.flush(); + packetWriter.flush(); } catch(InterruptedException e) { LOG.info("Interrupted while waiting for a packet to write"); Thread.currentThread().interrupt(); diff --git a/briar-core/src/org/briarproject/plugins/file/FilePlugin.java b/briar-core/src/org/briarproject/plugins/file/FilePlugin.java index 9c298b023..a187760aa 100644 --- a/briar-core/src/org/briarproject/plugins/file/FilePlugin.java +++ b/briar-core/src/org/briarproject/plugins/file/FilePlugin.java @@ -28,8 +28,7 @@ public abstract class FilePlugin implements SimplexPlugin { protected final Executor ioExecutor; protected final FileUtils fileUtils; protected final SimplexPluginCallback callback; - protected final int maxFrameLength; - protected final long maxLatency; + protected final int maxFrameLength, maxLatency; protected volatile boolean running = false; @@ -40,7 +39,7 @@ public abstract class FilePlugin implements SimplexPlugin { protected FilePlugin(Executor ioExecutor, FileUtils fileUtils, SimplexPluginCallback callback, int maxFrameLength, - long maxLatency) { + int maxLatency) { this.ioExecutor = ioExecutor; this.fileUtils = fileUtils; this.callback = callback; @@ -52,12 +51,12 @@ public abstract class FilePlugin implements SimplexPlugin { return maxFrameLength; } - public long getMaxLatency() { + public int getMaxLatency() { return maxLatency; } - public long getMaxIdleTime() { - return Long.MAX_VALUE; // We don't need keepalives + public int getMaxIdleTime() { + return Integer.MAX_VALUE; // We don't need keepalives } public boolean isRunning() { diff --git a/briar-core/src/org/briarproject/plugins/file/FileTransportWriter.java b/briar-core/src/org/briarproject/plugins/file/FileTransportWriter.java index ecba989ff..c2ffcde08 100644 --- a/briar-core/src/org/briarproject/plugins/file/FileTransportWriter.java +++ b/briar-core/src/org/briarproject/plugins/file/FileTransportWriter.java @@ -31,11 +31,11 @@ class FileTransportWriter implements TransportConnectionWriter { return plugin.getMaxFrameLength(); } - public long getMaxLatency() { + public int getMaxLatency() { return plugin.getMaxLatency(); } - public long getMaxIdleTime() { + public int getMaxIdleTime() { return plugin.getMaxIdleTime(); } diff --git a/briar-core/src/org/briarproject/plugins/tcp/LanTcpPlugin.java b/briar-core/src/org/briarproject/plugins/tcp/LanTcpPlugin.java index d585fa83e..6f15c6fe8 100644 --- a/briar-core/src/org/briarproject/plugins/tcp/LanTcpPlugin.java +++ b/briar-core/src/org/briarproject/plugins/tcp/LanTcpPlugin.java @@ -17,8 +17,8 @@ class LanTcpPlugin extends TcpPlugin { static final TransportId ID = new TransportId("lan"); LanTcpPlugin(Executor ioExecutor, DuplexPluginCallback callback, - int maxFrameLength, long maxLatency, long maxIdleTime, - long pollingInterval) { + int maxFrameLength, int maxLatency, int maxIdleTime, + int pollingInterval) { super(ioExecutor, callback, maxFrameLength, maxLatency, maxIdleTime, pollingInterval); } diff --git a/briar-core/src/org/briarproject/plugins/tcp/LanTcpPluginFactory.java b/briar-core/src/org/briarproject/plugins/tcp/LanTcpPluginFactory.java index 0d7aef843..8527df941 100644 --- a/briar-core/src/org/briarproject/plugins/tcp/LanTcpPluginFactory.java +++ b/briar-core/src/org/briarproject/plugins/tcp/LanTcpPluginFactory.java @@ -10,9 +10,9 @@ import org.briarproject.api.plugins.duplex.DuplexPluginFactory; public class LanTcpPluginFactory implements DuplexPluginFactory { private static final int MAX_FRAME_LENGTH = 1024; - private static final long MAX_LATENCY = 60 * 1000; // 1 minute - private static final long MAX_IDLE_TIME = 30 * 1000; // 30 seconds - private static final long POLLING_INTERVAL = 60 * 1000; // 1 minute + private static final int MAX_LATENCY = 30 * 1000; // 30 seconds + private static final int MAX_IDLE_TIME = 30 * 1000; // 30 seconds + private static final int POLLING_INTERVAL = 3 * 60 * 1000; // 3 minutes private final Executor ioExecutor; diff --git a/briar-core/src/org/briarproject/plugins/tcp/TcpPlugin.java b/briar-core/src/org/briarproject/plugins/tcp/TcpPlugin.java index d8dd77be6..0a4946b48 100644 --- a/briar-core/src/org/briarproject/plugins/tcp/TcpPlugin.java +++ b/briar-core/src/org/briarproject/plugins/tcp/TcpPlugin.java @@ -37,8 +37,8 @@ abstract class TcpPlugin implements DuplexPlugin { protected final Executor ioExecutor; protected final DuplexPluginCallback callback; - protected final int maxFrameLength, socketTimeout; - protected final long maxLatency, maxIdleTime, pollingInterval; + protected final int maxFrameLength, maxLatency, maxIdleTime; + protected final int pollingInterval, socketTimeout; protected volatile boolean running = false; protected volatile ServerSocket socket = null; @@ -53,28 +53,28 @@ abstract class TcpPlugin implements DuplexPlugin { protected abstract boolean isConnectable(InetSocketAddress remote); protected TcpPlugin(Executor ioExecutor, DuplexPluginCallback callback, - int maxFrameLength, long maxLatency, long maxIdleTime, - long pollingInterval) { + int maxFrameLength, int maxLatency, int maxIdleTime, + int pollingInterval) { this.ioExecutor = ioExecutor; this.callback = callback; this.maxFrameLength = maxFrameLength; this.maxLatency = maxLatency; this.maxIdleTime = maxIdleTime; this.pollingInterval = pollingInterval; - if(2 * maxIdleTime > Integer.MAX_VALUE) + if(maxIdleTime > Integer.MAX_VALUE / 2) socketTimeout = Integer.MAX_VALUE; - else socketTimeout = (int) (2 * maxIdleTime); + else socketTimeout = maxIdleTime * 2; } public int getMaxFrameLength() { return maxFrameLength; } - public long getMaxLatency() { + public int getMaxLatency() { return maxLatency; } - public long getMaxIdleTime() { + public int getMaxIdleTime() { return maxIdleTime; } @@ -171,7 +171,7 @@ abstract class TcpPlugin implements DuplexPlugin { return true; } - public long getPollingInterval() { + public int getPollingInterval() { return pollingInterval; } diff --git a/briar-core/src/org/briarproject/plugins/tcp/TcpTransportConnection.java b/briar-core/src/org/briarproject/plugins/tcp/TcpTransportConnection.java index 2df916265..fff4ee01b 100644 --- a/briar-core/src/org/briarproject/plugins/tcp/TcpTransportConnection.java +++ b/briar-core/src/org/briarproject/plugins/tcp/TcpTransportConnection.java @@ -63,11 +63,11 @@ class TcpTransportConnection implements DuplexTransportConnection { return plugin.getMaxFrameLength(); } - public long getMaxLatency() { + public int getMaxLatency() { return plugin.getMaxLatency(); } - public long getMaxIdleTime() { + public int getMaxIdleTime() { return plugin.getMaxIdleTime(); } diff --git a/briar-core/src/org/briarproject/plugins/tcp/WanTcpPlugin.java b/briar-core/src/org/briarproject/plugins/tcp/WanTcpPlugin.java index 8bc290c93..67be0c721 100644 --- a/briar-core/src/org/briarproject/plugins/tcp/WanTcpPlugin.java +++ b/briar-core/src/org/briarproject/plugins/tcp/WanTcpPlugin.java @@ -20,9 +20,9 @@ class WanTcpPlugin extends TcpPlugin { private volatile MappingResult mappingResult; - WanTcpPlugin(Executor ioExecutor, DuplexPluginCallback callback, - int maxFrameLength, long maxLatency, long maxIdleTime, - long pollingInterval, PortMapper portMapper) { + WanTcpPlugin(Executor ioExecutor, PortMapper portMapper, + DuplexPluginCallback callback, int maxFrameLength, int maxLatency, + int maxIdleTime, int pollingInterval) { super(ioExecutor, callback, maxFrameLength, maxLatency, maxIdleTime, pollingInterval); this.portMapper = portMapper; diff --git a/briar-core/src/org/briarproject/plugins/tcp/WanTcpPluginFactory.java b/briar-core/src/org/briarproject/plugins/tcp/WanTcpPluginFactory.java index c7381b125..8129661ff 100644 --- a/briar-core/src/org/briarproject/plugins/tcp/WanTcpPluginFactory.java +++ b/briar-core/src/org/briarproject/plugins/tcp/WanTcpPluginFactory.java @@ -11,9 +11,9 @@ import org.briarproject.api.plugins.duplex.DuplexPluginFactory; public class WanTcpPluginFactory implements DuplexPluginFactory { private static final int MAX_FRAME_LENGTH = 1024; - private static final long MAX_LATENCY = 60 * 1000; // 1 minute - private static final long MAX_IDLE_TIME = 30 * 1000; // 30 seconds - private static final long POLLING_INTERVAL = 5 * 60 * 1000; // 5 minutes + private static final int MAX_LATENCY = 30 * 1000; // 30 seconds + private static final int MAX_IDLE_TIME = 30 * 1000; // 30 seconds + private static final int POLLING_INTERVAL = 5 * 60 * 1000; // 5 minutes private final Executor ioExecutor; private final ShutdownManager shutdownManager; @@ -29,8 +29,8 @@ public class WanTcpPluginFactory implements DuplexPluginFactory { } public DuplexPlugin createPlugin(DuplexPluginCallback callback) { - return new WanTcpPlugin(ioExecutor, callback, MAX_FRAME_LENGTH, - MAX_LATENCY, MAX_IDLE_TIME, POLLING_INTERVAL, - new PortMapperImpl(shutdownManager)); + return new WanTcpPlugin(ioExecutor, new PortMapperImpl(shutdownManager), + callback, MAX_FRAME_LENGTH, MAX_LATENCY, MAX_IDLE_TIME, + POLLING_INTERVAL); } } diff --git a/briar-core/src/org/briarproject/transport/KeyManagerImpl.java b/briar-core/src/org/briarproject/transport/KeyManagerImpl.java index 16db0b216..735e9f17b 100644 --- a/briar-core/src/org/briarproject/transport/KeyManagerImpl.java +++ b/briar-core/src/org/briarproject/transport/KeyManagerImpl.java @@ -51,7 +51,7 @@ class KeyManagerImpl extends TimerTask implements KeyManager, EventListener { private final Timer timer; // All of the following are locking: this - private final Map maxLatencies; + private final Map maxLatencies; private final Map oldSecrets; private final Map currentSecrets; private final Map newSecrets; @@ -66,7 +66,7 @@ class KeyManagerImpl extends TimerTask implements KeyManager, EventListener { this.tagRecogniser = tagRecogniser; this.clock = clock; this.timer = timer; - maxLatencies = new HashMap(); + maxLatencies = new HashMap(); oldSecrets = new HashMap(); currentSecrets = new HashMap(); newSecrets = new HashMap(); @@ -116,7 +116,7 @@ class KeyManagerImpl extends TimerTask implements KeyManager, EventListener { Collection dead = new ArrayList(); for(TemporarySecret s : secrets) { // Discard the secret if the transport has been removed - Long maxLatency = maxLatencies.get(s.getTransportId()); + Integer maxLatency = maxLatencies.get(s.getTransportId()); if(maxLatency == null) { LOG.info("Discarding obsolete secret"); ByteUtils.erase(s.getSecret()); @@ -168,7 +168,7 @@ class KeyManagerImpl extends TimerTask implements KeyManager, EventListener { Collection created = new ArrayList(); for(Entry e : newest.entrySet()) { TemporarySecret s = e.getValue(); - Long maxLatency = maxLatencies.get(s.getTransportId()); + Integer maxLatency = maxLatencies.get(s.getTransportId()); if(maxLatency == null) throw new IllegalStateException(); // Work out which rotation period we're in long elapsed = now - s.getEpoch(); @@ -255,7 +255,7 @@ class KeyManagerImpl extends TimerTask implements KeyManager, EventListener { return new StreamContext(c, t, secret, streamNumber, s.getAlice()); } - public synchronized void endpointAdded(Endpoint ep, long maxLatency, + public synchronized void endpointAdded(Endpoint ep, int maxLatency, byte[] initialSecret) { maxLatencies.put(ep.getTransportId(), maxLatency); // Work out which rotation period we're in diff --git a/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothPlugin.java b/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothPlugin.java index 4a90f76ba..be87193ed 100644 --- a/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothPlugin.java +++ b/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothPlugin.java @@ -46,8 +46,7 @@ class BluetoothPlugin implements DuplexPlugin { private final Clock clock; private final SecureRandom secureRandom; private final DuplexPluginCallback callback; - private final int maxFrameLength; - private final long maxLatency, pollingInterval; + private final int maxFrameLength, maxLatency, pollingInterval; private final Semaphore discoverySemaphore = new Semaphore(1); private volatile boolean running = false; @@ -55,8 +54,8 @@ class BluetoothPlugin implements DuplexPlugin { private volatile LocalDevice localDevice = null; BluetoothPlugin(Executor ioExecutor, Clock clock, SecureRandom secureRandom, - DuplexPluginCallback callback, int maxFrameLength, long maxLatency, - long pollingInterval) { + DuplexPluginCallback callback, int maxFrameLength, int maxLatency, + int pollingInterval) { this.ioExecutor = ioExecutor; this.clock = clock; this.secureRandom = secureRandom; @@ -74,13 +73,13 @@ class BluetoothPlugin implements DuplexPlugin { return maxFrameLength; } - public long getMaxLatency() { + public int getMaxLatency() { return maxLatency; } - public long getMaxIdleTime() { + public int getMaxIdleTime() { // Bluetooth detects dead connections so we don't need keepalives - return Long.MAX_VALUE; + return Integer.MAX_VALUE; } public boolean start() throws IOException { @@ -186,7 +185,7 @@ class BluetoothPlugin implements DuplexPlugin { return true; } - public long getPollingInterval() { + public int getPollingInterval() { return pollingInterval; } diff --git a/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothPluginFactory.java b/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothPluginFactory.java index 446846305..a25a73c37 100644 --- a/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothPluginFactory.java +++ b/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothPluginFactory.java @@ -13,8 +13,8 @@ import org.briarproject.system.SystemClock; public class BluetoothPluginFactory implements DuplexPluginFactory { private static final int MAX_FRAME_LENGTH = 1024; - private static final long MAX_LATENCY = 60 * 1000; // 1 minute - private static final long POLLING_INTERVAL = 3 * 60 * 1000; // 3 minutes + private static final int MAX_LATENCY = 30 * 1000; // 30 seconds + private static final int POLLING_INTERVAL = 3 * 60 * 1000; // 3 minutes private final Executor ioExecutor; private final SecureRandom secureRandom; diff --git a/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothTransportConnection.java b/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothTransportConnection.java index 3de6a6a10..0767c42d9 100644 --- a/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothTransportConnection.java +++ b/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothTransportConnection.java @@ -64,11 +64,11 @@ class BluetoothTransportConnection implements DuplexTransportConnection { return plugin.getMaxFrameLength(); } - public long getMaxLatency() { + public int getMaxLatency() { return plugin.getMaxLatency(); } - public long getMaxIdleTime() { + public int getMaxIdleTime() { return plugin.getMaxIdleTime(); } diff --git a/briar-desktop/src/org/briarproject/plugins/file/PollingRemovableDriveMonitor.java b/briar-desktop/src/org/briarproject/plugins/file/PollingRemovableDriveMonitor.java index 2d8fd2876..a25649065 100644 --- a/briar-desktop/src/org/briarproject/plugins/file/PollingRemovableDriveMonitor.java +++ b/briar-desktop/src/org/briarproject/plugins/file/PollingRemovableDriveMonitor.java @@ -13,14 +13,14 @@ class PollingRemovableDriveMonitor implements RemovableDriveMonitor, Runnable { private final Executor ioExecutor; private final RemovableDriveFinder finder; - private final long pollingInterval; + private final int pollingInterval; private final Object pollingLock = new Object(); private volatile boolean running = false; private volatile Callback callback = null; public PollingRemovableDriveMonitor(Executor ioExecutor, - RemovableDriveFinder finder, long pollingInterval) { + RemovableDriveFinder finder, int pollingInterval) { this.ioExecutor = ioExecutor; this.finder = finder; this.pollingInterval = pollingInterval; diff --git a/briar-desktop/src/org/briarproject/plugins/file/RemovableDrivePlugin.java b/briar-desktop/src/org/briarproject/plugins/file/RemovableDrivePlugin.java index bdf9d84ef..faaf4b01c 100644 --- a/briar-desktop/src/org/briarproject/plugins/file/RemovableDrivePlugin.java +++ b/briar-desktop/src/org/briarproject/plugins/file/RemovableDrivePlugin.java @@ -29,7 +29,7 @@ implements RemovableDriveMonitor.Callback { RemovableDrivePlugin(Executor ioExecutor, FileUtils fileUtils, SimplexPluginCallback callback, RemovableDriveFinder finder, - RemovableDriveMonitor monitor, int maxFrameLength, long maxLatency) { + RemovableDriveMonitor monitor, int maxFrameLength, int maxLatency) { super(ioExecutor, fileUtils, callback, maxFrameLength, maxLatency); this.finder = finder; this.monitor = monitor; @@ -54,7 +54,7 @@ implements RemovableDriveMonitor.Callback { return false; } - public long getPollingInterval() { + public int getPollingInterval() { throw new UnsupportedOperationException(); } diff --git a/briar-desktop/src/org/briarproject/plugins/file/RemovableDrivePluginFactory.java b/briar-desktop/src/org/briarproject/plugins/file/RemovableDrivePluginFactory.java index 01688d403..4b7d6835f 100644 --- a/briar-desktop/src/org/briarproject/plugins/file/RemovableDrivePluginFactory.java +++ b/briar-desktop/src/org/briarproject/plugins/file/RemovableDrivePluginFactory.java @@ -14,8 +14,8 @@ import org.briarproject.util.OsUtils; public class RemovableDrivePluginFactory implements SimplexPluginFactory { // Maximum latency 14 days (Royal Mail or lackadaisical carrier pigeon) - private static final long MAX_LATENCY = 14 * 24 * 60 * 60 * 1000; - private static final long POLLING_INTERVAL = 10 * 1000; // 10 seconds + private static final int MAX_LATENCY = 14 * 24 * 60 * 60 * 1000; + private static final int POLLING_INTERVAL = 10 * 1000; // 10 seconds private final Executor ioExecutor; private final FileUtils fileUtils; diff --git a/briar-desktop/src/org/briarproject/plugins/modem/ModemPlugin.java b/briar-desktop/src/org/briarproject/plugins/modem/ModemPlugin.java index 983628497..092eeec8b 100644 --- a/briar-desktop/src/org/briarproject/plugins/modem/ModemPlugin.java +++ b/briar-desktop/src/org/briarproject/plugins/modem/ModemPlugin.java @@ -32,21 +32,18 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback { private final ModemFactory modemFactory; private final SerialPortList serialPortList; private final DuplexPluginCallback callback; - private final int maxFrameLength; - private final long maxLatency, pollingInterval; + private final int maxFrameLength, maxLatency; private volatile boolean running = false; private volatile Modem modem = null; ModemPlugin(ModemFactory modemFactory, SerialPortList serialPortList, - DuplexPluginCallback callback, int maxFrameLength, long maxLatency, - long pollingInterval) { + DuplexPluginCallback callback, int maxFrameLength, int maxLatency) { this.modemFactory = modemFactory; this.serialPortList = serialPortList; this.callback = callback; this.maxFrameLength = maxFrameLength; this.maxLatency = maxLatency; - this.pollingInterval = pollingInterval; } public TransportId getId() { @@ -57,13 +54,13 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback { return maxFrameLength; } - public long getMaxLatency() { + public int getMaxLatency() { return maxLatency; } - public long getMaxIdleTime() { + public int getMaxIdleTime() { // FIXME: Do we need keepalives for this transport? - return Long.MAX_VALUE; + return Integer.MAX_VALUE; } public boolean start() { @@ -103,8 +100,8 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback { return false; } - public long getPollingInterval() { - return pollingInterval; + public int getPollingInterval() { + throw new UnsupportedOperationException(); } public void poll(Collection connected) { @@ -226,11 +223,11 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback { return getMaxFrameLength(); } - public long getMaxLatency() { + public int getMaxLatency() { return getMaxLatency(); } - public long getMaxIdleTime() { + public int getMaxIdleTime() { return getMaxIdleTime(); } diff --git a/briar-desktop/src/org/briarproject/plugins/modem/ModemPluginFactory.java b/briar-desktop/src/org/briarproject/plugins/modem/ModemPluginFactory.java index 2732bbbc7..670be76fc 100644 --- a/briar-desktop/src/org/briarproject/plugins/modem/ModemPluginFactory.java +++ b/briar-desktop/src/org/briarproject/plugins/modem/ModemPluginFactory.java @@ -12,8 +12,7 @@ import org.briarproject.util.StringUtils; public class ModemPluginFactory implements DuplexPluginFactory { private static final int MAX_FRAME_LENGTH = 1024; - private static final long MAX_LATENCY = 60 * 1000; // 1 minute - private static final long POLLING_INTERVAL = 60 * 60 * 1000; // 1 hour + private static final int MAX_LATENCY = 30 * 1000; // 30 seconds private final ModemFactory modemFactory; private final SerialPortList serialPortList; @@ -33,6 +32,6 @@ public class ModemPluginFactory implements DuplexPluginFactory { String enabled = callback.getConfig().get("enabled"); if(StringUtils.isNullOrEmpty(enabled)) return null; return new ModemPlugin(modemFactory, serialPortList, callback, - MAX_FRAME_LENGTH, MAX_LATENCY, POLLING_INTERVAL); + MAX_FRAME_LENGTH, MAX_LATENCY); } } diff --git a/briar-tests/src/org/briarproject/db/DatabaseComponentTest.java b/briar-tests/src/org/briarproject/db/DatabaseComponentTest.java index 57855cfb6..338b8c957 100644 --- a/briar-tests/src/org/briarproject/db/DatabaseComponentTest.java +++ b/briar-tests/src/org/briarproject/db/DatabaseComponentTest.java @@ -75,6 +75,7 @@ public abstract class DatabaseComponentTest extends BriarTestCase { protected final Message message, message1; protected final TransportId transportId; protected final TransportProperties transportProperties; + protected final int maxLatency; protected final ContactId contactId; protected final Contact contact; protected final Endpoint endpoint; @@ -102,6 +103,7 @@ public abstract class DatabaseComponentTest extends BriarTestCase { transportId = new TransportId("id"); transportProperties = new TransportProperties(Collections.singletonMap( "bar", "baz")); + maxLatency = Integer.MAX_VALUE; contactId = new ContactId(234); contact = new Contact(contactId, author, localAuthorId); endpoint = new Endpoint(contactId, transportId, 123, true); @@ -691,11 +693,11 @@ public abstract class DatabaseComponentTest extends BriarTestCase { oneOf(database).getRawMessage(txn, messageId); will(returnValue(raw)); oneOf(database).updateExpiryTime(txn, contactId, messageId, - Long.MAX_VALUE); + maxLatency); oneOf(database).getRawMessage(txn, messageId1); will(returnValue(raw1)); oneOf(database).updateExpiryTime(txn, contactId, messageId1, - Long.MAX_VALUE); + maxLatency); oneOf(database).lowerRequestedFlag(txn, contactId, ids); oneOf(database).commitTransaction(txn); }}); @@ -703,7 +705,7 @@ public abstract class DatabaseComponentTest extends BriarTestCase { eventBus, shutdown); assertEquals(messages, db.generateBatch(contactId, size * 2, - Long.MAX_VALUE)); + maxLatency)); context.assertIsSatisfied(); } @@ -726,15 +728,15 @@ public abstract class DatabaseComponentTest extends BriarTestCase { oneOf(database).getMessagesToOffer(txn, contactId, 123); will(returnValue(ids)); oneOf(database).updateExpiryTime(txn, contactId, messageId, - Long.MAX_VALUE); + maxLatency); oneOf(database).updateExpiryTime(txn, contactId, messageId1, - Long.MAX_VALUE); + maxLatency); oneOf(database).commitTransaction(txn); }}); DatabaseComponent db = createDatabaseComponent(database, cleaner, eventBus, shutdown); - Offer o = db.generateOffer(contactId, 123, Long.MAX_VALUE); + Offer o = db.generateOffer(contactId, 123, maxLatency); assertEquals(ids, o.getMessageIds()); context.assertIsSatisfied(); @@ -791,11 +793,11 @@ public abstract class DatabaseComponentTest extends BriarTestCase { oneOf(database).getRawMessage(txn, messageId); will(returnValue(raw)); oneOf(database).updateExpiryTime(txn, contactId, messageId, - Long.MAX_VALUE); + maxLatency); oneOf(database).getRawMessage(txn, messageId1); will(returnValue(raw1)); oneOf(database).updateExpiryTime(txn, contactId, messageId1, - Long.MAX_VALUE); + maxLatency); oneOf(database).lowerRequestedFlag(txn, contactId, ids); oneOf(database).commitTransaction(txn); }}); @@ -803,7 +805,7 @@ public abstract class DatabaseComponentTest extends BriarTestCase { eventBus, shutdown); assertEquals(messages, db.generateRequestedBatch(contactId, size * 2, - Long.MAX_VALUE)); + maxLatency)); context.assertIsSatisfied(); } @@ -821,14 +823,14 @@ public abstract class DatabaseComponentTest extends BriarTestCase { will(returnValue(txn)); oneOf(database).containsContact(txn, contactId); will(returnValue(true)); - oneOf(database).getRetentionUpdate(txn, contactId, Long.MAX_VALUE); + oneOf(database).getRetentionUpdate(txn, contactId, maxLatency); will(returnValue(null)); oneOf(database).commitTransaction(txn); }}); DatabaseComponent db = createDatabaseComponent(database, cleaner, eventBus, shutdown); - assertNull(db.generateRetentionUpdate(contactId, Long.MAX_VALUE)); + assertNull(db.generateRetentionUpdate(contactId, maxLatency)); context.assertIsSatisfied(); } @@ -846,15 +848,14 @@ public abstract class DatabaseComponentTest extends BriarTestCase { will(returnValue(txn)); oneOf(database).containsContact(txn, contactId); will(returnValue(true)); - oneOf(database).getRetentionUpdate(txn, contactId, Long.MAX_VALUE); + oneOf(database).getRetentionUpdate(txn, contactId, maxLatency); will(returnValue(new RetentionUpdate(0, 1))); oneOf(database).commitTransaction(txn); }}); DatabaseComponent db = createDatabaseComponent(database, cleaner, eventBus, shutdown); - RetentionUpdate u = db.generateRetentionUpdate(contactId, - Long.MAX_VALUE); + RetentionUpdate u = db.generateRetentionUpdate(contactId, maxLatency); assertEquals(0, u.getRetentionTime()); assertEquals(1, u.getVersion()); @@ -874,15 +875,14 @@ public abstract class DatabaseComponentTest extends BriarTestCase { will(returnValue(txn)); oneOf(database).containsContact(txn, contactId); will(returnValue(true)); - oneOf(database).getSubscriptionUpdate(txn, contactId, - Long.MAX_VALUE); + oneOf(database).getSubscriptionUpdate(txn, contactId, maxLatency); will(returnValue(null)); oneOf(database).commitTransaction(txn); }}); DatabaseComponent db = createDatabaseComponent(database, cleaner, eventBus, shutdown); - assertNull(db.generateSubscriptionUpdate(contactId, Long.MAX_VALUE)); + assertNull(db.generateSubscriptionUpdate(contactId, maxLatency)); context.assertIsSatisfied(); } @@ -900,8 +900,7 @@ public abstract class DatabaseComponentTest extends BriarTestCase { will(returnValue(txn)); oneOf(database).containsContact(txn, contactId); will(returnValue(true)); - oneOf(database).getSubscriptionUpdate(txn, contactId, - Long.MAX_VALUE); + oneOf(database).getSubscriptionUpdate(txn, contactId, maxLatency); will(returnValue(new SubscriptionUpdate(Arrays.asList(group), 1))); oneOf(database).commitTransaction(txn); }}); @@ -909,7 +908,7 @@ public abstract class DatabaseComponentTest extends BriarTestCase { eventBus, shutdown); SubscriptionUpdate u = db.generateSubscriptionUpdate(contactId, - Long.MAX_VALUE); + maxLatency); assertEquals(Arrays.asList(group), u.getGroups()); assertEquals(1, u.getVersion()); @@ -929,14 +928,14 @@ public abstract class DatabaseComponentTest extends BriarTestCase { will(returnValue(txn)); oneOf(database).containsContact(txn, contactId); will(returnValue(true)); - oneOf(database).getTransportUpdates(txn, contactId, Long.MAX_VALUE); + oneOf(database).getTransportUpdates(txn, contactId, maxLatency); will(returnValue(null)); oneOf(database).commitTransaction(txn); }}); DatabaseComponent db = createDatabaseComponent(database, cleaner, eventBus, shutdown); - assertNull(db.generateTransportUpdates(contactId, Long.MAX_VALUE)); + assertNull(db.generateTransportUpdates(contactId, maxLatency)); context.assertIsSatisfied(); } @@ -954,7 +953,7 @@ public abstract class DatabaseComponentTest extends BriarTestCase { will(returnValue(txn)); oneOf(database).containsContact(txn, contactId); will(returnValue(true)); - oneOf(database).getTransportUpdates(txn, contactId, Long.MAX_VALUE); + oneOf(database).getTransportUpdates(txn, contactId, maxLatency); will(returnValue(Arrays.asList(new TransportUpdate(transportId, transportProperties, 1)))); oneOf(database).commitTransaction(txn); @@ -963,7 +962,7 @@ public abstract class DatabaseComponentTest extends BriarTestCase { eventBus, shutdown); Collection updates = - db.generateTransportUpdates(contactId, Long.MAX_VALUE); + db.generateTransportUpdates(contactId, maxLatency); assertNotNull(updates); assertEquals(1, updates.size()); TransportUpdate u = updates.iterator().next(); diff --git a/briar-tests/src/org/briarproject/db/ExponentialBackoffTest.java b/briar-tests/src/org/briarproject/db/ExponentialBackoffTest.java index 923939e30..f758e8c9e 100644 --- a/briar-tests/src/org/briarproject/db/ExponentialBackoffTest.java +++ b/briar-tests/src/org/briarproject/db/ExponentialBackoffTest.java @@ -32,32 +32,30 @@ public class ExponentialBackoffTest extends BriarTestCase { assertEquals(now, fromNow - fromZero); } - @Test - public void testRoundTripTimeOverflow() { - long maxLatency = Long.MAX_VALUE / 2 + 1; // RTT will overflow - long expiry = ExponentialBackoff.calculateExpiry(0, maxLatency, 0); - assertEquals(Long.MAX_VALUE, expiry); // Overflow caught - } - @Test public void testTransmissionCountOverflow() { - long maxLatency = (Long.MAX_VALUE - 1) / 2; // RTT will not overflow + int maxLatency = Integer.MAX_VALUE; // RTT will not overflow long expiry = ExponentialBackoff.calculateExpiry(0, maxLatency, 0); - assertEquals(Long.MAX_VALUE - 1, expiry); // No overflow - expiry = ExponentialBackoff.calculateExpiry(0, maxLatency, 1); + assertEquals(Integer.MAX_VALUE * 2L, expiry); // No overflow + expiry = ExponentialBackoff.calculateExpiry(0, maxLatency, 31); + assertEquals(Integer.MAX_VALUE * (2L << 31), expiry); // No overflow + expiry = ExponentialBackoff.calculateExpiry(0, maxLatency, 32); assertEquals(Long.MAX_VALUE, expiry); // Overflow caught - expiry = ExponentialBackoff.calculateExpiry(0, maxLatency, 2); + expiry = ExponentialBackoff.calculateExpiry(0, maxLatency, 33); assertEquals(Long.MAX_VALUE, expiry); // Overflow caught } @Test public void testCurrentTimeOverflow() { - long maxLatency = (Long.MAX_VALUE - 1) / 2; // RTT will not overflow - long expiry = ExponentialBackoff.calculateExpiry(0, maxLatency, 0); + int maxLatency = Integer.MAX_VALUE; // RTT will not overflow + long now = Long.MAX_VALUE - (Integer.MAX_VALUE * (2L << 31)); + long expiry = ExponentialBackoff.calculateExpiry(now, maxLatency, 0); + assertEquals(now + Integer.MAX_VALUE * 2L, expiry); // No overflow + expiry = ExponentialBackoff.calculateExpiry(now - 1, maxLatency, 31); assertEquals(Long.MAX_VALUE - 1, expiry); // No overflow - expiry = ExponentialBackoff.calculateExpiry(1, maxLatency, 0); + expiry = ExponentialBackoff.calculateExpiry(now, maxLatency, 31); assertEquals(Long.MAX_VALUE, expiry); // No overflow - expiry = ExponentialBackoff.calculateExpiry(2, maxLatency, 0); + expiry = ExponentialBackoff.calculateExpiry(now + 1, maxLatency, 32); assertEquals(Long.MAX_VALUE, expiry); // Overflow caught } } diff --git a/briar-tests/src/org/briarproject/db/H2DatabaseTest.java b/briar-tests/src/org/briarproject/db/H2DatabaseTest.java index 3ecaf692a..b567c2778 100644 --- a/briar-tests/src/org/briarproject/db/H2DatabaseTest.java +++ b/briar-tests/src/org/briarproject/db/H2DatabaseTest.java @@ -381,7 +381,7 @@ public class H2DatabaseTest extends BriarTestCase { assertTrue(it.hasNext()); assertEquals(messageId, it.next()); assertFalse(it.hasNext()); - db.updateExpiryTime(txn, contactId, messageId, Long.MAX_VALUE); + db.updateExpiryTime(txn, contactId, messageId, Integer.MAX_VALUE); // The message should no longer be sendable it = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE).iterator(); @@ -1109,7 +1109,8 @@ public class H2DatabaseTest extends BriarTestCase { @Test public void testTemporarySecrets() throws Exception { // Create an endpoint and four consecutive temporary secrets - long epoch = 123, latency = 234; + long epoch = 123; + int latency = 234; boolean alice = false; long outgoing1 = 345, centre1 = 456; long outgoing2 = 567, centre2 = 678; @@ -1235,7 +1236,8 @@ public class H2DatabaseTest extends BriarTestCase { @Test public void testIncrementStreamCounter() throws Exception { // Create an endpoint and a temporary secret - long epoch = 123, latency = 234; + long epoch = 123; + int latency = 234; boolean alice = false; long period = 345, outgoing = 456, centre = 567; Endpoint ep = new Endpoint(contactId, transportId, epoch, alice); @@ -1290,7 +1292,8 @@ public class H2DatabaseTest extends BriarTestCase { @Test public void testSetReorderingWindow() throws Exception { // Create an endpoint and a temporary secret - long epoch = 123, latency = 234; + long epoch = 123; + int latency = 234; boolean alice = false; long period = 345, outgoing = 456, centre = 567; Endpoint ep = new Endpoint(contactId, transportId, epoch, alice); @@ -1359,8 +1362,8 @@ public class H2DatabaseTest extends BriarTestCase { @Test public void testEndpoints() throws Exception { // Create some endpoints - long epoch1 = 123, latency1 = 234; - long epoch2 = 345, latency2 = 456; + long epoch1 = 123, epoch2 = 234; + int latency1 = 345, latency2 = 456; boolean alice1 = true, alice2 = false; TransportId transportId1 = new TransportId("bar"); TransportId transportId2 = new TransportId("baz"); diff --git a/briar-tests/src/org/briarproject/messaging/SimplexMessagingIntegrationTest.java b/briar-tests/src/org/briarproject/messaging/SimplexMessagingIntegrationTest.java index 4d5b25767..7a24f0c94 100644 --- a/briar-tests/src/org/briarproject/messaging/SimplexMessagingIntegrationTest.java +++ b/briar-tests/src/org/briarproject/messaging/SimplexMessagingIntegrationTest.java @@ -2,6 +2,7 @@ package org.briarproject.messaging; import static org.briarproject.api.AuthorConstants.MAX_PUBLIC_KEY_LENGTH; import static org.briarproject.api.messaging.MessagingConstants.GROUP_SALT_LENGTH; +import static org.briarproject.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE; import static org.briarproject.api.transport.TransportConstants.MAX_FRAME_LENGTH; import static org.briarproject.api.transport.TransportConstants.TAG_LENGTH; @@ -32,7 +33,9 @@ import org.briarproject.api.messaging.Message; import org.briarproject.api.messaging.MessageFactory; import org.briarproject.api.messaging.MessageVerifier; import org.briarproject.api.messaging.MessagingSession; +import org.briarproject.api.messaging.PacketReader; import org.briarproject.api.messaging.PacketReaderFactory; +import org.briarproject.api.messaging.PacketWriter; import org.briarproject.api.messaging.PacketWriterFactory; import org.briarproject.api.transport.Endpoint; import org.briarproject.api.transport.StreamContext; @@ -56,8 +59,9 @@ import com.google.inject.Injector; public class SimplexMessagingIntegrationTest extends BriarTestCase { - private static final long CLOCK_DIFFERENCE = 60 * 1000; - private static final long LATENCY = 60 * 1000; + private static final int MAX_LATENCY = 2 * 60 * 1000; // 2 minutes + private static final int ROTATION_PERIOD = + MAX_CLOCK_DIFFERENCE + MAX_LATENCY; private final File testDir = TestUtils.getTestDirectory(); private final File aliceDir = new File(testDir, "alice"); @@ -73,8 +77,7 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase { // Create matching secrets for Alice and Bob initialSecret = new byte[32]; new Random().nextBytes(initialSecret); - long rotationPeriod = 2 * CLOCK_DIFFERENCE + LATENCY; - epoch = System.currentTimeMillis() - 2 * rotationPeriod; + epoch = System.currentTimeMillis() - 2 * ROTATION_PERIOD; } @Override @@ -121,10 +124,10 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase { db.addGroup(group); db.setInboxGroup(contactId, group); // Add the transport and the endpoint - db.addTransport(transportId, LATENCY); + db.addTransport(transportId, MAX_LATENCY); Endpoint ep = new Endpoint(contactId, transportId, epoch, true); db.addEndpoint(ep); - keyManager.endpointAdded(ep, LATENCY, initialSecret.clone()); + keyManager.endpointAdded(ep, MAX_LATENCY, initialSecret.clone()); // Send Bob a message String contentType = "text/plain"; long timestamp = System.currentTimeMillis(); @@ -145,10 +148,11 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase { EventBus eventBus = alice.getInstance(EventBus.class); PacketWriterFactory packetWriterFactory = alice.getInstance(PacketWriterFactory.class); - MessagingSession session = new SimplexOutgoingSession(db, - new ImmediateExecutor(), eventBus, packetWriterFactory, - contactId, transportId, Long.MAX_VALUE, + PacketWriter packetWriter = packetWriterFactory.createPacketWriter( streamWriter.getOutputStream()); + MessagingSession session = new SimplexOutgoingSession(db, + new ImmediateExecutor(), eventBus, contactId, transportId, + MAX_LATENCY, packetWriter); // Write whatever needs to be written session.run(); streamWriter.getOutputStream().close(); @@ -182,10 +186,10 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase { db.addGroup(group); db.setInboxGroup(contactId, group); // Add the transport and the endpoint - db.addTransport(transportId, LATENCY); + db.addTransport(transportId, MAX_LATENCY); Endpoint ep = new Endpoint(contactId, transportId, epoch, false); db.addEndpoint(ep); - keyManager.endpointAdded(ep, LATENCY, initialSecret.clone()); + keyManager.endpointAdded(ep, MAX_LATENCY, initialSecret.clone()); // Set up an event listener MessageListener listener = new MessageListener(); bob.getInstance(EventBus.class).addListener(listener); @@ -208,10 +212,11 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase { bob.getInstance(MessageVerifier.class); PacketReaderFactory packetReaderFactory = bob.getInstance(PacketReaderFactory.class); + PacketReader packetReader = packetReaderFactory.createPacketReader( + streamReader.getInputStream()); MessagingSession session = new IncomingSession(db, new ImmediateExecutor(), new ImmediateExecutor(), eventBus, - messageVerifier, packetReaderFactory, contactId, transportId, - streamReader.getInputStream()); + messageVerifier, contactId, transportId, packetReader); // No messages should have been added yet assertFalse(listener.messageAdded); // Read whatever needs to be read diff --git a/briar-tests/src/org/briarproject/messaging/SimplexOutgoingSessionTest.java b/briar-tests/src/org/briarproject/messaging/SimplexOutgoingSessionTest.java index f9fa68c6f..fa13af510 100644 --- a/briar-tests/src/org/briarproject/messaging/SimplexOutgoingSessionTest.java +++ b/briar-tests/src/org/briarproject/messaging/SimplexOutgoingSessionTest.java @@ -1,72 +1,53 @@ package org.briarproject.messaging; -import java.io.ByteArrayOutputStream; import java.util.Arrays; -import java.util.Random; import java.util.concurrent.Executor; import org.briarproject.BriarTestCase; import org.briarproject.TestUtils; import org.briarproject.api.ContactId; import org.briarproject.api.TransportId; -import org.briarproject.api.UniqueId; import org.briarproject.api.db.DatabaseComponent; import org.briarproject.api.event.EventBus; import org.briarproject.api.messaging.Ack; import org.briarproject.api.messaging.MessageId; -import org.briarproject.api.messaging.PacketWriterFactory; +import org.briarproject.api.messaging.PacketWriter; import org.briarproject.plugins.ImmediateExecutor; -import org.briarproject.serial.SerialModule; import org.jmock.Expectations; import org.jmock.Mockery; import org.junit.Test; -import com.google.inject.AbstractModule; -import com.google.inject.Guice; -import com.google.inject.Injector; -import com.google.inject.Module; - public class SimplexOutgoingSessionTest extends BriarTestCase { - // FIXME: This is an integration test, not a unit test + private static final int MAX_MESSAGES_PER_ACK = 10; private final Mockery context; private final DatabaseComponent db; private final Executor dbExecutor; private final EventBus eventBus; - private final PacketWriterFactory packetWriterFactory; private final ContactId contactId; private final TransportId transportId; private final MessageId messageId; - private final byte[] secret; + private final int maxLatency; + private final PacketWriter packetWriter; public SimplexOutgoingSessionTest() { context = new Mockery(); db = context.mock(DatabaseComponent.class); dbExecutor = new ImmediateExecutor(); - Module testModule = new AbstractModule() { - @Override - public void configure() { - bind(PacketWriterFactory.class).to( - PacketWriterFactoryImpl.class); - } - }; - Injector i = Guice.createInjector(testModule, new SerialModule()); eventBus = context.mock(EventBus.class); - packetWriterFactory = i.getInstance(PacketWriterFactory.class); + packetWriter = context.mock(PacketWriter.class); contactId = new ContactId(234); transportId = new TransportId("id"); messageId = new MessageId(TestUtils.getRandomId()); - secret = new byte[32]; - new Random().nextBytes(secret); + maxLatency = Integer.MAX_VALUE; } @Test public void testNothingToSend() throws Exception { - ByteArrayOutputStream out = new ByteArrayOutputStream(); final SimplexOutgoingSession session = new SimplexOutgoingSession(db, - dbExecutor, eventBus, packetWriterFactory, contactId, - transportId, Long.MAX_VALUE, out); + dbExecutor, eventBus, contactId, transportId, maxLatency, + packetWriter); context.checking(new Expectations() {{ // Add listener oneOf(eventBus).addListener(session); @@ -74,46 +55,45 @@ public class SimplexOutgoingSessionTest extends BriarTestCase { oneOf(db).generateTransportAcks(contactId); will(returnValue(null)); // No transport updates to send - oneOf(db).generateTransportUpdates(with(contactId), - with(any(long.class))); + oneOf(db).generateTransportUpdates(contactId, maxLatency); will(returnValue(null)); // No subscription ack to send oneOf(db).generateSubscriptionAck(contactId); will(returnValue(null)); // No subscription update to send - oneOf(db).generateSubscriptionUpdate(with(contactId), - with(any(long.class))); + oneOf(db).generateSubscriptionUpdate(contactId, maxLatency); will(returnValue(null)); // No retention ack to send oneOf(db).generateRetentionAck(contactId); will(returnValue(null)); // No retention update to send - oneOf(db).generateRetentionUpdate(with(contactId), - with(any(long.class))); + oneOf(db).generateRetentionUpdate(contactId, maxLatency); will(returnValue(null)); // No acks to send - oneOf(db).generateAck(with(contactId), with(any(int.class))); + oneOf(packetWriter).getMaxMessagesForAck(with(any(long.class))); + will(returnValue(MAX_MESSAGES_PER_ACK)); + oneOf(db).generateAck(contactId, MAX_MESSAGES_PER_ACK); will(returnValue(null)); // No messages to send oneOf(db).generateBatch(with(contactId), with(any(int.class)), - with(any(long.class))); + with(maxLatency)); will(returnValue(null)); + // Flush the output stream + oneOf(packetWriter).flush(); // Remove listener oneOf(eventBus).removeListener(session); }}); session.run(); - // Nothing should have been written - assertEquals(0, out.size()); context.assertIsSatisfied(); } @Test public void testSomethingToSend() throws Exception { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - final SimplexOutgoingSession session = new SimplexOutgoingSession(db, - dbExecutor, eventBus, packetWriterFactory, contactId, - transportId, Long.MAX_VALUE, out); + final Ack ack = new Ack(Arrays.asList(messageId)); final byte[] raw = new byte[1234]; + final SimplexOutgoingSession session = new SimplexOutgoingSession(db, + dbExecutor, eventBus, contactId, transportId, maxLatency, + packetWriter); context.checking(new Expectations() {{ // Add listener oneOf(eventBus).addListener(session); @@ -121,43 +101,46 @@ public class SimplexOutgoingSessionTest extends BriarTestCase { oneOf(db).generateTransportAcks(contactId); will(returnValue(null)); // No transport updates to send - oneOf(db).generateTransportUpdates(with(contactId), - with(any(long.class))); + oneOf(db).generateTransportUpdates(contactId, maxLatency); will(returnValue(null)); // No subscription ack to send oneOf(db).generateSubscriptionAck(contactId); will(returnValue(null)); // No subscription update to send - oneOf(db).generateSubscriptionUpdate(with(contactId), - with(any(long.class))); + oneOf(db).generateSubscriptionUpdate(contactId, maxLatency); will(returnValue(null)); // No retention ack to send oneOf(db).generateRetentionAck(contactId); will(returnValue(null)); // No retention update to send - oneOf(db).generateRetentionUpdate(with(contactId), - with(any(long.class))); + oneOf(db).generateRetentionUpdate(contactId, maxLatency); will(returnValue(null)); // One ack to send - oneOf(db).generateAck(with(contactId), with(any(int.class))); - will(returnValue(new Ack(Arrays.asList(messageId)))); + oneOf(packetWriter).getMaxMessagesForAck(with(any(long.class))); + will(returnValue(MAX_MESSAGES_PER_ACK)); + oneOf(db).generateAck(contactId, MAX_MESSAGES_PER_ACK); + will(returnValue(ack)); + oneOf(packetWriter).writeAck(ack); // No more acks - oneOf(db).generateAck(with(contactId), with(any(int.class))); + oneOf(packetWriter).getMaxMessagesForAck(with(any(long.class))); + will(returnValue(MAX_MESSAGES_PER_ACK)); + oneOf(db).generateAck(contactId, MAX_MESSAGES_PER_ACK); will(returnValue(null)); // One message to send oneOf(db).generateBatch(with(contactId), with(any(int.class)), - with(any(long.class))); + with(maxLatency)); will(returnValue(Arrays.asList(raw))); + oneOf(packetWriter).writeMessage(raw); // No more messages oneOf(db).generateBatch(with(contactId), with(any(int.class)), - with(any(long.class))); + with(maxLatency)); will(returnValue(null)); + // Flush the output stream + oneOf(packetWriter).flush(); // Remove listener oneOf(eventBus).removeListener(session); }}); session.run(); - // Something should have been written - assertTrue(out.size() > UniqueId.LENGTH + raw.length); context.assertIsSatisfied(); } } diff --git a/briar-tests/src/org/briarproject/plugins/PluginManagerImplTest.java b/briar-tests/src/org/briarproject/plugins/PluginManagerImplTest.java index 2e088fa30..8dab883cb 100644 --- a/briar-tests/src/org/briarproject/plugins/PluginManagerImplTest.java +++ b/briar-tests/src/org/briarproject/plugins/PluginManagerImplTest.java @@ -44,19 +44,19 @@ public class PluginManagerImplTest extends BriarTestCase { context.mock(SimplexPluginFactory.class); final SimplexPlugin simplexPlugin = context.mock(SimplexPlugin.class); final TransportId simplexId = new TransportId("simplex"); - final long simplexLatency = 12345; + final int simplexLatency = 12345; final SimplexPluginFactory simplexFailFactory = context.mock(SimplexPluginFactory.class, "simplexFailFactory"); final SimplexPlugin simplexFailPlugin = context.mock(SimplexPlugin.class, "simplexFailPlugin"); final TransportId simplexFailId = new TransportId("simplex1"); - final long simplexFailLatency = 23456; + final int simplexFailLatency = 23456; // Two duplex plugin factories: one creates a plugin, the other fails final DuplexPluginFactory duplexFactory = context.mock(DuplexPluginFactory.class); final DuplexPlugin duplexPlugin = context.mock(DuplexPlugin.class); final TransportId duplexId = new TransportId("duplex"); - final long duplexLatency = 34567; + final int duplexLatency = 34567; final DuplexPluginFactory duplexFailFactory = context.mock(DuplexPluginFactory.class, "duplexFailFactory"); final TransportId duplexFailId = new TransportId("duplex1"); diff --git a/briar-tests/src/org/briarproject/plugins/modem/ModemPluginTest.java b/briar-tests/src/org/briarproject/plugins/modem/ModemPluginTest.java index 3371bd7e0..3aa5dab23 100644 --- a/briar-tests/src/org/briarproject/plugins/modem/ModemPluginTest.java +++ b/briar-tests/src/org/briarproject/plugins/modem/ModemPluginTest.java @@ -24,7 +24,7 @@ public class ModemPluginTest extends BriarTestCase { final SerialPortList serialPortList = context.mock(SerialPortList.class); final ModemPlugin plugin = new ModemPlugin(modemFactory, - serialPortList, null, 0, 0, 0); + serialPortList, null, 0, 0); final Modem modem = context.mock(Modem.class); context.checking(new Expectations() {{ oneOf(serialPortList).getPortNames(); @@ -58,7 +58,7 @@ public class ModemPluginTest extends BriarTestCase { final DuplexPluginCallback callback = context.mock(DuplexPluginCallback.class); final ModemPlugin plugin = new ModemPlugin(modemFactory, - serialPortList, callback, 0, 0, 0); + serialPortList, callback, 0, 0); final Modem modem = context.mock(Modem.class); final TransportProperties local = new TransportProperties(); local.put("iso3166", ISO_1336); @@ -99,7 +99,7 @@ public class ModemPluginTest extends BriarTestCase { final DuplexPluginCallback callback = context.mock(DuplexPluginCallback.class); final ModemPlugin plugin = new ModemPlugin(modemFactory, - serialPortList, callback, 0, 0, 0); + serialPortList, callback, 0, 0); final Modem modem = context.mock(Modem.class); final TransportProperties local = new TransportProperties(); local.put("iso3166", ISO_1336); @@ -140,7 +140,7 @@ public class ModemPluginTest extends BriarTestCase { final DuplexPluginCallback callback = context.mock(DuplexPluginCallback.class); final ModemPlugin plugin = new ModemPlugin(modemFactory, - serialPortList, callback, 0, 0, 0); + serialPortList, callback, 0, 0); final Modem modem = context.mock(Modem.class); final TransportProperties local = new TransportProperties(); local.put("iso3166", ISO_1336); diff --git a/briar-tests/src/org/briarproject/transport/KeyManagerImplTest.java b/briar-tests/src/org/briarproject/transport/KeyManagerImplTest.java index f11f11f15..c160b59db 100644 --- a/briar-tests/src/org/briarproject/transport/KeyManagerImplTest.java +++ b/briar-tests/src/org/briarproject/transport/KeyManagerImplTest.java @@ -26,9 +26,9 @@ import org.junit.Test; public class KeyManagerImplTest extends BriarTestCase { private static final long EPOCH = 1000L * 1000L * 1000L * 1000L; - private static final long MAX_LATENCY = 2 * 60 * 1000; // 2 minutes - private static final long ROTATION_PERIOD_LENGTH = - MAX_LATENCY + MAX_CLOCK_DIFFERENCE; + private static final int MAX_LATENCY = 2 * 60 * 1000; // 2 minutes + private static final int ROTATION_PERIOD = + MAX_CLOCK_DIFFERENCE + MAX_LATENCY; private final ContactId contactId; private final TransportId transportId; @@ -294,7 +294,7 @@ public class KeyManagerImplTest extends BriarTestCase { MAX_LATENCY))); // The current time is the start of period 2 oneOf(clock).currentTimeMillis(); - will(returnValue(EPOCH + ROTATION_PERIOD_LENGTH)); + will(returnValue(EPOCH + ROTATION_PERIOD)); // The secret for period 3 should be derived and stored oneOf(crypto).deriveNextSecret(secret0, 1); will(returnValue(secret1.clone())); @@ -353,7 +353,7 @@ public class KeyManagerImplTest extends BriarTestCase { MAX_LATENCY))); // The current time is the end of period 3 oneOf(clock).currentTimeMillis(); - will(returnValue(EPOCH + 3 * ROTATION_PERIOD_LENGTH - 1)); + will(returnValue(EPOCH + 3 * ROTATION_PERIOD - 1)); // The secrets for periods 3 and 4 should be derived from secret 1 oneOf(crypto).deriveNextSecret(secret1, 2); will(returnValue(secret2.clone())); @@ -484,7 +484,7 @@ public class KeyManagerImplTest extends BriarTestCase { with(any(long.class)), with(any(long.class))); // run() during period 2: the secrets should be rotated oneOf(clock).currentTimeMillis(); - will(returnValue(EPOCH + ROTATION_PERIOD_LENGTH + 1)); + will(returnValue(EPOCH + ROTATION_PERIOD + 1)); oneOf(crypto).deriveNextSecret(secret0, 1); will(returnValue(secret1.clone())); oneOf(crypto).deriveNextSecret(secret1, 2); @@ -559,7 +559,7 @@ public class KeyManagerImplTest extends BriarTestCase { with(any(long.class)), with(any(long.class))); // run() during period 3 (late): the secrets should be rotated oneOf(clock).currentTimeMillis(); - will(returnValue(EPOCH + 2 * ROTATION_PERIOD_LENGTH + 1)); + will(returnValue(EPOCH + 2 * ROTATION_PERIOD + 1)); oneOf(crypto).deriveNextSecret(secret1, 2); will(returnValue(secret2.clone())); oneOf(crypto).deriveNextSecret(secret2, 3); diff --git a/briar-tests/src/org/briarproject/transport/KeyRotationIntegrationTest.java b/briar-tests/src/org/briarproject/transport/KeyRotationIntegrationTest.java index 1207f9363..70e8cfea3 100644 --- a/briar-tests/src/org/briarproject/transport/KeyRotationIntegrationTest.java +++ b/briar-tests/src/org/briarproject/transport/KeyRotationIntegrationTest.java @@ -32,9 +32,9 @@ import org.junit.Test; public class KeyRotationIntegrationTest extends BriarTestCase { private static final long EPOCH = 1000L * 1000L * 1000L * 1000L; - private static final long MAX_LATENCY = 2 * 60 * 1000; // 2 minutes - private static final long ROTATION_PERIOD_LENGTH = - MAX_LATENCY + MAX_CLOCK_DIFFERENCE; + private static final int MAX_LATENCY = 2 * 60 * 1000; // 2 minutes + private static final int ROTATION_PERIOD = + MAX_CLOCK_DIFFERENCE + MAX_LATENCY; private final ContactId contactId; private final TransportId transportId; @@ -653,7 +653,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase { MAX_LATENCY))); // The current time is the start of period 2 oneOf(clock).currentTimeMillis(); - will(returnValue(EPOCH + ROTATION_PERIOD_LENGTH)); + will(returnValue(EPOCH + ROTATION_PERIOD)); // The secret for period 3 should be derived and stored oneOf(crypto).deriveNextSecret(secret0, 1); will(returnValue(secret1.clone())); @@ -778,7 +778,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase { MAX_LATENCY))); // The current time is the end of period 3 oneOf(clock).currentTimeMillis(); - will(returnValue(EPOCH + 3 * ROTATION_PERIOD_LENGTH - 1)); + will(returnValue(EPOCH + 3 * ROTATION_PERIOD - 1)); // The secrets for periods 3 and 4 should be derived from secret 1 oneOf(crypto).deriveNextSecret(secret1, 2); will(returnValue(secret2.clone())); From 02a485ace044fd89d57c5af37d07b995f96a13f4 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Wed, 17 Dec 2014 08:34:44 +0000 Subject: [PATCH 04/10] Improved description of Bluetooth setting. Bug #73. --- briar-android/res/values/strings.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/briar-android/res/values/strings.xml b/briar-android/res/values/strings.xml index a1ed38a6a..3096f600e 100644 --- a/briar-android/res/values/strings.xml +++ b/briar-android/res/values/strings.xml @@ -93,8 +93,8 @@ Settings BLUETOOTH - Turn on Bluetooth - While signed in + Connect via Bluetooth + Whenever contacts are nearby Only when adding contacts NOTIFICATIONS Show alerts for private messages From f316d64afa0dca1e16bf7cc9ee989d936544833d Mon Sep 17 00:00:00 2001 From: akwizgran Date: Mon, 29 Dec 2014 19:55:05 +0000 Subject: [PATCH 05/10] Moved stream crypto to crypto component. --- .../api/crypto/StreamDecrypter.java | 14 ++++ .../api/crypto/StreamDecrypterFactory.java | 18 ++++ .../api/crypto/StreamEncrypter.java | 13 +++ .../api/crypto/StreamEncrypterFactory.java | 18 ++++ .../api/transport/StreamReader.java | 13 --- .../api/transport/StreamReaderFactory.java | 14 +++- .../api/transport/StreamWriter.java | 13 --- .../api/transport/StreamWriterFactory.java | 14 +++- .../org/briarproject/crypto/CryptoModule.java | 4 + .../{transport => crypto}/FrameEncoder.java | 2 +- .../crypto/StreamDecrypterFactoryImpl.java | 42 ++++++++++ .../StreamDecrypterImpl.java} | 22 +++-- .../crypto/StreamEncrypterFactoryImpl.java | 49 +++++++++++ .../StreamEncrypterImpl.java} | 27 +++--- .../invitation/AliceConnector.java | 18 ++-- .../briarproject/invitation/BobConnector.java | 18 ++-- .../plugins/ConnectionManagerImpl.java | 16 ++-- .../briarproject/transport/FrameReader.java | 12 --- .../briarproject/transport/FrameWriter.java | 13 --- .../transport/StreamReaderFactoryImpl.java | 35 ++++---- .../transport/StreamReaderImpl.java | 26 +++--- .../transport/StreamWriterFactoryImpl.java | 41 ++++----- .../transport/StreamWriterImpl.java | 39 ++++----- briar-tests/build.xml | 4 +- .../briarproject/ProtocolIntegrationTest.java | 13 ++- .../StreamDecrypterImplTest.java} | 47 +++++------ .../StreamEncrypterImplTest.java} | 17 ++-- .../SimplexMessagingIntegrationTest.java | 21 ++--- .../transport/StreamReaderImplTest.java | 41 ++++----- .../transport/StreamWriterImplTest.java | 63 +++++++------- .../transport/TestStreamDecrypter.java | 44 ++++++++++ .../transport/TestStreamEncrypter.java | 44 ++++++++++ .../transport/TransportIntegrationTest.java | 83 ++++++------------- 33 files changed, 504 insertions(+), 354 deletions(-) create mode 100644 briar-api/src/org/briarproject/api/crypto/StreamDecrypter.java create mode 100644 briar-api/src/org/briarproject/api/crypto/StreamDecrypterFactory.java create mode 100644 briar-api/src/org/briarproject/api/crypto/StreamEncrypter.java create mode 100644 briar-api/src/org/briarproject/api/crypto/StreamEncrypterFactory.java delete mode 100644 briar-api/src/org/briarproject/api/transport/StreamReader.java delete mode 100644 briar-api/src/org/briarproject/api/transport/StreamWriter.java rename briar-core/src/org/briarproject/{transport => crypto}/FrameEncoder.java (98%) create mode 100644 briar-core/src/org/briarproject/crypto/StreamDecrypterFactoryImpl.java rename briar-core/src/org/briarproject/{transport/IncomingEncryptionLayer.java => crypto/StreamDecrypterImpl.java} (78%) create mode 100644 briar-core/src/org/briarproject/crypto/StreamEncrypterFactoryImpl.java rename briar-core/src/org/briarproject/{transport/OutgoingEncryptionLayer.java => crypto/StreamEncrypterImpl.java} (79%) delete mode 100644 briar-core/src/org/briarproject/transport/FrameReader.java delete mode 100644 briar-core/src/org/briarproject/transport/FrameWriter.java rename briar-tests/src/org/briarproject/{transport/IncomingEncryptionLayerTest.java => crypto/StreamDecrypterImplTest.java} (80%) rename briar-tests/src/org/briarproject/{transport/OutgoingEncryptionLayerTest.java => crypto/StreamEncrypterImplTest.java} (88%) create mode 100644 briar-tests/src/org/briarproject/transport/TestStreamDecrypter.java create mode 100644 briar-tests/src/org/briarproject/transport/TestStreamEncrypter.java diff --git a/briar-api/src/org/briarproject/api/crypto/StreamDecrypter.java b/briar-api/src/org/briarproject/api/crypto/StreamDecrypter.java new file mode 100644 index 000000000..9f217c138 --- /dev/null +++ b/briar-api/src/org/briarproject/api/crypto/StreamDecrypter.java @@ -0,0 +1,14 @@ +package org.briarproject.api.crypto; + +import java.io.IOException; + +public interface StreamDecrypter { + + /** + * Reads a frame, decrypts its payload into the given buffer and returns + * the payload length, or -1 if no more frames can be read from the stream. + * @throws java.io.IOException if an error occurs while reading the frame, + * or if authenticated decryption fails. + */ + int readFrame(byte[] payload) throws IOException; +} diff --git a/briar-api/src/org/briarproject/api/crypto/StreamDecrypterFactory.java b/briar-api/src/org/briarproject/api/crypto/StreamDecrypterFactory.java new file mode 100644 index 000000000..46948f2a2 --- /dev/null +++ b/briar-api/src/org/briarproject/api/crypto/StreamDecrypterFactory.java @@ -0,0 +1,18 @@ +package org.briarproject.api.crypto; + +import java.io.InputStream; + +import org.briarproject.api.transport.StreamContext; + +public interface StreamDecrypterFactory { + + /** Creates a {@link StreamDecrypter} for decrypting a transport stream. */ + StreamDecrypter createStreamDecrypter(InputStream in, int maxFrameLength, + StreamContext ctx); + + /** + * Creates a {@link StreamDecrypter} for decrypting an invitation stream. + */ + StreamDecrypter createInvitationStreamDecrypter(InputStream in, + int maxFrameLength, byte[] secret, boolean alice); +} diff --git a/briar-api/src/org/briarproject/api/crypto/StreamEncrypter.java b/briar-api/src/org/briarproject/api/crypto/StreamEncrypter.java new file mode 100644 index 000000000..d48deff3a --- /dev/null +++ b/briar-api/src/org/briarproject/api/crypto/StreamEncrypter.java @@ -0,0 +1,13 @@ +package org.briarproject.api.crypto; + +import java.io.IOException; + +public interface StreamEncrypter { + + /** Encrypts the given frame and writes it to the stream. */ + void writeFrame(byte[] payload, int payloadLength, boolean finalFrame) + throws IOException; + + /** Flushes the stream. */ + void flush() throws IOException; +} diff --git a/briar-api/src/org/briarproject/api/crypto/StreamEncrypterFactory.java b/briar-api/src/org/briarproject/api/crypto/StreamEncrypterFactory.java new file mode 100644 index 000000000..95912937e --- /dev/null +++ b/briar-api/src/org/briarproject/api/crypto/StreamEncrypterFactory.java @@ -0,0 +1,18 @@ +package org.briarproject.api.crypto; + +import java.io.OutputStream; + +import org.briarproject.api.transport.StreamContext; + +public interface StreamEncrypterFactory { + + /** Creates a {@link StreamEncrypter} for encrypting a transport stream. */ + StreamEncrypter createStreamEncrypter(OutputStream out, + int maxFrameLength, StreamContext ctx); + + /** + * Creates a {@link StreamEncrypter} for encrypting an invitation stream. + */ + StreamEncrypter createInvitationStreamEncrypter(OutputStream out, + int maxFrameLength, byte[] secret, boolean alice); +} diff --git a/briar-api/src/org/briarproject/api/transport/StreamReader.java b/briar-api/src/org/briarproject/api/transport/StreamReader.java deleted file mode 100644 index 2fef7b4df..000000000 --- a/briar-api/src/org/briarproject/api/transport/StreamReader.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.briarproject.api.transport; - -import java.io.InputStream; - -/** Decrypts and authenticates data received over an underlying transport. */ -public interface StreamReader { - - /** - * Returns an input stream from which the decrypted, authenticated data can - * be read. - */ - InputStream getInputStream(); -} diff --git a/briar-api/src/org/briarproject/api/transport/StreamReaderFactory.java b/briar-api/src/org/briarproject/api/transport/StreamReaderFactory.java index 14459ec60..3bf4cf049 100644 --- a/briar-api/src/org/briarproject/api/transport/StreamReaderFactory.java +++ b/briar-api/src/org/briarproject/api/transport/StreamReaderFactory.java @@ -4,11 +4,17 @@ import java.io.InputStream; public interface StreamReaderFactory { - /** Creates a {@link StreamReader} for a transport connection. */ - StreamReader createStreamReader(InputStream in, int maxFrameLength, + /** + * Creates an {@link java.io.InputStream InputStream} for reading from a + * transport stream. + */ + InputStream createStreamReader(InputStream in, int maxFrameLength, StreamContext ctx); - /** Creates a {@link StreamReader} for an invitation connection. */ - StreamReader createInvitationStreamReader(InputStream in, + /** + * Creates an {@link java.io.InputStream InputStream} for reading from an + * invitation stream. + */ + InputStream createInvitationStreamReader(InputStream in, int maxFrameLength, byte[] secret, boolean alice); } diff --git a/briar-api/src/org/briarproject/api/transport/StreamWriter.java b/briar-api/src/org/briarproject/api/transport/StreamWriter.java deleted file mode 100644 index 2684742db..000000000 --- a/briar-api/src/org/briarproject/api/transport/StreamWriter.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.briarproject.api.transport; - -import java.io.OutputStream; - -/** Encrypts and authenticates data to be sent over an underlying transport. */ -public interface StreamWriter { - - /** - * Returns an output stream to which unencrypted, unauthenticated data can - * be written. - */ - OutputStream getOutputStream(); -} diff --git a/briar-api/src/org/briarproject/api/transport/StreamWriterFactory.java b/briar-api/src/org/briarproject/api/transport/StreamWriterFactory.java index f038a7522..04a924cc6 100644 --- a/briar-api/src/org/briarproject/api/transport/StreamWriterFactory.java +++ b/briar-api/src/org/briarproject/api/transport/StreamWriterFactory.java @@ -4,11 +4,17 @@ import java.io.OutputStream; public interface StreamWriterFactory { - /** Creates a {@link StreamWriter} for a transport connection. */ - StreamWriter createStreamWriter(OutputStream out, int maxFrameLength, + /** + * Creates an {@link java.io.OutputStream OutputStream} for writing to a + * transport stream + */ + OutputStream createStreamWriter(OutputStream out, int maxFrameLength, StreamContext ctx); - /** Creates a {@link StreamWriter} for an invitation connection. */ - StreamWriter createInvitationStreamWriter(OutputStream out, + /** + * Creates an {@link java.io.OutputStream OutputStream} for writing to an + * invitation stream. + */ + OutputStream createInvitationStreamWriter(OutputStream out, int maxFrameLength, byte[] secret, boolean alice); } diff --git a/briar-core/src/org/briarproject/crypto/CryptoModule.java b/briar-core/src/org/briarproject/crypto/CryptoModule.java index d7dd2fdb4..d4ac20c64 100644 --- a/briar-core/src/org/briarproject/crypto/CryptoModule.java +++ b/briar-core/src/org/briarproject/crypto/CryptoModule.java @@ -14,6 +14,8 @@ 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; @@ -44,6 +46,8 @@ public class CryptoModule extends AbstractModule { CryptoComponentImpl.class).in(Singleton.class); bind(PasswordStrengthEstimator.class).to( PasswordStrengthEstimatorImpl.class); + bind(StreamDecrypterFactory.class).to(StreamDecrypterFactoryImpl.class); + bind(StreamEncrypterFactory.class).to(StreamEncrypterFactoryImpl.class); } @Provides @Singleton @CryptoExecutor diff --git a/briar-core/src/org/briarproject/transport/FrameEncoder.java b/briar-core/src/org/briarproject/crypto/FrameEncoder.java similarity index 98% rename from briar-core/src/org/briarproject/transport/FrameEncoder.java rename to briar-core/src/org/briarproject/crypto/FrameEncoder.java index 684b87542..5a30593db 100644 --- a/briar-core/src/org/briarproject/transport/FrameEncoder.java +++ b/briar-core/src/org/briarproject/crypto/FrameEncoder.java @@ -1,4 +1,4 @@ -package org.briarproject.transport; +package org.briarproject.crypto; import static org.briarproject.api.transport.TransportConstants.AAD_LENGTH; import static org.briarproject.api.transport.TransportConstants.HEADER_LENGTH; diff --git a/briar-core/src/org/briarproject/crypto/StreamDecrypterFactoryImpl.java b/briar-core/src/org/briarproject/crypto/StreamDecrypterFactoryImpl.java new file mode 100644 index 000000000..8f04e686a --- /dev/null +++ b/briar-core/src/org/briarproject/crypto/StreamDecrypterFactoryImpl.java @@ -0,0 +1,42 @@ +package org.briarproject.crypto; + +import java.io.InputStream; + +import javax.inject.Inject; + +import org.briarproject.api.crypto.CryptoComponent; +import org.briarproject.api.crypto.SecretKey; +import org.briarproject.api.crypto.StreamDecrypter; +import org.briarproject.api.crypto.StreamDecrypterFactory; +import org.briarproject.api.transport.StreamContext; + +class StreamDecrypterFactoryImpl implements StreamDecrypterFactory { + + private final CryptoComponent crypto; + + @Inject + StreamDecrypterFactoryImpl(CryptoComponent crypto) { + this.crypto = crypto; + } + + public StreamDecrypter createStreamDecrypter(InputStream in, + int maxFrameLength, StreamContext ctx) { + byte[] secret = ctx.getSecret(); + long streamNumber = ctx.getStreamNumber(); + boolean alice = !ctx.getAlice(); + // Derive the frame key + SecretKey frameKey = crypto.deriveFrameKey(secret, streamNumber, alice); + // Create the decrypter + return new StreamDecrypterImpl(in, crypto.getFrameCipher(), frameKey, + maxFrameLength); + } + + public StreamDecrypter createInvitationStreamDecrypter(InputStream in, + int maxFrameLength, byte[] secret, boolean alice) { + // Derive the frame key + SecretKey frameKey = crypto.deriveFrameKey(secret, 0, alice); + // Create the decrypter + return new StreamDecrypterImpl(in, crypto.getFrameCipher(), frameKey, + maxFrameLength); + } +} diff --git a/briar-core/src/org/briarproject/transport/IncomingEncryptionLayer.java b/briar-core/src/org/briarproject/crypto/StreamDecrypterImpl.java similarity index 78% rename from briar-core/src/org/briarproject/transport/IncomingEncryptionLayer.java rename to briar-core/src/org/briarproject/crypto/StreamDecrypterImpl.java index e5e4381d8..ff29697df 100644 --- a/briar-core/src/org/briarproject/transport/IncomingEncryptionLayer.java +++ b/briar-core/src/org/briarproject/crypto/StreamDecrypterImpl.java @@ -1,4 +1,4 @@ -package org.briarproject.transport; +package org.briarproject.crypto; import static org.briarproject.api.transport.TransportConstants.AAD_LENGTH; import static org.briarproject.api.transport.TransportConstants.HEADER_LENGTH; @@ -13,19 +13,20 @@ import java.security.GeneralSecurityException; import org.briarproject.api.FormatException; import org.briarproject.api.crypto.AuthenticatedCipher; import org.briarproject.api.crypto.SecretKey; +import org.briarproject.api.crypto.StreamDecrypter; -class IncomingEncryptionLayer implements FrameReader { +class StreamDecrypterImpl implements StreamDecrypter { private final InputStream in; private final AuthenticatedCipher frameCipher; private final SecretKey frameKey; - private final byte[] iv, aad, ciphertext; + private final byte[] iv, aad, plaintext, ciphertext; private final int frameLength; private long frameNumber; private boolean finalFrame; - IncomingEncryptionLayer(InputStream in, AuthenticatedCipher frameCipher, + StreamDecrypterImpl(InputStream in, AuthenticatedCipher frameCipher, SecretKey frameKey, int frameLength) { this.in = in; this.frameCipher = frameCipher; @@ -33,12 +34,13 @@ class IncomingEncryptionLayer implements FrameReader { this.frameLength = frameLength; iv = new byte[IV_LENGTH]; aad = new byte[AAD_LENGTH]; + plaintext = new byte[frameLength - MAC_LENGTH]; ciphertext = new byte[frameLength]; frameNumber = 0; finalFrame = false; } - public int readFrame(byte[] frame) throws IOException { + public int readFrame(byte[] payload) throws IOException { if(finalFrame) return -1; // Read the frame int ciphertextLength = 0; @@ -61,23 +63,25 @@ class IncomingEncryptionLayer implements FrameReader { try { frameCipher.init(false, frameKey, iv, aad); int decrypted = frameCipher.doFinal(ciphertext, 0, ciphertextLength, - frame, 0); + plaintext, 0); if(decrypted != plaintextLength) throw new RuntimeException(); } catch(GeneralSecurityException e) { throw new FormatException(); } // Decode and validate the header - finalFrame = FrameEncoder.isFinalFrame(frame); + finalFrame = FrameEncoder.isFinalFrame(plaintext); if(!finalFrame && ciphertextLength < frameLength) throw new FormatException(); - int payloadLength = FrameEncoder.getPayloadLength(frame); + int payloadLength = FrameEncoder.getPayloadLength(plaintext); if(payloadLength > plaintextLength - HEADER_LENGTH) throw new FormatException(); // If there's any padding it must be all zeroes for(int i = HEADER_LENGTH + payloadLength; i < plaintextLength; i++) { - if(frame[i] != 0) throw new FormatException(); + if(plaintext[i] != 0) throw new FormatException(); } frameNumber++; + // Copy the payload + System.arraycopy(plaintext, HEADER_LENGTH, payload, 0, payloadLength); return payloadLength; } } \ No newline at end of file diff --git a/briar-core/src/org/briarproject/crypto/StreamEncrypterFactoryImpl.java b/briar-core/src/org/briarproject/crypto/StreamEncrypterFactoryImpl.java new file mode 100644 index 000000000..979ebb17c --- /dev/null +++ b/briar-core/src/org/briarproject/crypto/StreamEncrypterFactoryImpl.java @@ -0,0 +1,49 @@ +package org.briarproject.crypto; + +import static org.briarproject.api.transport.TransportConstants.TAG_LENGTH; + +import java.io.OutputStream; + +import javax.inject.Inject; + +import org.briarproject.api.crypto.CryptoComponent; +import org.briarproject.api.crypto.SecretKey; +import org.briarproject.api.crypto.StreamEncrypter; +import org.briarproject.api.crypto.StreamEncrypterFactory; +import org.briarproject.api.transport.StreamContext; + +class StreamEncrypterFactoryImpl implements StreamEncrypterFactory { + + private final CryptoComponent crypto; + + @Inject + StreamEncrypterFactoryImpl(CryptoComponent crypto) { + this.crypto = crypto; + } + + public StreamEncrypter createStreamEncrypter(OutputStream out, + int maxFrameLength, StreamContext ctx) { + byte[] secret = ctx.getSecret(); + long streamNumber = ctx.getStreamNumber(); + boolean alice = ctx.getAlice(); + // Encode the tag + byte[] tag = new byte[TAG_LENGTH]; + SecretKey tagKey = crypto.deriveTagKey(secret, alice); + crypto.encodeTag(tag, tagKey, streamNumber); + tagKey.erase(); + // Derive the frame key + SecretKey frameKey = crypto.deriveFrameKey(secret, streamNumber, alice); + // Create the encrypter + return new StreamEncrypterImpl(out, crypto.getFrameCipher(), frameKey, + maxFrameLength, tag); + } + + public StreamEncrypter createInvitationStreamEncrypter(OutputStream out, + int maxFrameLength, byte[] secret, boolean alice) { + // Derive the frame key + SecretKey frameKey = crypto.deriveFrameKey(secret, 0, alice); + // Create the encrypter + return new StreamEncrypterImpl(out, crypto.getFrameCipher(), frameKey, + maxFrameLength, null); + } +} diff --git a/briar-core/src/org/briarproject/transport/OutgoingEncryptionLayer.java b/briar-core/src/org/briarproject/crypto/StreamEncrypterImpl.java similarity index 79% rename from briar-core/src/org/briarproject/transport/OutgoingEncryptionLayer.java rename to briar-core/src/org/briarproject/crypto/StreamEncrypterImpl.java index 1bb90c1e8..d3e2e43ce 100644 --- a/briar-core/src/org/briarproject/transport/OutgoingEncryptionLayer.java +++ b/briar-core/src/org/briarproject/crypto/StreamEncrypterImpl.java @@ -1,4 +1,4 @@ -package org.briarproject.transport; +package org.briarproject.crypto; import static org.briarproject.api.transport.TransportConstants.AAD_LENGTH; import static org.briarproject.api.transport.TransportConstants.HEADER_LENGTH; @@ -12,19 +12,20 @@ import java.security.GeneralSecurityException; import org.briarproject.api.crypto.AuthenticatedCipher; import org.briarproject.api.crypto.SecretKey; +import org.briarproject.api.crypto.StreamEncrypter; -class OutgoingEncryptionLayer implements FrameWriter { +class StreamEncrypterImpl implements StreamEncrypter { private final OutputStream out; private final AuthenticatedCipher frameCipher; private final SecretKey frameKey; - private final byte[] tag, iv, aad, ciphertext; + private final byte[] tag, iv, aad, plaintext, ciphertext; private final int frameLength; private long frameNumber; private boolean writeTag; - OutgoingEncryptionLayer(OutputStream out, AuthenticatedCipher frameCipher, + StreamEncrypterImpl(OutputStream out, AuthenticatedCipher frameCipher, SecretKey frameKey, int frameLength, byte[] tag) { this.out = out; this.frameCipher = frameCipher; @@ -33,13 +34,14 @@ class OutgoingEncryptionLayer implements FrameWriter { this.tag = tag; iv = new byte[IV_LENGTH]; aad = new byte[AAD_LENGTH]; + plaintext = new byte[frameLength - MAC_LENGTH]; ciphertext = new byte[frameLength]; frameNumber = 0; writeTag = (tag != null); } - public void writeFrame(byte[] frame, int payloadLength, boolean finalFrame) - throws IOException { + public void writeFrame(byte[] payload, int payloadLength, + boolean finalFrame) throws IOException { if(frameNumber > MAX_32_BIT_UNSIGNED) throw new IllegalStateException(); // Write the tag if required if(writeTag) { @@ -51,8 +53,6 @@ class OutgoingEncryptionLayer implements FrameWriter { } writeTag = false; } - // Encode the header - FrameEncoder.encodeHeader(frame, finalFrame, payloadLength); // Don't pad the final frame int plaintextLength, ciphertextLength; if(finalFrame) { @@ -62,16 +62,19 @@ class OutgoingEncryptionLayer implements FrameWriter { plaintextLength = frameLength - MAC_LENGTH; ciphertextLength = frameLength; } + // Encode the header + FrameEncoder.encodeHeader(plaintext, finalFrame, payloadLength); + // Copy the payload + System.arraycopy(payload, 0, plaintext, HEADER_LENGTH, payloadLength); // If there's any padding it must all be zeroes - for(int i = HEADER_LENGTH + payloadLength; i < plaintextLength; i++) { - frame[i] = 0; - } + for(int i = HEADER_LENGTH + payloadLength; i < plaintextLength; i++) + plaintext[i] = 0; // Encrypt and authenticate the frame FrameEncoder.encodeIv(iv, frameNumber); FrameEncoder.encodeAad(aad, frameNumber, plaintextLength); try { frameCipher.init(true, frameKey, iv, aad); - int encrypted = frameCipher.doFinal(frame, 0, plaintextLength, + int encrypted = frameCipher.doFinal(plaintext, 0, plaintextLength, ciphertext, 0); if(encrypted != ciphertextLength) throw new RuntimeException(); } catch(GeneralSecurityException badCipher) { diff --git a/briar-core/src/org/briarproject/invitation/AliceConnector.java b/briar-core/src/org/briarproject/invitation/AliceConnector.java index 9c7fd31f3..8c0bd7813 100644 --- a/briar-core/src/org/briarproject/invitation/AliceConnector.java +++ b/briar-core/src/org/briarproject/invitation/AliceConnector.java @@ -29,9 +29,7 @@ import org.briarproject.api.serial.ReaderFactory; import org.briarproject.api.serial.Writer; import org.briarproject.api.serial.WriterFactory; import org.briarproject.api.system.Clock; -import org.briarproject.api.transport.StreamReader; import org.briarproject.api.transport.StreamReaderFactory; -import org.briarproject.api.transport.StreamWriter; import org.briarproject.api.transport.StreamWriterFactory; /** A connection thread for the peer being Alice in the invitation protocol. */ @@ -51,9 +49,9 @@ class AliceConnector extends Connector { Map localProps, PseudoRandom random) { super(crypto, db, readerFactory, writerFactory, streamReaderFactory, - streamWriterFactory, authorFactory, groupFactory, - keyManager, connectionManager, clock, reuseConnection, group, - plugin, localAuthor, localProps, random); + streamWriterFactory, authorFactory, groupFactory, keyManager, + connectionManager, clock, reuseConnection, group, plugin, + localAuthor, localProps, random); } @Override @@ -131,14 +129,16 @@ class AliceConnector extends Connector { if(LOG.isLoggable(INFO)) LOG.info(pluginName + " confirmation succeeded"); int maxFrameLength = conn.getReader().getMaxFrameLength(); - StreamReader streamReader = + // Create the readers + InputStream streamReader = streamReaderFactory.createInvitationStreamReader(in, maxFrameLength, secret, false); // Bob's stream - r = readerFactory.createReader(streamReader.getInputStream()); - StreamWriter streamWriter = + r = readerFactory.createReader(streamReader); + // Create the writers + OutputStream streamWriter = streamWriterFactory.createInvitationStreamWriter(out, maxFrameLength, secret, true); // Alice's stream - w = writerFactory.createWriter(streamWriter.getOutputStream()); + w = writerFactory.createWriter(streamWriter); // Derive the invitation nonces byte[][] nonces = crypto.deriveInvitationNonces(secret); byte[] aliceNonce = nonces[0], bobNonce = nonces[1]; diff --git a/briar-core/src/org/briarproject/invitation/BobConnector.java b/briar-core/src/org/briarproject/invitation/BobConnector.java index 205b3446d..6b435fd2a 100644 --- a/briar-core/src/org/briarproject/invitation/BobConnector.java +++ b/briar-core/src/org/briarproject/invitation/BobConnector.java @@ -29,9 +29,7 @@ import org.briarproject.api.serial.ReaderFactory; import org.briarproject.api.serial.Writer; import org.briarproject.api.serial.WriterFactory; import org.briarproject.api.system.Clock; -import org.briarproject.api.transport.StreamReader; import org.briarproject.api.transport.StreamReaderFactory; -import org.briarproject.api.transport.StreamWriter; import org.briarproject.api.transport.StreamWriterFactory; /** A connection thread for the peer being Bob in the invitation protocol. */ @@ -51,9 +49,9 @@ class BobConnector extends Connector { Map localProps, PseudoRandom random) { super(crypto, db, readerFactory, writerFactory, streamReaderFactory, - streamWriterFactory, authorFactory, groupFactory, - keyManager, connectionManager, clock, reuseConnection, group, - plugin, localAuthor, localProps, random); + streamWriterFactory, authorFactory, groupFactory, keyManager, + connectionManager, clock, reuseConnection, group, plugin, + localAuthor, localProps, random); } @Override @@ -131,14 +129,16 @@ class BobConnector extends Connector { if(LOG.isLoggable(INFO)) LOG.info(pluginName + " confirmation succeeded"); int maxFrameLength = conn.getReader().getMaxFrameLength(); - StreamReader streamReader = + // Create the readers + InputStream streamReader = streamReaderFactory.createInvitationStreamReader(in, maxFrameLength, secret, true); // Alice's stream - r = readerFactory.createReader(streamReader.getInputStream()); - StreamWriter streamWriter = + r = readerFactory.createReader(streamReader); + // Create the writers + OutputStream streamWriter = streamWriterFactory.createInvitationStreamWriter(out, maxFrameLength, secret, false); // Bob's stream - w = writerFactory.createWriter(streamWriter.getOutputStream()); + w = writerFactory.createWriter(streamWriter); // Derive the nonces byte[][] nonces = crypto.deriveInvitationNonces(secret); byte[] aliceNonce = nonces[0], bobNonce = nonces[1]; diff --git a/briar-core/src/org/briarproject/plugins/ConnectionManagerImpl.java b/briar-core/src/org/briarproject/plugins/ConnectionManagerImpl.java index 9dad32f2e..b72efb688 100644 --- a/briar-core/src/org/briarproject/plugins/ConnectionManagerImpl.java +++ b/briar-core/src/org/briarproject/plugins/ConnectionManagerImpl.java @@ -6,6 +6,7 @@ import static org.briarproject.api.transport.TransportConstants.TAG_LENGTH; import java.io.EOFException; import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; import java.util.concurrent.Executor; import java.util.logging.Logger; @@ -24,9 +25,7 @@ import org.briarproject.api.plugins.TransportConnectionReader; import org.briarproject.api.plugins.TransportConnectionWriter; import org.briarproject.api.plugins.duplex.DuplexTransportConnection; import org.briarproject.api.transport.StreamContext; -import org.briarproject.api.transport.StreamReader; import org.briarproject.api.transport.StreamReaderFactory; -import org.briarproject.api.transport.StreamWriter; import org.briarproject.api.transport.StreamWriterFactory; import org.briarproject.api.transport.TagRecogniser; import org.briarproject.util.ByteUtils; @@ -97,11 +96,10 @@ class ConnectionManagerImpl implements ConnectionManager { private MessagingSession createIncomingSession(StreamContext ctx, TransportConnectionReader r) throws IOException { try { - StreamReader streamReader = streamReaderFactory.createStreamReader( + InputStream streamReader = streamReaderFactory.createStreamReader( r.getInputStream(), r.getMaxFrameLength(), ctx); return messagingSessionFactory.createIncomingSession( - ctx.getContactId(), ctx.getTransportId(), - streamReader.getInputStream()); + ctx.getContactId(), ctx.getTransportId(), streamReader); } finally { ByteUtils.erase(ctx.getSecret()); } @@ -110,11 +108,11 @@ class ConnectionManagerImpl implements ConnectionManager { private MessagingSession createSimplexOutgoingSession(StreamContext ctx, TransportConnectionWriter w) throws IOException { try { - StreamWriter streamWriter = streamWriterFactory.createStreamWriter( + OutputStream streamWriter = streamWriterFactory.createStreamWriter( w.getOutputStream(), w.getMaxFrameLength(), ctx); return messagingSessionFactory.createSimplexOutgoingSession( ctx.getContactId(), ctx.getTransportId(), w.getMaxLatency(), - streamWriter.getOutputStream()); + streamWriter); } finally { ByteUtils.erase(ctx.getSecret()); } @@ -123,11 +121,11 @@ class ConnectionManagerImpl implements ConnectionManager { private MessagingSession createDuplexOutgoingSession(StreamContext ctx, TransportConnectionWriter w) throws IOException { try { - StreamWriter streamWriter = streamWriterFactory.createStreamWriter( + OutputStream streamWriter = streamWriterFactory.createStreamWriter( w.getOutputStream(), w.getMaxFrameLength(), ctx); return messagingSessionFactory.createDuplexOutgoingSession( ctx.getContactId(), ctx.getTransportId(), w.getMaxLatency(), - w.getMaxIdleTime(), streamWriter.getOutputStream()); + w.getMaxIdleTime(), streamWriter); } finally { ByteUtils.erase(ctx.getSecret()); } diff --git a/briar-core/src/org/briarproject/transport/FrameReader.java b/briar-core/src/org/briarproject/transport/FrameReader.java deleted file mode 100644 index 8284c47b8..000000000 --- a/briar-core/src/org/briarproject/transport/FrameReader.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.briarproject.transport; - -import java.io.IOException; - -interface FrameReader { - - /** - * Reads a frame into the given buffer and returns its payload length, or - * -1 if no more frames can be read from the connection. - */ - int readFrame(byte[] frame) throws IOException; -} diff --git a/briar-core/src/org/briarproject/transport/FrameWriter.java b/briar-core/src/org/briarproject/transport/FrameWriter.java deleted file mode 100644 index 4f29b7999..000000000 --- a/briar-core/src/org/briarproject/transport/FrameWriter.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.briarproject.transport; - -import java.io.IOException; - -interface FrameWriter { - - /** Writes the given frame. */ - void writeFrame(byte[] frame, int payloadLength, boolean finalFrame) - throws IOException; - - /** Flushes the stream. */ - void flush() throws IOException; -} diff --git a/briar-core/src/org/briarproject/transport/StreamReaderFactoryImpl.java b/briar-core/src/org/briarproject/transport/StreamReaderFactoryImpl.java index d71bfc50a..daa4f2bb7 100644 --- a/briar-core/src/org/briarproject/transport/StreamReaderFactoryImpl.java +++ b/briar-core/src/org/briarproject/transport/StreamReaderFactoryImpl.java @@ -4,37 +4,32 @@ import java.io.InputStream; import javax.inject.Inject; -import org.briarproject.api.crypto.CryptoComponent; -import org.briarproject.api.crypto.SecretKey; +import org.briarproject.api.crypto.StreamDecrypter; +import org.briarproject.api.crypto.StreamDecrypterFactory; import org.briarproject.api.transport.StreamContext; -import org.briarproject.api.transport.StreamReader; import org.briarproject.api.transport.StreamReaderFactory; class StreamReaderFactoryImpl implements StreamReaderFactory { - private final CryptoComponent crypto; + private final StreamDecrypterFactory streamDecrypterFactory; @Inject - StreamReaderFactoryImpl(CryptoComponent crypto) { - this.crypto = crypto; + StreamReaderFactoryImpl(StreamDecrypterFactory streamDecrypterFactory) { + this.streamDecrypterFactory = streamDecrypterFactory; } - public StreamReader createStreamReader(InputStream in, - int maxFrameLength, StreamContext ctx) { - byte[] secret = ctx.getSecret(); - long streamNumber = ctx.getStreamNumber(); - boolean alice = !ctx.getAlice(); - SecretKey frameKey = crypto.deriveFrameKey(secret, streamNumber, alice); - FrameReader frameReader = new IncomingEncryptionLayer(in, - crypto.getFrameCipher(), frameKey, maxFrameLength); - return new StreamReaderImpl(frameReader, maxFrameLength); + public InputStream createStreamReader(InputStream in, int maxFrameLength, + StreamContext ctx) { + StreamDecrypter s = streamDecrypterFactory.createStreamDecrypter(in, + maxFrameLength, ctx); + return new StreamReaderImpl(s, maxFrameLength); } - public StreamReader createInvitationStreamReader(InputStream in, + public InputStream createInvitationStreamReader(InputStream in, int maxFrameLength, byte[] secret, boolean alice) { - SecretKey frameKey = crypto.deriveFrameKey(secret, 0, alice); - FrameReader frameReader = new IncomingEncryptionLayer(in, - crypto.getFrameCipher(), frameKey, maxFrameLength); - return new StreamReaderImpl(frameReader, maxFrameLength); + StreamDecrypter s = + streamDecrypterFactory.createInvitationStreamDecrypter(in, + maxFrameLength, secret, alice); + return new StreamReaderImpl(s, maxFrameLength); } } diff --git a/briar-core/src/org/briarproject/transport/StreamReaderImpl.java b/briar-core/src/org/briarproject/transport/StreamReaderImpl.java index 0de048a6f..e9a30b24a 100644 --- a/briar-core/src/org/briarproject/transport/StreamReaderImpl.java +++ b/briar-core/src/org/briarproject/transport/StreamReaderImpl.java @@ -6,22 +6,18 @@ import static org.briarproject.api.transport.TransportConstants.MAC_LENGTH; import java.io.IOException; import java.io.InputStream; -import org.briarproject.api.transport.StreamReader; +import org.briarproject.api.crypto.StreamDecrypter; -class StreamReaderImpl extends InputStream implements StreamReader { +class StreamReaderImpl extends InputStream { - private final FrameReader in; - private final byte[] frame; + private final StreamDecrypter decrypter; + private final byte[] payload; private int offset = 0, length = 0; - StreamReaderImpl(FrameReader in, int frameLength) { - this.in = in; - frame = new byte[frameLength - MAC_LENGTH]; - } - - public InputStream getInputStream() { - return this; + StreamReaderImpl(StreamDecrypter decrypter, int frameLength) { + this.decrypter = decrypter; + payload = new byte[frameLength - HEADER_LENGTH - MAC_LENGTH]; } @Override @@ -30,7 +26,7 @@ class StreamReaderImpl extends InputStream implements StreamReader { if(length == -1) return -1; readFrame(); } - int b = frame[offset] & 0xff; + int b = payload[offset] & 0xff; offset++; length--; return b; @@ -48,7 +44,7 @@ class StreamReaderImpl extends InputStream implements StreamReader { readFrame(); } len = Math.min(len, length); - System.arraycopy(frame, offset, b, off, len); + System.arraycopy(payload, offset, b, off, len); offset += len; length -= len; return len; @@ -56,7 +52,7 @@ class StreamReaderImpl extends InputStream implements StreamReader { private void readFrame() throws IOException { assert length == 0; - offset = HEADER_LENGTH; - length = in.readFrame(frame); + offset = 0; + length = decrypter.readFrame(payload); } } diff --git a/briar-core/src/org/briarproject/transport/StreamWriterFactoryImpl.java b/briar-core/src/org/briarproject/transport/StreamWriterFactoryImpl.java index 638ecdff0..f57a8f69b 100644 --- a/briar-core/src/org/briarproject/transport/StreamWriterFactoryImpl.java +++ b/briar-core/src/org/briarproject/transport/StreamWriterFactoryImpl.java @@ -1,46 +1,35 @@ package org.briarproject.transport; -import static org.briarproject.api.transport.TransportConstants.TAG_LENGTH; - import java.io.OutputStream; import javax.inject.Inject; -import org.briarproject.api.crypto.CryptoComponent; -import org.briarproject.api.crypto.SecretKey; +import org.briarproject.api.crypto.StreamEncrypter; +import org.briarproject.api.crypto.StreamEncrypterFactory; import org.briarproject.api.transport.StreamContext; -import org.briarproject.api.transport.StreamWriter; import org.briarproject.api.transport.StreamWriterFactory; class StreamWriterFactoryImpl implements StreamWriterFactory { - private final CryptoComponent crypto; + private final StreamEncrypterFactory streamEncrypterFactory; @Inject - StreamWriterFactoryImpl(CryptoComponent crypto) { - this.crypto = crypto; + StreamWriterFactoryImpl(StreamEncrypterFactory streamEncrypterFactory) { + this.streamEncrypterFactory = streamEncrypterFactory; } - public StreamWriter createStreamWriter(OutputStream out, - int maxFrameLength, StreamContext ctx) { - byte[] secret = ctx.getSecret(); - long streamNumber = ctx.getStreamNumber(); - boolean alice = ctx.getAlice(); - byte[] tag = new byte[TAG_LENGTH]; - SecretKey tagKey = crypto.deriveTagKey(secret, alice); - crypto.encodeTag(tag, tagKey, streamNumber); - tagKey.erase(); - SecretKey frameKey = crypto.deriveFrameKey(secret, streamNumber, alice); - FrameWriter frameWriter = new OutgoingEncryptionLayer(out, - crypto.getFrameCipher(), frameKey, maxFrameLength, tag); - return new StreamWriterImpl(frameWriter, maxFrameLength); + public OutputStream createStreamWriter(OutputStream out, int maxFrameLength, + StreamContext ctx) { + StreamEncrypter s = streamEncrypterFactory.createStreamEncrypter(out, + maxFrameLength, ctx); + return new StreamWriterImpl(s, maxFrameLength); } - public StreamWriter createInvitationStreamWriter(OutputStream out, + public OutputStream createInvitationStreamWriter(OutputStream out, int maxFrameLength, byte[] secret, boolean alice) { - SecretKey frameKey = crypto.deriveFrameKey(secret, 0, alice); - FrameWriter frameWriter = new OutgoingEncryptionLayer(out, - crypto.getFrameCipher(), frameKey, maxFrameLength, null); - return new StreamWriterImpl(frameWriter, maxFrameLength); + StreamEncrypter s = + streamEncrypterFactory.createInvitationStreamEncrypter(out, + maxFrameLength, secret, alice); + return new StreamWriterImpl(s, maxFrameLength); } } \ No newline at end of file diff --git a/briar-core/src/org/briarproject/transport/StreamWriterImpl.java b/briar-core/src/org/briarproject/transport/StreamWriterImpl.java index 7e38809a8..05653fd42 100644 --- a/briar-core/src/org/briarproject/transport/StreamWriterImpl.java +++ b/briar-core/src/org/briarproject/transport/StreamWriterImpl.java @@ -6,7 +6,7 @@ import static org.briarproject.api.transport.TransportConstants.MAC_LENGTH; import java.io.IOException; import java.io.OutputStream; -import org.briarproject.api.transport.StreamWriter; +import org.briarproject.api.crypto.StreamEncrypter; /** * A {@link org.briarproject.api.transport.StreamWriter StreamWriter} that @@ -15,43 +15,36 @@ import org.briarproject.api.transport.StreamWriter; *

* This class is not thread-safe. */ -class StreamWriterImpl extends OutputStream implements StreamWriter { +class StreamWriterImpl extends OutputStream { - private final FrameWriter out; - private final byte[] frame; - private final int frameLength; + private final StreamEncrypter encrypter; + private final byte[] payload; private int length = 0; - StreamWriterImpl(FrameWriter out, int frameLength) { - this.out = out; - this.frameLength = frameLength; - frame = new byte[frameLength - MAC_LENGTH]; - } - - public OutputStream getOutputStream() { - return this; + StreamWriterImpl(StreamEncrypter encrypter, int maxFrameLength) { + this.encrypter = encrypter; + payload = new byte[maxFrameLength - HEADER_LENGTH - MAC_LENGTH]; } @Override public void close() throws IOException { writeFrame(true); - out.flush(); + encrypter.flush(); super.close(); } @Override public void flush() throws IOException { writeFrame(false); - out.flush(); + encrypter.flush(); } @Override public void write(int b) throws IOException { - frame[HEADER_LENGTH + length] = (byte) b; + payload[length] = (byte) b; length++; - if(HEADER_LENGTH + length + MAC_LENGTH == frameLength) - writeFrame(false); + if(length == payload.length) writeFrame(false); } @Override @@ -61,21 +54,21 @@ class StreamWriterImpl extends OutputStream implements StreamWriter { @Override public void write(byte[] b, int off, int len) throws IOException { - int available = frameLength - HEADER_LENGTH - length - MAC_LENGTH; + int available = payload.length - length; while(available <= len) { - System.arraycopy(b, off, frame, HEADER_LENGTH + length, available); + System.arraycopy(b, off, payload, length, available); length += available; writeFrame(false); off += available; len -= available; - available = frameLength - HEADER_LENGTH - length - MAC_LENGTH; + available = payload.length - length; } - System.arraycopy(b, off, frame, HEADER_LENGTH + length, len); + System.arraycopy(b, off, payload, length, len); length += len; } private void writeFrame(boolean finalFrame) throws IOException { - out.writeFrame(frame, length, finalFrame); + encrypter.writeFrame(payload, length, finalFrame); length = 0; } } diff --git a/briar-tests/build.xml b/briar-tests/build.xml index 2ab788bba..561a3fbe5 100644 --- a/briar-tests/build.xml +++ b/briar-tests/build.xml @@ -102,6 +102,8 @@ + + @@ -126,10 +128,8 @@ - - diff --git a/briar-tests/src/org/briarproject/ProtocolIntegrationTest.java b/briar-tests/src/org/briarproject/ProtocolIntegrationTest.java index cebd634d4..a3983b5a2 100644 --- a/briar-tests/src/org/briarproject/ProtocolIntegrationTest.java +++ b/briar-tests/src/org/briarproject/ProtocolIntegrationTest.java @@ -7,6 +7,7 @@ import static org.junit.Assert.assertArrayEquals; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.InputStream; +import java.io.OutputStream; import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -36,9 +37,7 @@ import org.briarproject.api.messaging.SubscriptionUpdate; import org.briarproject.api.messaging.TransportUpdate; import org.briarproject.api.messaging.UnverifiedMessage; import org.briarproject.api.transport.StreamContext; -import org.briarproject.api.transport.StreamReader; import org.briarproject.api.transport.StreamReaderFactory; -import org.briarproject.api.transport.StreamWriter; import org.briarproject.api.transport.StreamWriterFactory; import org.briarproject.crypto.CryptoModule; import org.briarproject.db.DatabaseModule; @@ -119,10 +118,10 @@ public class ProtocolIntegrationTest extends BriarTestCase { ByteArrayOutputStream out = new ByteArrayOutputStream(); StreamContext ctx = new StreamContext(contactId, transportId, secret.clone(), 0, true); - StreamWriter streamWriter = streamWriterFactory.createStreamWriter(out, + OutputStream streamWriter = streamWriterFactory.createStreamWriter(out, MAX_FRAME_LENGTH, ctx); PacketWriter packetWriter = packetWriterFactory.createPacketWriter( - streamWriter.getOutputStream()); + streamWriter); packetWriter.writeAck(new Ack(messageIds)); @@ -140,7 +139,7 @@ public class ProtocolIntegrationTest extends BriarTestCase { transportProperties, 1); packetWriter.writeTransportUpdate(tu); - streamWriter.getOutputStream().flush(); + streamWriter.flush(); return out.toByteArray(); } @@ -151,10 +150,10 @@ public class ProtocolIntegrationTest extends BriarTestCase { // FIXME: Check that the expected tag was received StreamContext ctx = new StreamContext(contactId, transportId, secret.clone(), 0, false); - StreamReader streamReader = streamReaderFactory.createStreamReader(in, + InputStream streamReader = streamReaderFactory.createStreamReader(in, MAX_FRAME_LENGTH, ctx); PacketReader packetReader = packetReaderFactory.createPacketReader( - streamReader.getInputStream()); + streamReader); // Read the ack assertTrue(packetReader.hasAck()); diff --git a/briar-tests/src/org/briarproject/transport/IncomingEncryptionLayerTest.java b/briar-tests/src/org/briarproject/crypto/StreamDecrypterImplTest.java similarity index 80% rename from briar-tests/src/org/briarproject/transport/IncomingEncryptionLayerTest.java rename to briar-tests/src/org/briarproject/crypto/StreamDecrypterImplTest.java index 8e1791785..1ee05436a 100644 --- a/briar-tests/src/org/briarproject/transport/IncomingEncryptionLayerTest.java +++ b/briar-tests/src/org/briarproject/crypto/StreamDecrypterImplTest.java @@ -1,4 +1,4 @@ -package org.briarproject.transport; +package org.briarproject.crypto; import static org.briarproject.api.transport.TransportConstants.AAD_LENGTH; import static org.briarproject.api.transport.TransportConstants.HEADER_LENGTH; @@ -14,13 +14,12 @@ import org.briarproject.api.FormatException; import org.briarproject.api.crypto.AuthenticatedCipher; import org.briarproject.api.crypto.CryptoComponent; import org.briarproject.api.crypto.SecretKey; -import org.briarproject.crypto.CryptoModule; import org.junit.Test; import com.google.inject.Guice; import com.google.inject.Injector; -public class IncomingEncryptionLayerTest extends BriarTestCase { +public class StreamDecrypterImplTest extends BriarTestCase { // FIXME: This is an integration test, not a unit test @@ -32,7 +31,7 @@ public class IncomingEncryptionLayerTest extends BriarTestCase { private final AuthenticatedCipher frameCipher; private final SecretKey frameKey; - public IncomingEncryptionLayerTest() { + public StreamDecrypterImplTest() { Injector i = Guice.createInjector(new CryptoModule(), new TestLifecycleModule(), new TestSystemModule()); crypto = i.getInstance(CryptoComponent.class); @@ -51,11 +50,11 @@ public class IncomingEncryptionLayerTest extends BriarTestCase { System.arraycopy(frame1, 0, valid, FRAME_LENGTH, FRAME_LENGTH); // Read the frames ByteArrayInputStream in = new ByteArrayInputStream(valid); - IncomingEncryptionLayer i = new IncomingEncryptionLayer(in, frameCipher, + StreamDecrypterImpl i = new StreamDecrypterImpl(in, frameCipher, frameKey, FRAME_LENGTH); - byte[] buf = new byte[FRAME_LENGTH - MAC_LENGTH]; - assertEquals(123, i.readFrame(buf)); - assertEquals(123, i.readFrame(buf)); + byte[] payload = new byte[MAX_PAYLOAD_LENGTH]; + assertEquals(123, i.readFrame(payload)); + assertEquals(123, i.readFrame(payload)); } @Test @@ -67,10 +66,10 @@ public class IncomingEncryptionLayerTest extends BriarTestCase { System.arraycopy(frame, 0, truncated, 0, FRAME_LENGTH - 1); // Try to read the frame, which should fail due to truncation ByteArrayInputStream in = new ByteArrayInputStream(truncated); - IncomingEncryptionLayer i = new IncomingEncryptionLayer(in, frameCipher, + StreamDecrypterImpl i = new StreamDecrypterImpl(in, frameCipher, frameKey, FRAME_LENGTH); try { - i.readFrame(new byte[FRAME_LENGTH - MAC_LENGTH]); + i.readFrame(new byte[MAX_PAYLOAD_LENGTH]); fail(); } catch(FormatException expected) {} } @@ -83,10 +82,10 @@ public class IncomingEncryptionLayerTest extends BriarTestCase { frame[(int) (Math.random() * FRAME_LENGTH)] ^= 1; // Try to read the frame, which should fail due to modification ByteArrayInputStream in = new ByteArrayInputStream(frame); - IncomingEncryptionLayer i = new IncomingEncryptionLayer(in, frameCipher, + StreamDecrypterImpl i = new StreamDecrypterImpl(in, frameCipher, frameKey, FRAME_LENGTH); try { - i.readFrame(new byte[FRAME_LENGTH - MAC_LENGTH]); + i.readFrame(new byte[MAX_PAYLOAD_LENGTH]); fail(); } catch(FormatException expected) {} } @@ -97,10 +96,10 @@ public class IncomingEncryptionLayerTest extends BriarTestCase { byte[] frame = generateFrame(0, FRAME_LENGTH - 1, 123, false, false); // Try to read the frame, which should fail due to invalid length ByteArrayInputStream in = new ByteArrayInputStream(frame); - IncomingEncryptionLayer i = new IncomingEncryptionLayer(in, frameCipher, + StreamDecrypterImpl i = new StreamDecrypterImpl(in, frameCipher, frameKey, FRAME_LENGTH); try { - i.readFrame(new byte[FRAME_LENGTH - MAC_LENGTH]); + i.readFrame(new byte[MAX_PAYLOAD_LENGTH]); fail(); } catch(FormatException expected) {} } @@ -111,9 +110,9 @@ public class IncomingEncryptionLayerTest extends BriarTestCase { byte[] frame = generateFrame(0, FRAME_LENGTH - 1, 123, true, false); // Read the frame ByteArrayInputStream in = new ByteArrayInputStream(frame); - IncomingEncryptionLayer i = new IncomingEncryptionLayer(in, frameCipher, + StreamDecrypterImpl i = new StreamDecrypterImpl(in, frameCipher, frameKey, FRAME_LENGTH); - int length = i.readFrame(new byte[FRAME_LENGTH - MAC_LENGTH]); + int length = i.readFrame(new byte[MAX_PAYLOAD_LENGTH]); assertEquals(123, length); } @@ -124,10 +123,10 @@ public class IncomingEncryptionLayerTest extends BriarTestCase { false, false); // Try to read the frame, which should fail due to invalid length ByteArrayInputStream in = new ByteArrayInputStream(frame); - IncomingEncryptionLayer i = new IncomingEncryptionLayer(in, frameCipher, + StreamDecrypterImpl i = new StreamDecrypterImpl(in, frameCipher, frameKey, FRAME_LENGTH); try { - i.readFrame(new byte[FRAME_LENGTH - MAC_LENGTH]); + i.readFrame(new byte[MAX_PAYLOAD_LENGTH]); fail(); } catch(FormatException expected) {} } @@ -138,10 +137,10 @@ public class IncomingEncryptionLayerTest extends BriarTestCase { byte[] frame = generateFrame(0, FRAME_LENGTH, 123, false, true); // Try to read the frame, which should fail due to bad padding ByteArrayInputStream in = new ByteArrayInputStream(frame); - IncomingEncryptionLayer i = new IncomingEncryptionLayer(in, frameCipher, + StreamDecrypterImpl i = new StreamDecrypterImpl(in, frameCipher, frameKey, FRAME_LENGTH); try { - i.readFrame(new byte[FRAME_LENGTH - MAC_LENGTH]); + i.readFrame(new byte[MAX_PAYLOAD_LENGTH]); fail(); } catch(FormatException expected) {} } @@ -158,12 +157,12 @@ public class IncomingEncryptionLayerTest extends BriarTestCase { System.arraycopy(frame1, 0, extraFrame, FRAME_LENGTH, FRAME_LENGTH); // Read the final frame, which should first read the tag ByteArrayInputStream in = new ByteArrayInputStream(extraFrame); - IncomingEncryptionLayer i = new IncomingEncryptionLayer(in, frameCipher, + StreamDecrypterImpl i = new StreamDecrypterImpl(in, frameCipher, frameKey, FRAME_LENGTH); - byte[] buf = new byte[FRAME_LENGTH - MAC_LENGTH]; - assertEquals(MAX_PAYLOAD_LENGTH, i.readFrame(buf)); + byte[] payload = new byte[MAX_PAYLOAD_LENGTH]; + assertEquals(MAX_PAYLOAD_LENGTH, i.readFrame(payload)); // The frame after the final frame should not be read - assertEquals(-1, i.readFrame(buf)); + assertEquals(-1, i.readFrame(payload)); } private byte[] generateFrame(long frameNumber, int frameLength, diff --git a/briar-tests/src/org/briarproject/transport/OutgoingEncryptionLayerTest.java b/briar-tests/src/org/briarproject/crypto/StreamEncrypterImplTest.java similarity index 88% rename from briar-tests/src/org/briarproject/transport/OutgoingEncryptionLayerTest.java rename to briar-tests/src/org/briarproject/crypto/StreamEncrypterImplTest.java index d9b734033..d4f8b33a5 100644 --- a/briar-tests/src/org/briarproject/transport/OutgoingEncryptionLayerTest.java +++ b/briar-tests/src/org/briarproject/crypto/StreamEncrypterImplTest.java @@ -1,4 +1,4 @@ -package org.briarproject.transport; +package org.briarproject.crypto; import static org.briarproject.api.transport.TransportConstants.AAD_LENGTH; import static org.briarproject.api.transport.TransportConstants.HEADER_LENGTH; @@ -15,13 +15,12 @@ import org.briarproject.TestSystemModule; import org.briarproject.api.crypto.AuthenticatedCipher; import org.briarproject.api.crypto.CryptoComponent; import org.briarproject.api.crypto.SecretKey; -import org.briarproject.crypto.CryptoModule; import org.junit.Test; import com.google.inject.Guice; import com.google.inject.Injector; -public class OutgoingEncryptionLayerTest extends BriarTestCase { +public class StreamEncrypterImplTest extends BriarTestCase { // FIXME: This is an integration test, not a unit test @@ -30,7 +29,7 @@ public class OutgoingEncryptionLayerTest extends BriarTestCase { private final CryptoComponent crypto; private final AuthenticatedCipher frameCipher; - public OutgoingEncryptionLayerTest() { + public StreamEncrypterImplTest() { Injector i = Guice.createInjector(new CryptoModule(), new TestLifecycleModule(), new TestSystemModule()); crypto = i.getInstance(CryptoComponent.class); @@ -52,9 +51,9 @@ public class OutgoingEncryptionLayerTest extends BriarTestCase { frameCipher.doFinal(plaintext, 0, plaintext.length, ciphertext, 0); // Check that the actual ciphertext matches what's expected ByteArrayOutputStream out = new ByteArrayOutputStream(); - OutgoingEncryptionLayer o = new OutgoingEncryptionLayer(out, + StreamEncrypterImpl o = new StreamEncrypterImpl(out, frameCipher, frameKey, FRAME_LENGTH, null); - o.writeFrame(new byte[FRAME_LENGTH - MAC_LENGTH], payloadLength, false); + o.writeFrame(new byte[payloadLength], payloadLength, false); byte[] actual = out.toByteArray(); assertEquals(FRAME_LENGTH, actual.length); for(int i = 0; i < FRAME_LENGTH; i++) @@ -78,9 +77,9 @@ public class OutgoingEncryptionLayerTest extends BriarTestCase { frameCipher.doFinal(plaintext, 0, plaintext.length, ciphertext, 0); // Check that the actual tag and ciphertext match what's expected ByteArrayOutputStream out = new ByteArrayOutputStream(); - OutgoingEncryptionLayer o = new OutgoingEncryptionLayer(out, + StreamEncrypterImpl o = new StreamEncrypterImpl(out, frameCipher, frameKey, FRAME_LENGTH, tag); - o.writeFrame(new byte[FRAME_LENGTH - MAC_LENGTH], payloadLength, false); + o.writeFrame(new byte[payloadLength], payloadLength, false); byte[] actual = out.toByteArray(); assertEquals(TAG_LENGTH + FRAME_LENGTH, actual.length); for(int i = 0; i < TAG_LENGTH; i++) assertEquals(tag[i], actual[i]); @@ -94,7 +93,7 @@ public class OutgoingEncryptionLayerTest extends BriarTestCase { new Random().nextBytes(tag); ByteArrayOutputStream out = new ByteArrayOutputStream(); // Initiator's constructor - OutgoingEncryptionLayer o = new OutgoingEncryptionLayer(out, + StreamEncrypterImpl o = new StreamEncrypterImpl(out, frameCipher, crypto.generateSecretKey(), FRAME_LENGTH, tag); // Write an empty final frame without having written any other frames o.writeFrame(new byte[FRAME_LENGTH - MAC_LENGTH], 0, true); diff --git a/briar-tests/src/org/briarproject/messaging/SimplexMessagingIntegrationTest.java b/briar-tests/src/org/briarproject/messaging/SimplexMessagingIntegrationTest.java index 7a24f0c94..3bce2a6e3 100644 --- a/briar-tests/src/org/briarproject/messaging/SimplexMessagingIntegrationTest.java +++ b/briar-tests/src/org/briarproject/messaging/SimplexMessagingIntegrationTest.java @@ -9,6 +9,8 @@ import static org.briarproject.api.transport.TransportConstants.TAG_LENGTH; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; +import java.io.InputStream; +import java.io.OutputStream; import java.util.Random; import org.briarproject.BriarTestCase; @@ -39,9 +41,7 @@ import org.briarproject.api.messaging.PacketWriter; import org.briarproject.api.messaging.PacketWriterFactory; import org.briarproject.api.transport.Endpoint; import org.briarproject.api.transport.StreamContext; -import org.briarproject.api.transport.StreamReader; import org.briarproject.api.transport.StreamReaderFactory; -import org.briarproject.api.transport.StreamWriter; import org.briarproject.api.transport.StreamWriterFactory; import org.briarproject.api.transport.TagRecogniser; import org.briarproject.crypto.CryptoModule; @@ -136,26 +136,27 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase { Message message = messageFactory.createAnonymousMessage(null, group, contentType, timestamp, body); db.addLocalMessage(message); + // Get a stream context + StreamContext ctx = keyManager.getStreamContext(contactId, transportId); + assertNotNull(ctx); // Create a stream writer ByteArrayOutputStream out = new ByteArrayOutputStream(); StreamWriterFactory streamWriterFactory = alice.getInstance(StreamWriterFactory.class); - StreamContext ctx = keyManager.getStreamContext(contactId, transportId); - assertNotNull(ctx); - StreamWriter streamWriter = streamWriterFactory.createStreamWriter(out, + OutputStream streamWriter = streamWriterFactory.createStreamWriter(out, MAX_FRAME_LENGTH, ctx); // Create an outgoing messaging session EventBus eventBus = alice.getInstance(EventBus.class); PacketWriterFactory packetWriterFactory = alice.getInstance(PacketWriterFactory.class); PacketWriter packetWriter = packetWriterFactory.createPacketWriter( - streamWriter.getOutputStream()); + streamWriter); MessagingSession session = new SimplexOutgoingSession(db, new ImmediateExecutor(), eventBus, contactId, transportId, MAX_LATENCY, packetWriter); // Write whatever needs to be written session.run(); - streamWriter.getOutputStream().close(); + streamWriter.close(); // Clean up keyManager.stop(); db.close(); @@ -204,7 +205,7 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase { // Create a stream reader StreamReaderFactory streamReaderFactory = bob.getInstance(StreamReaderFactory.class); - StreamReader streamReader = streamReaderFactory.createStreamReader(in, + InputStream streamReader = streamReaderFactory.createStreamReader(in, MAX_FRAME_LENGTH, ctx); // Create an incoming messaging session EventBus eventBus = bob.getInstance(EventBus.class); @@ -213,7 +214,7 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase { PacketReaderFactory packetReaderFactory = bob.getInstance(PacketReaderFactory.class); PacketReader packetReader = packetReaderFactory.createPacketReader( - streamReader.getInputStream()); + streamReader); MessagingSession session = new IncomingSession(db, new ImmediateExecutor(), new ImmediateExecutor(), eventBus, messageVerifier, contactId, transportId, packetReader); @@ -221,7 +222,7 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase { assertFalse(listener.messageAdded); // Read whatever needs to be read session.run(); - streamReader.getInputStream().close(); + streamReader.close(); // The private message from Alice should have been added assertTrue(listener.messageAdded); // Clean up diff --git a/briar-tests/src/org/briarproject/transport/StreamReaderImplTest.java b/briar-tests/src/org/briarproject/transport/StreamReaderImplTest.java index 67337a50c..988299852 100644 --- a/briar-tests/src/org/briarproject/transport/StreamReaderImplTest.java +++ b/briar-tests/src/org/briarproject/transport/StreamReaderImplTest.java @@ -4,6 +4,7 @@ import static org.briarproject.api.transport.TransportConstants.HEADER_LENGTH; import static org.briarproject.api.transport.TransportConstants.MAC_LENGTH; import org.briarproject.BriarTestCase; +import org.briarproject.api.crypto.StreamDecrypter; import org.jmock.Expectations; import org.jmock.Mockery; import org.junit.Test; @@ -17,18 +18,18 @@ public class StreamReaderImplTest extends BriarTestCase { @Test public void testEmptyFramesAreSkipped() throws Exception { Mockery context = new Mockery(); - final FrameReader reader = context.mock(FrameReader.class); + final StreamDecrypter decrypter = context.mock(StreamDecrypter.class); context.checking(new Expectations() {{ - oneOf(reader).readFrame(with(any(byte[].class))); + oneOf(decrypter).readFrame(with(any(byte[].class))); will(returnValue(0)); // Empty frame - oneOf(reader).readFrame(with(any(byte[].class))); + oneOf(decrypter).readFrame(with(any(byte[].class))); will(returnValue(2)); // Non-empty frame with two payload bytes - oneOf(reader).readFrame(with(any(byte[].class))); + oneOf(decrypter).readFrame(with(any(byte[].class))); will(returnValue(0)); // Empty frame - oneOf(reader).readFrame(with(any(byte[].class))); + oneOf(decrypter).readFrame(with(any(byte[].class))); will(returnValue(-1)); // No more frames }}); - StreamReaderImpl r = new StreamReaderImpl(reader, FRAME_LENGTH); + StreamReaderImpl r = new StreamReaderImpl(decrypter, FRAME_LENGTH); assertEquals(0, r.read()); // Skip the first empty frame, read a byte assertEquals(0, r.read()); // Read another byte assertEquals(-1, r.read()); // Skip the second empty frame, reach EOF @@ -40,18 +41,18 @@ public class StreamReaderImplTest extends BriarTestCase { @Test public void testEmptyFramesAreSkippedWithBuffer() throws Exception { Mockery context = new Mockery(); - final FrameReader reader = context.mock(FrameReader.class); + final StreamDecrypter decrypter = context.mock(StreamDecrypter.class); context.checking(new Expectations() {{ - oneOf(reader).readFrame(with(any(byte[].class))); + oneOf(decrypter).readFrame(with(any(byte[].class))); will(returnValue(0)); // Empty frame - oneOf(reader).readFrame(with(any(byte[].class))); + oneOf(decrypter).readFrame(with(any(byte[].class))); will(returnValue(2)); // Non-empty frame with two payload bytes - oneOf(reader).readFrame(with(any(byte[].class))); + oneOf(decrypter).readFrame(with(any(byte[].class))); will(returnValue(0)); // Empty frame - oneOf(reader).readFrame(with(any(byte[].class))); + oneOf(decrypter).readFrame(with(any(byte[].class))); will(returnValue(-1)); // No more frames }}); - StreamReaderImpl r = new StreamReaderImpl(reader, FRAME_LENGTH); + StreamReaderImpl r = new StreamReaderImpl(decrypter, FRAME_LENGTH); byte[] buf = new byte[MAX_PAYLOAD_LENGTH]; // Skip the first empty frame, read the two payload bytes assertEquals(2, r.read(buf)); @@ -66,14 +67,14 @@ public class StreamReaderImplTest extends BriarTestCase { @Test public void testMultipleReadsPerFrame() throws Exception { Mockery context = new Mockery(); - final FrameReader reader = context.mock(FrameReader.class); + final StreamDecrypter decrypter = context.mock(StreamDecrypter.class); context.checking(new Expectations() {{ - oneOf(reader).readFrame(with(any(byte[].class))); + oneOf(decrypter).readFrame(with(any(byte[].class))); will(returnValue(MAX_PAYLOAD_LENGTH)); // Nice long frame - oneOf(reader).readFrame(with(any(byte[].class))); + oneOf(decrypter).readFrame(with(any(byte[].class))); will(returnValue(-1)); // No more frames }}); - StreamReaderImpl r = new StreamReaderImpl(reader, FRAME_LENGTH); + StreamReaderImpl r = new StreamReaderImpl(decrypter, FRAME_LENGTH); byte[] buf = new byte[MAX_PAYLOAD_LENGTH / 2]; // Read the first half of the payload assertEquals(MAX_PAYLOAD_LENGTH / 2, r.read(buf)); @@ -88,14 +89,14 @@ public class StreamReaderImplTest extends BriarTestCase { @Test public void testMultipleReadsPerFrameWithOffsets() throws Exception { Mockery context = new Mockery(); - final FrameReader reader = context.mock(FrameReader.class); + final StreamDecrypter decrypter = context.mock(StreamDecrypter.class); context.checking(new Expectations() {{ - oneOf(reader).readFrame(with(any(byte[].class))); + oneOf(decrypter).readFrame(with(any(byte[].class))); will(returnValue(MAX_PAYLOAD_LENGTH)); // Nice long frame - oneOf(reader).readFrame(with(any(byte[].class))); + oneOf(decrypter).readFrame(with(any(byte[].class))); will(returnValue(-1)); // No more frames }}); - StreamReaderImpl r = new StreamReaderImpl(reader, FRAME_LENGTH); + StreamReaderImpl r = new StreamReaderImpl(decrypter, FRAME_LENGTH); byte[] buf = new byte[MAX_PAYLOAD_LENGTH]; // Read the first half of the payload assertEquals(MAX_PAYLOAD_LENGTH / 2, r.read(buf, MAX_PAYLOAD_LENGTH / 2, diff --git a/briar-tests/src/org/briarproject/transport/StreamWriterImplTest.java b/briar-tests/src/org/briarproject/transport/StreamWriterImplTest.java index 708769b2c..688621bd1 100644 --- a/briar-tests/src/org/briarproject/transport/StreamWriterImplTest.java +++ b/briar-tests/src/org/briarproject/transport/StreamWriterImplTest.java @@ -4,6 +4,7 @@ import static org.briarproject.api.transport.TransportConstants.HEADER_LENGTH; import static org.briarproject.api.transport.TransportConstants.MAC_LENGTH; import org.briarproject.BriarTestCase; +import org.briarproject.api.crypto.StreamEncrypter; import org.jmock.Expectations; import org.jmock.Mockery; import org.junit.Test; @@ -17,15 +18,15 @@ public class StreamWriterImplTest extends BriarTestCase { @Test public void testCloseWithoutWritingWritesFinalFrame() throws Exception { Mockery context = new Mockery(); - final FrameWriter writer = context.mock(FrameWriter.class); + final StreamEncrypter encrypter = context.mock(StreamEncrypter.class); context.checking(new Expectations() {{ // Write an empty final frame - oneOf(writer).writeFrame(with(any(byte[].class)), with(0), + oneOf(encrypter).writeFrame(with(any(byte[].class)), with(0), with(true)); // Flush the stream - oneOf(writer).flush(); + oneOf(encrypter).flush(); }}); - StreamWriterImpl w = new StreamWriterImpl(writer, FRAME_LENGTH); + StreamWriterImpl w = new StreamWriterImpl(encrypter, FRAME_LENGTH); w.close(); context.assertIsSatisfied(); } @@ -34,14 +35,14 @@ public class StreamWriterImplTest extends BriarTestCase { public void testFlushWithoutBufferedDataWritesFrameAndFlushes() throws Exception { Mockery context = new Mockery(); - final FrameWriter writer = context.mock(FrameWriter.class); - StreamWriterImpl w = new StreamWriterImpl(writer, FRAME_LENGTH); + final StreamEncrypter encrypter = context.mock(StreamEncrypter.class); + StreamWriterImpl w = new StreamWriterImpl(encrypter, FRAME_LENGTH); context.checking(new Expectations() {{ // Write a non-final frame with an empty payload - oneOf(writer).writeFrame(with(any(byte[].class)), with(0), + oneOf(encrypter).writeFrame(with(any(byte[].class)), with(0), with(false)); // Flush the stream - oneOf(writer).flush(); + oneOf(encrypter).flush(); }}); w.flush(); context.assertIsSatisfied(); @@ -49,9 +50,9 @@ public class StreamWriterImplTest extends BriarTestCase { // Clean up context.checking(new Expectations() {{ // Closing the writer writes a final frame and flushes again - oneOf(writer).writeFrame(with(any(byte[].class)), with(0), + oneOf(encrypter).writeFrame(with(any(byte[].class)), with(0), with(true)); - oneOf(writer).flush(); + oneOf(encrypter).flush(); }}); w.close(); context.assertIsSatisfied(); @@ -61,14 +62,14 @@ public class StreamWriterImplTest extends BriarTestCase { public void testFlushWithBufferedDataWritesFrameAndFlushes() throws Exception { Mockery context = new Mockery(); - final FrameWriter writer = context.mock(FrameWriter.class); - StreamWriterImpl w = new StreamWriterImpl(writer, FRAME_LENGTH); + final StreamEncrypter encrypter = context.mock(StreamEncrypter.class); + StreamWriterImpl w = new StreamWriterImpl(encrypter, FRAME_LENGTH); context.checking(new Expectations() {{ // Write a non-final frame with one payload byte - oneOf(writer).writeFrame(with(any(byte[].class)), with(1), + oneOf(encrypter).writeFrame(with(any(byte[].class)), with(1), with(false)); // Flush the stream - oneOf(writer).flush(); + oneOf(encrypter).flush(); }}); w.write(0); w.flush(); @@ -77,9 +78,9 @@ public class StreamWriterImplTest extends BriarTestCase { // Clean up context.checking(new Expectations() {{ // Closing the writer writes a final frame and flushes again - oneOf(writer).writeFrame(with(any(byte[].class)), with(0), + oneOf(encrypter).writeFrame(with(any(byte[].class)), with(0), with(true)); - oneOf(writer).flush(); + oneOf(encrypter).flush(); }}); w.close(); context.assertIsSatisfied(); @@ -88,11 +89,11 @@ public class StreamWriterImplTest extends BriarTestCase { @Test public void testSingleByteWritesWriteFullFrame() throws Exception { Mockery context = new Mockery(); - final FrameWriter writer = context.mock(FrameWriter.class); - StreamWriterImpl w = new StreamWriterImpl(writer, FRAME_LENGTH); + final StreamEncrypter encrypter = context.mock(StreamEncrypter.class); + StreamWriterImpl w = new StreamWriterImpl(encrypter, FRAME_LENGTH); context.checking(new Expectations() {{ // Write a full non-final frame - oneOf(writer).writeFrame(with(any(byte[].class)), + oneOf(encrypter).writeFrame(with(any(byte[].class)), with(MAX_PAYLOAD_LENGTH), with(false)); }}); for(int i = 0; i < MAX_PAYLOAD_LENGTH; i++) { @@ -103,9 +104,9 @@ public class StreamWriterImplTest extends BriarTestCase { // Clean up context.checking(new Expectations() {{ // Closing the writer writes a final frame and flushes again - oneOf(writer).writeFrame(with(any(byte[].class)), with(0), + oneOf(encrypter).writeFrame(with(any(byte[].class)), with(0), with(true)); - oneOf(writer).flush(); + oneOf(encrypter).flush(); }}); w.close(); context.assertIsSatisfied(); @@ -114,11 +115,11 @@ public class StreamWriterImplTest extends BriarTestCase { @Test public void testMultiByteWritesWriteFullFrames() throws Exception { Mockery context = new Mockery(); - final FrameWriter writer = context.mock(FrameWriter.class); - StreamWriterImpl w = new StreamWriterImpl(writer, FRAME_LENGTH); + final StreamEncrypter encrypter = context.mock(StreamEncrypter.class); + StreamWriterImpl w = new StreamWriterImpl(encrypter, FRAME_LENGTH); context.checking(new Expectations() {{ // Write two full non-final frames - exactly(2).of(writer).writeFrame(with(any(byte[].class)), + exactly(2).of(encrypter).writeFrame(with(any(byte[].class)), with(MAX_PAYLOAD_LENGTH), with(false)); }}); // Sanity check @@ -134,9 +135,9 @@ public class StreamWriterImplTest extends BriarTestCase { // Clean up context.checking(new Expectations() {{ // Closing the writer writes a final frame and flushes again - oneOf(writer).writeFrame(with(any(byte[].class)), with(0), + oneOf(encrypter).writeFrame(with(any(byte[].class)), with(0), with(true)); - oneOf(writer).flush(); + oneOf(encrypter).flush(); }}); w.close(); context.assertIsSatisfied(); @@ -145,17 +146,17 @@ public class StreamWriterImplTest extends BriarTestCase { @Test public void testLargeMultiByteWriteWritesFullFrames() throws Exception { Mockery context = new Mockery(); - final FrameWriter writer = context.mock(FrameWriter.class); - StreamWriterImpl w = new StreamWriterImpl(writer, FRAME_LENGTH); + final StreamEncrypter encrypter = context.mock(StreamEncrypter.class); + StreamWriterImpl w = new StreamWriterImpl(encrypter, FRAME_LENGTH); context.checking(new Expectations() {{ // Write two full non-final frames - exactly(2).of(writer).writeFrame(with(any(byte[].class)), + exactly(2).of(encrypter).writeFrame(with(any(byte[].class)), with(MAX_PAYLOAD_LENGTH), with(false)); // Write a final frame with a one-byte payload - oneOf(writer).writeFrame(with(any(byte[].class)), with(1), + oneOf(encrypter).writeFrame(with(any(byte[].class)), with(1), with(true)); // Flush the stream - oneOf(writer).flush(); + oneOf(encrypter).flush(); }}); // Write two full payloads using one large multi-byte write byte[] b = new byte[MAX_PAYLOAD_LENGTH * 2 + 1]; diff --git a/briar-tests/src/org/briarproject/transport/TestStreamDecrypter.java b/briar-tests/src/org/briarproject/transport/TestStreamDecrypter.java new file mode 100644 index 000000000..b0438801e --- /dev/null +++ b/briar-tests/src/org/briarproject/transport/TestStreamDecrypter.java @@ -0,0 +1,44 @@ +package org.briarproject.transport; + +import static org.briarproject.api.transport.TransportConstants.HEADER_LENGTH; +import static org.briarproject.api.transport.TransportConstants.MAC_LENGTH; + +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; + +import org.briarproject.api.FormatException; +import org.briarproject.api.crypto.StreamDecrypter; +import org.briarproject.util.ByteUtils; + +class TestStreamDecrypter implements StreamDecrypter { + + private final InputStream in; + private final byte[] frame; + + TestStreamDecrypter(InputStream in, int frameLength) { + this.in = in; + frame = new byte[frameLength]; + } + + public int readFrame(byte[] payload) throws IOException { + int offset = 0; + while(offset < HEADER_LENGTH) { + int read = in.read(frame, offset, HEADER_LENGTH - offset); + if(read == -1) throw new EOFException(); + offset += read; + } + boolean finalFrame = (frame[0] & 0x80) == 0x80; + int payloadLength = ByteUtils.readUint16(frame, 0) & 0x7FFF; + while(offset < frame.length) { + int read = in.read(frame, offset, frame.length - offset); + if(read == -1) break; + offset += read; + } + if(!finalFrame && offset < frame.length) throw new EOFException(); + if(offset < HEADER_LENGTH + payloadLength + MAC_LENGTH) + throw new FormatException(); + System.arraycopy(frame, HEADER_LENGTH, payload, 0, payloadLength); + return payloadLength; + } +} diff --git a/briar-tests/src/org/briarproject/transport/TestStreamEncrypter.java b/briar-tests/src/org/briarproject/transport/TestStreamEncrypter.java new file mode 100644 index 000000000..4ad4c667c --- /dev/null +++ b/briar-tests/src/org/briarproject/transport/TestStreamEncrypter.java @@ -0,0 +1,44 @@ +package org.briarproject.transport; + +import static org.briarproject.api.transport.TransportConstants.HEADER_LENGTH; +import static org.briarproject.api.transport.TransportConstants.MAC_LENGTH; + +import java.io.IOException; +import java.io.OutputStream; + +import org.briarproject.api.crypto.StreamEncrypter; +import org.briarproject.util.ByteUtils; + +class TestStreamEncrypter implements StreamEncrypter { + + private final OutputStream out; + private final byte[] tag, frame; + + private boolean writeTag = true; + + TestStreamEncrypter(OutputStream out, int frameLength, byte[] tag) { + this.out = out; + this.tag = tag; + frame = new byte[frameLength]; + } + + public void writeFrame(byte[] payload, int payloadLength, + boolean finalFrame) throws IOException { + if(writeTag) { + out.write(tag); + writeTag = false; + } + ByteUtils.writeUint16(payloadLength, frame, 0); + if(finalFrame) frame[0] |= 0x80; + System.arraycopy(payload, 0, frame, HEADER_LENGTH, payloadLength); + for(int i = HEADER_LENGTH + payloadLength; i < frame.length; i++) + frame[i] = 0; + if(finalFrame) + out.write(frame, 0, HEADER_LENGTH + payloadLength + MAC_LENGTH); + else out.write(frame, 0, frame.length); + } + + public void flush() throws IOException { + out.flush(); + } +} diff --git a/briar-tests/src/org/briarproject/transport/TransportIntegrationTest.java b/briar-tests/src/org/briarproject/transport/TransportIntegrationTest.java index 19153db75..f55e5b6e1 100644 --- a/briar-tests/src/org/briarproject/transport/TransportIntegrationTest.java +++ b/briar-tests/src/org/briarproject/transport/TransportIntegrationTest.java @@ -11,48 +11,18 @@ import java.io.OutputStream; import java.util.Random; import org.briarproject.BriarTestCase; -import org.briarproject.TestLifecycleModule; -import org.briarproject.TestSystemModule; -import org.briarproject.api.crypto.AuthenticatedCipher; -import org.briarproject.api.crypto.CryptoComponent; -import org.briarproject.api.crypto.SecretKey; -import org.briarproject.api.transport.StreamWriterFactory; -import org.briarproject.crypto.CryptoModule; +import org.briarproject.api.crypto.StreamDecrypter; +import org.briarproject.api.crypto.StreamEncrypter; import org.junit.Test; -import com.google.inject.AbstractModule; -import com.google.inject.Guice; -import com.google.inject.Injector; -import com.google.inject.Module; - public class TransportIntegrationTest extends BriarTestCase { private final int FRAME_LENGTH = 2048; - private final CryptoComponent crypto; - private final AuthenticatedCipher frameCipher; private final Random random; - private final byte[] secret; - private final SecretKey tagKey, frameKey; public TransportIntegrationTest() { - Module testModule = new AbstractModule() { - @Override - public void configure() { - bind(StreamWriterFactory.class).to( - StreamWriterFactoryImpl.class); - } - }; - Injector i = Guice.createInjector(testModule, new CryptoModule(), - new TestLifecycleModule(), new TestSystemModule()); - crypto = i.getInstance(CryptoComponent.class); - frameCipher = crypto.getFrameCipher(); random = new Random(); - // Since we're sending frames to ourselves, we only need outgoing keys - secret = new byte[32]; - random.nextBytes(secret); - tagKey = crypto.deriveTagKey(secret, true); - frameKey = crypto.deriveFrameKey(secret, 0, true); } @Test @@ -66,27 +36,24 @@ public class TransportIntegrationTest extends BriarTestCase { } private void testWriteAndRead(boolean initiator) throws Exception { - // Encode the tag + // Generate a random tag byte[] tag = new byte[TAG_LENGTH]; - crypto.encodeTag(tag, tagKey, 0); - // Generate two random frames - byte[] frame = new byte[1234]; - random.nextBytes(frame); - byte[] frame1 = new byte[321]; - random.nextBytes(frame1); - // Copy the frame key - the copy will be erased - SecretKey frameCopy = frameKey.copy(); + random.nextBytes(tag); + // Generate two frames with random payloads + byte[] payload1 = new byte[1234]; + random.nextBytes(payload1); + byte[] payload2 = new byte[321]; + random.nextBytes(payload2); // Write the tag and the frames ByteArrayOutputStream out = new ByteArrayOutputStream(); - FrameWriter frameWriter = new OutgoingEncryptionLayer(out, - frameCipher, frameCopy, FRAME_LENGTH, tag); - StreamWriterImpl streamWriter = new StreamWriterImpl(frameWriter, + StreamEncrypter encrypter = new TestStreamEncrypter(out, FRAME_LENGTH, + tag); + OutputStream streamWriter = new StreamWriterImpl(encrypter, FRAME_LENGTH); - OutputStream out1 = streamWriter.getOutputStream(); - out1.write(frame); - out1.flush(); - out1.write(frame1); - out1.flush(); + streamWriter.write(payload1); + streamWriter.flush(); + streamWriter.write(payload2); + streamWriter.flush(); byte[] output = out.toByteArray(); assertEquals(TAG_LENGTH + FRAME_LENGTH * 2, output.length); // Read the tag back @@ -95,17 +62,15 @@ public class TransportIntegrationTest extends BriarTestCase { read(in, recoveredTag); assertArrayEquals(tag, recoveredTag); // Read the frames back - FrameReader frameReader = new IncomingEncryptionLayer(in, frameCipher, - frameKey, FRAME_LENGTH); - StreamReaderImpl streamReader = new StreamReaderImpl(frameReader, + StreamDecrypter decrypter = new TestStreamDecrypter(in, FRAME_LENGTH); + InputStream streamReader = new StreamReaderImpl(decrypter, FRAME_LENGTH); - InputStream in1 = streamReader.getInputStream(); - byte[] recoveredFrame = new byte[frame.length]; - read(in1, recoveredFrame); - assertArrayEquals(frame, recoveredFrame); - byte[] recoveredFrame1 = new byte[frame1.length]; - read(in1, recoveredFrame1); - assertArrayEquals(frame1, recoveredFrame1); + byte[] recoveredPayload1 = new byte[payload1.length]; + read(streamReader, recoveredPayload1); + assertArrayEquals(payload1, recoveredPayload1); + byte[] recoveredPayload2 = new byte[payload2.length]; + read(streamReader, recoveredPayload2); + assertArrayEquals(payload2, recoveredPayload2); streamWriter.close(); streamReader.close(); } From 358166bc129650e588ae5fa3b64787083c5cf1cf Mon Sep 17 00:00:00 2001 From: akwizgran Date: Mon, 29 Dec 2014 21:08:27 +0000 Subject: [PATCH 06/10] Don't try to erase secrets from memory. 1. The things we're really trying to protect - contact identities, message contents, etc - can't be erased from memory because they're encapsulated inside objects we don't control. 2. Long-term secrets can't be protected by erasing them from memory because they're stored in the database and the database key has to be held in memory whenever the app's running. 3. If the runtime uses a compacting garbage collector then we have no way to ensure an object is erased from memory. 4. Trying to erase secrets from memory makes the code more complex. Conclusion: Let's not try to protect secrets from an attacker who can read arbitrary memory locations. --- .../android/PasswordActivity.java | 5 +- .../briarproject/android/SetupActivity.java | 35 +-- .../api/crypto/CryptoComponent.java | 4 +- .../briarproject/api/crypto/KeyManager.java | 5 +- .../api/crypto/PasswordStrengthEstimator.java | 2 +- .../briarproject/api/crypto/SecretKey.java | 22 +- .../crypto/AuthenticatedCipherImpl.java | 2 +- .../crypto/CryptoComponentImpl.java | 57 +---- .../crypto/PasswordStrengthEstimatorImpl.java | 5 +- .../briarproject/crypto/SecretKeyImpl.java | 30 --- .../crypto/StreamDecrypterImpl.java | 15 +- .../crypto/StreamEncrypterFactoryImpl.java | 1 - .../crypto/StreamEncrypterImpl.java | 21 +- .../src/org/briarproject/db/H2Database.java | 26 +-- .../plugins/ConnectionManagerImpl.java | 41 ++-- .../transport/KeyManagerImpl.java | 90 +++---- .../transport/TransportTagRecogniser.java | 7 +- .../src/org/briarproject/util/ByteUtils.java | 4 - briar-tests/build.xml | 3 +- .../briarproject/ProtocolIntegrationTest.java | 8 +- .../crypto/KeyDerivationTest.java | 9 +- .../crypto/PasswordBasedKdfTest.java | 4 +- ...=> PasswordStrengthEstimatorImplTest.java} | 15 +- .../crypto/SecretKeyImplTest.java | 27 --- .../SimplexMessagingIntegrationTest.java | 4 +- .../transport/KeyManagerImplTest.java | 100 ++++---- .../transport/KeyRotationIntegrationTest.java | 219 ++++-------------- .../transport/TransportTagRecogniserTest.java | 7 +- 28 files changed, 211 insertions(+), 557 deletions(-) delete mode 100644 briar-core/src/org/briarproject/crypto/SecretKeyImpl.java rename briar-tests/src/org/briarproject/crypto/{PasswordStrengthEstimatorTest.java => PasswordStrengthEstimatorImplTest.java} (50%) delete mode 100644 briar-tests/src/org/briarproject/crypto/SecretKeyImplTest.java diff --git a/briar-android/src/org/briarproject/android/PasswordActivity.java b/briar-android/src/org/briarproject/android/PasswordActivity.java index 26ac3dee0..727985f1b 100644 --- a/briar-android/src/org/briarproject/android/PasswordActivity.java +++ b/briar-android/src/org/briarproject/android/PasswordActivity.java @@ -133,10 +133,7 @@ public class PasswordActivity extends RoboActivity { continueButton.setVisibility(GONE); progress.setVisibility(VISIBLE); // Decrypt the database key in a background thread - int length = e.length(); - final char[] password = new char[length]; - e.getChars(0, length, password, 0); - e.delete(0, length); + final String password = e.toString(); cryptoExecutor.execute(new Runnable() { public void run() { byte[] key = crypto.decryptWithPassword(encrypted, password); diff --git a/briar-android/src/org/briarproject/android/SetupActivity.java b/briar-android/src/org/briarproject/android/SetupActivity.java index a71442eeb..109ce0cee 100644 --- a/briar-android/src/org/briarproject/android/SetupActivity.java +++ b/briar-android/src/org/briarproject/android/SetupActivity.java @@ -19,7 +19,6 @@ import static org.briarproject.android.util.CommonLayoutParams.WRAP_WRAP; import static org.briarproject.api.AuthorConstants.MAX_AUTHOR_NAME_LENGTH; import static org.briarproject.api.crypto.PasswordStrengthEstimator.WEAK; -import java.util.Arrays; import java.util.concurrent.Executor; import java.util.logging.Logger; @@ -43,7 +42,6 @@ import android.content.Intent; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.os.Bundle; -import android.text.Editable; import android.view.KeyEvent; import android.view.View; import android.view.View.OnClickListener; @@ -187,18 +185,16 @@ OnEditorActionListener { else strengthMeter.setVisibility(INVISIBLE); String nickname = nicknameEntry.getText().toString(); int nicknameLength = StringUtils.toUtf8(nickname).length; - char[] firstPassword = getChars(passwordEntry.getText()); - char[] secondPassword = getChars(passwordConfirmation.getText()); - boolean passwordsMatch = Arrays.equals(firstPassword, secondPassword); + String firstPassword = passwordEntry.getText().toString(); + String secondPassword = passwordConfirmation.getText().toString(); + boolean passwordsMatch = firstPassword.equals(secondPassword); float strength = strengthEstimator.estimateStrength(firstPassword); - for(int i = 0; i < firstPassword.length; i++) firstPassword[i] = 0; - for(int i = 0; i < secondPassword.length; i++) secondPassword[i] = 0; strengthMeter.setStrength(strength); if(nicknameLength > MAX_AUTHOR_NAME_LENGTH) { feedback.setText(R.string.name_too_long); - } else if(firstPassword.length == 0) { + } else if(firstPassword.length() == 0) { feedback.setText(""); - } else if(secondPassword.length == 0 || passwordsMatch) { + } else if(secondPassword.length() == 0 || passwordsMatch) { if(strength < PasswordStrengthEstimator.WEAK) feedback.setText(R.string.password_too_weak); else feedback.setText(""); @@ -212,13 +208,6 @@ OnEditorActionListener { && passwordsMatch && strength >= WEAK); } - private char[] getChars(Editable e) { - int length = e.length(); - char[] c = new char[length]; - e.getChars(0, length, c, 0); - return c; - } - public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { // Hide the soft keyboard Object o = getSystemService(INPUT_METHOD_SERVICE); @@ -231,18 +220,14 @@ OnEditorActionListener { feedback.setVisibility(GONE); continueButton.setVisibility(GONE); progress.setVisibility(VISIBLE); - // Copy the passwords and erase the originals final String nickname = nicknameEntry.getText().toString(); - final char[] password = getChars(passwordEntry.getText()); - delete(passwordEntry.getText()); - delete(passwordConfirmation.getText()); + final String password = passwordEntry.getText().toString(); // Store the DB key and create the identity in a background thread cryptoExecutor.execute(new Runnable() { public void run() { - byte[] key = crypto.generateSecretKey().getEncoded(); + byte[] key = crypto.generateSecretKey().getBytes(); databaseConfig.setEncryptionKey(key); byte[] encrypted = encryptDatabaseKey(key, password); - for(int i = 0; i < password.length; i++) password[i] = 0; storeEncryptedDatabaseKey(encrypted); LocalAuthor localAuthor = createLocalAuthor(nickname); showDashboard(referenceManager.putReference(localAuthor, @@ -251,10 +236,6 @@ OnEditorActionListener { }); } - private void delete(Editable e) { - e.delete(0, e.length()); - } - private void storeEncryptedDatabaseKey(final byte[] encrypted) { long now = System.currentTimeMillis(); SharedPreferences prefs = getSharedPreferences("db", MODE_PRIVATE); @@ -266,7 +247,7 @@ OnEditorActionListener { LOG.info("Key storage took " + duration + " ms"); } - private byte[] encryptDatabaseKey(byte[] key, char[] password) { + private byte[] encryptDatabaseKey(byte[] key, String password) { long now = System.currentTimeMillis(); byte[] encrypted = crypto.encryptWithPassword(key, password); long duration = System.currentTimeMillis() - now; diff --git a/briar-api/src/org/briarproject/api/crypto/CryptoComponent.java b/briar-api/src/org/briarproject/api/crypto/CryptoComponent.java index ba9c86224..558077ae4 100644 --- a/briar-api/src/org/briarproject/api/crypto/CryptoComponent.java +++ b/briar-api/src/org/briarproject/api/crypto/CryptoComponent.java @@ -89,7 +89,7 @@ public interface CryptoComponent { * given password. The ciphertext will be decryptable using the same * password after the app restarts. */ - byte[] encryptWithPassword(byte[] plaintext, char[] password); + byte[] encryptWithPassword(byte[] plaintext, String password); /** * Decrypts and authenticates the given ciphertext that has been read from @@ -97,5 +97,5 @@ public interface CryptoComponent { * given password. Returns null if the ciphertext cannot be decrypted and * authenticated (for example, if the password is wrong). */ - byte[] decryptWithPassword(byte[] ciphertext, char[] password); + byte[] decryptWithPassword(byte[] ciphertext, String password); } diff --git a/briar-api/src/org/briarproject/api/crypto/KeyManager.java b/briar-api/src/org/briarproject/api/crypto/KeyManager.java index 77c41132e..02a43e970 100644 --- a/briar-api/src/org/briarproject/api/crypto/KeyManager.java +++ b/briar-api/src/org/briarproject/api/crypto/KeyManager.java @@ -16,9 +16,6 @@ public interface KeyManager extends Service { */ StreamContext getStreamContext(ContactId c, TransportId t); - /** - * Called whenever an endpoint has been added. The initial secret is erased - * before returning. - */ + /** Called whenever an endpoint has been added. */ void endpointAdded(Endpoint ep, int maxLatency, byte[] initialSecret); } diff --git a/briar-api/src/org/briarproject/api/crypto/PasswordStrengthEstimator.java b/briar-api/src/org/briarproject/api/crypto/PasswordStrengthEstimator.java index 9ffa2dc24..93d27a6b3 100644 --- a/briar-api/src/org/briarproject/api/crypto/PasswordStrengthEstimator.java +++ b/briar-api/src/org/briarproject/api/crypto/PasswordStrengthEstimator.java @@ -12,5 +12,5 @@ public interface PasswordStrengthEstimator { * Returns an estimate between 0 (weakest) and 1 (strongest), inclusive, * of the strength of the given password. */ - float estimateStrength(char[] password); + float estimateStrength(String password); } diff --git a/briar-api/src/org/briarproject/api/crypto/SecretKey.java b/briar-api/src/org/briarproject/api/crypto/SecretKey.java index 63d1f7661..62b75a945 100644 --- a/briar-api/src/org/briarproject/api/crypto/SecretKey.java +++ b/briar-api/src/org/briarproject/api/crypto/SecretKey.java @@ -1,21 +1,15 @@ package org.briarproject.api.crypto; /** A secret key used for encryption and/or authentication. */ -public interface SecretKey { +public class SecretKey { - /** Returns the encoded representation of this key. */ - byte[] getEncoded(); + private final byte[] key; - /** - * Returns a copy of this key - erasing this key will erase the copy and - * vice versa. - */ - SecretKey copy(); + public SecretKey(byte[] key) { + this.key = key; + } - /** - * Erases this key from memory. Any copies derived from this key via the - * {@link #copy()} method, and any keys from which this key was derived via - * the {@link #copy()} method, are also erased. - */ - void erase(); + public byte[] getBytes() { + return key; + } } diff --git a/briar-core/src/org/briarproject/crypto/AuthenticatedCipherImpl.java b/briar-core/src/org/briarproject/crypto/AuthenticatedCipherImpl.java index 93807087d..bf80ca8c5 100644 --- a/briar-core/src/org/briarproject/crypto/AuthenticatedCipherImpl.java +++ b/briar-core/src/org/briarproject/crypto/AuthenticatedCipherImpl.java @@ -38,7 +38,7 @@ class AuthenticatedCipherImpl implements AuthenticatedCipher { public void init(boolean encrypt, SecretKey key, byte[] iv, byte[] aad) throws GeneralSecurityException { - KeyParameter k = new KeyParameter(key.getEncoded()); + KeyParameter k = new KeyParameter(key.getBytes()); AEADParameters params = new AEADParameters(k, macLength * 8, iv, aad); try { cipher.init(encrypt, params); diff --git a/briar-core/src/org/briarproject/crypto/CryptoComponentImpl.java b/briar-core/src/org/briarproject/crypto/CryptoComponentImpl.java index 4edd26a4f..29442f311 100644 --- a/briar-core/src/org/briarproject/crypto/CryptoComponentImpl.java +++ b/briar-core/src/org/briarproject/crypto/CryptoComponentImpl.java @@ -7,8 +7,6 @@ import static org.briarproject.crypto.EllipticCurveConstants.P; import static org.briarproject.crypto.EllipticCurveConstants.PARAMETERS; import static org.briarproject.util.ByteUtils.MAX_32_BIT_UNSIGNED; -import java.io.ByteArrayOutputStream; -import java.io.IOException; import java.security.GeneralSecurityException; import java.security.SecureRandom; import java.util.ArrayList; @@ -31,6 +29,7 @@ import org.briarproject.api.crypto.SecretKey; import org.briarproject.api.crypto.Signature; import org.briarproject.api.system.SeedProvider; import org.briarproject.util.ByteUtils; +import org.briarproject.util.StringUtils; import org.spongycastle.crypto.AsymmetricCipherKeyPair; import org.spongycastle.crypto.BlockCipher; import org.spongycastle.crypto.CipherParameters; @@ -48,7 +47,6 @@ import org.spongycastle.crypto.params.ECKeyGenerationParameters; import org.spongycastle.crypto.params.ECPrivateKeyParameters; import org.spongycastle.crypto.params.ECPublicKeyParameters; import org.spongycastle.crypto.params.KeyParameter; -import org.spongycastle.util.Strings; class CryptoComponentImpl implements CryptoComponent { @@ -114,7 +112,7 @@ class CryptoComponentImpl implements CryptoComponent { public SecretKey generateSecretKey() { byte[] b = new byte[CIPHER_KEY_BYTES]; secureRandom.nextBytes(b); - return new SecretKeyImpl(b); + return new SecretKey(b); } public MessageDigest getMessageDigest() { @@ -188,8 +186,6 @@ class CryptoComponentImpl implements CryptoComponent { int[] codes = new int[2]; codes[0] = ByteUtils.readUint(alice, CODE_BITS); codes[1] = ByteUtils.readUint(bob, CODE_BITS); - ByteUtils.erase(alice); - ByteUtils.erase(bob); return codes; } @@ -223,9 +219,7 @@ class CryptoComponentImpl implements CryptoComponent { byte[] raw = deriveSharedSecret(ourPriv, theirPub); // Derive the cooked secret from the raw secret using the // concatenation KDF - byte[] cooked = concatenationKdf(raw, MASTER, aliceInfo, bobInfo); - ByteUtils.erase(raw); - return cooked; + return concatenationKdf(raw, MASTER, aliceInfo, bobInfo); } // Package access for testing @@ -296,8 +290,7 @@ class CryptoComponentImpl implements CryptoComponent { } private SecretKey deriveKey(byte[] secret, byte[] label, long context) { - byte[] key = counterModeKdf(secret, label, context); - return new SecretKeyImpl(key); + return new SecretKey(counterModeKdf(secret, label, context)); } public AuthenticatedCipher getFrameCipher() { @@ -313,21 +306,19 @@ class CryptoComponentImpl implements CryptoComponent { ByteUtils.writeUint32(streamNumber, tag, 0); BlockCipher cipher = new AESLightEngine(); assert cipher.getBlockSize() == TAG_LENGTH; - KeyParameter k = new KeyParameter(tagKey.getEncoded()); + KeyParameter k = new KeyParameter(tagKey.getBytes()); cipher.init(true, k); cipher.processBlock(tag, 0, tag, 0); - ByteUtils.erase(k.getKey()); } - public byte[] encryptWithPassword(byte[] input, char[] password) { + public byte[] encryptWithPassword(byte[] input, String password) { // Generate a random salt byte[] salt = new byte[PBKDF_SALT_BYTES]; secureRandom.nextBytes(salt); // Calibrate the KDF int iterations = chooseIterationCount(PBKDF_TARGET_MILLIS); // Derive the key from the password - byte[] keyBytes = pbkdf2(password, salt, iterations); - SecretKey key = new SecretKeyImpl(keyBytes); + SecretKey key = new SecretKey(pbkdf2(password, salt, iterations)); // Generate a random IV byte[] iv = new byte[STORAGE_IV_BYTES]; secureRandom.nextBytes(iv); @@ -348,12 +339,10 @@ class CryptoComponentImpl implements CryptoComponent { return output; } catch(GeneralSecurityException e) { throw new RuntimeException(e); - } finally { - key.erase(); } } - public byte[] decryptWithPassword(byte[] input, char[] password) { + public byte[] decryptWithPassword(byte[] input, String password) { // The input contains the salt, iterations, IV, ciphertext and MAC if(input.length < PBKDF_SALT_BYTES + 4 + STORAGE_IV_BYTES + MAC_BYTES) return null; // Invalid @@ -365,8 +354,7 @@ class CryptoComponentImpl implements CryptoComponent { byte[] iv = new byte[STORAGE_IV_BYTES]; System.arraycopy(input, salt.length + 4, iv, 0, iv.length); // Derive the key from the password - byte[] keyBytes = pbkdf2(password, salt, (int) iterations); - SecretKey key = new SecretKeyImpl(keyBytes); + SecretKey key = new SecretKey(pbkdf2(password, salt, (int) iterations)); // Initialise the cipher AuthenticatedCipher cipher; try { @@ -374,7 +362,6 @@ class CryptoComponentImpl implements CryptoComponent { cipher = new AuthenticatedCipherImpl(a, MAC_BYTES); cipher.init(false, key, iv, null); } catch(GeneralSecurityException e) { - key.erase(); throw new RuntimeException(e); } // Try to decrypt the ciphertext (may be invalid) @@ -385,9 +372,7 @@ class CryptoComponentImpl implements CryptoComponent { cipher.doFinal(input, inputOff, inputLen, output, 0); return output; } catch(GeneralSecurityException e) { - return null; // Invalid - } finally { - key.erase(); + return null; // Invalid ciphertext } } @@ -417,7 +402,6 @@ class CryptoComponentImpl implements CryptoComponent { // The secret is the first CIPHER_KEY_BYTES bytes of the hash byte[] output = new byte[CIPHER_KEY_BYTES]; System.arraycopy(hash, 0, output, 0, output.length); - ByteUtils.erase(hash); return output; } @@ -447,20 +431,17 @@ class CryptoComponentImpl implements CryptoComponent { prf.update((byte) CIPHER_KEY_BYTES); // Output length prf.doFinal(mac, 0); System.arraycopy(mac, 0, output, 0, output.length); - ByteUtils.erase(mac); - ByteUtils.erase(k.getKey()); return output; } // Password-based key derivation function - see PKCS#5 v2.1, section 5.2 - private byte[] pbkdf2(char[] password, byte[] salt, int iterations) { - byte[] utf8 = toUtf8ByteArray(password); + private byte[] pbkdf2(String password, byte[] salt, int iterations) { + byte[] utf8 = StringUtils.toUtf8(password); Digest digest = new SHA384Digest(); PKCS5S2ParametersGenerator gen = new PKCS5S2ParametersGenerator(digest); gen.init(utf8, salt, iterations); int keyLengthInBits = CIPHER_KEY_BYTES * 8; CipherParameters p = gen.generateDerivedParameters(keyLengthInBits); - ByteUtils.erase(utf8); return ((KeyParameter) p).getKey(); } @@ -512,18 +493,4 @@ class CryptoComponentImpl implements CryptoComponent { if(size % 2 == 1) return list.get(size / 2); return list.get(size / 2 - 1) + list.get(size / 2) / 2; } - - private byte[] toUtf8ByteArray(char[] c) { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - try { - Strings.toUTF8ByteArray(c, out); - byte[] utf8 = out.toByteArray(); - // Erase the output stream's buffer - out.reset(); - out.write(new byte[utf8.length]); - return utf8; - } catch(IOException e) { - throw new RuntimeException(e); - } - } } diff --git a/briar-core/src/org/briarproject/crypto/PasswordStrengthEstimatorImpl.java b/briar-core/src/org/briarproject/crypto/PasswordStrengthEstimatorImpl.java index aeec2ddc3..1fd99f52b 100644 --- a/briar-core/src/org/briarproject/crypto/PasswordStrengthEstimatorImpl.java +++ b/briar-core/src/org/briarproject/crypto/PasswordStrengthEstimatorImpl.java @@ -13,9 +13,10 @@ class PasswordStrengthEstimatorImpl implements PasswordStrengthEstimator { private static final double STRONG = Math.log(Math.pow(LOWER + UPPER + DIGIT + OTHER, 10)); - public float estimateStrength(char[] password) { + public float estimateStrength(String password) { HashSet unique = new HashSet(); - for(char c : password) unique.add(c); + int length = password.length(); + for(int i = 0; i < length; i++) unique.add(password.charAt(i)); boolean lower = false, upper = false, digit = false, other = false; for(char c : unique) { if(Character.isLowerCase(c)) lower = true; diff --git a/briar-core/src/org/briarproject/crypto/SecretKeyImpl.java b/briar-core/src/org/briarproject/crypto/SecretKeyImpl.java deleted file mode 100644 index d7cdbdf05..000000000 --- a/briar-core/src/org/briarproject/crypto/SecretKeyImpl.java +++ /dev/null @@ -1,30 +0,0 @@ -package org.briarproject.crypto; - -import org.briarproject.api.crypto.SecretKey; -import org.briarproject.util.ByteUtils; - -class SecretKeyImpl implements SecretKey { - - private final byte[] key; - - private boolean erased = false; // Locking: this - - SecretKeyImpl(byte[] key) { - this.key = key; - } - - public synchronized byte[] getEncoded() { - if(erased) throw new IllegalStateException(); - return key; - } - - public SecretKey copy() { - return new SecretKeyImpl(key.clone()); - } - - public synchronized void erase() { - if(erased) throw new IllegalStateException(); - ByteUtils.erase(key); - erased = true; - } -} diff --git a/briar-core/src/org/briarproject/crypto/StreamDecrypterImpl.java b/briar-core/src/org/briarproject/crypto/StreamDecrypterImpl.java index ff29697df..4127e99a7 100644 --- a/briar-core/src/org/briarproject/crypto/StreamDecrypterImpl.java +++ b/briar-core/src/org/briarproject/crypto/StreamDecrypterImpl.java @@ -44,16 +44,11 @@ class StreamDecrypterImpl implements StreamDecrypter { if(finalFrame) return -1; // Read the frame int ciphertextLength = 0; - try { - while(ciphertextLength < frameLength) { - int read = in.read(ciphertext, ciphertextLength, - frameLength - ciphertextLength); - if(read == -1) break; // We'll check the length later - ciphertextLength += read; - } - } catch(IOException e) { - frameKey.erase(); - throw e; + while(ciphertextLength < frameLength) { + int read = in.read(ciphertext, ciphertextLength, + frameLength - ciphertextLength); + if(read == -1) break; // We'll check the length later + ciphertextLength += read; } int plaintextLength = ciphertextLength - MAC_LENGTH; if(plaintextLength < HEADER_LENGTH) throw new EOFException(); diff --git a/briar-core/src/org/briarproject/crypto/StreamEncrypterFactoryImpl.java b/briar-core/src/org/briarproject/crypto/StreamEncrypterFactoryImpl.java index 979ebb17c..07c9deaab 100644 --- a/briar-core/src/org/briarproject/crypto/StreamEncrypterFactoryImpl.java +++ b/briar-core/src/org/briarproject/crypto/StreamEncrypterFactoryImpl.java @@ -30,7 +30,6 @@ class StreamEncrypterFactoryImpl implements StreamEncrypterFactory { byte[] tag = new byte[TAG_LENGTH]; SecretKey tagKey = crypto.deriveTagKey(secret, alice); crypto.encodeTag(tag, tagKey, streamNumber); - tagKey.erase(); // Derive the frame key SecretKey frameKey = crypto.deriveFrameKey(secret, streamNumber, alice); // Create the encrypter diff --git a/briar-core/src/org/briarproject/crypto/StreamEncrypterImpl.java b/briar-core/src/org/briarproject/crypto/StreamEncrypterImpl.java index d3e2e43ce..43a640391 100644 --- a/briar-core/src/org/briarproject/crypto/StreamEncrypterImpl.java +++ b/briar-core/src/org/briarproject/crypto/StreamEncrypterImpl.java @@ -45,12 +45,7 @@ class StreamEncrypterImpl implements StreamEncrypter { if(frameNumber > MAX_32_BIT_UNSIGNED) throw new IllegalStateException(); // Write the tag if required if(writeTag) { - try { - out.write(tag, 0, tag.length); - } catch(IOException e) { - frameKey.erase(); - throw e; - } + out.write(tag, 0, tag.length); writeTag = false; } // Don't pad the final frame @@ -81,24 +76,14 @@ class StreamEncrypterImpl implements StreamEncrypter { throw new RuntimeException(badCipher); } // Write the frame - try { - out.write(ciphertext, 0, ciphertextLength); - } catch(IOException e) { - frameKey.erase(); - throw e; - } + out.write(ciphertext, 0, ciphertextLength); frameNumber++; } public void flush() throws IOException { // Write the tag if required if(writeTag) { - try { - out.write(tag, 0, tag.length); - } catch(IOException e) { - frameKey.erase(); - throw e; - } + out.write(tag, 0, tag.length); writeTag = false; } out.flush(); diff --git a/briar-core/src/org/briarproject/db/H2Database.java b/briar-core/src/org/briarproject/db/H2Database.java index d7f064ddb..fc91e20dc 100644 --- a/briar-core/src/org/briarproject/db/H2Database.java +++ b/briar-core/src/org/briarproject/db/H2Database.java @@ -81,34 +81,18 @@ class H2Database extends JdbcDatabase { } } + @Override protected Connection createConnection() throws SQLException { byte[] key = config.getEncryptionKey(); if(key == null) throw new IllegalStateException(); - char[] password = encodePassword(key); Properties props = new Properties(); props.setProperty("user", "user"); - props.put("password", password); - try { - return DriverManager.getConnection(url, props); - } finally { - for(int i = 0; i < password.length; i++) password[i] = 0; - } - } - - private char[] encodePassword(byte[] key) { - // The database password is the hex-encoded key - char[] hex = StringUtils.toHexChars(key); - // Separate the database password from the user password with a space - char[] user = "password".toCharArray(); - char[] combined = new char[hex.length + 1 + user.length]; - System.arraycopy(hex, 0, combined, 0, hex.length); - combined[hex.length] = ' '; - System.arraycopy(user, 0, combined, hex.length + 1, user.length); - // Erase the hex-encoded key - for(int i = 0; i < hex.length; i++) hex[i] = 0; - return combined; + // Separate the file password from the user password with a space + props.put("password", StringUtils.toHexString(key) + " password"); + return DriverManager.getConnection(url, props); } + @Override protected void flushBuffersToDisk(Statement s) throws SQLException { // FIXME: Remove this after implementing BTPv2? s.execute("CHECKPOINT SYNC"); diff --git a/briar-core/src/org/briarproject/plugins/ConnectionManagerImpl.java b/briar-core/src/org/briarproject/plugins/ConnectionManagerImpl.java index b72efb688..2b1a5c633 100644 --- a/briar-core/src/org/briarproject/plugins/ConnectionManagerImpl.java +++ b/briar-core/src/org/briarproject/plugins/ConnectionManagerImpl.java @@ -28,7 +28,6 @@ import org.briarproject.api.transport.StreamContext; import org.briarproject.api.transport.StreamReaderFactory; import org.briarproject.api.transport.StreamWriterFactory; import org.briarproject.api.transport.TagRecogniser; -import org.briarproject.util.ByteUtils; class ConnectionManagerImpl implements ConnectionManager { @@ -95,40 +94,28 @@ class ConnectionManagerImpl implements ConnectionManager { private MessagingSession createIncomingSession(StreamContext ctx, TransportConnectionReader r) throws IOException { - try { - InputStream streamReader = streamReaderFactory.createStreamReader( - r.getInputStream(), r.getMaxFrameLength(), ctx); - return messagingSessionFactory.createIncomingSession( - ctx.getContactId(), ctx.getTransportId(), streamReader); - } finally { - ByteUtils.erase(ctx.getSecret()); - } + InputStream streamReader = streamReaderFactory.createStreamReader( + r.getInputStream(), r.getMaxFrameLength(), ctx); + return messagingSessionFactory.createIncomingSession( + ctx.getContactId(), ctx.getTransportId(), streamReader); } private MessagingSession createSimplexOutgoingSession(StreamContext ctx, TransportConnectionWriter w) throws IOException { - try { - OutputStream streamWriter = streamWriterFactory.createStreamWriter( - w.getOutputStream(), w.getMaxFrameLength(), ctx); - return messagingSessionFactory.createSimplexOutgoingSession( - ctx.getContactId(), ctx.getTransportId(), w.getMaxLatency(), - streamWriter); - } finally { - ByteUtils.erase(ctx.getSecret()); - } + OutputStream streamWriter = streamWriterFactory.createStreamWriter( + w.getOutputStream(), w.getMaxFrameLength(), ctx); + return messagingSessionFactory.createSimplexOutgoingSession( + ctx.getContactId(), ctx.getTransportId(), w.getMaxLatency(), + streamWriter); } private MessagingSession createDuplexOutgoingSession(StreamContext ctx, TransportConnectionWriter w) throws IOException { - try { - OutputStream streamWriter = streamWriterFactory.createStreamWriter( - w.getOutputStream(), w.getMaxFrameLength(), ctx); - return messagingSessionFactory.createDuplexOutgoingSession( - ctx.getContactId(), ctx.getTransportId(), w.getMaxLatency(), - w.getMaxIdleTime(), streamWriter); - } finally { - ByteUtils.erase(ctx.getSecret()); - } + OutputStream streamWriter = streamWriterFactory.createStreamWriter( + w.getOutputStream(), w.getMaxFrameLength(), ctx); + return messagingSessionFactory.createDuplexOutgoingSession( + ctx.getContactId(), ctx.getTransportId(), w.getMaxLatency(), + w.getMaxIdleTime(), streamWriter); } private class ManageIncomingSimplexConnection implements Runnable { diff --git a/briar-core/src/org/briarproject/transport/KeyManagerImpl.java b/briar-core/src/org/briarproject/transport/KeyManagerImpl.java index 735e9f17b..089f724f8 100644 --- a/briar-core/src/org/briarproject/transport/KeyManagerImpl.java +++ b/briar-core/src/org/briarproject/transport/KeyManagerImpl.java @@ -33,7 +33,6 @@ import org.briarproject.api.transport.Endpoint; import org.briarproject.api.transport.StreamContext; import org.briarproject.api.transport.TagRecogniser; import org.briarproject.api.transport.TemporarySecret; -import org.briarproject.util.ByteUtils; // FIXME: Don't make alien calls with a lock held class KeyManagerImpl extends TimerTask implements KeyManager, EventListener { @@ -119,7 +118,6 @@ class KeyManagerImpl extends TimerTask implements KeyManager, EventListener { Integer maxLatency = maxLatencies.get(s.getTransportId()); if(maxLatency == null) { LOG.info("Discarding obsolete secret"); - ByteUtils.erase(s.getSecret()); continue; } long rotation = maxLatency + MAX_CLOCK_DIFFERENCE; @@ -143,7 +141,7 @@ class KeyManagerImpl extends TimerTask implements KeyManager, EventListener { return dead; } - // Replaces and erases the given secrets and returns any secrets created + // Replaces the given secrets and returns any secrets created // Locking: this private Collection replaceDeadSecrets(long now, Collection dead) { @@ -157,12 +155,10 @@ class KeyManagerImpl extends TimerTask implements KeyManager, EventListener { // There's no other secret for this endpoint newest.put(k, s); } else if(exists.getPeriod() < s.getPeriod()) { - // There's an older secret - erase it and use this one instead - ByteUtils.erase(exists.getSecret()); + // There's an older secret - use this one instead newest.put(k, s); } else { - // There's a newer secret - erase this one - ByteUtils.erase(s.getSecret()); + // There's a newer secret - keep using it } } Collection created = new ArrayList(); @@ -179,34 +175,23 @@ class KeyManagerImpl extends TimerTask implements KeyManager, EventListener { throw new IllegalStateException(); // Derive the old, current and new secrets byte[] b1 = s.getSecret(); - for(long p = s.getPeriod() + 1; p < period; p++) { - byte[] temp = crypto.deriveNextSecret(b1, p); - ByteUtils.erase(b1); - b1 = temp; - } + for(long p = s.getPeriod() + 1; p < period; p++) + b1 = crypto.deriveNextSecret(b1, p); byte[] b2 = crypto.deriveNextSecret(b1, period); byte[] b3 = crypto.deriveNextSecret(b2, period + 1); - // Add the secrets to their respective maps - copies may already - // exist, in which case erase the new copies (the old copies are - // referenced by the connection recogniser) + // Add the secrets to their respective maps if not already present EndpointKey k = e.getKey(); - if(oldSecrets.containsKey(k)) { - ByteUtils.erase(b1); - } else { + if(!oldSecrets.containsKey(k)) { TemporarySecret s1 = new TemporarySecret(s, period - 1, b1); oldSecrets.put(k, s1); created.add(s1); } - if(currentSecrets.containsKey(k)) { - ByteUtils.erase(b2); - } else { + if(!currentSecrets.containsKey(k)) { TemporarySecret s2 = new TemporarySecret(s, period, b2); currentSecrets.put(k, s2); created.add(s2); } - if(newSecrets.containsKey(k)) { - ByteUtils.erase(b3); - } else { + if(!newSecrets.containsKey(k)) { TemporarySecret s3 = new TemporarySecret(s, period + 1, b3); newSecrets.put(k, s3); created.add(s3); @@ -220,18 +205,12 @@ class KeyManagerImpl extends TimerTask implements KeyManager, EventListener { timer.cancel(); tagRecogniser.removeSecrets(); maxLatencies.clear(); - removeAndEraseSecrets(oldSecrets); - removeAndEraseSecrets(currentSecrets); - removeAndEraseSecrets(newSecrets); + oldSecrets.clear(); + currentSecrets.clear(); + newSecrets.clear(); return true; } - // Locking: this - private void removeAndEraseSecrets(Map m) { - for(TemporarySecret s : m.values()) ByteUtils.erase(s.getSecret()); - m.clear(); - } - public synchronized StreamContext getStreamContext(ContactId c, TransportId t) { TemporarySecret s = currentSecrets.get(new EndpointKey(c, t)); @@ -250,8 +229,7 @@ class KeyManagerImpl extends TimerTask implements KeyManager, EventListener { if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); return null; } - // Clone the secret - the original will be erased - byte[] secret = s.getSecret().clone(); + byte[] secret = s.getSecret(); return new StreamContext(c, t, secret, streamNumber, s.getAlice()); } @@ -265,11 +243,8 @@ class KeyManagerImpl extends TimerTask implements KeyManager, EventListener { if(period < 1) throw new IllegalStateException(); // Derive the old, current and new secrets byte[] b1 = initialSecret; - for(long p = 0; p < period; p++) { - byte[] temp = crypto.deriveNextSecret(b1, p); - ByteUtils.erase(b1); - b1 = temp; - } + for(long p = 0; p < period; p++) + b1 = crypto.deriveNextSecret(b1, p); byte[] b2 = crypto.deriveNextSecret(b1, period); byte[] b3 = crypto.deriveNextSecret(b2, period + 1); TemporarySecret s1 = new TemporarySecret(ep, period - 1, b1); @@ -341,28 +316,17 @@ class KeyManagerImpl extends TimerTask implements KeyManager, EventListener { } // Locking: this - private void removeAndEraseSecrets(ContactId c, Map m) { + private void removeSecrets(ContactId c, Map m) { Iterator it = m.values().iterator(); - while(it.hasNext()) { - TemporarySecret s = it.next(); - if(s.getContactId().equals(c)) { - ByteUtils.erase(s.getSecret()); - it.remove(); - } - } + while(it.hasNext()) + if(it.next().getContactId().equals(c)) it.remove(); } // Locking: this - private void removeAndEraseSecrets(TransportId t, - Map m) { + private void removeSecrets(TransportId t, Map m) { Iterator it = m.values().iterator(); - while(it.hasNext()) { - TemporarySecret s = it.next(); - if(s.getTransportId().equals(t)) { - ByteUtils.erase(s.getSecret()); - it.remove(); - } - } + while(it.hasNext()) + if(it.next().getTransportId().equals(t)) it.remove(); } private static class EndpointKey { @@ -408,9 +372,9 @@ class KeyManagerImpl extends TimerTask implements KeyManager, EventListener { ContactId c = event.getContactId(); tagRecogniser.removeSecrets(c); synchronized(KeyManagerImpl.this) { - removeAndEraseSecrets(c, oldSecrets); - removeAndEraseSecrets(c, currentSecrets); - removeAndEraseSecrets(c, newSecrets); + removeSecrets(c, oldSecrets); + removeSecrets(c, currentSecrets); + removeSecrets(c, newSecrets); } } } @@ -445,9 +409,9 @@ class KeyManagerImpl extends TimerTask implements KeyManager, EventListener { tagRecogniser.removeSecrets(t); synchronized(KeyManagerImpl.this) { maxLatencies.remove(t); - removeAndEraseSecrets(t, oldSecrets); - removeAndEraseSecrets(t, currentSecrets); - removeAndEraseSecrets(t, newSecrets); + removeSecrets(t, oldSecrets); + removeSecrets(t, currentSecrets); + removeSecrets(t, newSecrets); } } } diff --git a/briar-core/src/org/briarproject/transport/TransportTagRecogniser.java b/briar-core/src/org/briarproject/transport/TransportTagRecogniser.java index 3c9508397..285b4465e 100644 --- a/briar-core/src/org/briarproject/transport/TransportTagRecogniser.java +++ b/briar-core/src/org/briarproject/transport/TransportTagRecogniser.java @@ -56,13 +56,10 @@ class TransportTagRecogniser { assert duplicate == null; } } - key.erase(); // Store the updated reordering window in the DB db.setReorderingWindow(t.contactId, transportId, t.period, t.window.getCentre(), t.window.getBitmap()); - // Clone the secret - the key manager will erase the original - byte[] secret = t.secret.clone(); - return new StreamContext(t.contactId, transportId, secret, + return new StreamContext(t.contactId, transportId, t.secret, t.streamNumber, t.alice); } @@ -84,7 +81,6 @@ class TransportTagRecogniser { TagContext duplicate = tagMap.put(new Bytes(tag), added); assert duplicate == null; } - key.erase(); // Create a removal context to remove the window and the tags later RemovalContext r = new RemovalContext(window, secret, alice); removalMap.put(new RemovalKey(contactId, period), r); @@ -107,7 +103,6 @@ class TransportTagRecogniser { TagContext removed = tagMap.remove(new Bytes(tag)); assert removed != null; } - key.erase(); } synchronized void removeSecrets(ContactId c) { diff --git a/briar-core/src/org/briarproject/util/ByteUtils.java b/briar-core/src/org/briarproject/util/ByteUtils.java index ed40306e5..9cc9e6bc8 100644 --- a/briar-core/src/org/briarproject/util/ByteUtils.java +++ b/briar-core/src/org/briarproject/util/ByteUtils.java @@ -48,10 +48,6 @@ public class ByteUtils { | ((b[offset + 2] & 0xFFL) << 8) | (b[offset + 3] & 0xFFL); } - public static void erase(byte[] b) { - for(int i = 0; i < b.length; i++) b[i] = 0; - } - public static int readUint(byte[] b, int bits) { if(b.length << 3 < bits) throw new IllegalArgumentException(); int result = 0; diff --git a/briar-tests/build.xml b/briar-tests/build.xml index 561a3fbe5..eb4766a09 100644 --- a/briar-tests/build.xml +++ b/briar-tests/build.xml @@ -100,8 +100,7 @@ - - + diff --git a/briar-tests/src/org/briarproject/ProtocolIntegrationTest.java b/briar-tests/src/org/briarproject/ProtocolIntegrationTest.java index a3983b5a2..cfd5af2d5 100644 --- a/briar-tests/src/org/briarproject/ProtocolIntegrationTest.java +++ b/briar-tests/src/org/briarproject/ProtocolIntegrationTest.java @@ -116,8 +116,8 @@ public class ProtocolIntegrationTest extends BriarTestCase { private byte[] write() throws Exception { ByteArrayOutputStream out = new ByteArrayOutputStream(); - StreamContext ctx = new StreamContext(contactId, transportId, - secret.clone(), 0, true); + StreamContext ctx = new StreamContext(contactId, transportId, secret, + 0, true); OutputStream streamWriter = streamWriterFactory.createStreamWriter(out, MAX_FRAME_LENGTH, ctx); PacketWriter packetWriter = packetWriterFactory.createPacketWriter( @@ -148,8 +148,8 @@ public class ProtocolIntegrationTest extends BriarTestCase { byte[] tag = new byte[TAG_LENGTH]; assertEquals(TAG_LENGTH, in.read(tag, 0, TAG_LENGTH)); // FIXME: Check that the expected tag was received - StreamContext ctx = new StreamContext(contactId, transportId, - secret.clone(), 0, false); + StreamContext ctx = new StreamContext(contactId, transportId, secret, + 0, false); InputStream streamReader = streamReaderFactory.createStreamReader(in, MAX_FRAME_LENGTH, ctx); PacketReader packetReader = packetReaderFactory.createPacketReader( diff --git a/briar-tests/src/org/briarproject/crypto/KeyDerivationTest.java b/briar-tests/src/org/briarproject/crypto/KeyDerivationTest.java index 54c4a3c15..d0d71a7eb 100644 --- a/briar-tests/src/org/briarproject/crypto/KeyDerivationTest.java +++ b/briar-tests/src/org/briarproject/crypto/KeyDerivationTest.java @@ -30,9 +30,9 @@ public class KeyDerivationTest extends BriarTestCase { keys.add(crypto.deriveTagKey(secret, true)); keys.add(crypto.deriveTagKey(secret, false)); for(int i = 0; i < 4; i++) { - byte[] keyI = keys.get(i).getEncoded(); + byte[] keyI = keys.get(i).getBytes(); for(int j = 0; j < 4; j++) { - byte[] keyJ = keys.get(j).getEncoded(); + byte[] keyJ = keys.get(j).getBytes(); assertEquals(i == j, Arrays.equals(keyI, keyJ)); } } @@ -59,9 +59,8 @@ public class KeyDerivationTest extends BriarTestCase { @Test public void testStreamNumberAffectsDerivation() { List secrets = new ArrayList(); - for(int i = 0; i < 20; i++) { - secrets.add(crypto.deriveNextSecret(secret.clone(), i)); - } + for(int i = 0; i < 20; i++) + secrets.add(crypto.deriveNextSecret(secret, i)); for(int i = 0; i < 20; i++) { byte[] secretI = secrets.get(i); for(int j = 0; j < 20; j++) { diff --git a/briar-tests/src/org/briarproject/crypto/PasswordBasedKdfTest.java b/briar-tests/src/org/briarproject/crypto/PasswordBasedKdfTest.java index 151f78fb5..cdc59b332 100644 --- a/briar-tests/src/org/briarproject/crypto/PasswordBasedKdfTest.java +++ b/briar-tests/src/org/briarproject/crypto/PasswordBasedKdfTest.java @@ -18,7 +18,7 @@ public class PasswordBasedKdfTest extends BriarTestCase { Random random = new Random(); byte[] input = new byte[1234]; random.nextBytes(input); - char[] password = "password".toCharArray(); + String password = "password"; byte[] ciphertext = crypto.encryptWithPassword(input, password); byte[] output = crypto.decryptWithPassword(ciphertext, password); assertArrayEquals(input, output); @@ -29,7 +29,7 @@ public class PasswordBasedKdfTest extends BriarTestCase { Random random = new Random(); byte[] input = new byte[1234]; random.nextBytes(input); - char[] password = "password".toCharArray(); + String password = "password"; byte[] ciphertext = crypto.encryptWithPassword(input, password); // Modify the ciphertext int position = random.nextInt(ciphertext.length); diff --git a/briar-tests/src/org/briarproject/crypto/PasswordStrengthEstimatorTest.java b/briar-tests/src/org/briarproject/crypto/PasswordStrengthEstimatorImplTest.java similarity index 50% rename from briar-tests/src/org/briarproject/crypto/PasswordStrengthEstimatorTest.java rename to briar-tests/src/org/briarproject/crypto/PasswordStrengthEstimatorImplTest.java index 9f703b378..5407daf9a 100644 --- a/briar-tests/src/org/briarproject/crypto/PasswordStrengthEstimatorTest.java +++ b/briar-tests/src/org/briarproject/crypto/PasswordStrengthEstimatorImplTest.java @@ -6,24 +6,23 @@ import org.briarproject.BriarTestCase; import org.briarproject.api.crypto.PasswordStrengthEstimator; import org.junit.Test; -public class PasswordStrengthEstimatorTest extends BriarTestCase { +public class PasswordStrengthEstimatorImplTest extends BriarTestCase { @Test public void testWeakPasswords() { PasswordStrengthEstimator e = new PasswordStrengthEstimatorImpl(); - assertTrue(e.estimateStrength("".toCharArray()) < QUITE_STRONG); - assertTrue(e.estimateStrength("password".toCharArray()) < QUITE_STRONG); - assertTrue(e.estimateStrength("letmein".toCharArray()) < QUITE_STRONG); - assertTrue(e.estimateStrength("123456".toCharArray()) < QUITE_STRONG); + assertTrue(e.estimateStrength("") < QUITE_STRONG); + assertTrue(e.estimateStrength("password") < QUITE_STRONG); + assertTrue(e.estimateStrength("letmein") < QUITE_STRONG); + assertTrue(e.estimateStrength("123456") < QUITE_STRONG); } @Test public void testStrongPasswords() { PasswordStrengthEstimator e = new PasswordStrengthEstimatorImpl(); // Industry standard - assertTrue(e.estimateStrength("Tr0ub4dor&3".toCharArray()) - > QUITE_STRONG); - assertTrue(e.estimateStrength("correcthorsebatterystaple".toCharArray()) + assertTrue(e.estimateStrength("Tr0ub4dor&3") > QUITE_STRONG); + assertTrue(e.estimateStrength("correcthorsebatterystaple") > QUITE_STRONG); } } diff --git a/briar-tests/src/org/briarproject/crypto/SecretKeyImplTest.java b/briar-tests/src/org/briarproject/crypto/SecretKeyImplTest.java deleted file mode 100644 index 20ee3605b..000000000 --- a/briar-tests/src/org/briarproject/crypto/SecretKeyImplTest.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.briarproject.crypto; - -import static org.junit.Assert.assertArrayEquals; - -import java.util.Random; - -import org.briarproject.BriarTestCase; -import org.briarproject.api.crypto.SecretKey; -import org.junit.Test; - -public class SecretKeyImplTest extends BriarTestCase { - - private static final int KEY_BYTES = 32; // 256 bits - - @Test - public void testCopiesAreErased() { - byte[] master = new byte[KEY_BYTES]; - new Random().nextBytes(master); - SecretKey k = new SecretKeyImpl(master); - byte[] copy = k.getEncoded(); - assertArrayEquals(master, copy); - k.erase(); - byte[] blank = new byte[KEY_BYTES]; - assertArrayEquals(blank, master); - assertArrayEquals(blank, copy); - } -} diff --git a/briar-tests/src/org/briarproject/messaging/SimplexMessagingIntegrationTest.java b/briar-tests/src/org/briarproject/messaging/SimplexMessagingIntegrationTest.java index 3bce2a6e3..d0a8359af 100644 --- a/briar-tests/src/org/briarproject/messaging/SimplexMessagingIntegrationTest.java +++ b/briar-tests/src/org/briarproject/messaging/SimplexMessagingIntegrationTest.java @@ -127,7 +127,7 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase { db.addTransport(transportId, MAX_LATENCY); Endpoint ep = new Endpoint(contactId, transportId, epoch, true); db.addEndpoint(ep); - keyManager.endpointAdded(ep, MAX_LATENCY, initialSecret.clone()); + keyManager.endpointAdded(ep, MAX_LATENCY, initialSecret); // Send Bob a message String contentType = "text/plain"; long timestamp = System.currentTimeMillis(); @@ -190,7 +190,7 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase { db.addTransport(transportId, MAX_LATENCY); Endpoint ep = new Endpoint(contactId, transportId, epoch, false); db.addEndpoint(ep); - keyManager.endpointAdded(ep, MAX_LATENCY, initialSecret.clone()); + keyManager.endpointAdded(ep, MAX_LATENCY, initialSecret); // Set up an event listener MessageListener listener = new MessageListener(); bob.getInstance(EventBus.class).addListener(listener); diff --git a/briar-tests/src/org/briarproject/transport/KeyManagerImplTest.java b/briar-tests/src/org/briarproject/transport/KeyManagerImplTest.java index c160b59db..12880b1b8 100644 --- a/briar-tests/src/org/briarproject/transport/KeyManagerImplTest.java +++ b/briar-tests/src/org/briarproject/transport/KeyManagerImplTest.java @@ -103,9 +103,9 @@ public class KeyManagerImplTest extends BriarTestCase { // The secrets for periods 0 - 2 should be derived Endpoint ep = new Endpoint(contactId, transportId, EPOCH, true); - final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0.clone()); - final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1.clone()); - final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2.clone()); + final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0); + final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1); + final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2); context.checking(new Expectations() {{ // start() @@ -123,11 +123,11 @@ public class KeyManagerImplTest extends BriarTestCase { oneOf(clock).currentTimeMillis(); will(returnValue(EPOCH)); oneOf(crypto).deriveNextSecret(initialSecret, 0); - will(returnValue(secret0.clone())); + will(returnValue(secret0)); oneOf(crypto).deriveNextSecret(secret0, 1); - will(returnValue(secret1.clone())); + will(returnValue(secret1)); oneOf(crypto).deriveNextSecret(secret1, 2); - will(returnValue(secret2.clone())); + will(returnValue(secret2)); oneOf(db).addSecrets(Arrays.asList(s0, s1, s2)); // The secrets for periods 0 - 2 should be added to the recogniser oneOf(tagRecogniser).addSecret(s0); @@ -140,7 +140,7 @@ public class KeyManagerImplTest extends BriarTestCase { }}); assertTrue(keyManager.start()); - keyManager.endpointAdded(ep, MAX_LATENCY, initialSecret.clone()); + keyManager.endpointAdded(ep, MAX_LATENCY, initialSecret); keyManager.stop(); context.assertIsSatisfied(); @@ -161,9 +161,9 @@ public class KeyManagerImplTest extends BriarTestCase { // The secrets for periods 0 - 2 should be derived Endpoint ep = new Endpoint(contactId, transportId, EPOCH, true); - final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0.clone()); - final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1.clone()); - final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2.clone()); + final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0); + final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1); + final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2); context.checking(new Expectations() {{ // start() @@ -181,11 +181,11 @@ public class KeyManagerImplTest extends BriarTestCase { oneOf(clock).currentTimeMillis(); will(returnValue(EPOCH)); oneOf(crypto).deriveNextSecret(initialSecret, 0); - will(returnValue(secret0.clone())); + will(returnValue(secret0)); oneOf(crypto).deriveNextSecret(secret0, 1); - will(returnValue(secret1.clone())); + will(returnValue(secret1)); oneOf(crypto).deriveNextSecret(secret1, 2); - will(returnValue(secret2.clone())); + will(returnValue(secret2)); oneOf(db).addSecrets(Arrays.asList(s0, s1, s2)); // The secrets for periods 0 - 2 should be added to the recogniser oneOf(tagRecogniser).addSecret(s0); @@ -201,7 +201,7 @@ public class KeyManagerImplTest extends BriarTestCase { }}); assertTrue(keyManager.start()); - keyManager.endpointAdded(ep, MAX_LATENCY, initialSecret.clone()); + keyManager.endpointAdded(ep, MAX_LATENCY, initialSecret); StreamContext ctx = keyManager.getStreamContext(contactId, transportId); assertNotNull(ctx); @@ -230,9 +230,9 @@ public class KeyManagerImplTest extends BriarTestCase { // The DB contains the secrets for periods 0 - 2 Endpoint ep = new Endpoint(contactId, transportId, EPOCH, true); - final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0.clone()); - final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1.clone()); - final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2.clone()); + final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0); + final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1); + final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2); context.checking(new Expectations() {{ // start() @@ -278,11 +278,11 @@ public class KeyManagerImplTest extends BriarTestCase { // The DB contains the secrets for periods 0 - 2 Endpoint ep = new Endpoint(contactId, transportId, EPOCH, true); - final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0.clone()); - final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1.clone()); - final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2.clone()); + final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0); + final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1); + final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2); // The secret for period 3 should be derived and stored - final TemporarySecret s3 = new TemporarySecret(ep, 3, secret3.clone()); + final TemporarySecret s3 = new TemporarySecret(ep, 3, secret3); context.checking(new Expectations() {{ // start() @@ -297,11 +297,11 @@ public class KeyManagerImplTest extends BriarTestCase { will(returnValue(EPOCH + ROTATION_PERIOD)); // The secret for period 3 should be derived and stored oneOf(crypto).deriveNextSecret(secret0, 1); - will(returnValue(secret1.clone())); + will(returnValue(secret1)); oneOf(crypto).deriveNextSecret(secret1, 2); - will(returnValue(secret2.clone())); + will(returnValue(secret2)); oneOf(crypto).deriveNextSecret(secret2, 3); - will(returnValue(secret3.clone())); + will(returnValue(secret3)); oneOf(db).addSecrets(Arrays.asList(s3)); // The secrets for periods 1 - 3 should be added to the recogniser oneOf(tagRecogniser).addSecret(s1); @@ -336,12 +336,12 @@ public class KeyManagerImplTest extends BriarTestCase { // The DB contains the secrets for periods 0 - 2 Endpoint ep = new Endpoint(contactId, transportId, EPOCH, true); - final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0.clone()); - final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1.clone()); - final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2.clone()); + final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0); + final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1); + final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2); // The secrets for periods 3 and 4 should be derived and stored - final TemporarySecret s3 = new TemporarySecret(ep, 3, secret3.clone()); - final TemporarySecret s4 = new TemporarySecret(ep, 4, secret4.clone()); + final TemporarySecret s3 = new TemporarySecret(ep, 3, secret3); + final TemporarySecret s4 = new TemporarySecret(ep, 4, secret4); context.checking(new Expectations() {{ // start() @@ -356,11 +356,11 @@ public class KeyManagerImplTest extends BriarTestCase { will(returnValue(EPOCH + 3 * ROTATION_PERIOD - 1)); // The secrets for periods 3 and 4 should be derived from secret 1 oneOf(crypto).deriveNextSecret(secret1, 2); - will(returnValue(secret2.clone())); + will(returnValue(secret2)); oneOf(crypto).deriveNextSecret(secret2, 3); - will(returnValue(secret3.clone())); + will(returnValue(secret3)); oneOf(crypto).deriveNextSecret(secret3, 4); - will(returnValue(secret4.clone())); + will(returnValue(secret4)); // The new secrets should be stored oneOf(db).addSecrets(Arrays.asList(s3, s4)); // The secrets for periods 2 - 4 should be added to the recogniser @@ -396,9 +396,9 @@ public class KeyManagerImplTest extends BriarTestCase { // The DB contains the secrets for periods 0 - 2 Endpoint ep = new Endpoint(contactId, transportId, EPOCH, true); - final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0.clone()); - final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1.clone()); - final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2.clone()); + final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0); + final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1); + final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2); context.checking(new Expectations() {{ // start() @@ -459,11 +459,11 @@ public class KeyManagerImplTest extends BriarTestCase { // The DB contains the secrets for periods 0 - 2 Endpoint ep = new Endpoint(contactId, transportId, EPOCH, true); - final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0.clone()); - final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1.clone()); - final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2.clone()); + final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0); + final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1); + final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2); // The secret for period 3 should be derived and stored - final TemporarySecret s3 = new TemporarySecret(ep, 3, secret3.clone()); + final TemporarySecret s3 = new TemporarySecret(ep, 3, secret3); context.checking(new Expectations() {{ // start() @@ -486,11 +486,11 @@ public class KeyManagerImplTest extends BriarTestCase { oneOf(clock).currentTimeMillis(); will(returnValue(EPOCH + ROTATION_PERIOD + 1)); oneOf(crypto).deriveNextSecret(secret0, 1); - will(returnValue(secret1.clone())); + will(returnValue(secret1)); oneOf(crypto).deriveNextSecret(secret1, 2); - will(returnValue(secret2.clone())); + will(returnValue(secret2)); oneOf(crypto).deriveNextSecret(secret2, 3); - will(returnValue(secret3.clone())); + will(returnValue(secret3)); oneOf(tagRecogniser).removeSecret(contactId, transportId, 0); oneOf(db).addSecrets(Arrays.asList(s3)); oneOf(tagRecogniser).addSecret(s3); @@ -533,12 +533,12 @@ public class KeyManagerImplTest extends BriarTestCase { // The DB contains the secrets for periods 0 - 2 Endpoint ep = new Endpoint(contactId, transportId, EPOCH, true); - final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0.clone()); - final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1.clone()); - final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2.clone()); + final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0); + final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1); + final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2); // The secrets for periods 3 and 4 should be derived and stored - final TemporarySecret s3 = new TemporarySecret(ep, 3, secret3.clone()); - final TemporarySecret s4 = new TemporarySecret(ep, 4, secret4.clone()); + final TemporarySecret s3 = new TemporarySecret(ep, 3, secret3); + final TemporarySecret s4 = new TemporarySecret(ep, 4, secret4); context.checking(new Expectations() {{ // start() @@ -561,11 +561,11 @@ public class KeyManagerImplTest extends BriarTestCase { oneOf(clock).currentTimeMillis(); will(returnValue(EPOCH + 2 * ROTATION_PERIOD + 1)); oneOf(crypto).deriveNextSecret(secret1, 2); - will(returnValue(secret2.clone())); + will(returnValue(secret2)); oneOf(crypto).deriveNextSecret(secret2, 3); - will(returnValue(secret3.clone())); + will(returnValue(secret3)); oneOf(crypto).deriveNextSecret(secret3, 4); - will(returnValue(secret4.clone())); + will(returnValue(secret4)); oneOf(tagRecogniser).removeSecret(contactId, transportId, 0); oneOf(tagRecogniser).removeSecret(contactId, transportId, 1); oneOf(db).addSecrets(Arrays.asList(s3, s4)); diff --git a/briar-tests/src/org/briarproject/transport/KeyRotationIntegrationTest.java b/briar-tests/src/org/briarproject/transport/KeyRotationIntegrationTest.java index 70e8cfea3..84b6f8928 100644 --- a/briar-tests/src/org/briarproject/transport/KeyRotationIntegrationTest.java +++ b/briar-tests/src/org/briarproject/transport/KeyRotationIntegrationTest.java @@ -40,6 +40,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase { private final TransportId transportId; private final byte[] secret0, secret1, secret2, secret3, secret4; private final byte[] key0, key1, key2, key3, key4; + private final SecretKey k0, k1, k2, k3, k4; private final byte[] initialSecret; public KeyRotationIntegrationTest() { @@ -60,6 +61,11 @@ public class KeyRotationIntegrationTest extends BriarTestCase { key2 = new byte[32]; key3 = new byte[32]; key4 = new byte[32]; + k0 = new SecretKey(key0); + k1 = new SecretKey(key1); + k2 = new SecretKey(key2); + k3 = new SecretKey(key3); + k4 = new SecretKey(key4); for(int i = 0; i < key0.length; i++) key0[i] = 1; for(int i = 0; i < key1.length; i++) key1[i] = 2; for(int i = 0; i < key2.length; i++) key2[i] = 3; @@ -112,9 +118,6 @@ public class KeyRotationIntegrationTest extends BriarTestCase { final EventBus eventBus = context.mock(EventBus.class); final Clock clock = context.mock(Clock.class); final Timer timer = context.mock(Timer.class); - final SecretKey k0 = context.mock(SecretKey.class, "k0"); - final SecretKey k1 = context.mock(SecretKey.class, "k1"); - final SecretKey k2 = context.mock(SecretKey.class, "k2"); final TagRecogniser tagRecogniser = new TagRecogniserImpl(crypto, db); final KeyManagerImpl keyManager = new KeyManagerImpl(crypto, db, @@ -122,9 +125,9 @@ public class KeyRotationIntegrationTest extends BriarTestCase { // The secrets for periods 0 - 2 should be derived Endpoint ep = new Endpoint(contactId, transportId, EPOCH, true); - final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0.clone()); - final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1.clone()); - final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2.clone()); + final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0); + final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1); + final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2); context.checking(new Expectations() {{ // start() @@ -142,11 +145,11 @@ public class KeyRotationIntegrationTest extends BriarTestCase { oneOf(clock).currentTimeMillis(); will(returnValue(EPOCH)); oneOf(crypto).deriveNextSecret(initialSecret, 0); - will(returnValue(secret0.clone())); + will(returnValue(secret0)); oneOf(crypto).deriveNextSecret(secret0, 1); - will(returnValue(secret1.clone())); + will(returnValue(secret1)); oneOf(crypto).deriveNextSecret(secret1, 2); - will(returnValue(secret2.clone())); + will(returnValue(secret2)); oneOf(db).addSecrets(Arrays.asList(s0, s1, s2)); // The recogniser should derive the tags for period 0 oneOf(crypto).deriveTagKey(secret0, false); @@ -155,10 +158,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase { oneOf(crypto).encodeTag(with(any(byte[].class)), with(k0), with((long) i)); will(new EncodeTagAction()); - oneOf(k0).getEncoded(); - will(returnValue(key0)); } - oneOf(k0).erase(); // The recogniser should derive the tags for period 1 oneOf(crypto).deriveTagKey(secret1, false); will(returnValue(k1)); @@ -166,10 +166,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase { oneOf(crypto).encodeTag(with(any(byte[].class)), with(k1), with((long) i)); will(new EncodeTagAction()); - oneOf(k1).getEncoded(); - will(returnValue(key1)); } - oneOf(k1).erase(); // The recogniser should derive the tags for period 2 oneOf(crypto).deriveTagKey(secret2, false); will(returnValue(k2)); @@ -177,10 +174,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase { oneOf(crypto).encodeTag(with(any(byte[].class)), with(k2), with((long) i)); will(new EncodeTagAction()); - oneOf(k2).getEncoded(); - will(returnValue(key2)); } - oneOf(k2).erase(); // stop() // The recogniser should derive the tags for period 0 oneOf(crypto).deriveTagKey(secret0, false); @@ -189,10 +183,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase { oneOf(crypto).encodeTag(with(any(byte[].class)), with(k0), with((long) i)); will(new EncodeTagAction()); - oneOf(k0).getEncoded(); - will(returnValue(key0)); } - oneOf(k0).erase(); // The recogniser should derive the tags for period 1 oneOf(crypto).deriveTagKey(secret1, false); will(returnValue(k1)); @@ -200,10 +191,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase { oneOf(crypto).encodeTag(with(any(byte[].class)), with(k1), with((long) i)); will(new EncodeTagAction()); - oneOf(k1).getEncoded(); - will(returnValue(key1)); } - oneOf(k1).erase(); // The recogniser should derive the tags for period 2 oneOf(crypto).deriveTagKey(secret2, false); will(returnValue(k2)); @@ -211,17 +199,14 @@ public class KeyRotationIntegrationTest extends BriarTestCase { oneOf(crypto).encodeTag(with(any(byte[].class)), with(k2), with((long) i)); will(new EncodeTagAction()); - oneOf(k2).getEncoded(); - will(returnValue(key2)); } - oneOf(k2).erase(); // Remove the listener and stop the timer oneOf(eventBus).removeListener(with(any(EventListener.class))); oneOf(timer).cancel(); }}); assertTrue(keyManager.start()); - keyManager.endpointAdded(ep, MAX_LATENCY, initialSecret.clone()); + keyManager.endpointAdded(ep, MAX_LATENCY, initialSecret); keyManager.stop(); context.assertIsSatisfied(); @@ -235,9 +220,6 @@ public class KeyRotationIntegrationTest extends BriarTestCase { final EventBus eventBus = context.mock(EventBus.class); final Clock clock = context.mock(Clock.class); final Timer timer = context.mock(Timer.class); - final SecretKey k0 = context.mock(SecretKey.class, "k0"); - final SecretKey k1 = context.mock(SecretKey.class, "k1"); - final SecretKey k2 = context.mock(SecretKey.class, "k2"); final TagRecogniser tagRecogniser = new TagRecogniserImpl(crypto, db); final KeyManagerImpl keyManager = new KeyManagerImpl(crypto, db, @@ -245,9 +227,9 @@ public class KeyRotationIntegrationTest extends BriarTestCase { // The secrets for periods 0 - 2 should be derived Endpoint ep = new Endpoint(contactId, transportId, EPOCH, true); - final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0.clone()); - final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1.clone()); - final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2.clone()); + final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0); + final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1); + final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2); context.checking(new Expectations() {{ // start() @@ -265,11 +247,11 @@ public class KeyRotationIntegrationTest extends BriarTestCase { oneOf(clock).currentTimeMillis(); will(returnValue(EPOCH)); oneOf(crypto).deriveNextSecret(initialSecret, 0); - will(returnValue(secret0.clone())); + will(returnValue(secret0)); oneOf(crypto).deriveNextSecret(secret0, 1); - will(returnValue(secret1.clone())); + will(returnValue(secret1)); oneOf(crypto).deriveNextSecret(secret1, 2); - will(returnValue(secret2.clone())); + will(returnValue(secret2)); oneOf(db).addSecrets(Arrays.asList(s0, s1, s2)); // The recogniser should derive the tags for period 0 oneOf(crypto).deriveTagKey(secret0, false); @@ -278,10 +260,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase { oneOf(crypto).encodeTag(with(any(byte[].class)), with(k0), with((long) i)); will(new EncodeTagAction()); - oneOf(k0).getEncoded(); - will(returnValue(key0)); } - oneOf(k0).erase(); // The recogniser should derive the tags for period 1 oneOf(crypto).deriveTagKey(secret1, false); will(returnValue(k1)); @@ -289,10 +268,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase { oneOf(crypto).encodeTag(with(any(byte[].class)), with(k1), with((long) i)); will(new EncodeTagAction()); - oneOf(k1).getEncoded(); - will(returnValue(key1)); } - oneOf(k1).erase(); // The recogniser should derive the tags for period 2 oneOf(crypto).deriveTagKey(secret2, false); will(returnValue(k2)); @@ -300,10 +276,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase { oneOf(crypto).encodeTag(with(any(byte[].class)), with(k2), with((long) i)); will(new EncodeTagAction()); - oneOf(k2).getEncoded(); - will(returnValue(key2)); } - oneOf(k2).erase(); // getConnectionContext() oneOf(db).incrementStreamCounter(contactId, transportId, 1); will(returnValue(0L)); @@ -315,10 +288,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase { oneOf(crypto).encodeTag(with(any(byte[].class)), with(k0), with((long) i)); will(new EncodeTagAction()); - oneOf(k0).getEncoded(); - will(returnValue(key0)); } - oneOf(k0).erase(); // The recogniser should derive the tags for period 1 oneOf(crypto).deriveTagKey(secret1, false); will(returnValue(k1)); @@ -326,10 +296,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase { oneOf(crypto).encodeTag(with(any(byte[].class)), with(k1), with((long) i)); will(new EncodeTagAction()); - oneOf(k1).getEncoded(); - will(returnValue(key1)); } - oneOf(k1).erase(); // The recogniser should derive the tags for period 2 oneOf(crypto).deriveTagKey(secret2, false); will(returnValue(k2)); @@ -337,17 +304,14 @@ public class KeyRotationIntegrationTest extends BriarTestCase { oneOf(crypto).encodeTag(with(any(byte[].class)), with(k2), with((long) i)); will(new EncodeTagAction()); - oneOf(k2).getEncoded(); - will(returnValue(key2)); } - oneOf(k2).erase(); // Remove the listener and stop the timer oneOf(eventBus).removeListener(with(any(EventListener.class))); oneOf(timer).cancel(); }}); assertTrue(keyManager.start()); - keyManager.endpointAdded(ep, MAX_LATENCY, initialSecret.clone()); + keyManager.endpointAdded(ep, MAX_LATENCY, initialSecret); StreamContext ctx = keyManager.getStreamContext(contactId, transportId); assertNotNull(ctx); @@ -369,9 +333,6 @@ public class KeyRotationIntegrationTest extends BriarTestCase { final EventBus eventBus = context.mock(EventBus.class); final Clock clock = context.mock(Clock.class); final Timer timer = context.mock(Timer.class); - final SecretKey k0 = context.mock(SecretKey.class, "k0"); - final SecretKey k1 = context.mock(SecretKey.class, "k1"); - final SecretKey k2 = context.mock(SecretKey.class, "k2"); final TagRecogniser tagRecogniser = new TagRecogniserImpl(crypto, db); final KeyManagerImpl keyManager = new KeyManagerImpl(crypto, db, @@ -379,9 +340,9 @@ public class KeyRotationIntegrationTest extends BriarTestCase { // The secrets for periods 0 - 2 should be derived Endpoint ep = new Endpoint(contactId, transportId, EPOCH, true); - final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0.clone()); - final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1.clone()); - final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2.clone()); + final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0); + final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1); + final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2); context.checking(new Expectations() {{ // start() @@ -399,11 +360,11 @@ public class KeyRotationIntegrationTest extends BriarTestCase { oneOf(clock).currentTimeMillis(); will(returnValue(EPOCH)); oneOf(crypto).deriveNextSecret(initialSecret, 0); - will(returnValue(secret0.clone())); + will(returnValue(secret0)); oneOf(crypto).deriveNextSecret(secret0, 1); - will(returnValue(secret1.clone())); + will(returnValue(secret1)); oneOf(crypto).deriveNextSecret(secret1, 2); - will(returnValue(secret2.clone())); + will(returnValue(secret2)); oneOf(db).addSecrets(Arrays.asList(s0, s1, s2)); // The recogniser should derive the tags for period 0 oneOf(crypto).deriveTagKey(secret0, false); @@ -412,10 +373,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase { oneOf(crypto).encodeTag(with(any(byte[].class)), with(k0), with((long) i)); will(new EncodeTagAction()); - oneOf(k0).getEncoded(); - will(returnValue(key0)); } - oneOf(k0).erase(); // The recogniser should derive the tags for period 1 oneOf(crypto).deriveTagKey(secret1, false); will(returnValue(k1)); @@ -423,10 +381,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase { oneOf(crypto).encodeTag(with(any(byte[].class)), with(k1), with((long) i)); will(new EncodeTagAction()); - oneOf(k1).getEncoded(); - will(returnValue(key1)); } - oneOf(k1).erase(); // The recogniser should derive the tags for period 2 oneOf(crypto).deriveTagKey(secret2, false); will(returnValue(k2)); @@ -434,21 +389,15 @@ public class KeyRotationIntegrationTest extends BriarTestCase { oneOf(crypto).encodeTag(with(any(byte[].class)), with(k2), with((long) i)); will(new EncodeTagAction()); - oneOf(k2).getEncoded(); - will(returnValue(key2)); } - oneOf(k2).erase(); // acceptConnection() oneOf(crypto).deriveTagKey(secret2, false); will(returnValue(k2)); - oneOf(crypto).encodeTag(with(any(byte[].class)), - with(k2), with(16L)); + oneOf(crypto).encodeTag(with(any(byte[].class)), with(k2), + with(16L)); will(new EncodeTagAction()); - oneOf(k2).getEncoded(); - will(returnValue(key2)); oneOf(db).setReorderingWindow(contactId, transportId, 2, 1, new byte[] {0, 1, 0, 0}); - oneOf(k2).erase(); // stop() // The recogniser should derive the tags for period 0 oneOf(crypto).deriveTagKey(secret0, false); @@ -457,10 +406,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase { oneOf(crypto).encodeTag(with(any(byte[].class)), with(k0), with((long) i)); will(new EncodeTagAction()); - oneOf(k0).getEncoded(); - will(returnValue(key0)); } - oneOf(k0).erase(); // The recogniser should derive the tags for period 1 oneOf(crypto).deriveTagKey(secret1, false); will(returnValue(k1)); @@ -468,10 +414,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase { oneOf(crypto).encodeTag(with(any(byte[].class)), with(k1), with((long) i)); will(new EncodeTagAction()); - oneOf(k1).getEncoded(); - will(returnValue(key1)); } - oneOf(k1).erase(); // The recogniser should derive the updated tags for period 2 oneOf(crypto).deriveTagKey(secret2, false); will(returnValue(k2)); @@ -479,17 +422,14 @@ public class KeyRotationIntegrationTest extends BriarTestCase { oneOf(crypto).encodeTag(with(any(byte[].class)), with(k2), with((long) i)); will(new EncodeTagAction()); - oneOf(k2).getEncoded(); - will(returnValue(key2)); } - oneOf(k2).erase(); // Remove the listener and stop the timer oneOf(eventBus).removeListener(with(any(EventListener.class))); oneOf(timer).cancel(); }}); assertTrue(keyManager.start()); - keyManager.endpointAdded(ep, MAX_LATENCY, initialSecret.clone()); + keyManager.endpointAdded(ep, MAX_LATENCY, initialSecret); // Recognise the tag for connection 0 in period 2 byte[] tag = new byte[TAG_LENGTH]; encodeTag(tag, key2, 0); @@ -513,9 +453,6 @@ public class KeyRotationIntegrationTest extends BriarTestCase { final EventBus eventBus = context.mock(EventBus.class); final Clock clock = context.mock(Clock.class); final Timer timer = context.mock(Timer.class); - final SecretKey k0 = context.mock(SecretKey.class, "k0"); - final SecretKey k1 = context.mock(SecretKey.class, "k1"); - final SecretKey k2 = context.mock(SecretKey.class, "k2"); final TagRecogniser tagRecogniser = new TagRecogniserImpl(crypto, db); final KeyManagerImpl keyManager = new KeyManagerImpl(crypto, db, @@ -523,9 +460,9 @@ public class KeyRotationIntegrationTest extends BriarTestCase { // The DB contains the secrets for periods 0 - 2 Endpoint ep = new Endpoint(contactId, transportId, EPOCH, true); - final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0.clone()); - final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1.clone()); - final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2.clone()); + final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0); + final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1); + final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2); context.checking(new Expectations() {{ // start() @@ -545,10 +482,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase { oneOf(crypto).encodeTag(with(any(byte[].class)), with(k0), with((long) i)); will(new EncodeTagAction()); - oneOf(k0).getEncoded(); - will(returnValue(key0)); } - oneOf(k0).erase(); // The recogniser should derive the tags for period 1 oneOf(crypto).deriveTagKey(secret1, false); will(returnValue(k1)); @@ -556,10 +490,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase { oneOf(crypto).encodeTag(with(any(byte[].class)), with(k1), with((long) i)); will(new EncodeTagAction()); - oneOf(k1).getEncoded(); - will(returnValue(key1)); } - oneOf(k1).erase(); // The recogniser should derive the tags for period 2 oneOf(crypto).deriveTagKey(secret2, false); will(returnValue(k2)); @@ -567,10 +498,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase { oneOf(crypto).encodeTag(with(any(byte[].class)), with(k2), with((long) i)); will(new EncodeTagAction()); - oneOf(k2).getEncoded(); - will(returnValue(key2)); } - oneOf(k2).erase(); // Start the timer oneOf(timer).scheduleAtFixedRate(with(keyManager), with(any(long.class)), with(any(long.class))); @@ -582,10 +510,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase { oneOf(crypto).encodeTag(with(any(byte[].class)), with(k0), with((long) i)); will(new EncodeTagAction()); - oneOf(k0).getEncoded(); - will(returnValue(key0)); } - oneOf(k0).erase(); // The recogniser should derive the tags for period 1 oneOf(crypto).deriveTagKey(secret1, false); will(returnValue(k1)); @@ -593,10 +518,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase { oneOf(crypto).encodeTag(with(any(byte[].class)), with(k1), with((long) i)); will(new EncodeTagAction()); - oneOf(k1).getEncoded(); - will(returnValue(key1)); } - oneOf(k1).erase(); // The recogniser should derive the tags for period 2 oneOf(crypto).deriveTagKey(secret2, false); will(returnValue(k2)); @@ -604,10 +526,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase { oneOf(crypto).encodeTag(with(any(byte[].class)), with(k2), with((long) i)); will(new EncodeTagAction()); - oneOf(k2).getEncoded(); - will(returnValue(key2)); } - oneOf(k2).erase(); // Remove the listener and stop the timer oneOf(eventBus).removeListener(with(any(EventListener.class))); oneOf(timer).cancel(); @@ -627,9 +546,6 @@ public class KeyRotationIntegrationTest extends BriarTestCase { final EventBus eventBus = context.mock(EventBus.class); final Clock clock = context.mock(Clock.class); final Timer timer = context.mock(Timer.class); - final SecretKey k1 = context.mock(SecretKey.class, "k1"); - final SecretKey k2 = context.mock(SecretKey.class, "k2"); - final SecretKey k3 = context.mock(SecretKey.class, "k3"); final TagRecogniser tagRecogniser = new TagRecogniserImpl(crypto, db); final KeyManagerImpl keyManager = new KeyManagerImpl(crypto, db, @@ -637,11 +553,11 @@ public class KeyRotationIntegrationTest extends BriarTestCase { // The DB contains the secrets for periods 0 - 2 Endpoint ep = new Endpoint(contactId, transportId, EPOCH, true); - final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0.clone()); - final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1.clone()); - final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2.clone()); + final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0); + final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1); + final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2); // The secret for period 3 should be derived and stored - final TemporarySecret s3 = new TemporarySecret(ep, 3, secret3.clone()); + final TemporarySecret s3 = new TemporarySecret(ep, 3, secret3); context.checking(new Expectations() {{ // start() @@ -656,11 +572,11 @@ public class KeyRotationIntegrationTest extends BriarTestCase { will(returnValue(EPOCH + ROTATION_PERIOD)); // The secret for period 3 should be derived and stored oneOf(crypto).deriveNextSecret(secret0, 1); - will(returnValue(secret1.clone())); + will(returnValue(secret1)); oneOf(crypto).deriveNextSecret(secret1, 2); - will(returnValue(secret2.clone())); + will(returnValue(secret2)); oneOf(crypto).deriveNextSecret(secret2, 3); - will(returnValue(secret3.clone())); + will(returnValue(secret3)); oneOf(db).addSecrets(Arrays.asList(s3)); // The recogniser should derive the tags for period 1 oneOf(crypto).deriveTagKey(secret1, false); @@ -669,10 +585,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase { oneOf(crypto).encodeTag(with(any(byte[].class)), with(k1), with((long) i)); will(new EncodeTagAction()); - oneOf(k1).getEncoded(); - will(returnValue(key1)); } - oneOf(k1).erase(); // The recogniser should derive the tags for period 2 oneOf(crypto).deriveTagKey(secret2, false); will(returnValue(k2)); @@ -680,10 +593,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase { oneOf(crypto).encodeTag(with(any(byte[].class)), with(k2), with((long) i)); will(new EncodeTagAction()); - oneOf(k2).getEncoded(); - will(returnValue(key2)); } - oneOf(k2).erase(); // The recogniser should derive the tags for period 3 oneOf(crypto).deriveTagKey(secret3, false); will(returnValue(k3)); @@ -691,10 +601,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase { oneOf(crypto).encodeTag(with(any(byte[].class)), with(k3), with((long) i)); will(new EncodeTagAction()); - oneOf(k3).getEncoded(); - will(returnValue(key3)); } - oneOf(k3).erase(); // Start the timer oneOf(timer).scheduleAtFixedRate(with(keyManager), with(any(long.class)), with(any(long.class))); @@ -706,10 +613,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase { oneOf(crypto).encodeTag(with(any(byte[].class)), with(k1), with((long) i)); will(new EncodeTagAction()); - oneOf(k1).getEncoded(); - will(returnValue(key1)); } - oneOf(k1).erase(); // The recogniser should derive the tags for period 2 oneOf(crypto).deriveTagKey(secret2, false); will(returnValue(k2)); @@ -717,10 +621,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase { oneOf(crypto).encodeTag(with(any(byte[].class)), with(k2), with((long) i)); will(new EncodeTagAction()); - oneOf(k2).getEncoded(); - will(returnValue(key2)); } - oneOf(k2).erase(); // The recogniser should remove the tags for period 3 oneOf(crypto).deriveTagKey(secret3, false); will(returnValue(k3)); @@ -728,10 +629,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase { oneOf(crypto).encodeTag(with(any(byte[].class)), with(k3), with((long) i)); will(new EncodeTagAction()); - oneOf(k3).getEncoded(); - will(returnValue(key3)); } - oneOf(k3).erase(); // Remove the listener and stop the timer oneOf(eventBus).removeListener(with(any(EventListener.class))); oneOf(timer).cancel(); @@ -751,9 +649,6 @@ public class KeyRotationIntegrationTest extends BriarTestCase { final EventBus eventBus = context.mock(EventBus.class); final Clock clock = context.mock(Clock.class); final Timer timer = context.mock(Timer.class); - final SecretKey k2 = context.mock(SecretKey.class, "k2"); - final SecretKey k3 = context.mock(SecretKey.class, "k3"); - final SecretKey k4 = context.mock(SecretKey.class, "k4"); final TagRecogniser tagRecogniser = new TagRecogniserImpl(crypto, db); final KeyManagerImpl keyManager = new KeyManagerImpl(crypto, db, @@ -761,12 +656,12 @@ public class KeyRotationIntegrationTest extends BriarTestCase { // The DB contains the secrets for periods 0 - 2 Endpoint ep = new Endpoint(contactId, transportId, EPOCH, true); - final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0.clone()); - final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1.clone()); - final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2.clone()); + final TemporarySecret s0 = new TemporarySecret(ep, 0, secret0); + final TemporarySecret s1 = new TemporarySecret(ep, 1, secret1); + final TemporarySecret s2 = new TemporarySecret(ep, 2, secret2); // The secrets for periods 3 and 4 should be derived and stored - final TemporarySecret s3 = new TemporarySecret(ep, 3, secret3.clone()); - final TemporarySecret s4 = new TemporarySecret(ep, 4, secret4.clone()); + final TemporarySecret s3 = new TemporarySecret(ep, 3, secret3); + final TemporarySecret s4 = new TemporarySecret(ep, 4, secret4); context.checking(new Expectations() {{ // start() @@ -781,11 +676,11 @@ public class KeyRotationIntegrationTest extends BriarTestCase { will(returnValue(EPOCH + 3 * ROTATION_PERIOD - 1)); // The secrets for periods 3 and 4 should be derived from secret 1 oneOf(crypto).deriveNextSecret(secret1, 2); - will(returnValue(secret2.clone())); + will(returnValue(secret2)); oneOf(crypto).deriveNextSecret(secret2, 3); - will(returnValue(secret3.clone())); + will(returnValue(secret3)); oneOf(crypto).deriveNextSecret(secret3, 4); - will(returnValue(secret4.clone())); + will(returnValue(secret4)); // The new secrets should be stored oneOf(db).addSecrets(Arrays.asList(s3, s4)); // The recogniser should derive the tags for period 2 @@ -795,10 +690,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase { oneOf(crypto).encodeTag(with(any(byte[].class)), with(k2), with((long) i)); will(new EncodeTagAction()); - oneOf(k2).getEncoded(); - will(returnValue(key2)); } - oneOf(k2).erase(); // The recogniser should derive the tags for period 3 oneOf(crypto).deriveTagKey(secret3, false); will(returnValue(k3)); @@ -806,10 +698,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase { oneOf(crypto).encodeTag(with(any(byte[].class)), with(k3), with((long) i)); will(new EncodeTagAction()); - oneOf(k3).getEncoded(); - will(returnValue(key3)); } - oneOf(k3).erase(); // The recogniser should derive the tags for period 4 oneOf(crypto).deriveTagKey(secret4, false); will(returnValue(k4)); @@ -817,10 +706,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase { oneOf(crypto).encodeTag(with(any(byte[].class)), with(k4), with((long) i)); will(new EncodeTagAction()); - oneOf(k4).getEncoded(); - will(returnValue(key4)); } - oneOf(k4).erase(); // Start the timer oneOf(timer).scheduleAtFixedRate(with(keyManager), with(any(long.class)), with(any(long.class))); @@ -832,10 +718,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase { oneOf(crypto).encodeTag(with(any(byte[].class)), with(k2), with((long) i)); will(new EncodeTagAction()); - oneOf(k2).getEncoded(); - will(returnValue(key2)); } - oneOf(k2).erase(); // The recogniser should remove the tags for period 3 oneOf(crypto).deriveTagKey(secret3, false); will(returnValue(k3)); @@ -843,10 +726,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase { oneOf(crypto).encodeTag(with(any(byte[].class)), with(k3), with((long) i)); will(new EncodeTagAction()); - oneOf(k3).getEncoded(); - will(returnValue(key3)); } - oneOf(k3).erase(); // The recogniser should derive the tags for period 4 oneOf(crypto).deriveTagKey(secret4, false); will(returnValue(k4)); @@ -854,10 +734,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase { oneOf(crypto).encodeTag(with(any(byte[].class)), with(k4), with((long) i)); will(new EncodeTagAction()); - oneOf(k4).getEncoded(); - will(returnValue(key4)); } - oneOf(k4).erase(); // Remove the listener and stop the timer oneOf(eventBus).removeListener(with(any(EventListener.class))); oneOf(timer).cancel(); @@ -885,7 +762,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase { byte[] tag = (byte[]) invocation.getParameter(0); SecretKey key = (SecretKey) invocation.getParameter(1); long streamNumber = (Long) invocation.getParameter(2); - encodeTag(tag, key.getEncoded(), streamNumber); + encodeTag(tag, key.getBytes(), streamNumber); return null; } } diff --git a/briar-tests/src/org/briarproject/transport/TransportTagRecogniserTest.java b/briar-tests/src/org/briarproject/transport/TransportTagRecogniserTest.java index ba1e84d48..340745489 100644 --- a/briar-tests/src/org/briarproject/transport/TransportTagRecogniserTest.java +++ b/briar-tests/src/org/briarproject/transport/TransportTagRecogniserTest.java @@ -25,6 +25,7 @@ public class TransportTagRecogniserTest extends BriarTestCase { private final ContactId contactId = new ContactId(234); private final TransportId transportId = new TransportId("id"); + private final SecretKey tagKey = new SecretKey(new byte[32]); @Test public void testAddAndRemoveSecret() { @@ -33,7 +34,6 @@ public class TransportTagRecogniserTest extends BriarTestCase { final byte[] secret = new byte[32]; new Random().nextBytes(secret); final boolean alice = false; - final SecretKey tagKey = context.mock(SecretKey.class); final DatabaseComponent db = context.mock(DatabaseComponent.class); context.checking(new Expectations() {{ // Add secret @@ -44,7 +44,6 @@ public class TransportTagRecogniserTest extends BriarTestCase { with((long) i)); will(new EncodeTagAction()); } - oneOf(tagKey).erase(); // Remove secret oneOf(crypto).deriveTagKey(secret, !alice); will(returnValue(tagKey)); @@ -53,7 +52,6 @@ public class TransportTagRecogniserTest extends BriarTestCase { with((long) i)); will(new EncodeTagAction()); } - oneOf(tagKey).erase(); }}); TemporarySecret s = new TemporarySecret(contactId, transportId, 123, alice, 0, secret, 0, 0, new byte[4]); @@ -71,7 +69,6 @@ public class TransportTagRecogniserTest extends BriarTestCase { final byte[] secret = new byte[32]; new Random().nextBytes(secret); final boolean alice = false; - final SecretKey tagKey = context.mock(SecretKey.class); final DatabaseComponent db = context.mock(DatabaseComponent.class); context.checking(new Expectations() {{ // Add secret @@ -82,7 +79,6 @@ public class TransportTagRecogniserTest extends BriarTestCase { with((long) i)); will(new EncodeTagAction()); } - oneOf(tagKey).erase(); // Recognise tag 0 oneOf(crypto).deriveTagKey(secret, !alice); will(returnValue(tagKey)); @@ -93,7 +89,6 @@ public class TransportTagRecogniserTest extends BriarTestCase { // The updated window should be stored oneOf(db).setReorderingWindow(contactId, transportId, 0, 1, new byte[] {0, 1, 0, 0}); - oneOf(tagKey).erase(); // Recognise tag again - no expectations }}); TemporarySecret s = new TemporarySecret(contactId, transportId, 123, From d3bf2d59a1224ae30d73c5834c7a3c68f5b164e4 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Mon, 5 Jan 2015 16:24:44 +0000 Subject: [PATCH 07/10] Use the same maximum frame length for all transports. --- .../plugins/droidtooth/DroidtoothPlugin.java | 9 +-- .../droidtooth/DroidtoothPluginFactory.java | 4 +- .../DroidtoothTransportConnection.java | 8 --- .../plugins/tcp/AndroidLanTcpPlugin.java | 5 +- .../tcp/AndroidLanTcpPluginFactory.java | 3 +- .../briarproject/plugins/tor/TorPlugin.java | 11 +--- .../plugins/tor/TorPluginFactory.java | 3 +- .../plugins/tor/TorTransportConnection.java | 8 --- .../api/crypto/AuthenticatedCipher.java | 2 +- .../api/crypto/StreamDecrypterFactory.java | 5 +- .../api/crypto/StreamEncrypterFactory.java | 5 +- .../org/briarproject/api/plugins/Plugin.java | 3 - .../plugins/TransportConnectionReader.java | 3 - .../plugins/TransportConnectionWriter.java | 3 - .../api/transport/StreamReaderFactory.java | 5 +- .../api/transport/StreamWriterFactory.java | 5 +- .../api/transport/TransportConstants.java | 2 +- .../crypto/StreamDecrypterFactoryImpl.java | 10 ++- .../crypto/StreamDecrypterImpl.java | 15 ++--- .../crypto/StreamEncrypterFactoryImpl.java | 8 +-- .../crypto/StreamEncrypterImpl.java | 13 ++-- .../invitation/AliceConnector.java | 5 +- .../briarproject/invitation/BobConnector.java | 5 +- .../plugins/ConnectionManagerImpl.java | 6 +- .../briarproject/plugins/file/FilePlugin.java | 10 +-- .../plugins/file/FileTransportReader.java | 4 -- .../plugins/file/FileTransportWriter.java | 4 -- .../plugins/tcp/LanTcpPlugin.java | 6 +- .../plugins/tcp/LanTcpPluginFactory.java | 5 +- .../briarproject/plugins/tcp/TcpPlugin.java | 11 +--- .../plugins/tcp/TcpTransportConnection.java | 8 --- .../plugins/tcp/WanTcpPlugin.java | 7 +- .../plugins/tcp/WanTcpPluginFactory.java | 4 +- .../transport/StreamReaderFactoryImpl.java | 16 ++--- .../transport/StreamReaderImpl.java | 5 +- .../transport/StreamWriterFactoryImpl.java | 15 ++--- .../transport/StreamWriterImpl.java | 5 +- .../plugins/bluetooth/BluetoothPlugin.java | 9 +-- .../bluetooth/BluetoothPluginFactory.java | 3 +- .../BluetoothTransportConnection.java | 8 --- .../plugins/file/RemovableDrivePlugin.java | 4 +- .../file/RemovableDrivePluginFactory.java | 4 +- .../plugins/modem/ModemPlugin.java | 17 +---- .../plugins/modem/ModemPluginFactory.java | 3 +- .../briarproject/ProtocolIntegrationTest.java | 9 ++- .../crypto/StreamDecrypterImplTest.java | 65 ++++++++++--------- .../crypto/StreamEncrypterImplTest.java | 33 +++++----- .../SimplexMessagingIntegrationTest.java | 9 ++- .../bluetooth/BluetoothClientTest.java | 4 +- .../bluetooth/BluetoothServerTest.java | 2 +- .../file/RemovableDrivePluginTest.java | 19 +++--- .../plugins/modem/ModemPluginTest.java | 8 +-- .../plugins/tcp/LanTcpClientTest.java | 5 +- .../plugins/tcp/LanTcpPluginTest.java | 6 +- .../plugins/tcp/LanTcpServerTest.java | 5 +- .../transport/StreamReaderImplTest.java | 12 ++-- .../transport/StreamWriterImplTest.java | 16 ++--- .../transport/TestStreamDecrypter.java | 5 +- .../transport/TestStreamEncrypter.java | 5 +- .../transport/TransportIntegrationTest.java | 18 ++--- 60 files changed, 194 insertions(+), 321 deletions(-) diff --git a/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothPlugin.java b/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothPlugin.java index 1aff5ba37..a63bbc7eb 100644 --- a/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothPlugin.java +++ b/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothPlugin.java @@ -69,7 +69,7 @@ class DroidtoothPlugin implements DuplexPlugin { private final SecureRandom secureRandom; private final Clock clock; private final DuplexPluginCallback callback; - private final int maxFrameLength, maxLatency, pollingInterval; + private final int maxLatency, pollingInterval; private volatile boolean running = false; private volatile boolean wasDisabled = false; @@ -81,7 +81,7 @@ class DroidtoothPlugin implements DuplexPlugin { DroidtoothPlugin(Executor ioExecutor, AndroidExecutor androidExecutor, Context appContext, SecureRandom secureRandom, Clock clock, - DuplexPluginCallback callback, int maxFrameLength, int maxLatency, + DuplexPluginCallback callback, int maxLatency, int pollingInterval) { this.ioExecutor = ioExecutor; this.androidExecutor = androidExecutor; @@ -89,7 +89,6 @@ class DroidtoothPlugin implements DuplexPlugin { this.secureRandom = secureRandom; this.clock = clock; this.callback = callback; - this.maxFrameLength = maxFrameLength; this.maxLatency = maxLatency; this.pollingInterval = pollingInterval; } @@ -98,10 +97,6 @@ class DroidtoothPlugin implements DuplexPlugin { return ID; } - public int getMaxFrameLength() { - return maxFrameLength; - } - public int getMaxLatency() { return maxLatency; } diff --git a/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothPluginFactory.java b/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothPluginFactory.java index 8cc21085d..2b04481c4 100644 --- a/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothPluginFactory.java +++ b/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothPluginFactory.java @@ -15,7 +15,6 @@ import android.content.Context; public class DroidtoothPluginFactory implements DuplexPluginFactory { - private static final int MAX_FRAME_LENGTH = 1024; private static final int MAX_LATENCY = 30 * 1000; // 30 seconds private static final int POLLING_INTERVAL = 3 * 60 * 1000; // 3 minutes @@ -41,7 +40,6 @@ public class DroidtoothPluginFactory implements DuplexPluginFactory { public DuplexPlugin createPlugin(DuplexPluginCallback callback) { return new DroidtoothPlugin(ioExecutor, androidExecutor, appContext, - secureRandom, clock, callback, MAX_FRAME_LENGTH, MAX_LATENCY, - POLLING_INTERVAL); + secureRandom, clock, callback, MAX_LATENCY, POLLING_INTERVAL); } } diff --git a/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothTransportConnection.java b/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothTransportConnection.java index fa38875de..e9b645e1c 100644 --- a/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothTransportConnection.java +++ b/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothTransportConnection.java @@ -39,10 +39,6 @@ class DroidtoothTransportConnection implements DuplexTransportConnection { private class Reader implements TransportConnectionReader { - public int getMaxFrameLength() { - return plugin.getMaxFrameLength(); - } - public long getMaxLatency() { return plugin.getMaxLatency(); } @@ -60,10 +56,6 @@ class DroidtoothTransportConnection implements DuplexTransportConnection { private class Writer implements TransportConnectionWriter { - public int getMaxFrameLength() { - return plugin.getMaxFrameLength(); - } - public int getMaxLatency() { return plugin.getMaxLatency(); } diff --git a/briar-android/src/org/briarproject/plugins/tcp/AndroidLanTcpPlugin.java b/briar-android/src/org/briarproject/plugins/tcp/AndroidLanTcpPlugin.java index 6194e2ee8..a7689bbda 100644 --- a/briar-android/src/org/briarproject/plugins/tcp/AndroidLanTcpPlugin.java +++ b/briar-android/src/org/briarproject/plugins/tcp/AndroidLanTcpPlugin.java @@ -26,10 +26,9 @@ class AndroidLanTcpPlugin extends LanTcpPlugin { private volatile BroadcastReceiver networkStateReceiver = null; AndroidLanTcpPlugin(Executor ioExecutor, Context appContext, - DuplexPluginCallback callback, int maxFrameLength, int maxLatency, + DuplexPluginCallback callback, int maxLatency, int maxIdleTime, int pollingInterval) { - super(ioExecutor, callback, maxFrameLength, maxLatency, maxIdleTime, - pollingInterval); + super(ioExecutor, callback, maxLatency, maxIdleTime, pollingInterval); this.appContext = appContext; } diff --git a/briar-android/src/org/briarproject/plugins/tcp/AndroidLanTcpPluginFactory.java b/briar-android/src/org/briarproject/plugins/tcp/AndroidLanTcpPluginFactory.java index 7e0a5469c..debad159c 100644 --- a/briar-android/src/org/briarproject/plugins/tcp/AndroidLanTcpPluginFactory.java +++ b/briar-android/src/org/briarproject/plugins/tcp/AndroidLanTcpPluginFactory.java @@ -11,7 +11,6 @@ import android.content.Context; public class AndroidLanTcpPluginFactory implements DuplexPluginFactory { - private static final int MAX_FRAME_LENGTH = 1024; private static final int MAX_LATENCY = 30 * 1000; // 30 seconds private static final int MAX_IDLE_TIME = 30 * 1000; // 30 seconds private static final int POLLING_INTERVAL = 3 * 60 * 1000; // 3 minutes @@ -30,6 +29,6 @@ public class AndroidLanTcpPluginFactory implements DuplexPluginFactory { public DuplexPlugin createPlugin(DuplexPluginCallback callback) { return new AndroidLanTcpPlugin(ioExecutor, appContext, callback, - MAX_FRAME_LENGTH, MAX_LATENCY, MAX_IDLE_TIME, POLLING_INTERVAL); + MAX_LATENCY, MAX_IDLE_TIME, POLLING_INTERVAL); } } diff --git a/briar-android/src/org/briarproject/plugins/tor/TorPlugin.java b/briar-android/src/org/briarproject/plugins/tor/TorPlugin.java index 4222da1ba..0d8983261 100644 --- a/briar-android/src/org/briarproject/plugins/tor/TorPlugin.java +++ b/briar-android/src/org/briarproject/plugins/tor/TorPlugin.java @@ -75,8 +75,7 @@ class TorPlugin implements DuplexPlugin, EventHandler { private final Context appContext; private final LocationUtils locationUtils; private final DuplexPluginCallback callback; - private final int maxFrameLength, maxLatency, maxIdleTime, pollingInterval; - private final int socketTimeout; + private final int maxLatency, maxIdleTime, pollingInterval, socketTimeout; private final File torDirectory, torFile, geoIpFile, configFile, doneFile; private final File cookieFile, hostnameFile; private final AtomicBoolean circuitBuilt; @@ -90,13 +89,11 @@ class TorPlugin implements DuplexPlugin, EventHandler { TorPlugin(Executor ioExecutor, Context appContext, LocationUtils locationUtils, DuplexPluginCallback callback, - int maxFrameLength, int maxLatency, int maxIdleTime, - int pollingInterval) { + int maxLatency, int maxIdleTime, int pollingInterval) { this.ioExecutor = ioExecutor; this.appContext = appContext; this.locationUtils = locationUtils; this.callback = callback; - this.maxFrameLength = maxFrameLength; this.maxLatency = maxLatency; this.maxIdleTime = maxIdleTime; this.pollingInterval = pollingInterval; @@ -117,10 +114,6 @@ class TorPlugin implements DuplexPlugin, EventHandler { return ID; } - public int getMaxFrameLength() { - return maxFrameLength; - } - public int getMaxLatency() { return maxLatency; } diff --git a/briar-android/src/org/briarproject/plugins/tor/TorPluginFactory.java b/briar-android/src/org/briarproject/plugins/tor/TorPluginFactory.java index bf44a3593..4861ba6b7 100644 --- a/briar-android/src/org/briarproject/plugins/tor/TorPluginFactory.java +++ b/briar-android/src/org/briarproject/plugins/tor/TorPluginFactory.java @@ -17,7 +17,6 @@ public class TorPluginFactory implements DuplexPluginFactory { private static final Logger LOG = Logger.getLogger(TorPluginFactory.class.getName()); - private static final int MAX_FRAME_LENGTH = 1024; private static final int MAX_LATENCY = 30 * 1000; // 30 seconds private static final int MAX_IDLE_TIME = 30 * 1000; // 30 seconds private static final int POLLING_INTERVAL = 3 * 60 * 1000; // 3 minutes @@ -44,6 +43,6 @@ public class TorPluginFactory implements DuplexPluginFactory { return null; } return new TorPlugin(ioExecutor,appContext, locationUtils, callback, - MAX_FRAME_LENGTH, MAX_LATENCY, MAX_IDLE_TIME, POLLING_INTERVAL); + MAX_LATENCY, MAX_IDLE_TIME, POLLING_INTERVAL); } } diff --git a/briar-android/src/org/briarproject/plugins/tor/TorTransportConnection.java b/briar-android/src/org/briarproject/plugins/tor/TorTransportConnection.java index 12880977f..4640eb1f6 100644 --- a/briar-android/src/org/briarproject/plugins/tor/TorTransportConnection.java +++ b/briar-android/src/org/briarproject/plugins/tor/TorTransportConnection.java @@ -38,10 +38,6 @@ class TorTransportConnection implements DuplexTransportConnection { private class Reader implements TransportConnectionReader { - public int getMaxFrameLength() { - return plugin.getMaxFrameLength(); - } - public long getMaxLatency() { return plugin.getMaxLatency(); } @@ -59,10 +55,6 @@ class TorTransportConnection implements DuplexTransportConnection { private class Writer implements TransportConnectionWriter { - public int getMaxFrameLength() { - return plugin.getMaxFrameLength(); - } - public int getMaxLatency() { return plugin.getMaxLatency(); } diff --git a/briar-api/src/org/briarproject/api/crypto/AuthenticatedCipher.java b/briar-api/src/org/briarproject/api/crypto/AuthenticatedCipher.java index 1a6d95522..444fcf13f 100644 --- a/briar-api/src/org/briarproject/api/crypto/AuthenticatedCipher.java +++ b/briar-api/src/org/briarproject/api/crypto/AuthenticatedCipher.java @@ -2,7 +2,7 @@ package org.briarproject.api.crypto; import java.security.GeneralSecurityException; -/** An authenticated cipher that support additional authenticated data. */ +/** An authenticated cipher that supports additional authenticated data. */ public interface AuthenticatedCipher { /** diff --git a/briar-api/src/org/briarproject/api/crypto/StreamDecrypterFactory.java b/briar-api/src/org/briarproject/api/crypto/StreamDecrypterFactory.java index 46948f2a2..8b758ec11 100644 --- a/briar-api/src/org/briarproject/api/crypto/StreamDecrypterFactory.java +++ b/briar-api/src/org/briarproject/api/crypto/StreamDecrypterFactory.java @@ -7,12 +7,11 @@ import org.briarproject.api.transport.StreamContext; public interface StreamDecrypterFactory { /** Creates a {@link StreamDecrypter} for decrypting a transport stream. */ - StreamDecrypter createStreamDecrypter(InputStream in, int maxFrameLength, - StreamContext ctx); + StreamDecrypter createStreamDecrypter(InputStream in, StreamContext ctx); /** * Creates a {@link StreamDecrypter} for decrypting an invitation stream. */ StreamDecrypter createInvitationStreamDecrypter(InputStream in, - int maxFrameLength, byte[] secret, boolean alice); + byte[] secret, boolean alice); } diff --git a/briar-api/src/org/briarproject/api/crypto/StreamEncrypterFactory.java b/briar-api/src/org/briarproject/api/crypto/StreamEncrypterFactory.java index 95912937e..86df7bbe2 100644 --- a/briar-api/src/org/briarproject/api/crypto/StreamEncrypterFactory.java +++ b/briar-api/src/org/briarproject/api/crypto/StreamEncrypterFactory.java @@ -7,12 +7,11 @@ import org.briarproject.api.transport.StreamContext; public interface StreamEncrypterFactory { /** Creates a {@link StreamEncrypter} for encrypting a transport stream. */ - StreamEncrypter createStreamEncrypter(OutputStream out, - int maxFrameLength, StreamContext ctx); + StreamEncrypter createStreamEncrypter(OutputStream out, StreamContext ctx); /** * Creates a {@link StreamEncrypter} for encrypting an invitation stream. */ StreamEncrypter createInvitationStreamEncrypter(OutputStream out, - int maxFrameLength, byte[] secret, boolean alice); + byte[] secret, boolean alice); } diff --git a/briar-api/src/org/briarproject/api/plugins/Plugin.java b/briar-api/src/org/briarproject/api/plugins/Plugin.java index eafb91007..cc0338a4a 100644 --- a/briar-api/src/org/briarproject/api/plugins/Plugin.java +++ b/briar-api/src/org/briarproject/api/plugins/Plugin.java @@ -11,9 +11,6 @@ public interface Plugin { /** Returns the plugin's transport identifier. */ TransportId getId(); - /** Returns the transport's maximum frame length in bytes. */ - int getMaxFrameLength(); - /** Returns the transport's maximum latency in milliseconds. */ int getMaxLatency(); diff --git a/briar-api/src/org/briarproject/api/plugins/TransportConnectionReader.java b/briar-api/src/org/briarproject/api/plugins/TransportConnectionReader.java index c4c99dfa3..e071c4432 100644 --- a/briar-api/src/org/briarproject/api/plugins/TransportConnectionReader.java +++ b/briar-api/src/org/briarproject/api/plugins/TransportConnectionReader.java @@ -9,9 +9,6 @@ import java.io.InputStream; */ public interface TransportConnectionReader { - /** Returns the maximum frame length of the transport in bytes. */ - int getMaxFrameLength(); - /** Returns the maximum latency of the transport in milliseconds. */ long getMaxLatency(); diff --git a/briar-api/src/org/briarproject/api/plugins/TransportConnectionWriter.java b/briar-api/src/org/briarproject/api/plugins/TransportConnectionWriter.java index 7f07411c6..d75522f1b 100644 --- a/briar-api/src/org/briarproject/api/plugins/TransportConnectionWriter.java +++ b/briar-api/src/org/briarproject/api/plugins/TransportConnectionWriter.java @@ -9,9 +9,6 @@ import java.io.OutputStream; */ public interface TransportConnectionWriter { - /** Returns the maximum frame length of the transport in bytes. */ - int getMaxFrameLength(); - /** Returns the maximum latency of the transport in milliseconds. */ int getMaxLatency(); diff --git a/briar-api/src/org/briarproject/api/transport/StreamReaderFactory.java b/briar-api/src/org/briarproject/api/transport/StreamReaderFactory.java index 3bf4cf049..5cf4fd639 100644 --- a/briar-api/src/org/briarproject/api/transport/StreamReaderFactory.java +++ b/briar-api/src/org/briarproject/api/transport/StreamReaderFactory.java @@ -8,13 +8,12 @@ public interface StreamReaderFactory { * Creates an {@link java.io.InputStream InputStream} for reading from a * transport stream. */ - InputStream createStreamReader(InputStream in, int maxFrameLength, - StreamContext ctx); + InputStream createStreamReader(InputStream in, StreamContext ctx); /** * Creates an {@link java.io.InputStream InputStream} for reading from an * invitation stream. */ InputStream createInvitationStreamReader(InputStream in, - int maxFrameLength, byte[] secret, boolean alice); + byte[] secret, boolean alice); } diff --git a/briar-api/src/org/briarproject/api/transport/StreamWriterFactory.java b/briar-api/src/org/briarproject/api/transport/StreamWriterFactory.java index 04a924cc6..38e373ccc 100644 --- a/briar-api/src/org/briarproject/api/transport/StreamWriterFactory.java +++ b/briar-api/src/org/briarproject/api/transport/StreamWriterFactory.java @@ -8,13 +8,12 @@ public interface StreamWriterFactory { * Creates an {@link java.io.OutputStream OutputStream} for writing to a * transport stream */ - OutputStream createStreamWriter(OutputStream out, int maxFrameLength, - StreamContext ctx); + OutputStream createStreamWriter(OutputStream out, StreamContext ctx); /** * Creates an {@link java.io.OutputStream OutputStream} for writing to an * invitation stream. */ OutputStream createInvitationStreamWriter(OutputStream out, - int maxFrameLength, byte[] secret, boolean alice); + byte[] secret, boolean alice); } diff --git a/briar-api/src/org/briarproject/api/transport/TransportConstants.java b/briar-api/src/org/briarproject/api/transport/TransportConstants.java index 666d74e96..7a13dbe9e 100644 --- a/briar-api/src/org/briarproject/api/transport/TransportConstants.java +++ b/briar-api/src/org/briarproject/api/transport/TransportConstants.java @@ -6,7 +6,7 @@ public interface TransportConstants { int TAG_LENGTH = 16; /** The maximum length of a frame in bytes, including the header and MAC. */ - int MAX_FRAME_LENGTH = 32768; // 2^15, 32 KiB + int MAX_FRAME_LENGTH = 1024; /** The length of the initalisation vector (IV) in bytes. */ int IV_LENGTH = 12; diff --git a/briar-core/src/org/briarproject/crypto/StreamDecrypterFactoryImpl.java b/briar-core/src/org/briarproject/crypto/StreamDecrypterFactoryImpl.java index 8f04e686a..5fb504b84 100644 --- a/briar-core/src/org/briarproject/crypto/StreamDecrypterFactoryImpl.java +++ b/briar-core/src/org/briarproject/crypto/StreamDecrypterFactoryImpl.java @@ -20,23 +20,21 @@ class StreamDecrypterFactoryImpl implements StreamDecrypterFactory { } public StreamDecrypter createStreamDecrypter(InputStream in, - int maxFrameLength, StreamContext ctx) { + StreamContext ctx) { byte[] secret = ctx.getSecret(); long streamNumber = ctx.getStreamNumber(); boolean alice = !ctx.getAlice(); // Derive the frame key SecretKey frameKey = crypto.deriveFrameKey(secret, streamNumber, alice); // Create the decrypter - return new StreamDecrypterImpl(in, crypto.getFrameCipher(), frameKey, - maxFrameLength); + return new StreamDecrypterImpl(in, crypto.getFrameCipher(), frameKey); } public StreamDecrypter createInvitationStreamDecrypter(InputStream in, - int maxFrameLength, byte[] secret, boolean alice) { + byte[] secret, boolean alice) { // Derive the frame key SecretKey frameKey = crypto.deriveFrameKey(secret, 0, alice); // Create the decrypter - return new StreamDecrypterImpl(in, crypto.getFrameCipher(), frameKey, - maxFrameLength); + return new StreamDecrypterImpl(in, crypto.getFrameCipher(), frameKey); } } diff --git a/briar-core/src/org/briarproject/crypto/StreamDecrypterImpl.java b/briar-core/src/org/briarproject/crypto/StreamDecrypterImpl.java index 4127e99a7..206a12c61 100644 --- a/briar-core/src/org/briarproject/crypto/StreamDecrypterImpl.java +++ b/briar-core/src/org/briarproject/crypto/StreamDecrypterImpl.java @@ -4,6 +4,7 @@ import static org.briarproject.api.transport.TransportConstants.AAD_LENGTH; import static org.briarproject.api.transport.TransportConstants.HEADER_LENGTH; import static org.briarproject.api.transport.TransportConstants.IV_LENGTH; import static org.briarproject.api.transport.TransportConstants.MAC_LENGTH; +import static org.briarproject.api.transport.TransportConstants.MAX_FRAME_LENGTH; import java.io.EOFException; import java.io.IOException; @@ -21,21 +22,19 @@ class StreamDecrypterImpl implements StreamDecrypter { private final AuthenticatedCipher frameCipher; private final SecretKey frameKey; private final byte[] iv, aad, plaintext, ciphertext; - private final int frameLength; private long frameNumber; private boolean finalFrame; StreamDecrypterImpl(InputStream in, AuthenticatedCipher frameCipher, - SecretKey frameKey, int frameLength) { + SecretKey frameKey) { this.in = in; this.frameCipher = frameCipher; this.frameKey = frameKey; - this.frameLength = frameLength; iv = new byte[IV_LENGTH]; aad = new byte[AAD_LENGTH]; - plaintext = new byte[frameLength - MAC_LENGTH]; - ciphertext = new byte[frameLength]; + plaintext = new byte[MAX_FRAME_LENGTH - MAC_LENGTH]; + ciphertext = new byte[MAX_FRAME_LENGTH]; frameNumber = 0; finalFrame = false; } @@ -44,9 +43,9 @@ class StreamDecrypterImpl implements StreamDecrypter { if(finalFrame) return -1; // Read the frame int ciphertextLength = 0; - while(ciphertextLength < frameLength) { + while(ciphertextLength < MAX_FRAME_LENGTH) { int read = in.read(ciphertext, ciphertextLength, - frameLength - ciphertextLength); + MAX_FRAME_LENGTH - ciphertextLength); if(read == -1) break; // We'll check the length later ciphertextLength += read; } @@ -65,7 +64,7 @@ class StreamDecrypterImpl implements StreamDecrypter { } // Decode and validate the header finalFrame = FrameEncoder.isFinalFrame(plaintext); - if(!finalFrame && ciphertextLength < frameLength) + if(!finalFrame && ciphertextLength < MAX_FRAME_LENGTH) throw new FormatException(); int payloadLength = FrameEncoder.getPayloadLength(plaintext); if(payloadLength > plaintextLength - HEADER_LENGTH) diff --git a/briar-core/src/org/briarproject/crypto/StreamEncrypterFactoryImpl.java b/briar-core/src/org/briarproject/crypto/StreamEncrypterFactoryImpl.java index 07c9deaab..ec8286e06 100644 --- a/briar-core/src/org/briarproject/crypto/StreamEncrypterFactoryImpl.java +++ b/briar-core/src/org/briarproject/crypto/StreamEncrypterFactoryImpl.java @@ -22,7 +22,7 @@ class StreamEncrypterFactoryImpl implements StreamEncrypterFactory { } public StreamEncrypter createStreamEncrypter(OutputStream out, - int maxFrameLength, StreamContext ctx) { + StreamContext ctx) { byte[] secret = ctx.getSecret(); long streamNumber = ctx.getStreamNumber(); boolean alice = ctx.getAlice(); @@ -34,15 +34,15 @@ class StreamEncrypterFactoryImpl implements StreamEncrypterFactory { SecretKey frameKey = crypto.deriveFrameKey(secret, streamNumber, alice); // Create the encrypter return new StreamEncrypterImpl(out, crypto.getFrameCipher(), frameKey, - maxFrameLength, tag); + tag); } public StreamEncrypter createInvitationStreamEncrypter(OutputStream out, - int maxFrameLength, byte[] secret, boolean alice) { + byte[] secret, boolean alice) { // Derive the frame key SecretKey frameKey = crypto.deriveFrameKey(secret, 0, alice); // Create the encrypter return new StreamEncrypterImpl(out, crypto.getFrameCipher(), frameKey, - maxFrameLength, null); + null); } } diff --git a/briar-core/src/org/briarproject/crypto/StreamEncrypterImpl.java b/briar-core/src/org/briarproject/crypto/StreamEncrypterImpl.java index 43a640391..0a09fc205 100644 --- a/briar-core/src/org/briarproject/crypto/StreamEncrypterImpl.java +++ b/briar-core/src/org/briarproject/crypto/StreamEncrypterImpl.java @@ -4,6 +4,7 @@ import static org.briarproject.api.transport.TransportConstants.AAD_LENGTH; import static org.briarproject.api.transport.TransportConstants.HEADER_LENGTH; import static org.briarproject.api.transport.TransportConstants.IV_LENGTH; import static org.briarproject.api.transport.TransportConstants.MAC_LENGTH; +import static org.briarproject.api.transport.TransportConstants.MAX_FRAME_LENGTH; import static org.briarproject.util.ByteUtils.MAX_32_BIT_UNSIGNED; import java.io.IOException; @@ -20,22 +21,20 @@ class StreamEncrypterImpl implements StreamEncrypter { private final AuthenticatedCipher frameCipher; private final SecretKey frameKey; private final byte[] tag, iv, aad, plaintext, ciphertext; - private final int frameLength; private long frameNumber; private boolean writeTag; StreamEncrypterImpl(OutputStream out, AuthenticatedCipher frameCipher, - SecretKey frameKey, int frameLength, byte[] tag) { + SecretKey frameKey, byte[] tag) { this.out = out; this.frameCipher = frameCipher; this.frameKey = frameKey; - this.frameLength = frameLength; this.tag = tag; iv = new byte[IV_LENGTH]; aad = new byte[AAD_LENGTH]; - plaintext = new byte[frameLength - MAC_LENGTH]; - ciphertext = new byte[frameLength]; + plaintext = new byte[MAX_FRAME_LENGTH - MAC_LENGTH]; + ciphertext = new byte[MAX_FRAME_LENGTH]; frameNumber = 0; writeTag = (tag != null); } @@ -54,8 +53,8 @@ class StreamEncrypterImpl implements StreamEncrypter { plaintextLength = HEADER_LENGTH + payloadLength; ciphertextLength = plaintextLength + MAC_LENGTH; } else { - plaintextLength = frameLength - MAC_LENGTH; - ciphertextLength = frameLength; + plaintextLength = MAX_FRAME_LENGTH - MAC_LENGTH; + ciphertextLength = MAX_FRAME_LENGTH; } // Encode the header FrameEncoder.encodeHeader(plaintext, finalFrame, payloadLength); diff --git a/briar-core/src/org/briarproject/invitation/AliceConnector.java b/briar-core/src/org/briarproject/invitation/AliceConnector.java index 8c0bd7813..f641af40a 100644 --- a/briar-core/src/org/briarproject/invitation/AliceConnector.java +++ b/briar-core/src/org/briarproject/invitation/AliceConnector.java @@ -128,16 +128,15 @@ class AliceConnector extends Connector { // Confirmation succeeded - upgrade to a secure connection if(LOG.isLoggable(INFO)) LOG.info(pluginName + " confirmation succeeded"); - int maxFrameLength = conn.getReader().getMaxFrameLength(); // Create the readers InputStream streamReader = streamReaderFactory.createInvitationStreamReader(in, - maxFrameLength, secret, false); // Bob's stream + secret, false); // Bob's stream r = readerFactory.createReader(streamReader); // Create the writers OutputStream streamWriter = streamWriterFactory.createInvitationStreamWriter(out, - maxFrameLength, secret, true); // Alice's stream + secret, true); // Alice's stream w = writerFactory.createWriter(streamWriter); // Derive the invitation nonces byte[][] nonces = crypto.deriveInvitationNonces(secret); diff --git a/briar-core/src/org/briarproject/invitation/BobConnector.java b/briar-core/src/org/briarproject/invitation/BobConnector.java index 6b435fd2a..dae869192 100644 --- a/briar-core/src/org/briarproject/invitation/BobConnector.java +++ b/briar-core/src/org/briarproject/invitation/BobConnector.java @@ -128,16 +128,15 @@ class BobConnector extends Connector { // Confirmation succeeded - upgrade to a secure connection if(LOG.isLoggable(INFO)) LOG.info(pluginName + " confirmation succeeded"); - int maxFrameLength = conn.getReader().getMaxFrameLength(); // Create the readers InputStream streamReader = streamReaderFactory.createInvitationStreamReader(in, - maxFrameLength, secret, true); // Alice's stream + secret, true); // Alice's stream r = readerFactory.createReader(streamReader); // Create the writers OutputStream streamWriter = streamWriterFactory.createInvitationStreamWriter(out, - maxFrameLength, secret, false); // Bob's stream + secret, false); // Bob's stream w = writerFactory.createWriter(streamWriter); // Derive the nonces byte[][] nonces = crypto.deriveInvitationNonces(secret); diff --git a/briar-core/src/org/briarproject/plugins/ConnectionManagerImpl.java b/briar-core/src/org/briarproject/plugins/ConnectionManagerImpl.java index 2b1a5c633..b7cb70c1b 100644 --- a/briar-core/src/org/briarproject/plugins/ConnectionManagerImpl.java +++ b/briar-core/src/org/briarproject/plugins/ConnectionManagerImpl.java @@ -95,7 +95,7 @@ class ConnectionManagerImpl implements ConnectionManager { private MessagingSession createIncomingSession(StreamContext ctx, TransportConnectionReader r) throws IOException { InputStream streamReader = streamReaderFactory.createStreamReader( - r.getInputStream(), r.getMaxFrameLength(), ctx); + r.getInputStream(), ctx); return messagingSessionFactory.createIncomingSession( ctx.getContactId(), ctx.getTransportId(), streamReader); } @@ -103,7 +103,7 @@ class ConnectionManagerImpl implements ConnectionManager { private MessagingSession createSimplexOutgoingSession(StreamContext ctx, TransportConnectionWriter w) throws IOException { OutputStream streamWriter = streamWriterFactory.createStreamWriter( - w.getOutputStream(), w.getMaxFrameLength(), ctx); + w.getOutputStream(), ctx); return messagingSessionFactory.createSimplexOutgoingSession( ctx.getContactId(), ctx.getTransportId(), w.getMaxLatency(), streamWriter); @@ -112,7 +112,7 @@ class ConnectionManagerImpl implements ConnectionManager { private MessagingSession createDuplexOutgoingSession(StreamContext ctx, TransportConnectionWriter w) throws IOException { OutputStream streamWriter = streamWriterFactory.createStreamWriter( - w.getOutputStream(), w.getMaxFrameLength(), ctx); + w.getOutputStream(), ctx); return messagingSessionFactory.createDuplexOutgoingSession( ctx.getContactId(), ctx.getTransportId(), w.getMaxLatency(), w.getMaxIdleTime(), streamWriter); diff --git a/briar-core/src/org/briarproject/plugins/file/FilePlugin.java b/briar-core/src/org/briarproject/plugins/file/FilePlugin.java index a187760aa..abaa63492 100644 --- a/briar-core/src/org/briarproject/plugins/file/FilePlugin.java +++ b/briar-core/src/org/briarproject/plugins/file/FilePlugin.java @@ -28,7 +28,7 @@ public abstract class FilePlugin implements SimplexPlugin { protected final Executor ioExecutor; protected final FileUtils fileUtils; protected final SimplexPluginCallback callback; - protected final int maxFrameLength, maxLatency; + protected final int maxLatency; protected volatile boolean running = false; @@ -38,19 +38,13 @@ public abstract class FilePlugin implements SimplexPlugin { protected abstract void readerFinished(File f); protected FilePlugin(Executor ioExecutor, FileUtils fileUtils, - SimplexPluginCallback callback, int maxFrameLength, - int maxLatency) { + SimplexPluginCallback callback, int maxLatency) { this.ioExecutor = ioExecutor; this.fileUtils = fileUtils; this.callback = callback; - this.maxFrameLength = maxFrameLength; this.maxLatency = maxLatency; } - public int getMaxFrameLength() { - return maxFrameLength; - } - public int getMaxLatency() { return maxLatency; } diff --git a/briar-core/src/org/briarproject/plugins/file/FileTransportReader.java b/briar-core/src/org/briarproject/plugins/file/FileTransportReader.java index 316773ec0..4c434faa6 100644 --- a/briar-core/src/org/briarproject/plugins/file/FileTransportReader.java +++ b/briar-core/src/org/briarproject/plugins/file/FileTransportReader.java @@ -24,10 +24,6 @@ class FileTransportReader implements TransportConnectionReader { this.plugin = plugin; } - public int getMaxFrameLength() { - return plugin.getMaxFrameLength(); - } - public long getMaxLatency() { return plugin.getMaxLatency(); } diff --git a/briar-core/src/org/briarproject/plugins/file/FileTransportWriter.java b/briar-core/src/org/briarproject/plugins/file/FileTransportWriter.java index c2ffcde08..f9b14651e 100644 --- a/briar-core/src/org/briarproject/plugins/file/FileTransportWriter.java +++ b/briar-core/src/org/briarproject/plugins/file/FileTransportWriter.java @@ -27,10 +27,6 @@ class FileTransportWriter implements TransportConnectionWriter { this.plugin = plugin; } - public int getMaxFrameLength() { - return plugin.getMaxFrameLength(); - } - public int getMaxLatency() { return plugin.getMaxLatency(); } diff --git a/briar-core/src/org/briarproject/plugins/tcp/LanTcpPlugin.java b/briar-core/src/org/briarproject/plugins/tcp/LanTcpPlugin.java index 6f15c6fe8..ea030c40e 100644 --- a/briar-core/src/org/briarproject/plugins/tcp/LanTcpPlugin.java +++ b/briar-core/src/org/briarproject/plugins/tcp/LanTcpPlugin.java @@ -17,10 +17,8 @@ class LanTcpPlugin extends TcpPlugin { static final TransportId ID = new TransportId("lan"); LanTcpPlugin(Executor ioExecutor, DuplexPluginCallback callback, - int maxFrameLength, int maxLatency, int maxIdleTime, - int pollingInterval) { - super(ioExecutor, callback, maxFrameLength, maxLatency, maxIdleTime, - pollingInterval); + int maxLatency, int maxIdleTime, int pollingInterval) { + super(ioExecutor, callback, maxLatency, maxIdleTime, pollingInterval); } public TransportId getId() { diff --git a/briar-core/src/org/briarproject/plugins/tcp/LanTcpPluginFactory.java b/briar-core/src/org/briarproject/plugins/tcp/LanTcpPluginFactory.java index 8527df941..68f2edc0e 100644 --- a/briar-core/src/org/briarproject/plugins/tcp/LanTcpPluginFactory.java +++ b/briar-core/src/org/briarproject/plugins/tcp/LanTcpPluginFactory.java @@ -9,7 +9,6 @@ import org.briarproject.api.plugins.duplex.DuplexPluginFactory; public class LanTcpPluginFactory implements DuplexPluginFactory { - private static final int MAX_FRAME_LENGTH = 1024; private static final int MAX_LATENCY = 30 * 1000; // 30 seconds private static final int MAX_IDLE_TIME = 30 * 1000; // 30 seconds private static final int POLLING_INTERVAL = 3 * 60 * 1000; // 3 minutes @@ -25,7 +24,7 @@ public class LanTcpPluginFactory implements DuplexPluginFactory { } public DuplexPlugin createPlugin(DuplexPluginCallback callback) { - return new LanTcpPlugin(ioExecutor, callback, MAX_FRAME_LENGTH, - MAX_LATENCY, MAX_IDLE_TIME, POLLING_INTERVAL); + return new LanTcpPlugin(ioExecutor, callback, MAX_LATENCY, + MAX_IDLE_TIME, POLLING_INTERVAL); } } diff --git a/briar-core/src/org/briarproject/plugins/tcp/TcpPlugin.java b/briar-core/src/org/briarproject/plugins/tcp/TcpPlugin.java index 0a4946b48..083f46598 100644 --- a/briar-core/src/org/briarproject/plugins/tcp/TcpPlugin.java +++ b/briar-core/src/org/briarproject/plugins/tcp/TcpPlugin.java @@ -37,8 +37,7 @@ abstract class TcpPlugin implements DuplexPlugin { protected final Executor ioExecutor; protected final DuplexPluginCallback callback; - protected final int maxFrameLength, maxLatency, maxIdleTime; - protected final int pollingInterval, socketTimeout; + protected final int maxLatency, maxIdleTime, pollingInterval, socketTimeout; protected volatile boolean running = false; protected volatile ServerSocket socket = null; @@ -53,11 +52,9 @@ abstract class TcpPlugin implements DuplexPlugin { protected abstract boolean isConnectable(InetSocketAddress remote); protected TcpPlugin(Executor ioExecutor, DuplexPluginCallback callback, - int maxFrameLength, int maxLatency, int maxIdleTime, - int pollingInterval) { + int maxLatency, int maxIdleTime, int pollingInterval) { this.ioExecutor = ioExecutor; this.callback = callback; - this.maxFrameLength = maxFrameLength; this.maxLatency = maxLatency; this.maxIdleTime = maxIdleTime; this.pollingInterval = pollingInterval; @@ -66,10 +63,6 @@ abstract class TcpPlugin implements DuplexPlugin { else socketTimeout = maxIdleTime * 2; } - public int getMaxFrameLength() { - return maxFrameLength; - } - public int getMaxLatency() { return maxLatency; } diff --git a/briar-core/src/org/briarproject/plugins/tcp/TcpTransportConnection.java b/briar-core/src/org/briarproject/plugins/tcp/TcpTransportConnection.java index fff4ee01b..aae3c53ba 100644 --- a/briar-core/src/org/briarproject/plugins/tcp/TcpTransportConnection.java +++ b/briar-core/src/org/briarproject/plugins/tcp/TcpTransportConnection.java @@ -38,10 +38,6 @@ class TcpTransportConnection implements DuplexTransportConnection { private class Reader implements TransportConnectionReader { - public int getMaxFrameLength() { - return plugin.getMaxFrameLength(); - } - public long getMaxLatency() { return plugin.getMaxLatency(); } @@ -59,10 +55,6 @@ class TcpTransportConnection implements DuplexTransportConnection { private class Writer implements TransportConnectionWriter { - public int getMaxFrameLength() { - return plugin.getMaxFrameLength(); - } - public int getMaxLatency() { return plugin.getMaxLatency(); } diff --git a/briar-core/src/org/briarproject/plugins/tcp/WanTcpPlugin.java b/briar-core/src/org/briarproject/plugins/tcp/WanTcpPlugin.java index 67be0c721..15a4dfde8 100644 --- a/briar-core/src/org/briarproject/plugins/tcp/WanTcpPlugin.java +++ b/briar-core/src/org/briarproject/plugins/tcp/WanTcpPlugin.java @@ -21,10 +21,9 @@ class WanTcpPlugin extends TcpPlugin { private volatile MappingResult mappingResult; WanTcpPlugin(Executor ioExecutor, PortMapper portMapper, - DuplexPluginCallback callback, int maxFrameLength, int maxLatency, - int maxIdleTime, int pollingInterval) { - super(ioExecutor, callback, maxFrameLength, maxLatency, maxIdleTime, - pollingInterval); + DuplexPluginCallback callback, int maxLatency, int maxIdleTime, + int pollingInterval) { + super(ioExecutor, callback, maxLatency, maxIdleTime, pollingInterval); this.portMapper = portMapper; } diff --git a/briar-core/src/org/briarproject/plugins/tcp/WanTcpPluginFactory.java b/briar-core/src/org/briarproject/plugins/tcp/WanTcpPluginFactory.java index 8129661ff..bd326ebbc 100644 --- a/briar-core/src/org/briarproject/plugins/tcp/WanTcpPluginFactory.java +++ b/briar-core/src/org/briarproject/plugins/tcp/WanTcpPluginFactory.java @@ -10,7 +10,6 @@ import org.briarproject.api.plugins.duplex.DuplexPluginFactory; public class WanTcpPluginFactory implements DuplexPluginFactory { - private static final int MAX_FRAME_LENGTH = 1024; private static final int MAX_LATENCY = 30 * 1000; // 30 seconds private static final int MAX_IDLE_TIME = 30 * 1000; // 30 seconds private static final int POLLING_INTERVAL = 5 * 60 * 1000; // 5 minutes @@ -30,7 +29,6 @@ public class WanTcpPluginFactory implements DuplexPluginFactory { public DuplexPlugin createPlugin(DuplexPluginCallback callback) { return new WanTcpPlugin(ioExecutor, new PortMapperImpl(shutdownManager), - callback, MAX_FRAME_LENGTH, MAX_LATENCY, MAX_IDLE_TIME, - POLLING_INTERVAL); + callback, MAX_LATENCY, MAX_IDLE_TIME, POLLING_INTERVAL); } } diff --git a/briar-core/src/org/briarproject/transport/StreamReaderFactoryImpl.java b/briar-core/src/org/briarproject/transport/StreamReaderFactoryImpl.java index daa4f2bb7..d066cacd4 100644 --- a/briar-core/src/org/briarproject/transport/StreamReaderFactoryImpl.java +++ b/briar-core/src/org/briarproject/transport/StreamReaderFactoryImpl.java @@ -4,7 +4,6 @@ import java.io.InputStream; import javax.inject.Inject; -import org.briarproject.api.crypto.StreamDecrypter; import org.briarproject.api.crypto.StreamDecrypterFactory; import org.briarproject.api.transport.StreamContext; import org.briarproject.api.transport.StreamReaderFactory; @@ -18,18 +17,15 @@ class StreamReaderFactoryImpl implements StreamReaderFactory { this.streamDecrypterFactory = streamDecrypterFactory; } - public InputStream createStreamReader(InputStream in, int maxFrameLength, - StreamContext ctx) { - StreamDecrypter s = streamDecrypterFactory.createStreamDecrypter(in, - maxFrameLength, ctx); - return new StreamReaderImpl(s, maxFrameLength); + public InputStream createStreamReader(InputStream in, StreamContext ctx) { + return new StreamReaderImpl( + streamDecrypterFactory.createStreamDecrypter(in, ctx)); } public InputStream createInvitationStreamReader(InputStream in, - int maxFrameLength, byte[] secret, boolean alice) { - StreamDecrypter s = + byte[] secret, boolean alice) { + return new StreamReaderImpl( streamDecrypterFactory.createInvitationStreamDecrypter(in, - maxFrameLength, secret, alice); - return new StreamReaderImpl(s, maxFrameLength); + secret, alice)); } } diff --git a/briar-core/src/org/briarproject/transport/StreamReaderImpl.java b/briar-core/src/org/briarproject/transport/StreamReaderImpl.java index e9a30b24a..f0a1a26c1 100644 --- a/briar-core/src/org/briarproject/transport/StreamReaderImpl.java +++ b/briar-core/src/org/briarproject/transport/StreamReaderImpl.java @@ -2,6 +2,7 @@ package org.briarproject.transport; import static org.briarproject.api.transport.TransportConstants.HEADER_LENGTH; import static org.briarproject.api.transport.TransportConstants.MAC_LENGTH; +import static org.briarproject.api.transport.TransportConstants.MAX_FRAME_LENGTH; import java.io.IOException; import java.io.InputStream; @@ -15,9 +16,9 @@ class StreamReaderImpl extends InputStream { private int offset = 0, length = 0; - StreamReaderImpl(StreamDecrypter decrypter, int frameLength) { + StreamReaderImpl(StreamDecrypter decrypter) { this.decrypter = decrypter; - payload = new byte[frameLength - HEADER_LENGTH - MAC_LENGTH]; + payload = new byte[MAX_FRAME_LENGTH - HEADER_LENGTH - MAC_LENGTH]; } @Override diff --git a/briar-core/src/org/briarproject/transport/StreamWriterFactoryImpl.java b/briar-core/src/org/briarproject/transport/StreamWriterFactoryImpl.java index f57a8f69b..89da3a464 100644 --- a/briar-core/src/org/briarproject/transport/StreamWriterFactoryImpl.java +++ b/briar-core/src/org/briarproject/transport/StreamWriterFactoryImpl.java @@ -4,7 +4,6 @@ import java.io.OutputStream; import javax.inject.Inject; -import org.briarproject.api.crypto.StreamEncrypter; import org.briarproject.api.crypto.StreamEncrypterFactory; import org.briarproject.api.transport.StreamContext; import org.briarproject.api.transport.StreamWriterFactory; @@ -18,18 +17,16 @@ class StreamWriterFactoryImpl implements StreamWriterFactory { this.streamEncrypterFactory = streamEncrypterFactory; } - public OutputStream createStreamWriter(OutputStream out, int maxFrameLength, + public OutputStream createStreamWriter(OutputStream out, StreamContext ctx) { - StreamEncrypter s = streamEncrypterFactory.createStreamEncrypter(out, - maxFrameLength, ctx); - return new StreamWriterImpl(s, maxFrameLength); + return new StreamWriterImpl( + streamEncrypterFactory.createStreamEncrypter(out, ctx)); } public OutputStream createInvitationStreamWriter(OutputStream out, - int maxFrameLength, byte[] secret, boolean alice) { - StreamEncrypter s = + byte[] secret, boolean alice) { + return new StreamWriterImpl( streamEncrypterFactory.createInvitationStreamEncrypter(out, - maxFrameLength, secret, alice); - return new StreamWriterImpl(s, maxFrameLength); + secret, alice)); } } \ No newline at end of file diff --git a/briar-core/src/org/briarproject/transport/StreamWriterImpl.java b/briar-core/src/org/briarproject/transport/StreamWriterImpl.java index 05653fd42..22384dd22 100644 --- a/briar-core/src/org/briarproject/transport/StreamWriterImpl.java +++ b/briar-core/src/org/briarproject/transport/StreamWriterImpl.java @@ -2,6 +2,7 @@ package org.briarproject.transport; import static org.briarproject.api.transport.TransportConstants.HEADER_LENGTH; import static org.briarproject.api.transport.TransportConstants.MAC_LENGTH; +import static org.briarproject.api.transport.TransportConstants.MAX_FRAME_LENGTH; import java.io.IOException; import java.io.OutputStream; @@ -22,9 +23,9 @@ class StreamWriterImpl extends OutputStream { private int length = 0; - StreamWriterImpl(StreamEncrypter encrypter, int maxFrameLength) { + StreamWriterImpl(StreamEncrypter encrypter) { this.encrypter = encrypter; - payload = new byte[maxFrameLength - HEADER_LENGTH - MAC_LENGTH]; + payload = new byte[MAX_FRAME_LENGTH - HEADER_LENGTH - MAC_LENGTH]; } @Override diff --git a/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothPlugin.java b/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothPlugin.java index be87193ed..45dca315f 100644 --- a/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothPlugin.java +++ b/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothPlugin.java @@ -46,7 +46,7 @@ class BluetoothPlugin implements DuplexPlugin { private final Clock clock; private final SecureRandom secureRandom; private final DuplexPluginCallback callback; - private final int maxFrameLength, maxLatency, pollingInterval; + private final int maxLatency, pollingInterval; private final Semaphore discoverySemaphore = new Semaphore(1); private volatile boolean running = false; @@ -54,13 +54,12 @@ class BluetoothPlugin implements DuplexPlugin { private volatile LocalDevice localDevice = null; BluetoothPlugin(Executor ioExecutor, Clock clock, SecureRandom secureRandom, - DuplexPluginCallback callback, int maxFrameLength, int maxLatency, + DuplexPluginCallback callback, int maxLatency, int pollingInterval) { this.ioExecutor = ioExecutor; this.clock = clock; this.secureRandom = secureRandom; this.callback = callback; - this.maxFrameLength = maxFrameLength; this.maxLatency = maxLatency; this.pollingInterval = pollingInterval; } @@ -69,10 +68,6 @@ class BluetoothPlugin implements DuplexPlugin { return ID; } - public int getMaxFrameLength() { - return maxFrameLength; - } - public int getMaxLatency() { return maxLatency; } diff --git a/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothPluginFactory.java b/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothPluginFactory.java index a25a73c37..28859c4d7 100644 --- a/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothPluginFactory.java +++ b/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothPluginFactory.java @@ -12,7 +12,6 @@ import org.briarproject.system.SystemClock; public class BluetoothPluginFactory implements DuplexPluginFactory { - private static final int MAX_FRAME_LENGTH = 1024; private static final int MAX_LATENCY = 30 * 1000; // 30 seconds private static final int POLLING_INTERVAL = 3 * 60 * 1000; // 3 minutes @@ -33,6 +32,6 @@ public class BluetoothPluginFactory implements DuplexPluginFactory { public DuplexPlugin createPlugin(DuplexPluginCallback callback) { return new BluetoothPlugin(ioExecutor, clock, secureRandom, callback, - MAX_FRAME_LENGTH, MAX_LATENCY, POLLING_INTERVAL); + MAX_LATENCY, POLLING_INTERVAL); } } diff --git a/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothTransportConnection.java b/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothTransportConnection.java index 0767c42d9..8e70db480 100644 --- a/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothTransportConnection.java +++ b/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothTransportConnection.java @@ -39,10 +39,6 @@ class BluetoothTransportConnection implements DuplexTransportConnection { private class Reader implements TransportConnectionReader { - public int getMaxFrameLength() { - return plugin.getMaxFrameLength(); - } - public long getMaxLatency() { return plugin.getMaxLatency(); } @@ -60,10 +56,6 @@ class BluetoothTransportConnection implements DuplexTransportConnection { private class Writer implements TransportConnectionWriter { - public int getMaxFrameLength() { - return plugin.getMaxFrameLength(); - } - public int getMaxLatency() { return plugin.getMaxLatency(); } diff --git a/briar-desktop/src/org/briarproject/plugins/file/RemovableDrivePlugin.java b/briar-desktop/src/org/briarproject/plugins/file/RemovableDrivePlugin.java index faaf4b01c..f648ff092 100644 --- a/briar-desktop/src/org/briarproject/plugins/file/RemovableDrivePlugin.java +++ b/briar-desktop/src/org/briarproject/plugins/file/RemovableDrivePlugin.java @@ -29,8 +29,8 @@ implements RemovableDriveMonitor.Callback { RemovableDrivePlugin(Executor ioExecutor, FileUtils fileUtils, SimplexPluginCallback callback, RemovableDriveFinder finder, - RemovableDriveMonitor monitor, int maxFrameLength, int maxLatency) { - super(ioExecutor, fileUtils, callback, maxFrameLength, maxLatency); + RemovableDriveMonitor monitor, int maxLatency) { + super(ioExecutor, fileUtils, callback, maxLatency); this.finder = finder; this.monitor = monitor; } diff --git a/briar-desktop/src/org/briarproject/plugins/file/RemovableDrivePluginFactory.java b/briar-desktop/src/org/briarproject/plugins/file/RemovableDrivePluginFactory.java index 4b7d6835f..68b1eaf31 100644 --- a/briar-desktop/src/org/briarproject/plugins/file/RemovableDrivePluginFactory.java +++ b/briar-desktop/src/org/briarproject/plugins/file/RemovableDrivePluginFactory.java @@ -1,7 +1,5 @@ package org.briarproject.plugins.file; -import static org.briarproject.api.transport.TransportConstants.MAX_FRAME_LENGTH; - import java.util.concurrent.Executor; import org.briarproject.api.TransportId; @@ -52,6 +50,6 @@ public class RemovableDrivePluginFactory implements SimplexPluginFactory { return null; } return new RemovableDrivePlugin(ioExecutor, fileUtils, callback, - finder, monitor, MAX_FRAME_LENGTH, MAX_LATENCY); + finder, monitor, MAX_LATENCY); } } diff --git a/briar-desktop/src/org/briarproject/plugins/modem/ModemPlugin.java b/briar-desktop/src/org/briarproject/plugins/modem/ModemPlugin.java index 092eeec8b..b0a58969c 100644 --- a/briar-desktop/src/org/briarproject/plugins/modem/ModemPlugin.java +++ b/briar-desktop/src/org/briarproject/plugins/modem/ModemPlugin.java @@ -32,17 +32,16 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback { private final ModemFactory modemFactory; private final SerialPortList serialPortList; private final DuplexPluginCallback callback; - private final int maxFrameLength, maxLatency; + private final int maxLatency; private volatile boolean running = false; private volatile Modem modem = null; ModemPlugin(ModemFactory modemFactory, SerialPortList serialPortList, - DuplexPluginCallback callback, int maxFrameLength, int maxLatency) { + DuplexPluginCallback callback, int maxLatency) { this.modemFactory = modemFactory; this.serialPortList = serialPortList; this.callback = callback; - this.maxFrameLength = maxFrameLength; this.maxLatency = maxLatency; } @@ -50,10 +49,6 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback { return ID; } - public int getMaxFrameLength() { - return maxFrameLength; - } - public int getMaxLatency() { return maxLatency; } @@ -199,10 +194,6 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback { private class Reader implements TransportConnectionReader { - public int getMaxFrameLength() { - return maxFrameLength; - } - public long getMaxLatency() { return maxLatency; } @@ -219,10 +210,6 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback { private class Writer implements TransportConnectionWriter { - public int getMaxFrameLength() { - return getMaxFrameLength(); - } - public int getMaxLatency() { return getMaxLatency(); } diff --git a/briar-desktop/src/org/briarproject/plugins/modem/ModemPluginFactory.java b/briar-desktop/src/org/briarproject/plugins/modem/ModemPluginFactory.java index 670be76fc..f70fc3be7 100644 --- a/briar-desktop/src/org/briarproject/plugins/modem/ModemPluginFactory.java +++ b/briar-desktop/src/org/briarproject/plugins/modem/ModemPluginFactory.java @@ -11,7 +11,6 @@ import org.briarproject.util.StringUtils; public class ModemPluginFactory implements DuplexPluginFactory { - private static final int MAX_FRAME_LENGTH = 1024; private static final int MAX_LATENCY = 30 * 1000; // 30 seconds private final ModemFactory modemFactory; @@ -32,6 +31,6 @@ public class ModemPluginFactory implements DuplexPluginFactory { String enabled = callback.getConfig().get("enabled"); if(StringUtils.isNullOrEmpty(enabled)) return null; return new ModemPlugin(modemFactory, serialPortList, callback, - MAX_FRAME_LENGTH, MAX_LATENCY); + MAX_LATENCY); } } diff --git a/briar-tests/src/org/briarproject/ProtocolIntegrationTest.java b/briar-tests/src/org/briarproject/ProtocolIntegrationTest.java index cfd5af2d5..633a4929a 100644 --- a/briar-tests/src/org/briarproject/ProtocolIntegrationTest.java +++ b/briar-tests/src/org/briarproject/ProtocolIntegrationTest.java @@ -1,6 +1,5 @@ package org.briarproject; -import static org.briarproject.api.transport.TransportConstants.MAX_FRAME_LENGTH; import static org.briarproject.api.transport.TransportConstants.TAG_LENGTH; import static org.junit.Assert.assertArrayEquals; @@ -118,8 +117,8 @@ public class ProtocolIntegrationTest extends BriarTestCase { ByteArrayOutputStream out = new ByteArrayOutputStream(); StreamContext ctx = new StreamContext(contactId, transportId, secret, 0, true); - OutputStream streamWriter = streamWriterFactory.createStreamWriter(out, - MAX_FRAME_LENGTH, ctx); + OutputStream streamWriter = + streamWriterFactory.createStreamWriter(out, ctx); PacketWriter packetWriter = packetWriterFactory.createPacketWriter( streamWriter); @@ -150,8 +149,8 @@ public class ProtocolIntegrationTest extends BriarTestCase { // FIXME: Check that the expected tag was received StreamContext ctx = new StreamContext(contactId, transportId, secret, 0, false); - InputStream streamReader = streamReaderFactory.createStreamReader(in, - MAX_FRAME_LENGTH, ctx); + InputStream streamReader = + streamReaderFactory.createStreamReader(in, ctx); PacketReader packetReader = packetReaderFactory.createPacketReader( streamReader); diff --git a/briar-tests/src/org/briarproject/crypto/StreamDecrypterImplTest.java b/briar-tests/src/org/briarproject/crypto/StreamDecrypterImplTest.java index 1ee05436a..b0b5f239a 100644 --- a/briar-tests/src/org/briarproject/crypto/StreamDecrypterImplTest.java +++ b/briar-tests/src/org/briarproject/crypto/StreamDecrypterImplTest.java @@ -4,6 +4,7 @@ import static org.briarproject.api.transport.TransportConstants.AAD_LENGTH; import static org.briarproject.api.transport.TransportConstants.HEADER_LENGTH; import static org.briarproject.api.transport.TransportConstants.IV_LENGTH; import static org.briarproject.api.transport.TransportConstants.MAC_LENGTH; +import static org.briarproject.api.transport.TransportConstants.MAX_FRAME_LENGTH; import java.io.ByteArrayInputStream; @@ -14,6 +15,7 @@ import org.briarproject.api.FormatException; import org.briarproject.api.crypto.AuthenticatedCipher; import org.briarproject.api.crypto.CryptoComponent; import org.briarproject.api.crypto.SecretKey; +import org.briarproject.util.ByteUtils; import org.junit.Test; import com.google.inject.Guice; @@ -23,9 +25,8 @@ public class StreamDecrypterImplTest extends BriarTestCase { // FIXME: This is an integration test, not a unit test - private static final int FRAME_LENGTH = 1024; private static final int MAX_PAYLOAD_LENGTH = - FRAME_LENGTH - HEADER_LENGTH - MAC_LENGTH; + MAX_FRAME_LENGTH - HEADER_LENGTH - MAC_LENGTH; private final CryptoComponent crypto; private final AuthenticatedCipher frameCipher; @@ -42,16 +43,16 @@ public class StreamDecrypterImplTest extends BriarTestCase { @Test public void testReadValidFrames() throws Exception { // Generate two valid frames - byte[] frame = generateFrame(0, FRAME_LENGTH, 123, false, false); - byte[] frame1 = generateFrame(1, FRAME_LENGTH, 123, false, false); + byte[] frame = generateFrame(0, MAX_FRAME_LENGTH, 123, false, false); + byte[] frame1 = generateFrame(1, MAX_FRAME_LENGTH, 123, false, false); // Concatenate the frames - byte[] valid = new byte[FRAME_LENGTH * 2]; - System.arraycopy(frame, 0, valid, 0, FRAME_LENGTH); - System.arraycopy(frame1, 0, valid, FRAME_LENGTH, FRAME_LENGTH); + byte[] valid = new byte[MAX_FRAME_LENGTH * 2]; + System.arraycopy(frame, 0, valid, 0, MAX_FRAME_LENGTH); + System.arraycopy(frame1, 0, valid, MAX_FRAME_LENGTH, MAX_FRAME_LENGTH); // Read the frames ByteArrayInputStream in = new ByteArrayInputStream(valid); StreamDecrypterImpl i = new StreamDecrypterImpl(in, frameCipher, - frameKey, FRAME_LENGTH); + frameKey); byte[] payload = new byte[MAX_PAYLOAD_LENGTH]; assertEquals(123, i.readFrame(payload)); assertEquals(123, i.readFrame(payload)); @@ -60,14 +61,14 @@ public class StreamDecrypterImplTest extends BriarTestCase { @Test public void testTruncatedFrameThrowsException() throws Exception { // Generate a valid frame - byte[] frame = generateFrame(0, FRAME_LENGTH, 123, false, false); + byte[] frame = generateFrame(0, MAX_FRAME_LENGTH, 123, false, false); // Chop off the last byte - byte[] truncated = new byte[FRAME_LENGTH - 1]; - System.arraycopy(frame, 0, truncated, 0, FRAME_LENGTH - 1); + byte[] truncated = new byte[MAX_FRAME_LENGTH - 1]; + System.arraycopy(frame, 0, truncated, 0, MAX_FRAME_LENGTH - 1); // Try to read the frame, which should fail due to truncation ByteArrayInputStream in = new ByteArrayInputStream(truncated); StreamDecrypterImpl i = new StreamDecrypterImpl(in, frameCipher, - frameKey, FRAME_LENGTH); + frameKey); try { i.readFrame(new byte[MAX_PAYLOAD_LENGTH]); fail(); @@ -77,13 +78,13 @@ public class StreamDecrypterImplTest extends BriarTestCase { @Test public void testModifiedFrameThrowsException() throws Exception { // Generate a valid frame - byte[] frame = generateFrame(0, FRAME_LENGTH, 123, false, false); + byte[] frame = generateFrame(0, MAX_FRAME_LENGTH, 123, false, false); // Modify a randomly chosen byte of the frame - frame[(int) (Math.random() * FRAME_LENGTH)] ^= 1; + frame[(int) (Math.random() * MAX_FRAME_LENGTH)] ^= 1; // Try to read the frame, which should fail due to modification ByteArrayInputStream in = new ByteArrayInputStream(frame); StreamDecrypterImpl i = new StreamDecrypterImpl(in, frameCipher, - frameKey, FRAME_LENGTH); + frameKey); try { i.readFrame(new byte[MAX_PAYLOAD_LENGTH]); fail(); @@ -93,11 +94,12 @@ public class StreamDecrypterImplTest extends BriarTestCase { @Test public void testShortNonFinalFrameThrowsException() throws Exception { // Generate a short non-final frame - byte[] frame = generateFrame(0, FRAME_LENGTH - 1, 123, false, false); + byte[] frame = generateFrame(0, MAX_FRAME_LENGTH - 1, 123, false, + false); // Try to read the frame, which should fail due to invalid length ByteArrayInputStream in = new ByteArrayInputStream(frame); StreamDecrypterImpl i = new StreamDecrypterImpl(in, frameCipher, - frameKey, FRAME_LENGTH); + frameKey); try { i.readFrame(new byte[MAX_PAYLOAD_LENGTH]); fail(); @@ -107,11 +109,11 @@ public class StreamDecrypterImplTest extends BriarTestCase { @Test public void testShortFinalFrameDoesNotThrowException() throws Exception { // Generate a short final frame - byte[] frame = generateFrame(0, FRAME_LENGTH - 1, 123, true, false); + byte[] frame = generateFrame(0, MAX_FRAME_LENGTH - 1, 123, true, false); // Read the frame ByteArrayInputStream in = new ByteArrayInputStream(frame); StreamDecrypterImpl i = new StreamDecrypterImpl(in, frameCipher, - frameKey, FRAME_LENGTH); + frameKey); int length = i.readFrame(new byte[MAX_PAYLOAD_LENGTH]); assertEquals(123, length); } @@ -119,12 +121,12 @@ public class StreamDecrypterImplTest extends BriarTestCase { @Test public void testInvalidPayloadLengthThrowsException() throws Exception { // Generate a frame with an invalid payload length - byte[] frame = generateFrame(0, FRAME_LENGTH, MAX_PAYLOAD_LENGTH + 1, - false, false); + byte[] frame = generateFrame(0, MAX_FRAME_LENGTH, 123, false, false); + ByteUtils.writeUint16(MAX_PAYLOAD_LENGTH + 1, frame, 0); // Try to read the frame, which should fail due to invalid length ByteArrayInputStream in = new ByteArrayInputStream(frame); StreamDecrypterImpl i = new StreamDecrypterImpl(in, frameCipher, - frameKey, FRAME_LENGTH); + frameKey); try { i.readFrame(new byte[MAX_PAYLOAD_LENGTH]); fail(); @@ -134,11 +136,11 @@ public class StreamDecrypterImplTest extends BriarTestCase { @Test public void testNonZeroPaddingThrowsException() throws Exception { // Generate a frame with bad padding - byte[] frame = generateFrame(0, FRAME_LENGTH, 123, false, true); + byte[] frame = generateFrame(0, MAX_FRAME_LENGTH, 123, false, true); // Try to read the frame, which should fail due to bad padding ByteArrayInputStream in = new ByteArrayInputStream(frame); StreamDecrypterImpl i = new StreamDecrypterImpl(in, frameCipher, - frameKey, FRAME_LENGTH); + frameKey); try { i.readFrame(new byte[MAX_PAYLOAD_LENGTH]); fail(); @@ -148,17 +150,18 @@ public class StreamDecrypterImplTest extends BriarTestCase { @Test public void testCannotReadBeyondFinalFrame() throws Exception { // Generate a valid final frame and another valid final frame after it - byte[] frame = generateFrame(0, FRAME_LENGTH, MAX_PAYLOAD_LENGTH, true, - false); - byte[] frame1 = generateFrame(1, FRAME_LENGTH, 123, true, false); + byte[] frame = generateFrame(0, MAX_FRAME_LENGTH, MAX_PAYLOAD_LENGTH, + true, false); + byte[] frame1 = generateFrame(1, MAX_FRAME_LENGTH, 123, true, false); // Concatenate the frames - byte[] extraFrame = new byte[FRAME_LENGTH * 2]; - System.arraycopy(frame, 0, extraFrame, 0, FRAME_LENGTH); - System.arraycopy(frame1, 0, extraFrame, FRAME_LENGTH, FRAME_LENGTH); + byte[] extraFrame = new byte[MAX_FRAME_LENGTH * 2]; + System.arraycopy(frame, 0, extraFrame, 0, MAX_FRAME_LENGTH); + System.arraycopy(frame1, 0, extraFrame, MAX_FRAME_LENGTH, + MAX_FRAME_LENGTH); // Read the final frame, which should first read the tag ByteArrayInputStream in = new ByteArrayInputStream(extraFrame); StreamDecrypterImpl i = new StreamDecrypterImpl(in, frameCipher, - frameKey, FRAME_LENGTH); + frameKey); byte[] payload = new byte[MAX_PAYLOAD_LENGTH]; assertEquals(MAX_PAYLOAD_LENGTH, i.readFrame(payload)); // The frame after the final frame should not be read diff --git a/briar-tests/src/org/briarproject/crypto/StreamEncrypterImplTest.java b/briar-tests/src/org/briarproject/crypto/StreamEncrypterImplTest.java index d4f8b33a5..8b5c3d74c 100644 --- a/briar-tests/src/org/briarproject/crypto/StreamEncrypterImplTest.java +++ b/briar-tests/src/org/briarproject/crypto/StreamEncrypterImplTest.java @@ -4,6 +4,7 @@ import static org.briarproject.api.transport.TransportConstants.AAD_LENGTH; import static org.briarproject.api.transport.TransportConstants.HEADER_LENGTH; import static org.briarproject.api.transport.TransportConstants.IV_LENGTH; import static org.briarproject.api.transport.TransportConstants.MAC_LENGTH; +import static org.briarproject.api.transport.TransportConstants.MAX_FRAME_LENGTH; import static org.briarproject.api.transport.TransportConstants.TAG_LENGTH; import java.io.ByteArrayOutputStream; @@ -24,8 +25,6 @@ public class StreamEncrypterImplTest extends BriarTestCase { // FIXME: This is an integration test, not a unit test - private static final int FRAME_LENGTH = 1024; - private final CryptoComponent crypto; private final AuthenticatedCipher frameCipher; @@ -40,8 +39,8 @@ public class StreamEncrypterImplTest extends BriarTestCase { public void testEncryptionWithoutTag() throws Exception { int payloadLength = 123; byte[] iv = new byte[IV_LENGTH], aad = new byte[AAD_LENGTH]; - byte[] plaintext = new byte[FRAME_LENGTH - MAC_LENGTH]; - byte[] ciphertext = new byte[FRAME_LENGTH]; + byte[] plaintext = new byte[MAX_FRAME_LENGTH - MAC_LENGTH]; + byte[] ciphertext = new byte[MAX_FRAME_LENGTH]; SecretKey frameKey = crypto.generateSecretKey(); // Calculate the expected ciphertext FrameEncoder.encodeIv(iv, 0); @@ -51,12 +50,12 @@ public class StreamEncrypterImplTest extends BriarTestCase { frameCipher.doFinal(plaintext, 0, plaintext.length, ciphertext, 0); // Check that the actual ciphertext matches what's expected ByteArrayOutputStream out = new ByteArrayOutputStream(); - StreamEncrypterImpl o = new StreamEncrypterImpl(out, - frameCipher, frameKey, FRAME_LENGTH, null); + StreamEncrypterImpl o = new StreamEncrypterImpl(out, frameCipher, + frameKey, null); o.writeFrame(new byte[payloadLength], payloadLength, false); byte[] actual = out.toByteArray(); - assertEquals(FRAME_LENGTH, actual.length); - for(int i = 0; i < FRAME_LENGTH; i++) + assertEquals(MAX_FRAME_LENGTH, actual.length); + for(int i = 0; i < MAX_FRAME_LENGTH; i++) assertEquals(ciphertext[i], actual[i]); } @@ -66,8 +65,8 @@ public class StreamEncrypterImplTest extends BriarTestCase { new Random().nextBytes(tag); int payloadLength = 123; byte[] iv = new byte[IV_LENGTH], aad = new byte[AAD_LENGTH]; - byte[] plaintext = new byte[FRAME_LENGTH - MAC_LENGTH]; - byte[] ciphertext = new byte[FRAME_LENGTH]; + byte[] plaintext = new byte[MAX_FRAME_LENGTH - MAC_LENGTH]; + byte[] ciphertext = new byte[MAX_FRAME_LENGTH]; SecretKey frameKey = crypto.generateSecretKey(); // Calculate the expected ciphertext FrameEncoder.encodeIv(iv, 0); @@ -77,13 +76,13 @@ public class StreamEncrypterImplTest extends BriarTestCase { frameCipher.doFinal(plaintext, 0, plaintext.length, ciphertext, 0); // Check that the actual tag and ciphertext match what's expected ByteArrayOutputStream out = new ByteArrayOutputStream(); - StreamEncrypterImpl o = new StreamEncrypterImpl(out, - frameCipher, frameKey, FRAME_LENGTH, tag); + StreamEncrypterImpl o = new StreamEncrypterImpl(out, frameCipher, + frameKey, tag); o.writeFrame(new byte[payloadLength], payloadLength, false); byte[] actual = out.toByteArray(); - assertEquals(TAG_LENGTH + FRAME_LENGTH, actual.length); + assertEquals(TAG_LENGTH + MAX_FRAME_LENGTH, actual.length); for(int i = 0; i < TAG_LENGTH; i++) assertEquals(tag[i], actual[i]); - for(int i = 0; i < FRAME_LENGTH; i++) + for(int i = 0; i < MAX_FRAME_LENGTH; i++) assertEquals(ciphertext[i], actual[TAG_LENGTH + i]); } @@ -93,10 +92,10 @@ public class StreamEncrypterImplTest extends BriarTestCase { new Random().nextBytes(tag); ByteArrayOutputStream out = new ByteArrayOutputStream(); // Initiator's constructor - StreamEncrypterImpl o = new StreamEncrypterImpl(out, - frameCipher, crypto.generateSecretKey(), FRAME_LENGTH, tag); + StreamEncrypterImpl o = new StreamEncrypterImpl(out, frameCipher, + crypto.generateSecretKey(), tag); // Write an empty final frame without having written any other frames - o.writeFrame(new byte[FRAME_LENGTH - MAC_LENGTH], 0, true); + o.writeFrame(new byte[MAX_FRAME_LENGTH - MAC_LENGTH], 0, true); // The tag and the empty frame should be written to the output stream assertEquals(TAG_LENGTH + HEADER_LENGTH + MAC_LENGTH, out.size()); } diff --git a/briar-tests/src/org/briarproject/messaging/SimplexMessagingIntegrationTest.java b/briar-tests/src/org/briarproject/messaging/SimplexMessagingIntegrationTest.java index d0a8359af..755836070 100644 --- a/briar-tests/src/org/briarproject/messaging/SimplexMessagingIntegrationTest.java +++ b/briar-tests/src/org/briarproject/messaging/SimplexMessagingIntegrationTest.java @@ -3,7 +3,6 @@ package org.briarproject.messaging; import static org.briarproject.api.AuthorConstants.MAX_PUBLIC_KEY_LENGTH; import static org.briarproject.api.messaging.MessagingConstants.GROUP_SALT_LENGTH; import static org.briarproject.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE; -import static org.briarproject.api.transport.TransportConstants.MAX_FRAME_LENGTH; import static org.briarproject.api.transport.TransportConstants.TAG_LENGTH; import java.io.ByteArrayInputStream; @@ -143,8 +142,8 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase { ByteArrayOutputStream out = new ByteArrayOutputStream(); StreamWriterFactory streamWriterFactory = alice.getInstance(StreamWriterFactory.class); - OutputStream streamWriter = streamWriterFactory.createStreamWriter(out, - MAX_FRAME_LENGTH, ctx); + OutputStream streamWriter = + streamWriterFactory.createStreamWriter(out, ctx); // Create an outgoing messaging session EventBus eventBus = alice.getInstance(EventBus.class); PacketWriterFactory packetWriterFactory = @@ -205,8 +204,8 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase { // Create a stream reader StreamReaderFactory streamReaderFactory = bob.getInstance(StreamReaderFactory.class); - InputStream streamReader = streamReaderFactory.createStreamReader(in, - MAX_FRAME_LENGTH, ctx); + InputStream streamReader = + streamReaderFactory.createStreamReader(in, ctx); // Create an incoming messaging session EventBus eventBus = bob.getInstance(EventBus.class); MessageVerifier messageVerifier = diff --git a/briar-tests/src/org/briarproject/plugins/bluetooth/BluetoothClientTest.java b/briar-tests/src/org/briarproject/plugins/bluetooth/BluetoothClientTest.java index 3b86da8a1..b046f3a6b 100644 --- a/briar-tests/src/org/briarproject/plugins/bluetooth/BluetoothClientTest.java +++ b/briar-tests/src/org/briarproject/plugins/bluetooth/BluetoothClientTest.java @@ -23,12 +23,12 @@ public class BluetoothClientTest extends DuplexClientTest { p.put("address", serverAddress); p.put("uuid", BluetoothTest.EMPTY_UUID); Map remote = - Collections.singletonMap(contactId, p); + Collections.singletonMap(contactId, p); // Create the plugin callback = new ClientCallback(new TransportConfig(), new TransportProperties(), remote); plugin = new BluetoothPlugin(executor, new SystemClock(), - new SecureRandom(), callback, 0, 0, 0); + new SecureRandom(), callback, 0, 0); } public static void main(String[] args) throws Exception { diff --git a/briar-tests/src/org/briarproject/plugins/bluetooth/BluetoothServerTest.java b/briar-tests/src/org/briarproject/plugins/bluetooth/BluetoothServerTest.java index 1dfbf841d..121f71b40 100644 --- a/briar-tests/src/org/briarproject/plugins/bluetooth/BluetoothServerTest.java +++ b/briar-tests/src/org/briarproject/plugins/bluetooth/BluetoothServerTest.java @@ -23,7 +23,7 @@ public class BluetoothServerTest extends DuplexServerTest { callback = new ServerCallback(new TransportConfig(), local, Collections.singletonMap(contactId, new TransportProperties())); plugin = new BluetoothPlugin(executor, new SystemClock(), - new SecureRandom(), callback, 0, 0, 0); + new SecureRandom(), callback, 0, 0); } public static void main(String[] args) throws Exception { diff --git a/briar-tests/src/org/briarproject/plugins/file/RemovableDrivePluginTest.java b/briar-tests/src/org/briarproject/plugins/file/RemovableDrivePluginTest.java index b8e4ee88b..5ae0bbb50 100644 --- a/briar-tests/src/org/briarproject/plugins/file/RemovableDrivePluginTest.java +++ b/briar-tests/src/org/briarproject/plugins/file/RemovableDrivePluginTest.java @@ -1,6 +1,5 @@ package org.briarproject.plugins.file; -import static org.briarproject.api.transport.TransportConstants.MAX_FRAME_LENGTH; import static org.briarproject.api.transport.TransportConstants.MIN_STREAM_LENGTH; import java.io.File; @@ -58,7 +57,7 @@ public class RemovableDrivePluginTest extends BriarTestCase { }}); RemovableDrivePlugin plugin = new RemovableDrivePlugin(executor, - fileUtils, callback, finder, monitor, MAX_FRAME_LENGTH, 0); + fileUtils, callback, finder, monitor, 0); plugin.start(); assertNull(plugin.createWriter(contactId)); @@ -93,7 +92,7 @@ public class RemovableDrivePluginTest extends BriarTestCase { }}); RemovableDrivePlugin plugin = new RemovableDrivePlugin(executor, - fileUtils, callback, finder, monitor, MAX_FRAME_LENGTH, 0); + fileUtils, callback, finder, monitor, 0); plugin.start(); assertNull(plugin.createWriter(contactId)); @@ -130,7 +129,7 @@ public class RemovableDrivePluginTest extends BriarTestCase { }}); RemovableDrivePlugin plugin = new RemovableDrivePlugin(executor, - fileUtils, callback, finder, monitor, MAX_FRAME_LENGTH, 0); + fileUtils, callback, finder, monitor, 0); plugin.start(); assertNull(plugin.createWriter(contactId)); @@ -169,7 +168,7 @@ public class RemovableDrivePluginTest extends BriarTestCase { }}); RemovableDrivePlugin plugin = new RemovableDrivePlugin(executor, - fileUtils, callback, finder, monitor, MAX_FRAME_LENGTH, 0); + fileUtils, callback, finder, monitor, 0); plugin.start(); assertNull(plugin.createWriter(contactId)); @@ -208,7 +207,7 @@ public class RemovableDrivePluginTest extends BriarTestCase { }}); RemovableDrivePlugin plugin = new RemovableDrivePlugin(executor, - fileUtils, callback, finder, monitor, MAX_FRAME_LENGTH, 0); + fileUtils, callback, finder, monitor, 0); plugin.start(); assertNotNull(plugin.createWriter(contactId)); @@ -251,7 +250,7 @@ public class RemovableDrivePluginTest extends BriarTestCase { }}); RemovableDrivePlugin plugin = new RemovableDrivePlugin(executor, - fileUtils, callback, finder, monitor, MAX_FRAME_LENGTH, 0); + fileUtils, callback, finder, monitor, 0); plugin.start(); TransportConnectionWriter writer = plugin.createWriter(contactId); @@ -290,7 +289,7 @@ public class RemovableDrivePluginTest extends BriarTestCase { }}); RemovableDrivePlugin plugin = new RemovableDrivePlugin(executor, - fileUtils, callback, finder, monitor, MAX_FRAME_LENGTH, 0); + fileUtils, callback, finder, monitor, 0); plugin.start(); plugin.driveInserted(testDir); @@ -310,7 +309,7 @@ public class RemovableDrivePluginTest extends BriarTestCase { context.mock(RemovableDriveMonitor.class); RemovableDrivePlugin plugin = new RemovableDrivePlugin(executor, - fileUtils, callback, finder, monitor, MAX_FRAME_LENGTH, 0); + fileUtils, callback, finder, monitor, 0); assertFalse(plugin.isPossibleConnectionFilename("abcdefg.dat")); assertFalse(plugin.isPossibleConnectionFilename("abcdefghi.dat")); @@ -339,7 +338,7 @@ public class RemovableDrivePluginTest extends BriarTestCase { RemovableDrivePlugin plugin = new RemovableDrivePlugin( new ImmediateExecutor(), fileUtils, callback, finder, monitor, - MAX_FRAME_LENGTH, 0); + 0); plugin.start(); File f = new File(testDir, "abcdefgh.dat"); diff --git a/briar-tests/src/org/briarproject/plugins/modem/ModemPluginTest.java b/briar-tests/src/org/briarproject/plugins/modem/ModemPluginTest.java index 3aa5dab23..7966ef8c4 100644 --- a/briar-tests/src/org/briarproject/plugins/modem/ModemPluginTest.java +++ b/briar-tests/src/org/briarproject/plugins/modem/ModemPluginTest.java @@ -24,7 +24,7 @@ public class ModemPluginTest extends BriarTestCase { final SerialPortList serialPortList = context.mock(SerialPortList.class); final ModemPlugin plugin = new ModemPlugin(modemFactory, - serialPortList, null, 0, 0); + serialPortList, null, 0); final Modem modem = context.mock(Modem.class); context.checking(new Expectations() {{ oneOf(serialPortList).getPortNames(); @@ -58,7 +58,7 @@ public class ModemPluginTest extends BriarTestCase { final DuplexPluginCallback callback = context.mock(DuplexPluginCallback.class); final ModemPlugin plugin = new ModemPlugin(modemFactory, - serialPortList, callback, 0, 0); + serialPortList, callback, 0); final Modem modem = context.mock(Modem.class); final TransportProperties local = new TransportProperties(); local.put("iso3166", ISO_1336); @@ -99,7 +99,7 @@ public class ModemPluginTest extends BriarTestCase { final DuplexPluginCallback callback = context.mock(DuplexPluginCallback.class); final ModemPlugin plugin = new ModemPlugin(modemFactory, - serialPortList, callback, 0, 0); + serialPortList, callback, 0); final Modem modem = context.mock(Modem.class); final TransportProperties local = new TransportProperties(); local.put("iso3166", ISO_1336); @@ -140,7 +140,7 @@ public class ModemPluginTest extends BriarTestCase { final DuplexPluginCallback callback = context.mock(DuplexPluginCallback.class); final ModemPlugin plugin = new ModemPlugin(modemFactory, - serialPortList, callback, 0, 0); + serialPortList, callback, 0); final Modem modem = context.mock(Modem.class); final TransportProperties local = new TransportProperties(); local.put("iso3166", ISO_1336); diff --git a/briar-tests/src/org/briarproject/plugins/tcp/LanTcpClientTest.java b/briar-tests/src/org/briarproject/plugins/tcp/LanTcpClientTest.java index 3bf190ee8..19168a567 100644 --- a/briar-tests/src/org/briarproject/plugins/tcp/LanTcpClientTest.java +++ b/briar-tests/src/org/briarproject/plugins/tcp/LanTcpClientTest.java @@ -15,7 +15,6 @@ import org.briarproject.plugins.DuplexClientTest; // is running on another machine public class LanTcpClientTest extends DuplexClientTest { - private static final int MAX_FRAME_LENGTH = 1024; private static final int MAX_LATENCY = 60 * 1000; private static final int MAX_IDLE_TIME = 30 * 1000; private static final int POLLING_INTERVAL = 60 * 1000; @@ -31,8 +30,8 @@ public class LanTcpClientTest extends DuplexClientTest { // Create the plugin callback = new ClientCallback(new TransportConfig(), new TransportProperties(), remote); - plugin = new LanTcpPlugin(executor, callback, MAX_FRAME_LENGTH, - MAX_LATENCY, MAX_IDLE_TIME, POLLING_INTERVAL); + plugin = new LanTcpPlugin(executor, callback, MAX_LATENCY, + MAX_IDLE_TIME, POLLING_INTERVAL); } public static void main(String[] args) throws Exception { diff --git a/briar-tests/src/org/briarproject/plugins/tcp/LanTcpPluginTest.java b/briar-tests/src/org/briarproject/plugins/tcp/LanTcpPluginTest.java index c65fe2f96..f3a321bbc 100644 --- a/briar-tests/src/org/briarproject/plugins/tcp/LanTcpPluginTest.java +++ b/briar-tests/src/org/briarproject/plugins/tcp/LanTcpPluginTest.java @@ -32,7 +32,7 @@ public class LanTcpPluginTest extends BriarTestCase { @Test public void testAddressesAreOnSameLan() { - LanTcpPlugin plugin = new LanTcpPlugin(null, null, 0, 0, 0, 0); + LanTcpPlugin plugin = new LanTcpPlugin(null, null, 0, 0, 0); // Local and remote in 10.0.0.0/8 should return true assertTrue(plugin.addressesAreOnSameLan(makeAddress(10, 0, 0, 0), makeAddress(10, 255, 255, 255))); @@ -81,7 +81,7 @@ public class LanTcpPluginTest extends BriarTestCase { } Callback callback = new Callback(); Executor executor = Executors.newCachedThreadPool(); - DuplexPlugin plugin = new LanTcpPlugin(executor, callback, 0, 0, 0, 0); + DuplexPlugin plugin = new LanTcpPlugin(executor, callback, 0, 0, 0); plugin.start(); // The plugin should have bound a socket and stored the port number assertTrue(callback.propertiesLatch.await(5, SECONDS)); @@ -113,7 +113,7 @@ public class LanTcpPluginTest extends BriarTestCase { } Callback callback = new Callback(); Executor executor = Executors.newCachedThreadPool(); - DuplexPlugin plugin = new LanTcpPlugin(executor, callback, 0, 0, 0, 0); + DuplexPlugin plugin = new LanTcpPlugin(executor, callback, 0, 0, 0); plugin.start(); // The plugin should have bound a socket and stored the port number assertTrue(callback.propertiesLatch.await(5, SECONDS)); diff --git a/briar-tests/src/org/briarproject/plugins/tcp/LanTcpServerTest.java b/briar-tests/src/org/briarproject/plugins/tcp/LanTcpServerTest.java index 198489c00..753197814 100644 --- a/briar-tests/src/org/briarproject/plugins/tcp/LanTcpServerTest.java +++ b/briar-tests/src/org/briarproject/plugins/tcp/LanTcpServerTest.java @@ -13,7 +13,6 @@ import org.briarproject.plugins.DuplexServerTest; // is running on another machine public class LanTcpServerTest extends DuplexServerTest { - private static final int MAX_FRAME_LENGTH = 1024; private static final int MAX_LATENCY = 60 * 1000; private static final int MAX_IDLE_TIME = 30 * 1000; private static final int POLLING_INTERVAL = 60 * 1000; @@ -22,8 +21,8 @@ public class LanTcpServerTest extends DuplexServerTest { callback = new ServerCallback(new TransportConfig(), new TransportProperties(), Collections.singletonMap(contactId, new TransportProperties())); - plugin = new LanTcpPlugin(executor, callback, MAX_FRAME_LENGTH, - MAX_LATENCY, MAX_IDLE_TIME, POLLING_INTERVAL); + plugin = new LanTcpPlugin(executor, callback, MAX_LATENCY, + MAX_IDLE_TIME, POLLING_INTERVAL); } public static void main(String[] args) throws Exception { diff --git a/briar-tests/src/org/briarproject/transport/StreamReaderImplTest.java b/briar-tests/src/org/briarproject/transport/StreamReaderImplTest.java index 988299852..3a71ce74c 100644 --- a/briar-tests/src/org/briarproject/transport/StreamReaderImplTest.java +++ b/briar-tests/src/org/briarproject/transport/StreamReaderImplTest.java @@ -2,6 +2,7 @@ package org.briarproject.transport; import static org.briarproject.api.transport.TransportConstants.HEADER_LENGTH; import static org.briarproject.api.transport.TransportConstants.MAC_LENGTH; +import static org.briarproject.api.transport.TransportConstants.MAX_FRAME_LENGTH; import org.briarproject.BriarTestCase; import org.briarproject.api.crypto.StreamDecrypter; @@ -11,9 +12,8 @@ import org.junit.Test; public class StreamReaderImplTest extends BriarTestCase { - private static final int FRAME_LENGTH = 1024; private static final int MAX_PAYLOAD_LENGTH = - FRAME_LENGTH - HEADER_LENGTH - MAC_LENGTH; + MAX_FRAME_LENGTH - HEADER_LENGTH - MAC_LENGTH; @Test public void testEmptyFramesAreSkipped() throws Exception { @@ -29,7 +29,7 @@ public class StreamReaderImplTest extends BriarTestCase { oneOf(decrypter).readFrame(with(any(byte[].class))); will(returnValue(-1)); // No more frames }}); - StreamReaderImpl r = new StreamReaderImpl(decrypter, FRAME_LENGTH); + StreamReaderImpl r = new StreamReaderImpl(decrypter); assertEquals(0, r.read()); // Skip the first empty frame, read a byte assertEquals(0, r.read()); // Read another byte assertEquals(-1, r.read()); // Skip the second empty frame, reach EOF @@ -52,7 +52,7 @@ public class StreamReaderImplTest extends BriarTestCase { oneOf(decrypter).readFrame(with(any(byte[].class))); will(returnValue(-1)); // No more frames }}); - StreamReaderImpl r = new StreamReaderImpl(decrypter, FRAME_LENGTH); + StreamReaderImpl r = new StreamReaderImpl(decrypter); byte[] buf = new byte[MAX_PAYLOAD_LENGTH]; // Skip the first empty frame, read the two payload bytes assertEquals(2, r.read(buf)); @@ -74,7 +74,7 @@ public class StreamReaderImplTest extends BriarTestCase { oneOf(decrypter).readFrame(with(any(byte[].class))); will(returnValue(-1)); // No more frames }}); - StreamReaderImpl r = new StreamReaderImpl(decrypter, FRAME_LENGTH); + StreamReaderImpl r = new StreamReaderImpl(decrypter); byte[] buf = new byte[MAX_PAYLOAD_LENGTH / 2]; // Read the first half of the payload assertEquals(MAX_PAYLOAD_LENGTH / 2, r.read(buf)); @@ -96,7 +96,7 @@ public class StreamReaderImplTest extends BriarTestCase { oneOf(decrypter).readFrame(with(any(byte[].class))); will(returnValue(-1)); // No more frames }}); - StreamReaderImpl r = new StreamReaderImpl(decrypter, FRAME_LENGTH); + StreamReaderImpl r = new StreamReaderImpl(decrypter); byte[] buf = new byte[MAX_PAYLOAD_LENGTH]; // Read the first half of the payload assertEquals(MAX_PAYLOAD_LENGTH / 2, r.read(buf, MAX_PAYLOAD_LENGTH / 2, diff --git a/briar-tests/src/org/briarproject/transport/StreamWriterImplTest.java b/briar-tests/src/org/briarproject/transport/StreamWriterImplTest.java index 688621bd1..4ea8916dd 100644 --- a/briar-tests/src/org/briarproject/transport/StreamWriterImplTest.java +++ b/briar-tests/src/org/briarproject/transport/StreamWriterImplTest.java @@ -2,6 +2,7 @@ package org.briarproject.transport; import static org.briarproject.api.transport.TransportConstants.HEADER_LENGTH; import static org.briarproject.api.transport.TransportConstants.MAC_LENGTH; +import static org.briarproject.api.transport.TransportConstants.MAX_FRAME_LENGTH; import org.briarproject.BriarTestCase; import org.briarproject.api.crypto.StreamEncrypter; @@ -11,9 +12,8 @@ import org.junit.Test; public class StreamWriterImplTest extends BriarTestCase { - private static final int FRAME_LENGTH = 1024; private static final int MAX_PAYLOAD_LENGTH = - FRAME_LENGTH - HEADER_LENGTH - MAC_LENGTH; + MAX_FRAME_LENGTH - HEADER_LENGTH - MAC_LENGTH; @Test public void testCloseWithoutWritingWritesFinalFrame() throws Exception { @@ -26,7 +26,7 @@ public class StreamWriterImplTest extends BriarTestCase { // Flush the stream oneOf(encrypter).flush(); }}); - StreamWriterImpl w = new StreamWriterImpl(encrypter, FRAME_LENGTH); + StreamWriterImpl w = new StreamWriterImpl(encrypter); w.close(); context.assertIsSatisfied(); } @@ -36,7 +36,7 @@ public class StreamWriterImplTest extends BriarTestCase { throws Exception { Mockery context = new Mockery(); final StreamEncrypter encrypter = context.mock(StreamEncrypter.class); - StreamWriterImpl w = new StreamWriterImpl(encrypter, FRAME_LENGTH); + StreamWriterImpl w = new StreamWriterImpl(encrypter); context.checking(new Expectations() {{ // Write a non-final frame with an empty payload oneOf(encrypter).writeFrame(with(any(byte[].class)), with(0), @@ -63,7 +63,7 @@ public class StreamWriterImplTest extends BriarTestCase { throws Exception { Mockery context = new Mockery(); final StreamEncrypter encrypter = context.mock(StreamEncrypter.class); - StreamWriterImpl w = new StreamWriterImpl(encrypter, FRAME_LENGTH); + StreamWriterImpl w = new StreamWriterImpl(encrypter); context.checking(new Expectations() {{ // Write a non-final frame with one payload byte oneOf(encrypter).writeFrame(with(any(byte[].class)), with(1), @@ -90,7 +90,7 @@ public class StreamWriterImplTest extends BriarTestCase { public void testSingleByteWritesWriteFullFrame() throws Exception { Mockery context = new Mockery(); final StreamEncrypter encrypter = context.mock(StreamEncrypter.class); - StreamWriterImpl w = new StreamWriterImpl(encrypter, FRAME_LENGTH); + StreamWriterImpl w = new StreamWriterImpl(encrypter); context.checking(new Expectations() {{ // Write a full non-final frame oneOf(encrypter).writeFrame(with(any(byte[].class)), @@ -116,7 +116,7 @@ public class StreamWriterImplTest extends BriarTestCase { public void testMultiByteWritesWriteFullFrames() throws Exception { Mockery context = new Mockery(); final StreamEncrypter encrypter = context.mock(StreamEncrypter.class); - StreamWriterImpl w = new StreamWriterImpl(encrypter, FRAME_LENGTH); + StreamWriterImpl w = new StreamWriterImpl(encrypter); context.checking(new Expectations() {{ // Write two full non-final frames exactly(2).of(encrypter).writeFrame(with(any(byte[].class)), @@ -147,7 +147,7 @@ public class StreamWriterImplTest extends BriarTestCase { public void testLargeMultiByteWriteWritesFullFrames() throws Exception { Mockery context = new Mockery(); final StreamEncrypter encrypter = context.mock(StreamEncrypter.class); - StreamWriterImpl w = new StreamWriterImpl(encrypter, FRAME_LENGTH); + StreamWriterImpl w = new StreamWriterImpl(encrypter); context.checking(new Expectations() {{ // Write two full non-final frames exactly(2).of(encrypter).writeFrame(with(any(byte[].class)), diff --git a/briar-tests/src/org/briarproject/transport/TestStreamDecrypter.java b/briar-tests/src/org/briarproject/transport/TestStreamDecrypter.java index b0438801e..b901678a6 100644 --- a/briar-tests/src/org/briarproject/transport/TestStreamDecrypter.java +++ b/briar-tests/src/org/briarproject/transport/TestStreamDecrypter.java @@ -2,6 +2,7 @@ package org.briarproject.transport; import static org.briarproject.api.transport.TransportConstants.HEADER_LENGTH; import static org.briarproject.api.transport.TransportConstants.MAC_LENGTH; +import static org.briarproject.api.transport.TransportConstants.MAX_FRAME_LENGTH; import java.io.EOFException; import java.io.IOException; @@ -16,9 +17,9 @@ class TestStreamDecrypter implements StreamDecrypter { private final InputStream in; private final byte[] frame; - TestStreamDecrypter(InputStream in, int frameLength) { + TestStreamDecrypter(InputStream in) { this.in = in; - frame = new byte[frameLength]; + frame = new byte[MAX_FRAME_LENGTH]; } public int readFrame(byte[] payload) throws IOException { diff --git a/briar-tests/src/org/briarproject/transport/TestStreamEncrypter.java b/briar-tests/src/org/briarproject/transport/TestStreamEncrypter.java index 4ad4c667c..6939c71b5 100644 --- a/briar-tests/src/org/briarproject/transport/TestStreamEncrypter.java +++ b/briar-tests/src/org/briarproject/transport/TestStreamEncrypter.java @@ -2,6 +2,7 @@ package org.briarproject.transport; import static org.briarproject.api.transport.TransportConstants.HEADER_LENGTH; import static org.briarproject.api.transport.TransportConstants.MAC_LENGTH; +import static org.briarproject.api.transport.TransportConstants.MAX_FRAME_LENGTH; import java.io.IOException; import java.io.OutputStream; @@ -16,10 +17,10 @@ class TestStreamEncrypter implements StreamEncrypter { private boolean writeTag = true; - TestStreamEncrypter(OutputStream out, int frameLength, byte[] tag) { + TestStreamEncrypter(OutputStream out, byte[] tag) { this.out = out; this.tag = tag; - frame = new byte[frameLength]; + frame = new byte[MAX_FRAME_LENGTH]; } public void writeFrame(byte[] payload, int payloadLength, diff --git a/briar-tests/src/org/briarproject/transport/TransportIntegrationTest.java b/briar-tests/src/org/briarproject/transport/TransportIntegrationTest.java index f55e5b6e1..af006350a 100644 --- a/briar-tests/src/org/briarproject/transport/TransportIntegrationTest.java +++ b/briar-tests/src/org/briarproject/transport/TransportIntegrationTest.java @@ -1,5 +1,6 @@ package org.briarproject.transport; +import static org.briarproject.api.transport.TransportConstants.MAX_FRAME_LENGTH; import static org.briarproject.api.transport.TransportConstants.TAG_LENGTH; import static org.junit.Assert.assertArrayEquals; @@ -17,8 +18,6 @@ import org.junit.Test; public class TransportIntegrationTest extends BriarTestCase { - private final int FRAME_LENGTH = 2048; - private final Random random; public TransportIntegrationTest() { @@ -40,31 +39,28 @@ public class TransportIntegrationTest extends BriarTestCase { byte[] tag = new byte[TAG_LENGTH]; random.nextBytes(tag); // Generate two frames with random payloads - byte[] payload1 = new byte[1234]; + byte[] payload1 = new byte[123]; random.nextBytes(payload1); byte[] payload2 = new byte[321]; random.nextBytes(payload2); // Write the tag and the frames ByteArrayOutputStream out = new ByteArrayOutputStream(); - StreamEncrypter encrypter = new TestStreamEncrypter(out, FRAME_LENGTH, - tag); - OutputStream streamWriter = new StreamWriterImpl(encrypter, - FRAME_LENGTH); + StreamEncrypter encrypter = new TestStreamEncrypter(out, tag); + OutputStream streamWriter = new StreamWriterImpl(encrypter); streamWriter.write(payload1); streamWriter.flush(); streamWriter.write(payload2); streamWriter.flush(); byte[] output = out.toByteArray(); - assertEquals(TAG_LENGTH + FRAME_LENGTH * 2, output.length); + assertEquals(TAG_LENGTH + MAX_FRAME_LENGTH * 2, output.length); // Read the tag back ByteArrayInputStream in = new ByteArrayInputStream(output); byte[] recoveredTag = new byte[tag.length]; read(in, recoveredTag); assertArrayEquals(tag, recoveredTag); // Read the frames back - StreamDecrypter decrypter = new TestStreamDecrypter(in, FRAME_LENGTH); - InputStream streamReader = new StreamReaderImpl(decrypter, - FRAME_LENGTH); + StreamDecrypter decrypter = new TestStreamDecrypter(in); + InputStream streamReader = new StreamReaderImpl(decrypter); byte[] recoveredPayload1 = new byte[payload1.length]; read(streamReader, recoveredPayload1); assertArrayEquals(payload1, recoveredPayload1); From 1f69f0d2f6686f14785f4f6780fa92f406ba6194 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Mon, 5 Jan 2015 17:35:29 +0000 Subject: [PATCH 08/10] Variable-length frames (untested). --- .../api/crypto/AuthenticatedCipher.java | 4 +- .../api/crypto/StreamEncrypter.java | 4 +- .../api/transport/TransportConstants.java | 19 ++- .../crypto/AuthenticatedCipherImpl.java | 2 +- .../crypto/CryptoComponentImpl.java | 4 +- .../org/briarproject/crypto/FrameEncoder.java | 36 ++-- .../crypto/StreamDecrypterFactoryImpl.java | 2 +- .../crypto/StreamDecrypterImpl.java | 74 ++++---- .../crypto/StreamEncrypterImpl.java | 61 ++++--- .../transport/StreamReaderImpl.java | 6 +- .../transport/StreamWriterImpl.java | 8 +- .../crypto/StreamDecrypterImplTest.java | 160 +----------------- .../crypto/StreamEncrypterImplTest.java | 93 +--------- .../transport/StreamReaderImplTest.java | 7 +- .../transport/StreamWriterImplTest.java | 33 ++-- .../transport/TestStreamEncrypter.java | 2 +- 16 files changed, 147 insertions(+), 368 deletions(-) diff --git a/briar-api/src/org/briarproject/api/crypto/AuthenticatedCipher.java b/briar-api/src/org/briarproject/api/crypto/AuthenticatedCipher.java index 444fcf13f..6f60ed052 100644 --- a/briar-api/src/org/briarproject/api/crypto/AuthenticatedCipher.java +++ b/briar-api/src/org/briarproject/api/crypto/AuthenticatedCipher.java @@ -13,10 +13,10 @@ public interface AuthenticatedCipher { throws GeneralSecurityException; /** Encrypts or decrypts data in a single-part operation. */ - int doFinal(byte[] input, int inputOff, int len, byte[] output, + int process(byte[] input, int inputOff, int len, byte[] output, int outputOff) throws GeneralSecurityException; - /** Returns the length of the message authenticated code (MAC) in bytes. */ + /** Returns the length of the message authentication code (MAC) in bytes. */ int getMacLength(); /** Returns the block size of the cipher in bytes. */ diff --git a/briar-api/src/org/briarproject/api/crypto/StreamEncrypter.java b/briar-api/src/org/briarproject/api/crypto/StreamEncrypter.java index d48deff3a..a332743bb 100644 --- a/briar-api/src/org/briarproject/api/crypto/StreamEncrypter.java +++ b/briar-api/src/org/briarproject/api/crypto/StreamEncrypter.java @@ -5,8 +5,8 @@ import java.io.IOException; public interface StreamEncrypter { /** Encrypts the given frame and writes it to the stream. */ - void writeFrame(byte[] payload, int payloadLength, boolean finalFrame) - throws IOException; + void writeFrame(byte[] payload, int payloadLength, int paddingLength, + boolean finalFrame) throws IOException; /** Flushes the stream. */ void flush() throws IOException; diff --git a/briar-api/src/org/briarproject/api/transport/TransportConstants.java b/briar-api/src/org/briarproject/api/transport/TransportConstants.java index 7a13dbe9e..8f05eb23a 100644 --- a/briar-api/src/org/briarproject/api/transport/TransportConstants.java +++ b/briar-api/src/org/briarproject/api/transport/TransportConstants.java @@ -1,5 +1,6 @@ package org.briarproject.api.transport; + public interface TransportConstants { /** The length of the pseudo-random tag in bytes. */ @@ -8,18 +9,18 @@ public interface TransportConstants { /** The maximum length of a frame in bytes, including the header and MAC. */ int MAX_FRAME_LENGTH = 1024; - /** The length of the initalisation vector (IV) in bytes. */ - int IV_LENGTH = 12; - - /** The length of the additional authenticated data (AAD) in bytes. */ - int AAD_LENGTH = 6; - - /** The length of the frame header in bytes. */ - int HEADER_LENGTH = 2; - /** The length of the message authentication code (MAC) in bytes. */ int MAC_LENGTH = 16; + /** The length of the frame header in bytes. */ + int HEADER_LENGTH = 4 + MAC_LENGTH; + + /** The maximum total length of the frame payload and padding in bytes. */ + int MAX_PAYLOAD_LENGTH = MAX_FRAME_LENGTH - HEADER_LENGTH - MAC_LENGTH; + + /** The length of the initalisation vector (IV) in bytes. */ + int IV_LENGTH = 12; + /** * The minimum stream length in bytes that all transport plugins must * support. Streams may be shorter than this length, but all transport diff --git a/briar-core/src/org/briarproject/crypto/AuthenticatedCipherImpl.java b/briar-core/src/org/briarproject/crypto/AuthenticatedCipherImpl.java index bf80ca8c5..d001b60c5 100644 --- a/briar-core/src/org/briarproject/crypto/AuthenticatedCipherImpl.java +++ b/briar-core/src/org/briarproject/crypto/AuthenticatedCipherImpl.java @@ -20,7 +20,7 @@ class AuthenticatedCipherImpl implements AuthenticatedCipher { this.macLength = macLength; } - public int doFinal(byte[] input, int inputOff, int len, byte[] output, + public int process(byte[] input, int inputOff, int len, byte[] output, int outputOff) throws GeneralSecurityException { int processed = 0; if(len != 0) { diff --git a/briar-core/src/org/briarproject/crypto/CryptoComponentImpl.java b/briar-core/src/org/briarproject/crypto/CryptoComponentImpl.java index 29442f311..10c2c0cff 100644 --- a/briar-core/src/org/briarproject/crypto/CryptoComponentImpl.java +++ b/briar-core/src/org/briarproject/crypto/CryptoComponentImpl.java @@ -335,7 +335,7 @@ class CryptoComponentImpl implements CryptoComponent { MAC_BYTES); cipher.init(true, key, iv, null); int outputOff = salt.length + 4 + iv.length; - cipher.doFinal(input, 0, input.length, output, outputOff); + cipher.process(input, 0, input.length, output, outputOff); return output; } catch(GeneralSecurityException e) { throw new RuntimeException(e); @@ -369,7 +369,7 @@ class CryptoComponentImpl implements CryptoComponent { int inputOff = salt.length + 4 + iv.length; int inputLen = input.length - inputOff; byte[] output = new byte[inputLen - MAC_BYTES]; - cipher.doFinal(input, inputOff, inputLen, output, 0); + cipher.process(input, inputOff, inputLen, output, 0); return output; } catch(GeneralSecurityException e) { return null; // Invalid ciphertext diff --git a/briar-core/src/org/briarproject/crypto/FrameEncoder.java b/briar-core/src/org/briarproject/crypto/FrameEncoder.java index 5a30593db..2cc6ffd58 100644 --- a/briar-core/src/org/briarproject/crypto/FrameEncoder.java +++ b/briar-core/src/org/briarproject/crypto/FrameEncoder.java @@ -1,44 +1,33 @@ package org.briarproject.crypto; -import static org.briarproject.api.transport.TransportConstants.AAD_LENGTH; import static org.briarproject.api.transport.TransportConstants.HEADER_LENGTH; import static org.briarproject.api.transport.TransportConstants.IV_LENGTH; -import static org.briarproject.api.transport.TransportConstants.MAC_LENGTH; -import static org.briarproject.api.transport.TransportConstants.MAX_FRAME_LENGTH; +import static org.briarproject.api.transport.TransportConstants.MAX_PAYLOAD_LENGTH; import static org.briarproject.util.ByteUtils.MAX_32_BIT_UNSIGNED; import org.briarproject.util.ByteUtils; class FrameEncoder { - static void encodeIv(byte[] iv, long frameNumber) { + static void encodeIv(byte[] iv, long frameNumber, boolean header) { if(iv.length < IV_LENGTH) throw new IllegalArgumentException(); if(frameNumber < 0 || frameNumber > MAX_32_BIT_UNSIGNED) throw new IllegalArgumentException(); ByteUtils.writeUint32(frameNumber, iv, 0); - for(int i = 4; i < IV_LENGTH; i++) iv[i] = 0; - } - - static void encodeAad(byte[] aad, long frameNumber, int plaintextLength) { - if(aad.length < AAD_LENGTH) throw new IllegalArgumentException(); - if(frameNumber < 0 || frameNumber > MAX_32_BIT_UNSIGNED) - throw new IllegalArgumentException(); - if(plaintextLength < HEADER_LENGTH) - throw new IllegalArgumentException(); - if(plaintextLength > MAX_FRAME_LENGTH - MAC_LENGTH) - throw new IllegalArgumentException(); - ByteUtils.writeUint32(frameNumber, aad, 0); - ByteUtils.writeUint16(plaintextLength, aad, 4); + if(header) iv[4] = 1; + else iv[4] = 0; + for(int i = 5; i < IV_LENGTH; i++) iv[i] = 0; } static void encodeHeader(byte[] header, boolean finalFrame, - int payloadLength) { + int payloadLength, int paddingLength) { if(header.length < HEADER_LENGTH) throw new IllegalArgumentException(); - if(payloadLength < 0) - throw new IllegalArgumentException(); - if(payloadLength > MAX_FRAME_LENGTH - HEADER_LENGTH - MAC_LENGTH) + if(payloadLength < 0) throw new IllegalArgumentException(); + if(paddingLength < 0) throw new IllegalArgumentException(); + if(payloadLength + paddingLength > MAX_PAYLOAD_LENGTH) throw new IllegalArgumentException(); ByteUtils.writeUint16(payloadLength, header, 0); + ByteUtils.writeUint16(paddingLength, header, 2); if(finalFrame) header[0] |= 0x80; } @@ -51,4 +40,9 @@ class FrameEncoder { if(header.length < HEADER_LENGTH) throw new IllegalArgumentException(); return ByteUtils.readUint16(header, 0) & 0x7FFF; } + + static int getPaddingLength(byte[] header) { + if(header.length < HEADER_LENGTH) throw new IllegalArgumentException(); + return ByteUtils.readUint16(header, 2); + } } diff --git a/briar-core/src/org/briarproject/crypto/StreamDecrypterFactoryImpl.java b/briar-core/src/org/briarproject/crypto/StreamDecrypterFactoryImpl.java index 5fb504b84..bed0503c2 100644 --- a/briar-core/src/org/briarproject/crypto/StreamDecrypterFactoryImpl.java +++ b/briar-core/src/org/briarproject/crypto/StreamDecrypterFactoryImpl.java @@ -21,10 +21,10 @@ class StreamDecrypterFactoryImpl implements StreamDecrypterFactory { public StreamDecrypter createStreamDecrypter(InputStream in, StreamContext ctx) { + // Derive the frame key byte[] secret = ctx.getSecret(); long streamNumber = ctx.getStreamNumber(); boolean alice = !ctx.getAlice(); - // Derive the frame key SecretKey frameKey = crypto.deriveFrameKey(secret, streamNumber, alice); // Create the decrypter return new StreamDecrypterImpl(in, crypto.getFrameCipher(), frameKey); diff --git a/briar-core/src/org/briarproject/crypto/StreamDecrypterImpl.java b/briar-core/src/org/briarproject/crypto/StreamDecrypterImpl.java index 206a12c61..b27b0cf9e 100644 --- a/briar-core/src/org/briarproject/crypto/StreamDecrypterImpl.java +++ b/briar-core/src/org/briarproject/crypto/StreamDecrypterImpl.java @@ -1,10 +1,10 @@ package org.briarproject.crypto; -import static org.briarproject.api.transport.TransportConstants.AAD_LENGTH; import static org.briarproject.api.transport.TransportConstants.HEADER_LENGTH; import static org.briarproject.api.transport.TransportConstants.IV_LENGTH; import static org.briarproject.api.transport.TransportConstants.MAC_LENGTH; import static org.briarproject.api.transport.TransportConstants.MAX_FRAME_LENGTH; +import static org.briarproject.api.transport.TransportConstants.MAX_PAYLOAD_LENGTH; import java.io.EOFException; import java.io.IOException; @@ -21,7 +21,7 @@ class StreamDecrypterImpl implements StreamDecrypter { private final InputStream in; private final AuthenticatedCipher frameCipher; private final SecretKey frameKey; - private final byte[] iv, aad, plaintext, ciphertext; + private final byte[] iv, aad, header, ciphertext; private long frameNumber; private boolean finalFrame; @@ -32,50 +32,66 @@ class StreamDecrypterImpl implements StreamDecrypter { this.frameCipher = frameCipher; this.frameKey = frameKey; iv = new byte[IV_LENGTH]; - aad = new byte[AAD_LENGTH]; - plaintext = new byte[MAX_FRAME_LENGTH - MAC_LENGTH]; + aad = new byte[IV_LENGTH]; + header = new byte[HEADER_LENGTH]; ciphertext = new byte[MAX_FRAME_LENGTH]; frameNumber = 0; finalFrame = false; } public int readFrame(byte[] payload) throws IOException { + if(payload.length < MAX_PAYLOAD_LENGTH) + throw new IllegalArgumentException(); if(finalFrame) return -1; - // Read the frame - int ciphertextLength = 0; - while(ciphertextLength < MAX_FRAME_LENGTH) { - int read = in.read(ciphertext, ciphertextLength, - MAX_FRAME_LENGTH - ciphertextLength); - if(read == -1) break; // We'll check the length later - ciphertextLength += read; + // Read the header + int offset = 0; + while(offset < HEADER_LENGTH) { + int read = in.read(ciphertext, offset, HEADER_LENGTH - offset); + if(read == -1) throw new EOFException(); + offset += read; } - int plaintextLength = ciphertextLength - MAC_LENGTH; - if(plaintextLength < HEADER_LENGTH) throw new EOFException(); - // Decrypt and authenticate the frame - FrameEncoder.encodeIv(iv, frameNumber); - FrameEncoder.encodeAad(aad, frameNumber, plaintextLength); + // Decrypt and authenticate the header + FrameEncoder.encodeIv(iv, frameNumber, true); + FrameEncoder.encodeIv(aad, frameNumber, true); try { frameCipher.init(false, frameKey, iv, aad); - int decrypted = frameCipher.doFinal(ciphertext, 0, ciphertextLength, - plaintext, 0); - if(decrypted != plaintextLength) throw new RuntimeException(); + int decrypted = frameCipher.process(ciphertext, 0, HEADER_LENGTH, + header, 0); + if(decrypted != HEADER_LENGTH - MAC_LENGTH) + throw new RuntimeException(); } catch(GeneralSecurityException e) { throw new FormatException(); } // Decode and validate the header - finalFrame = FrameEncoder.isFinalFrame(plaintext); - if(!finalFrame && ciphertextLength < MAX_FRAME_LENGTH) + finalFrame = FrameEncoder.isFinalFrame(header); + int payloadLength = FrameEncoder.getPayloadLength(header); + int paddingLength = FrameEncoder.getPaddingLength(header); + if(payloadLength + paddingLength > MAX_PAYLOAD_LENGTH) throw new FormatException(); - int payloadLength = FrameEncoder.getPayloadLength(plaintext); - if(payloadLength > plaintextLength - HEADER_LENGTH) - throw new FormatException(); - // If there's any padding it must be all zeroes - for(int i = HEADER_LENGTH + payloadLength; i < plaintextLength; i++) { - if(plaintext[i] != 0) throw new FormatException(); + // Read the payload and padding + int frameLength = HEADER_LENGTH + payloadLength + paddingLength + + MAC_LENGTH; + while(offset < frameLength) { + int read = in.read(ciphertext, offset, frameLength - offset); + if(read == -1) throw new EOFException(); + offset += read; } + // Decrypt and authenticate the payload and padding + FrameEncoder.encodeIv(iv, frameNumber, false); + FrameEncoder.encodeIv(aad, frameNumber, false); + try { + frameCipher.init(false, frameKey, iv, aad); + int decrypted = frameCipher.process(ciphertext, HEADER_LENGTH, + payloadLength + paddingLength + MAC_LENGTH, payload, 0); + if(decrypted != payloadLength + paddingLength) + throw new RuntimeException(); + } catch(GeneralSecurityException e) { + throw new FormatException(); + } + // If there's any padding it must be all zeroes + for(int i = 0; i < paddingLength; i++) + if(payload[payloadLength + i] != 0) throw new FormatException(); frameNumber++; - // Copy the payload - System.arraycopy(plaintext, HEADER_LENGTH, payload, 0, payloadLength); return payloadLength; } } \ No newline at end of file diff --git a/briar-core/src/org/briarproject/crypto/StreamEncrypterImpl.java b/briar-core/src/org/briarproject/crypto/StreamEncrypterImpl.java index 0a09fc205..475c62f59 100644 --- a/briar-core/src/org/briarproject/crypto/StreamEncrypterImpl.java +++ b/briar-core/src/org/briarproject/crypto/StreamEncrypterImpl.java @@ -1,10 +1,10 @@ package org.briarproject.crypto; -import static org.briarproject.api.transport.TransportConstants.AAD_LENGTH; import static org.briarproject.api.transport.TransportConstants.HEADER_LENGTH; import static org.briarproject.api.transport.TransportConstants.IV_LENGTH; import static org.briarproject.api.transport.TransportConstants.MAC_LENGTH; import static org.briarproject.api.transport.TransportConstants.MAX_FRAME_LENGTH; +import static org.briarproject.api.transport.TransportConstants.MAX_PAYLOAD_LENGTH; import static org.briarproject.util.ByteUtils.MAX_32_BIT_UNSIGNED; import java.io.IOException; @@ -32,50 +32,57 @@ class StreamEncrypterImpl implements StreamEncrypter { this.frameKey = frameKey; this.tag = tag; iv = new byte[IV_LENGTH]; - aad = new byte[AAD_LENGTH]; - plaintext = new byte[MAX_FRAME_LENGTH - MAC_LENGTH]; + aad = new byte[IV_LENGTH]; + plaintext = new byte[HEADER_LENGTH + MAX_PAYLOAD_LENGTH]; ciphertext = new byte[MAX_FRAME_LENGTH]; frameNumber = 0; writeTag = (tag != null); } public void writeFrame(byte[] payload, int payloadLength, - boolean finalFrame) throws IOException { - if(frameNumber > MAX_32_BIT_UNSIGNED) throw new IllegalStateException(); + int paddingLength, boolean finalFrame) throws IOException { + if(payloadLength + paddingLength > MAX_PAYLOAD_LENGTH) + throw new IllegalArgumentException(); + // Don't allow the frame counter to wrap + if(frameNumber > MAX_32_BIT_UNSIGNED) throw new IOException(); // Write the tag if required if(writeTag) { out.write(tag, 0, tag.length); writeTag = false; } - // Don't pad the final frame - int plaintextLength, ciphertextLength; - if(finalFrame) { - plaintextLength = HEADER_LENGTH + payloadLength; - ciphertextLength = plaintextLength + MAC_LENGTH; - } else { - plaintextLength = MAX_FRAME_LENGTH - MAC_LENGTH; - ciphertextLength = MAX_FRAME_LENGTH; - } // Encode the header - FrameEncoder.encodeHeader(plaintext, finalFrame, payloadLength); - // Copy the payload - System.arraycopy(payload, 0, plaintext, HEADER_LENGTH, payloadLength); - // If there's any padding it must all be zeroes - for(int i = HEADER_LENGTH + payloadLength; i < plaintextLength; i++) - plaintext[i] = 0; - // Encrypt and authenticate the frame - FrameEncoder.encodeIv(iv, frameNumber); - FrameEncoder.encodeAad(aad, frameNumber, plaintextLength); + FrameEncoder.encodeHeader(plaintext, finalFrame, payloadLength, + paddingLength); + // Encrypt and authenticate the header + FrameEncoder.encodeIv(iv, frameNumber, true); + FrameEncoder.encodeIv(aad, frameNumber, true); try { frameCipher.init(true, frameKey, iv, aad); - int encrypted = frameCipher.doFinal(plaintext, 0, plaintextLength, - ciphertext, 0); - if(encrypted != ciphertextLength) throw new RuntimeException(); + int encrypted = frameCipher.process(plaintext, 0, + HEADER_LENGTH - MAC_LENGTH, ciphertext, 0); + if(encrypted != HEADER_LENGTH) throw new RuntimeException(); + } catch(GeneralSecurityException badCipher) { + throw new RuntimeException(badCipher); + } + // Combine the payload and padding + System.arraycopy(payload, 0, plaintext, HEADER_LENGTH, payloadLength); + for(int i = 0; i < paddingLength; i++) + plaintext[HEADER_LENGTH + payloadLength + i] = 0; + // Encrypt and authenticate the payload and padding + FrameEncoder.encodeIv(iv, frameNumber, false); + FrameEncoder.encodeIv(aad, frameNumber, false); + try { + frameCipher.init(true, frameKey, iv, aad); + int encrypted = frameCipher.process(plaintext, HEADER_LENGTH, + payloadLength + paddingLength, ciphertext, HEADER_LENGTH); + if(encrypted != payloadLength + paddingLength + MAC_LENGTH) + throw new RuntimeException(); } catch(GeneralSecurityException badCipher) { throw new RuntimeException(badCipher); } // Write the frame - out.write(ciphertext, 0, ciphertextLength); + out.write(ciphertext, 0, HEADER_LENGTH + payloadLength + paddingLength + + MAC_LENGTH); frameNumber++; } diff --git a/briar-core/src/org/briarproject/transport/StreamReaderImpl.java b/briar-core/src/org/briarproject/transport/StreamReaderImpl.java index f0a1a26c1..cc94ff505 100644 --- a/briar-core/src/org/briarproject/transport/StreamReaderImpl.java +++ b/briar-core/src/org/briarproject/transport/StreamReaderImpl.java @@ -1,8 +1,6 @@ package org.briarproject.transport; -import static org.briarproject.api.transport.TransportConstants.HEADER_LENGTH; -import static org.briarproject.api.transport.TransportConstants.MAC_LENGTH; -import static org.briarproject.api.transport.TransportConstants.MAX_FRAME_LENGTH; +import static org.briarproject.api.transport.TransportConstants.MAX_PAYLOAD_LENGTH; import java.io.IOException; import java.io.InputStream; @@ -18,7 +16,7 @@ class StreamReaderImpl extends InputStream { StreamReaderImpl(StreamDecrypter decrypter) { this.decrypter = decrypter; - payload = new byte[MAX_FRAME_LENGTH - HEADER_LENGTH - MAC_LENGTH]; + payload = new byte[MAX_PAYLOAD_LENGTH]; } @Override diff --git a/briar-core/src/org/briarproject/transport/StreamWriterImpl.java b/briar-core/src/org/briarproject/transport/StreamWriterImpl.java index 22384dd22..6d7b90ff7 100644 --- a/briar-core/src/org/briarproject/transport/StreamWriterImpl.java +++ b/briar-core/src/org/briarproject/transport/StreamWriterImpl.java @@ -1,8 +1,6 @@ package org.briarproject.transport; -import static org.briarproject.api.transport.TransportConstants.HEADER_LENGTH; -import static org.briarproject.api.transport.TransportConstants.MAC_LENGTH; -import static org.briarproject.api.transport.TransportConstants.MAX_FRAME_LENGTH; +import static org.briarproject.api.transport.TransportConstants.MAX_PAYLOAD_LENGTH; import java.io.IOException; import java.io.OutputStream; @@ -25,7 +23,7 @@ class StreamWriterImpl extends OutputStream { StreamWriterImpl(StreamEncrypter encrypter) { this.encrypter = encrypter; - payload = new byte[MAX_FRAME_LENGTH - HEADER_LENGTH - MAC_LENGTH]; + payload = new byte[MAX_PAYLOAD_LENGTH]; } @Override @@ -69,7 +67,7 @@ class StreamWriterImpl extends OutputStream { } private void writeFrame(boolean finalFrame) throws IOException { - encrypter.writeFrame(payload, length, finalFrame); + encrypter.writeFrame(payload, length, 0, finalFrame); length = 0; } } diff --git a/briar-tests/src/org/briarproject/crypto/StreamDecrypterImplTest.java b/briar-tests/src/org/briarproject/crypto/StreamDecrypterImplTest.java index b0b5f239a..c907f37e2 100644 --- a/briar-tests/src/org/briarproject/crypto/StreamDecrypterImplTest.java +++ b/briar-tests/src/org/briarproject/crypto/StreamDecrypterImplTest.java @@ -1,185 +1,37 @@ package org.briarproject.crypto; -import static org.briarproject.api.transport.TransportConstants.AAD_LENGTH; -import static org.briarproject.api.transport.TransportConstants.HEADER_LENGTH; -import static org.briarproject.api.transport.TransportConstants.IV_LENGTH; -import static org.briarproject.api.transport.TransportConstants.MAC_LENGTH; -import static org.briarproject.api.transport.TransportConstants.MAX_FRAME_LENGTH; - -import java.io.ByteArrayInputStream; - import org.briarproject.BriarTestCase; -import org.briarproject.TestLifecycleModule; -import org.briarproject.TestSystemModule; -import org.briarproject.api.FormatException; -import org.briarproject.api.crypto.AuthenticatedCipher; -import org.briarproject.api.crypto.CryptoComponent; -import org.briarproject.api.crypto.SecretKey; -import org.briarproject.util.ByteUtils; import org.junit.Test; -import com.google.inject.Guice; -import com.google.inject.Injector; - public class StreamDecrypterImplTest extends BriarTestCase { - // FIXME: This is an integration test, not a unit test - - private static final int MAX_PAYLOAD_LENGTH = - MAX_FRAME_LENGTH - HEADER_LENGTH - MAC_LENGTH; - - private final CryptoComponent crypto; - private final AuthenticatedCipher frameCipher; - private final SecretKey frameKey; - - public StreamDecrypterImplTest() { - Injector i = Guice.createInjector(new CryptoModule(), - new TestLifecycleModule(), new TestSystemModule()); - crypto = i.getInstance(CryptoComponent.class); - frameCipher = crypto.getFrameCipher(); - frameKey = crypto.generateSecretKey(); - } - @Test public void testReadValidFrames() throws Exception { - // Generate two valid frames - byte[] frame = generateFrame(0, MAX_FRAME_LENGTH, 123, false, false); - byte[] frame1 = generateFrame(1, MAX_FRAME_LENGTH, 123, false, false); - // Concatenate the frames - byte[] valid = new byte[MAX_FRAME_LENGTH * 2]; - System.arraycopy(frame, 0, valid, 0, MAX_FRAME_LENGTH); - System.arraycopy(frame1, 0, valid, MAX_FRAME_LENGTH, MAX_FRAME_LENGTH); - // Read the frames - ByteArrayInputStream in = new ByteArrayInputStream(valid); - StreamDecrypterImpl i = new StreamDecrypterImpl(in, frameCipher, - frameKey); - byte[] payload = new byte[MAX_PAYLOAD_LENGTH]; - assertEquals(123, i.readFrame(payload)); - assertEquals(123, i.readFrame(payload)); + // FIXME } @Test public void testTruncatedFrameThrowsException() throws Exception { - // Generate a valid frame - byte[] frame = generateFrame(0, MAX_FRAME_LENGTH, 123, false, false); - // Chop off the last byte - byte[] truncated = new byte[MAX_FRAME_LENGTH - 1]; - System.arraycopy(frame, 0, truncated, 0, MAX_FRAME_LENGTH - 1); - // Try to read the frame, which should fail due to truncation - ByteArrayInputStream in = new ByteArrayInputStream(truncated); - StreamDecrypterImpl i = new StreamDecrypterImpl(in, frameCipher, - frameKey); - try { - i.readFrame(new byte[MAX_PAYLOAD_LENGTH]); - fail(); - } catch(FormatException expected) {} + // FIXME } @Test public void testModifiedFrameThrowsException() throws Exception { - // Generate a valid frame - byte[] frame = generateFrame(0, MAX_FRAME_LENGTH, 123, false, false); - // Modify a randomly chosen byte of the frame - frame[(int) (Math.random() * MAX_FRAME_LENGTH)] ^= 1; - // Try to read the frame, which should fail due to modification - ByteArrayInputStream in = new ByteArrayInputStream(frame); - StreamDecrypterImpl i = new StreamDecrypterImpl(in, frameCipher, - frameKey); - try { - i.readFrame(new byte[MAX_PAYLOAD_LENGTH]); - fail(); - } catch(FormatException expected) {} - } - - @Test - public void testShortNonFinalFrameThrowsException() throws Exception { - // Generate a short non-final frame - byte[] frame = generateFrame(0, MAX_FRAME_LENGTH - 1, 123, false, - false); - // Try to read the frame, which should fail due to invalid length - ByteArrayInputStream in = new ByteArrayInputStream(frame); - StreamDecrypterImpl i = new StreamDecrypterImpl(in, frameCipher, - frameKey); - try { - i.readFrame(new byte[MAX_PAYLOAD_LENGTH]); - fail(); - } catch(FormatException expected) {} - } - - @Test - public void testShortFinalFrameDoesNotThrowException() throws Exception { - // Generate a short final frame - byte[] frame = generateFrame(0, MAX_FRAME_LENGTH - 1, 123, true, false); - // Read the frame - ByteArrayInputStream in = new ByteArrayInputStream(frame); - StreamDecrypterImpl i = new StreamDecrypterImpl(in, frameCipher, - frameKey); - int length = i.readFrame(new byte[MAX_PAYLOAD_LENGTH]); - assertEquals(123, length); + // FIXME } @Test public void testInvalidPayloadLengthThrowsException() throws Exception { - // Generate a frame with an invalid payload length - byte[] frame = generateFrame(0, MAX_FRAME_LENGTH, 123, false, false); - ByteUtils.writeUint16(MAX_PAYLOAD_LENGTH + 1, frame, 0); - // Try to read the frame, which should fail due to invalid length - ByteArrayInputStream in = new ByteArrayInputStream(frame); - StreamDecrypterImpl i = new StreamDecrypterImpl(in, frameCipher, - frameKey); - try { - i.readFrame(new byte[MAX_PAYLOAD_LENGTH]); - fail(); - } catch(FormatException expected) {} + // FIXME } @Test public void testNonZeroPaddingThrowsException() throws Exception { - // Generate a frame with bad padding - byte[] frame = generateFrame(0, MAX_FRAME_LENGTH, 123, false, true); - // Try to read the frame, which should fail due to bad padding - ByteArrayInputStream in = new ByteArrayInputStream(frame); - StreamDecrypterImpl i = new StreamDecrypterImpl(in, frameCipher, - frameKey); - try { - i.readFrame(new byte[MAX_PAYLOAD_LENGTH]); - fail(); - } catch(FormatException expected) {} + // FIXME } @Test public void testCannotReadBeyondFinalFrame() throws Exception { - // Generate a valid final frame and another valid final frame after it - byte[] frame = generateFrame(0, MAX_FRAME_LENGTH, MAX_PAYLOAD_LENGTH, - true, false); - byte[] frame1 = generateFrame(1, MAX_FRAME_LENGTH, 123, true, false); - // Concatenate the frames - byte[] extraFrame = new byte[MAX_FRAME_LENGTH * 2]; - System.arraycopy(frame, 0, extraFrame, 0, MAX_FRAME_LENGTH); - System.arraycopy(frame1, 0, extraFrame, MAX_FRAME_LENGTH, - MAX_FRAME_LENGTH); - // Read the final frame, which should first read the tag - ByteArrayInputStream in = new ByteArrayInputStream(extraFrame); - StreamDecrypterImpl i = new StreamDecrypterImpl(in, frameCipher, - frameKey); - byte[] payload = new byte[MAX_PAYLOAD_LENGTH]; - assertEquals(MAX_PAYLOAD_LENGTH, i.readFrame(payload)); - // The frame after the final frame should not be read - assertEquals(-1, i.readFrame(payload)); - } - - private byte[] generateFrame(long frameNumber, int frameLength, - int payloadLength, boolean finalFrame, boolean badPadding) - throws Exception { - byte[] iv = new byte[IV_LENGTH], aad = new byte[AAD_LENGTH]; - byte[] plaintext = new byte[frameLength - MAC_LENGTH]; - byte[] ciphertext = new byte[frameLength]; - FrameEncoder.encodeIv(iv, frameNumber); - FrameEncoder.encodeAad(aad, frameNumber, plaintext.length); - frameCipher.init(true, frameKey, iv, aad); - FrameEncoder.encodeHeader(plaintext, finalFrame, payloadLength); - if(badPadding) plaintext[HEADER_LENGTH + payloadLength] = 1; - frameCipher.doFinal(plaintext, 0, plaintext.length, ciphertext, 0); - return ciphertext; + // FIXME } } diff --git a/briar-tests/src/org/briarproject/crypto/StreamEncrypterImplTest.java b/briar-tests/src/org/briarproject/crypto/StreamEncrypterImplTest.java index 8b5c3d74c..a4738b56d 100644 --- a/briar-tests/src/org/briarproject/crypto/StreamEncrypterImplTest.java +++ b/briar-tests/src/org/briarproject/crypto/StreamEncrypterImplTest.java @@ -1,102 +1,27 @@ package org.briarproject.crypto; -import static org.briarproject.api.transport.TransportConstants.AAD_LENGTH; -import static org.briarproject.api.transport.TransportConstants.HEADER_LENGTH; -import static org.briarproject.api.transport.TransportConstants.IV_LENGTH; -import static org.briarproject.api.transport.TransportConstants.MAC_LENGTH; -import static org.briarproject.api.transport.TransportConstants.MAX_FRAME_LENGTH; -import static org.briarproject.api.transport.TransportConstants.TAG_LENGTH; - -import java.io.ByteArrayOutputStream; -import java.util.Random; - import org.briarproject.BriarTestCase; -import org.briarproject.TestLifecycleModule; -import org.briarproject.TestSystemModule; -import org.briarproject.api.crypto.AuthenticatedCipher; -import org.briarproject.api.crypto.CryptoComponent; -import org.briarproject.api.crypto.SecretKey; import org.junit.Test; -import com.google.inject.Guice; -import com.google.inject.Injector; - public class StreamEncrypterImplTest extends BriarTestCase { - // FIXME: This is an integration test, not a unit test - - private final CryptoComponent crypto; - private final AuthenticatedCipher frameCipher; - - public StreamEncrypterImplTest() { - Injector i = Guice.createInjector(new CryptoModule(), - new TestLifecycleModule(), new TestSystemModule()); - crypto = i.getInstance(CryptoComponent.class); - frameCipher = crypto.getFrameCipher(); - } - @Test public void testEncryptionWithoutTag() throws Exception { - int payloadLength = 123; - byte[] iv = new byte[IV_LENGTH], aad = new byte[AAD_LENGTH]; - byte[] plaintext = new byte[MAX_FRAME_LENGTH - MAC_LENGTH]; - byte[] ciphertext = new byte[MAX_FRAME_LENGTH]; - SecretKey frameKey = crypto.generateSecretKey(); - // Calculate the expected ciphertext - FrameEncoder.encodeIv(iv, 0); - FrameEncoder.encodeAad(aad, 0, plaintext.length); - frameCipher.init(true, frameKey, iv, aad); - FrameEncoder.encodeHeader(plaintext, false, payloadLength); - frameCipher.doFinal(plaintext, 0, plaintext.length, ciphertext, 0); - // Check that the actual ciphertext matches what's expected - ByteArrayOutputStream out = new ByteArrayOutputStream(); - StreamEncrypterImpl o = new StreamEncrypterImpl(out, frameCipher, - frameKey, null); - o.writeFrame(new byte[payloadLength], payloadLength, false); - byte[] actual = out.toByteArray(); - assertEquals(MAX_FRAME_LENGTH, actual.length); - for(int i = 0; i < MAX_FRAME_LENGTH; i++) - assertEquals(ciphertext[i], actual[i]); + // FIXME } @Test public void testEncryptionWithTag() throws Exception { - byte[] tag = new byte[TAG_LENGTH]; - new Random().nextBytes(tag); - int payloadLength = 123; - byte[] iv = new byte[IV_LENGTH], aad = new byte[AAD_LENGTH]; - byte[] plaintext = new byte[MAX_FRAME_LENGTH - MAC_LENGTH]; - byte[] ciphertext = new byte[MAX_FRAME_LENGTH]; - SecretKey frameKey = crypto.generateSecretKey(); - // Calculate the expected ciphertext - FrameEncoder.encodeIv(iv, 0); - FrameEncoder.encodeAad(aad, 0, plaintext.length); - frameCipher.init(true, frameKey, iv, aad); - FrameEncoder.encodeHeader(plaintext, false, payloadLength); - frameCipher.doFinal(plaintext, 0, plaintext.length, ciphertext, 0); - // Check that the actual tag and ciphertext match what's expected - ByteArrayOutputStream out = new ByteArrayOutputStream(); - StreamEncrypterImpl o = new StreamEncrypterImpl(out, frameCipher, - frameKey, tag); - o.writeFrame(new byte[payloadLength], payloadLength, false); - byte[] actual = out.toByteArray(); - assertEquals(TAG_LENGTH + MAX_FRAME_LENGTH, actual.length); - for(int i = 0; i < TAG_LENGTH; i++) assertEquals(tag[i], actual[i]); - for(int i = 0; i < MAX_FRAME_LENGTH; i++) - assertEquals(ciphertext[i], actual[TAG_LENGTH + i]); + // FIXME } @Test - public void testCloseConnectionWithoutWriting() throws Exception { - byte[] tag = new byte[TAG_LENGTH]; - new Random().nextBytes(tag); - ByteArrayOutputStream out = new ByteArrayOutputStream(); - // Initiator's constructor - StreamEncrypterImpl o = new StreamEncrypterImpl(out, frameCipher, - crypto.generateSecretKey(), tag); - // Write an empty final frame without having written any other frames - o.writeFrame(new byte[MAX_FRAME_LENGTH - MAC_LENGTH], 0, true); - // The tag and the empty frame should be written to the output stream - assertEquals(TAG_LENGTH + HEADER_LENGTH + MAC_LENGTH, out.size()); + public void testFlushWritesTagIfNotAlreadyWritten() throws Exception { + // FIXME + } + + @Test + public void testFlushDoesNotWriteTagIfAlreadyWritten() throws Exception { + // FIXME } } diff --git a/briar-tests/src/org/briarproject/transport/StreamReaderImplTest.java b/briar-tests/src/org/briarproject/transport/StreamReaderImplTest.java index 3a71ce74c..7e9e97bb2 100644 --- a/briar-tests/src/org/briarproject/transport/StreamReaderImplTest.java +++ b/briar-tests/src/org/briarproject/transport/StreamReaderImplTest.java @@ -1,8 +1,6 @@ package org.briarproject.transport; -import static org.briarproject.api.transport.TransportConstants.HEADER_LENGTH; -import static org.briarproject.api.transport.TransportConstants.MAC_LENGTH; -import static org.briarproject.api.transport.TransportConstants.MAX_FRAME_LENGTH; +import static org.briarproject.api.transport.TransportConstants.MAX_PAYLOAD_LENGTH; import org.briarproject.BriarTestCase; import org.briarproject.api.crypto.StreamDecrypter; @@ -12,9 +10,6 @@ import org.junit.Test; public class StreamReaderImplTest extends BriarTestCase { - private static final int MAX_PAYLOAD_LENGTH = - MAX_FRAME_LENGTH - HEADER_LENGTH - MAC_LENGTH; - @Test public void testEmptyFramesAreSkipped() throws Exception { Mockery context = new Mockery(); diff --git a/briar-tests/src/org/briarproject/transport/StreamWriterImplTest.java b/briar-tests/src/org/briarproject/transport/StreamWriterImplTest.java index 4ea8916dd..37c979f2d 100644 --- a/briar-tests/src/org/briarproject/transport/StreamWriterImplTest.java +++ b/briar-tests/src/org/briarproject/transport/StreamWriterImplTest.java @@ -1,8 +1,6 @@ package org.briarproject.transport; -import static org.briarproject.api.transport.TransportConstants.HEADER_LENGTH; -import static org.briarproject.api.transport.TransportConstants.MAC_LENGTH; -import static org.briarproject.api.transport.TransportConstants.MAX_FRAME_LENGTH; +import static org.briarproject.api.transport.TransportConstants.MAX_PAYLOAD_LENGTH; import org.briarproject.BriarTestCase; import org.briarproject.api.crypto.StreamEncrypter; @@ -12,9 +10,6 @@ import org.junit.Test; public class StreamWriterImplTest extends BriarTestCase { - private static final int MAX_PAYLOAD_LENGTH = - MAX_FRAME_LENGTH - HEADER_LENGTH - MAC_LENGTH; - @Test public void testCloseWithoutWritingWritesFinalFrame() throws Exception { Mockery context = new Mockery(); @@ -22,7 +17,7 @@ public class StreamWriterImplTest extends BriarTestCase { context.checking(new Expectations() {{ // Write an empty final frame oneOf(encrypter).writeFrame(with(any(byte[].class)), with(0), - with(true)); + with(0), with(true)); // Flush the stream oneOf(encrypter).flush(); }}); @@ -40,7 +35,7 @@ public class StreamWriterImplTest extends BriarTestCase { context.checking(new Expectations() {{ // Write a non-final frame with an empty payload oneOf(encrypter).writeFrame(with(any(byte[].class)), with(0), - with(false)); + with(0), with(false)); // Flush the stream oneOf(encrypter).flush(); }}); @@ -51,7 +46,7 @@ public class StreamWriterImplTest extends BriarTestCase { context.checking(new Expectations() {{ // Closing the writer writes a final frame and flushes again oneOf(encrypter).writeFrame(with(any(byte[].class)), with(0), - with(true)); + with(0), with(true)); oneOf(encrypter).flush(); }}); w.close(); @@ -67,7 +62,7 @@ public class StreamWriterImplTest extends BriarTestCase { context.checking(new Expectations() {{ // Write a non-final frame with one payload byte oneOf(encrypter).writeFrame(with(any(byte[].class)), with(1), - with(false)); + with(0), with(false)); // Flush the stream oneOf(encrypter).flush(); }}); @@ -79,7 +74,7 @@ public class StreamWriterImplTest extends BriarTestCase { context.checking(new Expectations() {{ // Closing the writer writes a final frame and flushes again oneOf(encrypter).writeFrame(with(any(byte[].class)), with(0), - with(true)); + with(0), with(true)); oneOf(encrypter).flush(); }}); w.close(); @@ -94,18 +89,16 @@ public class StreamWriterImplTest extends BriarTestCase { context.checking(new Expectations() {{ // Write a full non-final frame oneOf(encrypter).writeFrame(with(any(byte[].class)), - with(MAX_PAYLOAD_LENGTH), with(false)); + with(MAX_PAYLOAD_LENGTH), with(0), with(false)); }}); - for(int i = 0; i < MAX_PAYLOAD_LENGTH; i++) { - w.write(0); - } + for(int i = 0; i < MAX_PAYLOAD_LENGTH; i++) w.write(0); context.assertIsSatisfied(); // Clean up context.checking(new Expectations() {{ // Closing the writer writes a final frame and flushes again oneOf(encrypter).writeFrame(with(any(byte[].class)), with(0), - with(true)); + with(0), with(true)); oneOf(encrypter).flush(); }}); w.close(); @@ -120,7 +113,7 @@ public class StreamWriterImplTest extends BriarTestCase { context.checking(new Expectations() {{ // Write two full non-final frames exactly(2).of(encrypter).writeFrame(with(any(byte[].class)), - with(MAX_PAYLOAD_LENGTH), with(false)); + with(MAX_PAYLOAD_LENGTH), with(0), with(false)); }}); // Sanity check assertEquals(0, MAX_PAYLOAD_LENGTH % 2); @@ -136,7 +129,7 @@ public class StreamWriterImplTest extends BriarTestCase { context.checking(new Expectations() {{ // Closing the writer writes a final frame and flushes again oneOf(encrypter).writeFrame(with(any(byte[].class)), with(0), - with(true)); + with(0), with(true)); oneOf(encrypter).flush(); }}); w.close(); @@ -151,10 +144,10 @@ public class StreamWriterImplTest extends BriarTestCase { context.checking(new Expectations() {{ // Write two full non-final frames exactly(2).of(encrypter).writeFrame(with(any(byte[].class)), - with(MAX_PAYLOAD_LENGTH), with(false)); + with(MAX_PAYLOAD_LENGTH), with(0), with(false)); // Write a final frame with a one-byte payload oneOf(encrypter).writeFrame(with(any(byte[].class)), with(1), - with(true)); + with(0), with(true)); // Flush the stream oneOf(encrypter).flush(); }}); diff --git a/briar-tests/src/org/briarproject/transport/TestStreamEncrypter.java b/briar-tests/src/org/briarproject/transport/TestStreamEncrypter.java index 6939c71b5..d78b4aa3c 100644 --- a/briar-tests/src/org/briarproject/transport/TestStreamEncrypter.java +++ b/briar-tests/src/org/briarproject/transport/TestStreamEncrypter.java @@ -24,7 +24,7 @@ class TestStreamEncrypter implements StreamEncrypter { } public void writeFrame(byte[] payload, int payloadLength, - boolean finalFrame) throws IOException { + int paddingLength, boolean finalFrame) throws IOException { if(writeTag) { out.write(tag); writeTag = false; From ed79719bab45661a8e4c4e76a57a90b767e4c9be Mon Sep 17 00:00:00 2001 From: akwizgran Date: Mon, 5 Jan 2015 18:55:17 +0000 Subject: [PATCH 09/10] Unit tests for StreamEncrypterImpl. --- .../crypto/StreamEncrypterImplTest.java | 242 +++++++++++++++++- .../crypto/TestAuthenticatedCipher.java | 45 ++++ 2 files changed, 280 insertions(+), 7 deletions(-) create mode 100644 briar-tests/src/org/briarproject/crypto/TestAuthenticatedCipher.java diff --git a/briar-tests/src/org/briarproject/crypto/StreamEncrypterImplTest.java b/briar-tests/src/org/briarproject/crypto/StreamEncrypterImplTest.java index a4738b56d..a87431416 100644 --- a/briar-tests/src/org/briarproject/crypto/StreamEncrypterImplTest.java +++ b/briar-tests/src/org/briarproject/crypto/StreamEncrypterImplTest.java @@ -1,27 +1,255 @@ package org.briarproject.crypto; +import static org.briarproject.api.transport.TransportConstants.HEADER_LENGTH; +import static org.briarproject.api.transport.TransportConstants.MAC_LENGTH; +import static org.briarproject.api.transport.TransportConstants.TAG_LENGTH; +import static org.junit.Assert.assertArrayEquals; + +import java.io.ByteArrayOutputStream; +import java.util.Random; + import org.briarproject.BriarTestCase; +import org.briarproject.api.crypto.AuthenticatedCipher; +import org.briarproject.api.crypto.SecretKey; import org.junit.Test; public class StreamEncrypterImplTest extends BriarTestCase { - @Test - public void testEncryptionWithoutTag() throws Exception { - // FIXME + private final AuthenticatedCipher frameCipher; + private final SecretKey frameKey; + private final byte[] tag; + + public StreamEncrypterImplTest() { + frameCipher = new TestAuthenticatedCipher(); + frameKey = new SecretKey(new byte[32]); + tag = new byte[TAG_LENGTH]; + new Random().nextBytes(tag); } @Test - public void testEncryptionWithTag() throws Exception { - // FIXME + public void testWriteUnpaddedNonFinalFrameWithTag() throws Exception { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + StreamEncrypterImpl s = new StreamEncrypterImpl(out, frameCipher, + frameKey, tag); + int payloadLength = 123; + byte[] payload = new byte[payloadLength]; + new Random().nextBytes(payload); + + s.writeFrame(payload, payloadLength, 0, false); + + byte[] header = new byte[HEADER_LENGTH]; + FrameEncoder.encodeHeader(header, false, payloadLength, 0); + byte[] expected = new byte[TAG_LENGTH + HEADER_LENGTH + payloadLength + + MAC_LENGTH]; + System.arraycopy(tag, 0, expected, 0, TAG_LENGTH); + System.arraycopy(header, 0, expected, TAG_LENGTH, HEADER_LENGTH); + System.arraycopy(payload, 0, expected, TAG_LENGTH + HEADER_LENGTH, + payloadLength); + assertArrayEquals(expected, out.toByteArray()); + } + + @Test + public void testWriteUnpaddedFinalFrameWithTag() throws Exception { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + StreamEncrypterImpl s = new StreamEncrypterImpl(out, frameCipher, + frameKey, tag); + int payloadLength = 123; + byte[] payload = new byte[payloadLength]; + new Random().nextBytes(payload); + + s.writeFrame(payload, payloadLength, 0, true); + + byte[] header = new byte[HEADER_LENGTH]; + FrameEncoder.encodeHeader(header, true, payloadLength, 0); + byte[] expected = new byte[TAG_LENGTH + HEADER_LENGTH + payloadLength + + MAC_LENGTH]; + System.arraycopy(tag, 0, expected, 0, TAG_LENGTH); + System.arraycopy(header, 0, expected, TAG_LENGTH, HEADER_LENGTH); + System.arraycopy(payload, 0, expected, TAG_LENGTH + HEADER_LENGTH, + payloadLength); + assertArrayEquals(expected, out.toByteArray()); + } + + @Test + public void testWriteUnpaddedNonFinalFrameWithoutTag() throws Exception { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + StreamEncrypterImpl s = new StreamEncrypterImpl(out, frameCipher, + frameKey, null); + int payloadLength = 123; + byte[] payload = new byte[payloadLength]; + new Random().nextBytes(payload); + + s.writeFrame(payload, payloadLength, 0, false); + + byte[] header = new byte[HEADER_LENGTH]; + FrameEncoder.encodeHeader(header, false, payloadLength, 0); + byte[] expected = new byte[HEADER_LENGTH + payloadLength + MAC_LENGTH]; + System.arraycopy(header, 0, expected, 0, HEADER_LENGTH); + System.arraycopy(payload, 0, expected, HEADER_LENGTH, payloadLength); + assertArrayEquals(expected, out.toByteArray()); + } + + @Test + public void testWriteUnpaddedFinalFrameWithoutTag() throws Exception { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + StreamEncrypterImpl s = new StreamEncrypterImpl(out, frameCipher, + frameKey, null); + int payloadLength = 123; + byte[] payload = new byte[payloadLength]; + new Random().nextBytes(payload); + + s.writeFrame(payload, payloadLength, 0, true); + + byte[] header = new byte[HEADER_LENGTH]; + FrameEncoder.encodeHeader(header, true, payloadLength, 0); + byte[] expected = new byte[HEADER_LENGTH + payloadLength + MAC_LENGTH]; + System.arraycopy(header, 0, expected, 0, HEADER_LENGTH); + System.arraycopy(payload, 0, expected, HEADER_LENGTH, payloadLength); + assertArrayEquals(expected, out.toByteArray()); + } + + @Test + public void testWritePaddedNonFinalFrameWithTag() throws Exception { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + StreamEncrypterImpl s = new StreamEncrypterImpl(out, frameCipher, + frameKey, tag); + int payloadLength = 123, paddingLength = 234; + byte[] payload = new byte[payloadLength]; + new Random().nextBytes(payload); + + s.writeFrame(payload, payloadLength, paddingLength, false); + + byte[] header = new byte[HEADER_LENGTH]; + FrameEncoder.encodeHeader(header, false, payloadLength, paddingLength); + byte[] expected = new byte[TAG_LENGTH + HEADER_LENGTH + payloadLength + + paddingLength + MAC_LENGTH]; + System.arraycopy(tag, 0, expected, 0, TAG_LENGTH); + System.arraycopy(header, 0, expected, TAG_LENGTH, HEADER_LENGTH); + System.arraycopy(payload, 0, expected, TAG_LENGTH + HEADER_LENGTH, + payloadLength); + assertArrayEquals(expected, out.toByteArray()); + } + + @Test + public void testWritePaddedFinalFrameWithTag() throws Exception { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + StreamEncrypterImpl s = new StreamEncrypterImpl(out, frameCipher, + frameKey, tag); + int payloadLength = 123, paddingLength = 234; + byte[] payload = new byte[payloadLength]; + new Random().nextBytes(payload); + + s.writeFrame(payload, payloadLength, paddingLength, true); + + byte[] header = new byte[HEADER_LENGTH]; + FrameEncoder.encodeHeader(header, true, payloadLength, paddingLength); + byte[] expected = new byte[TAG_LENGTH + HEADER_LENGTH + payloadLength + + paddingLength + MAC_LENGTH]; + System.arraycopy(tag, 0, expected, 0, TAG_LENGTH); + System.arraycopy(header, 0, expected, TAG_LENGTH, HEADER_LENGTH); + System.arraycopy(payload, 0, expected, TAG_LENGTH + HEADER_LENGTH, + payloadLength); + assertArrayEquals(expected, out.toByteArray()); + } + + @Test + public void testWritePaddedNonFinalFrameWithoutTag() throws Exception { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + StreamEncrypterImpl s = new StreamEncrypterImpl(out, frameCipher, + frameKey, null); + int payloadLength = 123, paddingLength = 234; + byte[] payload = new byte[payloadLength]; + new Random().nextBytes(payload); + + s.writeFrame(payload, payloadLength, paddingLength, false); + + byte[] header = new byte[HEADER_LENGTH]; + FrameEncoder.encodeHeader(header, false, payloadLength, paddingLength); + byte[] expected = new byte[HEADER_LENGTH + payloadLength + + paddingLength + MAC_LENGTH]; + System.arraycopy(header, 0, expected, 0, HEADER_LENGTH); + System.arraycopy(payload, 0, expected, HEADER_LENGTH, payloadLength); + assertArrayEquals(expected, out.toByteArray()); + } + + @Test + public void testWritePaddedFinalFrameWithoutTag() throws Exception { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + StreamEncrypterImpl s = new StreamEncrypterImpl(out, frameCipher, + frameKey, null); + int payloadLength = 123, paddingLength = 234; + byte[] payload = new byte[payloadLength]; + new Random().nextBytes(payload); + + s.writeFrame(payload, payloadLength, paddingLength, true); + + byte[] header = new byte[HEADER_LENGTH]; + FrameEncoder.encodeHeader(header, true, payloadLength, paddingLength); + byte[] expected = new byte[HEADER_LENGTH + payloadLength + + paddingLength + MAC_LENGTH]; + System.arraycopy(header, 0, expected, 0, HEADER_LENGTH); + System.arraycopy(payload, 0, expected, HEADER_LENGTH, payloadLength); + assertArrayEquals(expected, out.toByteArray()); + } + + @Test + public void testWriteTwoFrames() throws Exception { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + StreamEncrypterImpl s = new StreamEncrypterImpl(out, frameCipher, + frameKey, null); + int payloadLength = 123, paddingLength = 234; + byte[] payload = new byte[payloadLength]; + new Random().nextBytes(payload); + int payloadLength1 = 345, paddingLength1 = 456; + byte[] payload1 = new byte[payloadLength1]; + new Random().nextBytes(payload1); + + s.writeFrame(payload, payloadLength, paddingLength, false); + s.writeFrame(payload1, payloadLength1, paddingLength1, true); + + byte[] header = new byte[HEADER_LENGTH]; + FrameEncoder.encodeHeader(header, false, payloadLength, paddingLength); + byte[] header1 = new byte[HEADER_LENGTH]; + FrameEncoder.encodeHeader(header1, true, payloadLength1, + paddingLength1); + byte[] expected = new byte[HEADER_LENGTH + payloadLength + + paddingLength + MAC_LENGTH + + HEADER_LENGTH + payloadLength1 + + paddingLength1 + MAC_LENGTH]; + System.arraycopy(header, 0, expected, 0, HEADER_LENGTH); + System.arraycopy(payload, 0, expected, HEADER_LENGTH, payloadLength); + System.arraycopy(header1, 0, expected, HEADER_LENGTH + payloadLength + + paddingLength + MAC_LENGTH, HEADER_LENGTH); + System.arraycopy(payload1, 0, expected, HEADER_LENGTH + payloadLength + + paddingLength + MAC_LENGTH + HEADER_LENGTH, payloadLength1); + assertArrayEquals(expected, out.toByteArray()); } @Test public void testFlushWritesTagIfNotAlreadyWritten() throws Exception { - // FIXME + ByteArrayOutputStream out = new ByteArrayOutputStream(); + StreamEncrypterImpl s = new StreamEncrypterImpl(out, frameCipher, + frameKey, tag); + s.flush(); + assertArrayEquals(tag, out.toByteArray()); } @Test public void testFlushDoesNotWriteTagIfAlreadyWritten() throws Exception { - // FIXME + ByteArrayOutputStream out = new ByteArrayOutputStream(); + StreamEncrypterImpl s = new StreamEncrypterImpl(out, frameCipher, + frameKey, tag); + s.flush(); + s.flush(); + assertArrayEquals(tag, out.toByteArray()); + } + + @Test + public void testFlushDoesNotWriteTagIfNull() throws Exception { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + StreamEncrypterImpl s = new StreamEncrypterImpl(out, frameCipher, + frameKey, null); + s.flush(); + assertEquals(0, out.size()); } } diff --git a/briar-tests/src/org/briarproject/crypto/TestAuthenticatedCipher.java b/briar-tests/src/org/briarproject/crypto/TestAuthenticatedCipher.java new file mode 100644 index 000000000..0271975bd --- /dev/null +++ b/briar-tests/src/org/briarproject/crypto/TestAuthenticatedCipher.java @@ -0,0 +1,45 @@ +package org.briarproject.crypto; + +import static org.briarproject.api.transport.TransportConstants.MAC_LENGTH; + +import java.security.GeneralSecurityException; + +import org.briarproject.api.crypto.AuthenticatedCipher; +import org.briarproject.api.crypto.SecretKey; + +class TestAuthenticatedCipher implements AuthenticatedCipher { + + private static final int BLOCK_BYTES = 16; + + private boolean encrypt = false; + + public void init(boolean encrypt, SecretKey key, byte[] iv, byte[] aad) + throws GeneralSecurityException { + this.encrypt = encrypt; + } + + public int process(byte[] input, int inputOff, int len, byte[] output, + int outputOff) throws GeneralSecurityException { + if(encrypt) { + System.arraycopy(input, inputOff, output, outputOff, len); + for(int i = 0; i < MAC_LENGTH; i++) + output[outputOff + len + i] = 0; + return len + MAC_LENGTH; + } else { + for(int i = 0; i < MAC_LENGTH; i++) + if(input[inputOff + len - MAC_LENGTH + i] != 0) + throw new GeneralSecurityException(); + System.arraycopy(input, inputOff, output, outputOff, + len - MAC_LENGTH); + return len - MAC_LENGTH; + } + } + + public int getMacLength() { + return MAC_LENGTH; + } + + public int getBlockSize() { + return BLOCK_BYTES; + } +} From 4e57029d9819b7611df3fadb4f9b41fbe0d4d2de Mon Sep 17 00:00:00 2001 From: akwizgran Date: Tue, 6 Jan 2015 19:30:11 +0000 Subject: [PATCH 10/10] Use constant-time GCM multiplier. --- .../briarproject/api/crypto/CryptoComponent.java | 2 +- .../briarproject/crypto/CryptoComponentImpl.java | 16 +++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/briar-api/src/org/briarproject/api/crypto/CryptoComponent.java b/briar-api/src/org/briarproject/api/crypto/CryptoComponent.java index 558077ae4..0f448daef 100644 --- a/briar-api/src/org/briarproject/api/crypto/CryptoComponent.java +++ b/briar-api/src/org/briarproject/api/crypto/CryptoComponent.java @@ -65,7 +65,7 @@ public interface CryptoComponent { /** * Derives a tag key from the given temporary secret. - * @param alice indicates whether the key is for connections initiated by + * @param alice indicates whether the key is for streams initiated by * Alice or Bob. */ SecretKey deriveTagKey(byte[] secret, boolean alice); diff --git a/briar-core/src/org/briarproject/crypto/CryptoComponentImpl.java b/briar-core/src/org/briarproject/crypto/CryptoComponentImpl.java index 10c2c0cff..5612c4077 100644 --- a/briar-core/src/org/briarproject/crypto/CryptoComponentImpl.java +++ b/briar-core/src/org/briarproject/crypto/CryptoComponentImpl.java @@ -43,6 +43,7 @@ import org.spongycastle.crypto.generators.PKCS5S2ParametersGenerator; import org.spongycastle.crypto.macs.HMac; import org.spongycastle.crypto.modes.AEADBlockCipher; import org.spongycastle.crypto.modes.GCMBlockCipher; +import org.spongycastle.crypto.modes.gcm.BasicGCMMultiplier; import org.spongycastle.crypto.params.ECKeyGenerationParameters; import org.spongycastle.crypto.params.ECPrivateKeyParameters; import org.spongycastle.crypto.params.ECPublicKeyParameters; @@ -294,7 +295,12 @@ class CryptoComponentImpl implements CryptoComponent { } public AuthenticatedCipher getFrameCipher() { - AEADBlockCipher a = new GCMBlockCipher(new AESLightEngine()); + return getAuthenticatedCipher(); + } + + private AuthenticatedCipher getAuthenticatedCipher() { + AEADBlockCipher a = new GCMBlockCipher(new AESLightEngine(), + new BasicGCMMultiplier()); return new AuthenticatedCipherImpl(a, MAC_BYTES); } @@ -329,10 +335,8 @@ class CryptoComponentImpl implements CryptoComponent { ByteUtils.writeUint32(iterations, output, salt.length); System.arraycopy(iv, 0, output, salt.length + 4, iv.length); // Initialise the cipher and encrypt the plaintext + AuthenticatedCipher cipher = getAuthenticatedCipher(); try { - AEADBlockCipher a = new GCMBlockCipher(new AESLightEngine()); - AuthenticatedCipher cipher = new AuthenticatedCipherImpl(a, - MAC_BYTES); cipher.init(true, key, iv, null); int outputOff = salt.length + 4 + iv.length; cipher.process(input, 0, input.length, output, outputOff); @@ -356,10 +360,8 @@ class CryptoComponentImpl implements CryptoComponent { // Derive the key from the password SecretKey key = new SecretKey(pbkdf2(password, salt, (int) iterations)); // Initialise the cipher - AuthenticatedCipher cipher; + AuthenticatedCipher cipher = getAuthenticatedCipher(); try { - AEADBlockCipher a = new GCMBlockCipher(new AESLightEngine()); - cipher = new AuthenticatedCipherImpl(a, MAC_BYTES); cipher.init(false, key, iv, null); } catch(GeneralSecurityException e) { throw new RuntimeException(e);