Skip to content
Snippets Groups Projects
Commit a104548f authored by akwizgran's avatar akwizgran
Browse files

Allow for the maximum overhead when calculating capacity.

parent 521ed076
No related branches found
No related tags found
No related merge requests found
package net.sf.briar.api.protocol; package net.sf.briar.api.protocol;
import net.sf.briar.api.transport.TransportConstants; import static net.sf.briar.api.transport.TransportConstants.MIN_CONNECTION_LENGTH;
public interface ProtocolConstants { public interface ProtocolConstants {
/** /**
* The maximum length of a serialised packet in bytes. To allow for future * The maximum length of a serialised packet in bytes. To allow for future
* changes in the protocol, this is smaller than the minimum connection * changes in the protocol, this is smaller than the minimum connection
* length minus the encryption and authentication overhead. * length minus the maximum encryption and authentication overhead.
*/ */
static final int MAX_PACKET_LENGTH = static final int MAX_PACKET_LENGTH = MIN_CONNECTION_LENGTH / 2;
TransportConstants.MIN_CONNECTION_LENGTH - 1024;
/** The maximum number of transports a node may support. */ /** The maximum number of transports a node may support. */
static final int MAX_TRANSPORTS = 50; static final int MAX_TRANSPORTS = 25;
/** The maximum number of properties per transport. */ /** The maximum number of properties per transport. */
static final int MAX_PROPERTIES_PER_TRANSPORT = 100; static final int MAX_PROPERTIES_PER_TRANSPORT = 100;
......
...@@ -35,11 +35,7 @@ class ConnectionWriterImpl extends OutputStream implements ConnectionWriter { ...@@ -35,11 +35,7 @@ class ConnectionWriterImpl extends OutputStream implements ConnectionWriter {
} }
public long getRemainingCapacity() { public long getRemainingCapacity() {
long capacity = out.getRemainingCapacity(); return out.getRemainingCapacity();
int maxPayloadLength = frameLength - HEADER_LENGTH - MAC_LENGTH;
long frames = (long) Math.ceil((double) capacity / maxPayloadLength);
long overhead = (frames + 1) * (HEADER_LENGTH + MAC_LENGTH);
return capacity - overhead - length;
} }
@Override @Override
...@@ -83,12 +79,9 @@ class ConnectionWriterImpl extends OutputStream implements ConnectionWriter { ...@@ -83,12 +79,9 @@ class ConnectionWriterImpl extends OutputStream implements ConnectionWriter {
length += len; length += len;
} }
private void writeFrame(boolean lastFrame) throws IOException { private void writeFrame(boolean finalFrame) throws IOException {
if(frameNumber > MAX_32_BIT_UNSIGNED) throw new IllegalStateException(); if(frameNumber > MAX_32_BIT_UNSIGNED) throw new IllegalStateException();
int capacity = (int) Math.min(frameLength, out.getRemainingCapacity()); out.writeFrame(frame, length, finalFrame);
int paddingLength = capacity - HEADER_LENGTH - length - MAC_LENGTH;
if(paddingLength < 0) throw new IllegalStateException();
out.writeFrame(frame, length, lastFrame ? 0 : paddingLength, lastFrame);
length = 0; length = 0;
frameNumber++; frameNumber++;
} }
......
...@@ -5,8 +5,8 @@ import java.io.IOException; ...@@ -5,8 +5,8 @@ import java.io.IOException;
interface FrameWriter { interface FrameWriter {
/** Writes the given frame. */ /** Writes the given frame. */
void writeFrame(byte[] frame, int payloadLength, int paddingLength, void writeFrame(byte[] frame, int payloadLength, boolean finalFrame)
boolean lastFrame) throws IOException; throws IOException;
/** Flushes the stack. */ /** Flushes the stack. */
void flush() throws IOException; void flush() throws IOException;
......
...@@ -6,6 +6,7 @@ import static net.sf.briar.api.transport.TransportConstants.HEADER_LENGTH; ...@@ -6,6 +6,7 @@ import static net.sf.briar.api.transport.TransportConstants.HEADER_LENGTH;
import static net.sf.briar.api.transport.TransportConstants.IV_LENGTH; import static net.sf.briar.api.transport.TransportConstants.IV_LENGTH;
import static net.sf.briar.api.transport.TransportConstants.MAC_LENGTH; import static net.sf.briar.api.transport.TransportConstants.MAC_LENGTH;
import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH; import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
import static net.sf.briar.util.ByteUtils.MAX_32_BIT_UNSIGNED;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
...@@ -33,7 +34,7 @@ class OutgoingEncryptionLayer implements FrameWriter { ...@@ -33,7 +34,7 @@ class OutgoingEncryptionLayer implements FrameWriter {
AuthenticatedCipher frameCipher, ErasableKey tagKey, AuthenticatedCipher frameCipher, ErasableKey tagKey,
ErasableKey frameKey, int frameLength) { ErasableKey frameKey, int frameLength) {
this.out = out; this.out = out;
this.capacity = capacity - TAG_LENGTH; this.capacity = capacity;
this.tagCipher = tagCipher; this.tagCipher = tagCipher;
this.frameCipher = frameCipher; this.frameCipher = frameCipher;
this.tagKey = tagKey; this.tagKey = tagKey;
...@@ -64,17 +65,11 @@ class OutgoingEncryptionLayer implements FrameWriter { ...@@ -64,17 +65,11 @@ class OutgoingEncryptionLayer implements FrameWriter {
writeTag = false; writeTag = false;
} }
public void writeFrame(byte[] frame, int payloadLength, int paddingLength, public void writeFrame(byte[] frame, int payloadLength, boolean finalFrame)
boolean lastFrame) throws IOException { throws IOException {
int plaintextLength = HEADER_LENGTH + payloadLength + paddingLength;
int ciphertextLength = plaintextLength + MAC_LENGTH;
if(ciphertextLength > frameLength)
throw new IllegalArgumentException();
if(!lastFrame && ciphertextLength < frameLength)
throw new IllegalArgumentException();
// If the initiator's side of the connection is closed without writing // If the initiator's side of the connection is closed without writing
// any payload or padding, don't write a tag or an empty frame // any data, don't write anything to the underlying transport
if(writeTag && lastFrame && payloadLength + paddingLength == 0) return; if(writeTag && finalFrame && payloadLength == 0) return;
// Write the tag if required // Write the tag if required
if(writeTag) { if(writeTag) {
TagEncoder.encodeTag(ciphertext, tagCipher, tagKey); TagEncoder.encodeTag(ciphertext, tagCipher, tagKey);
...@@ -85,10 +80,20 @@ class OutgoingEncryptionLayer implements FrameWriter { ...@@ -85,10 +80,20 @@ class OutgoingEncryptionLayer implements FrameWriter {
tagKey.erase(); tagKey.erase();
throw e; throw e;
} }
capacity -= TAG_LENGTH;
writeTag = false; writeTag = false;
} }
// Encode the header // Encode the header
FrameEncoder.encodeHeader(frame, lastFrame, payloadLength); FrameEncoder.encodeHeader(frame, finalFrame, payloadLength);
// Don't pad the final frame
int plaintextLength, ciphertextLength;
if(finalFrame) {
plaintextLength = HEADER_LENGTH + payloadLength;
ciphertextLength = plaintextLength + MAC_LENGTH;
} else {
plaintextLength = frameLength - MAC_LENGTH;
ciphertextLength = frameLength;
}
// If there's any padding it must all be zeroes // If there's any padding it must all be zeroes
for(int i = HEADER_LENGTH + payloadLength; i < plaintextLength; i++) for(int i = HEADER_LENGTH + payloadLength; i < plaintextLength; i++)
frame[i] = 0; frame[i] = 0;
...@@ -120,6 +125,10 @@ class OutgoingEncryptionLayer implements FrameWriter { ...@@ -120,6 +125,10 @@ class OutgoingEncryptionLayer implements FrameWriter {
} }
public long getRemainingCapacity() { public long getRemainingCapacity() {
return capacity; long capacityExcludingTag = writeTag ? capacity - TAG_LENGTH : capacity;
long frames = capacityExcludingTag / frameLength;
long frameNumbers = MAX_32_BIT_UNSIGNED - frameNumber + 1;
int maxPayloadLength = frameLength - HEADER_LENGTH - MAC_LENGTH;
return maxPayloadLength * Math.min(frames, frameNumbers);
} }
} }
\ No newline at end of file
...@@ -48,14 +48,14 @@ public class ConnectionWriterTest extends BriarTestCase { ...@@ -48,14 +48,14 @@ public class ConnectionWriterTest extends BriarTestCase {
MIN_CONNECTION_LENGTH, secret, true); MIN_CONNECTION_LENGTH, secret, true);
// Check that the connection writer thinks there's room for a packet // Check that the connection writer thinks there's room for a packet
long capacity = w.getRemainingCapacity(); long capacity = w.getRemainingCapacity();
assertTrue(capacity >= MAX_PACKET_LENGTH); assertTrue(capacity > MAX_PACKET_LENGTH);
assertTrue(capacity <= MIN_CONNECTION_LENGTH); assertTrue(capacity < MIN_CONNECTION_LENGTH);
// Check that there really is room for a packet // Check that there really is room for a packet
byte[] payload = new byte[MAX_PACKET_LENGTH]; byte[] payload = new byte[MAX_PACKET_LENGTH];
w.getOutputStream().write(payload); w.getOutputStream().write(payload);
w.getOutputStream().close(); w.getOutputStream().close();
long used = out.size(); long used = out.size();
assertTrue(used >= MAX_PACKET_LENGTH); assertTrue(used > MAX_PACKET_LENGTH);
assertTrue(used <= MIN_CONNECTION_LENGTH); assertTrue(used <= MIN_CONNECTION_LENGTH);
} }
...@@ -67,14 +67,14 @@ public class ConnectionWriterTest extends BriarTestCase { ...@@ -67,14 +67,14 @@ public class ConnectionWriterTest extends BriarTestCase {
MIN_CONNECTION_LENGTH, secret, false); MIN_CONNECTION_LENGTH, secret, false);
// Check that the connection writer thinks there's room for a packet // Check that the connection writer thinks there's room for a packet
long capacity = w.getRemainingCapacity(); long capacity = w.getRemainingCapacity();
assertTrue(capacity >= MAX_PACKET_LENGTH); assertTrue(capacity > MAX_PACKET_LENGTH);
assertTrue(capacity <= MIN_CONNECTION_LENGTH); assertTrue(capacity < MIN_CONNECTION_LENGTH);
// Check that there really is room for a packet // Check that there really is room for a packet
byte[] payload = new byte[MAX_PACKET_LENGTH]; byte[] payload = new byte[MAX_PACKET_LENGTH];
w.getOutputStream().write(payload); w.getOutputStream().write(payload);
w.getOutputStream().close(); w.getOutputStream().close();
long used = out.size(); long used = out.size();
assertTrue(used >= MAX_PACKET_LENGTH); assertTrue(used > MAX_PACKET_LENGTH);
assertTrue(used <= MIN_CONNECTION_LENGTH); assertTrue(used <= MIN_CONNECTION_LENGTH);
} }
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment