mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-19 06:09:55 +01:00
More refactoring to connect ConnectionRecogniser to ConnectionReader.
Added TestDatabaseModule so tests can specify their own DB configuration. The modules are currently too tightly coupled - see whether any dependencies can be removed.
This commit is contained in:
@@ -22,19 +22,30 @@ implements ConnectionDecrypter {
|
||||
|
||||
private final Cipher frameCipher;
|
||||
private final SecretKey frameKey;
|
||||
private final byte[] buf, iv;
|
||||
private final byte[] iv, buf;
|
||||
|
||||
private int bufOff = 0, bufLen = 0;
|
||||
private long frame = 0L;
|
||||
private boolean betweenFrames = true;
|
||||
|
||||
ConnectionDecrypterImpl(InputStream in, boolean initiator, int transportId,
|
||||
long connection, Cipher frameCipher, SecretKey frameKey) {
|
||||
ConnectionDecrypterImpl(InputStream in, byte[] encryptedIv, Cipher ivCipher,
|
||||
Cipher frameCipher, SecretKey ivKey, SecretKey frameKey) {
|
||||
super(in);
|
||||
this.frameCipher = frameCipher;
|
||||
this.frameKey = frameKey;
|
||||
// Decrypt the IV
|
||||
try {
|
||||
ivCipher.init(Cipher.DECRYPT_MODE, ivKey);
|
||||
iv = ivCipher.doFinal(encryptedIv);
|
||||
} catch(BadPaddingException badCipher) {
|
||||
throw new IllegalArgumentException(badCipher);
|
||||
} catch(IllegalBlockSizeException badCipher) {
|
||||
throw new IllegalArgumentException(badCipher);
|
||||
} catch(InvalidKeyException badKey) {
|
||||
throw new IllegalArgumentException(badKey);
|
||||
}
|
||||
if(iv.length != IV_LENGTH) throw new IllegalArgumentException();
|
||||
buf = new byte[IV_LENGTH];
|
||||
iv = IvEncoder.encodeIv(initiator, transportId, connection);
|
||||
}
|
||||
|
||||
public InputStream getInputStream() {
|
||||
|
||||
@@ -13,5 +13,5 @@ interface ConnectionEncrypter {
|
||||
void writeMac(byte[] mac) throws IOException;
|
||||
|
||||
/** Returns the maximum number of bytes that can be written. */
|
||||
long getCapacity();
|
||||
long getRemainingCapacity();
|
||||
}
|
||||
|
||||
@@ -18,29 +18,34 @@ import javax.crypto.spec.IvParameterSpec;
|
||||
class ConnectionEncrypterImpl extends FilterOutputStream
|
||||
implements ConnectionEncrypter {
|
||||
|
||||
private final Cipher ivCipher, frameCipher;
|
||||
private final Cipher frameCipher;
|
||||
private final SecretKey frameKey;
|
||||
private final byte[] iv;
|
||||
private final byte[] iv, encryptedIv;
|
||||
|
||||
private long capacity, frame = 0L;
|
||||
private boolean ivWritten = false, betweenFrames = false;
|
||||
|
||||
ConnectionEncrypterImpl(OutputStream out, long capacity, boolean initiator,
|
||||
int transportId, long connection, Cipher ivCipher,
|
||||
Cipher frameCipher, SecretKey ivKey, SecretKey frameKey) {
|
||||
ConnectionEncrypterImpl(OutputStream out, long capacity, byte[] iv,
|
||||
Cipher ivCipher, Cipher frameCipher, SecretKey ivKey,
|
||||
SecretKey frameKey) {
|
||||
super(out);
|
||||
this.ivCipher = ivCipher;
|
||||
this.capacity = capacity;
|
||||
this.iv = iv;
|
||||
this.frameCipher = frameCipher;
|
||||
this.frameKey = frameKey;
|
||||
iv = IvEncoder.encodeIv(initiator, transportId, connection);
|
||||
// Encrypt the IV
|
||||
try {
|
||||
ivCipher.init(Cipher.ENCRYPT_MODE, ivKey);
|
||||
encryptedIv = ivCipher.doFinal(iv);
|
||||
} catch(BadPaddingException badCipher) {
|
||||
throw new IllegalArgumentException(badCipher);
|
||||
} catch(IllegalBlockSizeException badCipher) {
|
||||
throw new IllegalArgumentException(badCipher);
|
||||
} catch(InvalidKeyException badKey) {
|
||||
throw new IllegalArgumentException(badKey);
|
||||
}
|
||||
if(ivCipher.getOutputSize(IV_LENGTH) != IV_LENGTH)
|
||||
if(encryptedIv.length != IV_LENGTH)
|
||||
throw new IllegalArgumentException();
|
||||
this.capacity = capacity;
|
||||
}
|
||||
|
||||
public OutputStream getOutputStream() {
|
||||
@@ -60,7 +65,7 @@ implements ConnectionEncrypter {
|
||||
betweenFrames = true;
|
||||
}
|
||||
|
||||
public long getCapacity() {
|
||||
public long getRemainingCapacity() {
|
||||
return capacity;
|
||||
}
|
||||
|
||||
@@ -90,14 +95,8 @@ implements ConnectionEncrypter {
|
||||
private void writeIv() throws IOException {
|
||||
assert !ivWritten;
|
||||
assert !betweenFrames;
|
||||
try {
|
||||
out.write(ivCipher.doFinal(iv));
|
||||
} catch(BadPaddingException badCipher) {
|
||||
throw new RuntimeException(badCipher);
|
||||
} catch(IllegalBlockSizeException badCipher) {
|
||||
throw new RuntimeException(badCipher);
|
||||
}
|
||||
capacity -= iv.length;
|
||||
out.write(encryptedIv);
|
||||
capacity -= encryptedIv.length;
|
||||
ivWritten = true;
|
||||
betweenFrames = true;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package net.sf.briar.transport;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.security.InvalidKeyException;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.Mac;
|
||||
@@ -23,19 +22,17 @@ class ConnectionReaderFactoryImpl implements ConnectionReaderFactory {
|
||||
}
|
||||
|
||||
public ConnectionReader createConnectionReader(InputStream in,
|
||||
boolean initiator, int transportId, long connection,
|
||||
byte[] secret) {
|
||||
SecretKey macKey = crypto.deriveIncomingMacKey(secret);
|
||||
SecretKey frameKey = crypto.deriveIncomingFrameKey(secret);
|
||||
byte[] encryptedIv, byte[] secret) {
|
||||
// Create the decrypter
|
||||
Cipher ivCipher = crypto.getIvCipher();
|
||||
Cipher frameCipher = crypto.getFrameCipher();
|
||||
Mac mac = crypto.getMac();
|
||||
try {
|
||||
mac.init(macKey);
|
||||
} catch(InvalidKeyException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
SecretKey ivKey = crypto.deriveIncomingIvKey(secret);
|
||||
SecretKey frameKey = crypto.deriveIncomingFrameKey(secret);
|
||||
ConnectionDecrypter decrypter = new ConnectionDecrypterImpl(in,
|
||||
initiator, transportId, connection, frameCipher, frameKey);
|
||||
return new ConnectionReaderImpl(decrypter, mac);
|
||||
encryptedIv, ivCipher, frameCipher, ivKey, frameKey);
|
||||
// Create the reader
|
||||
Mac mac = crypto.getMac();
|
||||
SecretKey macKey = crypto.deriveIncomingMacKey(secret);
|
||||
return new ConnectionReaderImpl(decrypter, mac, macKey);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,9 +7,11 @@ import java.io.EOFException;
|
||||
import java.io.FilterInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.SecretKey;
|
||||
|
||||
import net.sf.briar.api.FormatException;
|
||||
import net.sf.briar.api.transport.ConnectionReader;
|
||||
@@ -27,10 +29,17 @@ implements ConnectionReader {
|
||||
private int payloadOff = 0, payloadLen = 0;
|
||||
private boolean betweenFrames = true;
|
||||
|
||||
ConnectionReaderImpl(ConnectionDecrypter decrypter, Mac mac) {
|
||||
ConnectionReaderImpl(ConnectionDecrypter decrypter, Mac mac,
|
||||
SecretKey macKey) {
|
||||
super(decrypter.getInputStream());
|
||||
this.decrypter = decrypter;
|
||||
this.mac = mac;
|
||||
// Initialise the MAC
|
||||
try {
|
||||
mac.init(macKey);
|
||||
} catch(InvalidKeyException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
maxPayloadLength = MAX_FRAME_LENGTH - 4 - mac.getMacLength();
|
||||
header = new byte[4];
|
||||
payload = new byte[maxPayloadLength];
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package net.sf.briar.transport;
|
||||
|
||||
import net.sf.briar.api.crypto.CryptoComponent;
|
||||
import net.sf.briar.api.db.DatabaseComponent;
|
||||
import net.sf.briar.api.transport.ConnectionRecogniser;
|
||||
import net.sf.briar.api.transport.ConnectionRecogniserFactory;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
class ConnectionRecogniserFactoryImpl implements ConnectionRecogniserFactory {
|
||||
|
||||
private final CryptoComponent crypto;
|
||||
private final DatabaseComponent db;
|
||||
|
||||
@Inject
|
||||
ConnectionRecogniserFactoryImpl(CryptoComponent crypto,
|
||||
DatabaseComponent db) {
|
||||
this.crypto = crypto;
|
||||
this.db = db;
|
||||
}
|
||||
|
||||
public ConnectionRecogniser createConnectionRecogniser(int transportId) {
|
||||
return new ConnectionRecogniserImpl(transportId, crypto, db);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
package net.sf.briar.transport;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.security.InvalidKeyException;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.Mac;
|
||||
@@ -25,20 +24,17 @@ class ConnectionWriterFactoryImpl implements ConnectionWriterFactory {
|
||||
public ConnectionWriter createConnectionWriter(OutputStream out,
|
||||
long capacity, boolean initiator, int transportId, long connection,
|
||||
byte[] secret) {
|
||||
SecretKey macKey = crypto.deriveOutgoingMacKey(secret);
|
||||
SecretKey ivKey = crypto.deriveOutgoingIvKey(secret);
|
||||
SecretKey frameKey = crypto.deriveOutgoingFrameKey(secret);
|
||||
// Create the encrypter
|
||||
Cipher ivCipher = crypto.getIvCipher();
|
||||
Cipher frameCipher = crypto.getFrameCipher();
|
||||
Mac mac = crypto.getMac();
|
||||
try {
|
||||
mac.init(macKey);
|
||||
} catch(InvalidKeyException badKey) {
|
||||
throw new IllegalArgumentException(badKey);
|
||||
}
|
||||
SecretKey ivKey = crypto.deriveOutgoingIvKey(secret);
|
||||
SecretKey frameKey = crypto.deriveOutgoingFrameKey(secret);
|
||||
byte[] iv = IvEncoder.encodeIv(initiator, transportId, connection);
|
||||
ConnectionEncrypter encrypter = new ConnectionEncrypterImpl(out,
|
||||
capacity, initiator, transportId, connection, ivCipher,
|
||||
frameCipher, ivKey, frameKey);
|
||||
return new ConnectionWriterImpl(encrypter, mac);
|
||||
capacity, iv, ivCipher, frameCipher, ivKey, frameKey);
|
||||
// Create the writer
|
||||
Mac mac = crypto.getMac();
|
||||
SecretKey macKey = crypto.deriveOutgoingMacKey(secret);
|
||||
return new ConnectionWriterImpl(encrypter, mac, macKey);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,8 +7,10 @@ import java.io.ByteArrayOutputStream;
|
||||
import java.io.FilterOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.security.InvalidKeyException;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.SecretKey;
|
||||
|
||||
import net.sf.briar.api.transport.ConnectionWriter;
|
||||
import net.sf.briar.util.ByteUtils;
|
||||
@@ -28,10 +30,17 @@ implements ConnectionWriter {
|
||||
|
||||
protected long frame = 0L;
|
||||
|
||||
ConnectionWriterImpl(ConnectionEncrypter encrypter, Mac mac) {
|
||||
ConnectionWriterImpl(ConnectionEncrypter encrypter, Mac mac,
|
||||
SecretKey macKey) {
|
||||
super(encrypter.getOutputStream());
|
||||
this.encrypter = encrypter;
|
||||
this.mac = mac;
|
||||
// Initialise the MAC
|
||||
try {
|
||||
mac.init(macKey);
|
||||
} catch(InvalidKeyException badKey) {
|
||||
throw new IllegalArgumentException(badKey);
|
||||
}
|
||||
maxPayloadLength = MAX_FRAME_LENGTH - 4 - mac.getMacLength();
|
||||
buf = new ByteArrayOutputStream(maxPayloadLength);
|
||||
header = new byte[4];
|
||||
@@ -41,8 +50,8 @@ implements ConnectionWriter {
|
||||
return this;
|
||||
}
|
||||
|
||||
public long getCapacity() {
|
||||
long capacity = encrypter.getCapacity();
|
||||
public long getRemainingCapacity() {
|
||||
long capacity = encrypter.getRemainingCapacity();
|
||||
// If there's any data buffered, subtract it and its auth overhead
|
||||
int overheadPerFrame = header.length + mac.getMacLength();
|
||||
if(buf.size() > 0) capacity -= buf.size() + overheadPerFrame;
|
||||
|
||||
@@ -5,6 +5,7 @@ import static net.sf.briar.util.ByteUtils.MAX_32_BIT_UNSIGNED;
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.SecretKey;
|
||||
|
||||
import net.sf.briar.util.ByteUtils;
|
||||
|
||||
@@ -21,8 +22,9 @@ class PaddedConnectionWriter extends ConnectionWriterImpl {
|
||||
private boolean closed = false;
|
||||
private IOException exception = null;
|
||||
|
||||
PaddedConnectionWriter(ConnectionEncrypter encrypter, Mac mac) {
|
||||
super(encrypter, mac);
|
||||
PaddedConnectionWriter(ConnectionEncrypter encrypter, Mac mac,
|
||||
SecretKey macKey) {
|
||||
super(encrypter, mac, macKey);
|
||||
padding = new byte[maxPayloadLength];
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package net.sf.briar.transport;
|
||||
|
||||
import net.sf.briar.api.transport.ConnectionReaderFactory;
|
||||
import net.sf.briar.api.transport.ConnectionRecogniserFactory;
|
||||
import net.sf.briar.api.transport.ConnectionWindowFactory;
|
||||
import net.sf.briar.api.transport.ConnectionWriterFactory;
|
||||
|
||||
@@ -12,6 +13,8 @@ public class TransportModule extends AbstractModule {
|
||||
protected void configure() {
|
||||
bind(ConnectionReaderFactory.class).to(
|
||||
ConnectionReaderFactoryImpl.class);
|
||||
bind(ConnectionRecogniserFactory.class).to(
|
||||
ConnectionRecogniserFactoryImpl.class);
|
||||
bind(ConnectionWindowFactory.class).to(
|
||||
ConnectionWindowFactoryImpl.class);
|
||||
bind(ConnectionWriterFactory.class).to(
|
||||
|
||||
@@ -33,13 +33,13 @@ class OutgoingBatchConnection {
|
||||
void write() throws DbException, IOException {
|
||||
OutputStream out = conn.getOutputStream();
|
||||
// There should be enough space for a packet
|
||||
long capacity = conn.getCapacity();
|
||||
long capacity = conn.getRemainingCapacity();
|
||||
if(capacity < MAX_PACKET_LENGTH) throw new IOException();
|
||||
// Write a transport update
|
||||
TransportWriter t = protoFactory.createTransportWriter(out);
|
||||
db.generateTransportUpdate(contactId, t);
|
||||
// If there's space, write a subscription update
|
||||
capacity = conn.getCapacity();
|
||||
capacity = conn.getRemainingCapacity();
|
||||
if(capacity >= MAX_PACKET_LENGTH) {
|
||||
SubscriptionWriter s = protoFactory.createSubscriptionWriter(out);
|
||||
db.generateSubscriptionUpdate(contactId, s);
|
||||
@@ -47,14 +47,14 @@ class OutgoingBatchConnection {
|
||||
// Write acks until you can't write acks no more
|
||||
AckWriter a = protoFactory.createAckWriter(out);
|
||||
do {
|
||||
capacity = conn.getCapacity();
|
||||
capacity = conn.getRemainingCapacity();
|
||||
int max = (int) Math.min(MAX_PACKET_LENGTH, capacity);
|
||||
a.setMaxPacketLength(max);
|
||||
} while(db.generateAck(contactId, a));
|
||||
// Write batches until you can't write batches no more
|
||||
BatchWriter b = protoFactory.createBatchWriter(out);
|
||||
do {
|
||||
capacity = conn.getCapacity();
|
||||
capacity = conn.getRemainingCapacity();
|
||||
int max = (int) Math.min(MAX_PACKET_LENGTH, capacity);
|
||||
b.setMaxPacketLength(max);
|
||||
} while(db.generateBatch(contactId, b));
|
||||
|
||||
Reference in New Issue
Block a user