Don't create tag ciphers and tag keys unnecessarily.

This commit is contained in:
akwizgran
2012-08-28 12:02:37 +01:00
parent 1762eaf3e9
commit 6965f809c7
5 changed files with 101 additions and 43 deletions

View File

@@ -26,15 +26,26 @@ class ConnectionReaderFactoryImpl implements ConnectionReaderFactory {
public ConnectionReader createConnectionReader(InputStream in, public ConnectionReader createConnectionReader(InputStream in,
byte[] secret, boolean initiator) { byte[] secret, boolean initiator) {
// Derive the keys and erase the secret if(initiator) {
ErasableKey tagKey = crypto.deriveTagKey(secret, initiator); // Derive the frame key and erase the secret
ErasableKey frameKey = crypto.deriveFrameKey(secret, initiator); ErasableKey frameKey = crypto.deriveFrameKey(secret, initiator);
ByteUtils.erase(secret); ByteUtils.erase(secret);
// Create the reader // Create a reader for the responder's side of the connection
Cipher tagCipher = crypto.getTagCipher(); AuthenticatedCipher frameCipher = crypto.getFrameCipher();
AuthenticatedCipher frameCipher = crypto.getFrameCipher(); FrameReader encryption = new IncomingEncryptionLayer(in,
FrameReader encryption = new IncomingEncryptionLayer(in, tagCipher, frameCipher, frameKey, MAX_FRAME_LENGTH);
frameCipher, tagKey, frameKey, !initiator, MAX_FRAME_LENGTH); return new ConnectionReaderImpl(encryption, MAX_FRAME_LENGTH);
return new ConnectionReaderImpl(encryption, MAX_FRAME_LENGTH); } else {
// Derive the tag and frame keys and erase the secret
ErasableKey tagKey = crypto.deriveTagKey(secret, initiator);
ErasableKey frameKey = crypto.deriveFrameKey(secret, initiator);
ByteUtils.erase(secret);
// Create a reader for the initiator's side of the connection
Cipher tagCipher = crypto.getTagCipher();
AuthenticatedCipher frameCipher = crypto.getFrameCipher();
FrameReader encryption = new IncomingEncryptionLayer(in, tagCipher,
frameCipher, tagKey, frameKey, MAX_FRAME_LENGTH);
return new ConnectionReaderImpl(encryption, MAX_FRAME_LENGTH);
}
} }
} }

View File

@@ -26,16 +26,26 @@ class ConnectionWriterFactoryImpl implements ConnectionWriterFactory {
public ConnectionWriter createConnectionWriter(OutputStream out, public ConnectionWriter createConnectionWriter(OutputStream out,
long capacity, byte[] secret, boolean initiator) { long capacity, byte[] secret, boolean initiator) {
// Derive the keys and erase the secret if(initiator) {
ErasableKey tagKey = crypto.deriveTagKey(secret, initiator); // Derive the tag and frame keys and erase the secret
ErasableKey frameKey = crypto.deriveFrameKey(secret, initiator); ErasableKey tagKey = crypto.deriveTagKey(secret, initiator);
ByteUtils.erase(secret); ErasableKey frameKey = crypto.deriveFrameKey(secret, initiator);
// Create the writer ByteUtils.erase(secret);
Cipher tagCipher = crypto.getTagCipher(); // Create a writer for the initiator's side of the connection
AuthenticatedCipher frameCipher = crypto.getFrameCipher(); Cipher tagCipher = crypto.getTagCipher();
FrameWriter encryption = new OutgoingEncryptionLayer(out, capacity, AuthenticatedCipher frameCipher = crypto.getFrameCipher();
tagCipher, frameCipher, tagKey, frameKey, initiator, FrameWriter encryption = new OutgoingEncryptionLayer(out, capacity,
MAX_FRAME_LENGTH); tagCipher, frameCipher, tagKey, frameKey, MAX_FRAME_LENGTH);
return new ConnectionWriterImpl(encryption, MAX_FRAME_LENGTH); return new ConnectionWriterImpl(encryption, MAX_FRAME_LENGTH);
} else {
// Derive the frame key and erase the secret
ErasableKey frameKey = crypto.deriveFrameKey(secret, initiator);
ByteUtils.erase(secret);
// Create a writer for the responder's side of the connection
AuthenticatedCipher frameCipher = crypto.getFrameCipher();
FrameWriter encryption = new OutgoingEncryptionLayer(out, capacity,
frameCipher, frameKey, MAX_FRAME_LENGTH);
return new ConnectionWriterImpl(encryption, MAX_FRAME_LENGTH);
}
} }
} }

View File

@@ -25,26 +25,44 @@ class IncomingEncryptionLayer implements FrameReader {
private final AuthenticatedCipher frameCipher; private final AuthenticatedCipher frameCipher;
private final ErasableKey tagKey, frameKey; private final ErasableKey tagKey, frameKey;
private final byte[] iv, aad, ciphertext; private final byte[] iv, aad, ciphertext;
private final int maxFrameLength; private final int frameLength;
private boolean readTag, lastFrame;
private long frameNumber; private long frameNumber;
private boolean readTag, lastFrame;
/** Constructor for the initiator's side of a connection. */
IncomingEncryptionLayer(InputStream in, Cipher tagCipher, IncomingEncryptionLayer(InputStream in, Cipher tagCipher,
AuthenticatedCipher frameCipher, ErasableKey tagKey, AuthenticatedCipher frameCipher, ErasableKey tagKey,
ErasableKey frameKey, boolean readTag, int maxFrameLength) { ErasableKey frameKey, int frameLength) {
this.in = in; this.in = in;
this.tagCipher = tagCipher; this.tagCipher = tagCipher;
this.frameCipher = frameCipher; this.frameCipher = frameCipher;
this.tagKey = tagKey; this.tagKey = tagKey;
this.frameKey = frameKey; this.frameKey = frameKey;
this.readTag = readTag; this.frameLength = frameLength;
this.maxFrameLength = maxFrameLength;
lastFrame = false;
iv = new byte[IV_LENGTH]; iv = new byte[IV_LENGTH];
aad = new byte[AAD_LENGTH]; aad = new byte[AAD_LENGTH];
ciphertext = new byte[maxFrameLength]; ciphertext = new byte[frameLength];
frameNumber = 0L; frameNumber = 0L;
readTag = true;
lastFrame = false;
}
/** Constructor for the responder's side of a connection. */
IncomingEncryptionLayer(InputStream in, AuthenticatedCipher frameCipher,
ErasableKey frameKey, int frameLength) {
this.in = in;
this.frameCipher = frameCipher;
this.frameKey = frameKey;
this.frameLength = frameLength;
tagCipher = null;
tagKey = null;
iv = new byte[IV_LENGTH];
aad = new byte[AAD_LENGTH];
ciphertext = new byte[frameLength];
frameNumber = 0L;
readTag = false;
lastFrame = false;
} }
public int readFrame(byte[] frame) throws IOException { public int readFrame(byte[] frame) throws IOException {
@@ -70,9 +88,9 @@ class IncomingEncryptionLayer implements FrameReader {
// Read the frame // Read the frame
int ciphertextLength = 0; int ciphertextLength = 0;
try { try {
while(ciphertextLength < maxFrameLength) { while(ciphertextLength < frameLength) {
int read = in.read(ciphertext, ciphertextLength, int read = in.read(ciphertext, ciphertextLength,
maxFrameLength - ciphertextLength); frameLength - ciphertextLength);
if(read == -1) break; // We'll check the length later if(read == -1) break; // We'll check the length later
ciphertextLength += read; ciphertextLength += read;
} }
@@ -96,7 +114,7 @@ class IncomingEncryptionLayer implements FrameReader {
} }
// Decode and validate the header // Decode and validate the header
lastFrame = FrameEncoder.isLastFrame(frame); lastFrame = FrameEncoder.isLastFrame(frame);
if(!lastFrame && ciphertextLength < maxFrameLength) if(!lastFrame && ciphertextLength < frameLength)
throw new EOFException(); throw new EOFException();
int payloadLength = FrameEncoder.getPayloadLength(frame); int payloadLength = FrameEncoder.getPayloadLength(frame);
if(payloadLength > plaintextLength - HEADER_LENGTH) if(payloadLength > plaintextLength - HEADER_LENGTH)

View File

@@ -23,35 +23,54 @@ class OutgoingEncryptionLayer implements FrameWriter {
private final AuthenticatedCipher frameCipher; private final AuthenticatedCipher frameCipher;
private final ErasableKey tagKey, frameKey; private final ErasableKey tagKey, frameKey;
private final byte[] iv, aad, ciphertext; private final byte[] iv, aad, ciphertext;
private final int maxFrameLength; private final int frameLength;
private boolean writeTag;
private long capacity, frameNumber; private long capacity, frameNumber;
private boolean writeTag;
/** Constructor for the initiator's side of a connection. */
OutgoingEncryptionLayer(OutputStream out, long capacity, Cipher tagCipher, OutgoingEncryptionLayer(OutputStream out, long capacity, Cipher tagCipher,
AuthenticatedCipher frameCipher, ErasableKey tagKey, AuthenticatedCipher frameCipher, ErasableKey tagKey,
ErasableKey frameKey, boolean writeTag, int maxFrameLength) { ErasableKey frameKey, int frameLength) {
this.out = out; this.out = out;
this.capacity = writeTag ? capacity - TAG_LENGTH : capacity; this.capacity = capacity - TAG_LENGTH;
this.tagCipher = tagCipher; this.tagCipher = tagCipher;
this.frameCipher = frameCipher; this.frameCipher = frameCipher;
this.tagKey = tagKey; this.tagKey = tagKey;
this.frameKey = frameKey; this.frameKey = frameKey;
this.writeTag = writeTag; this.frameLength = frameLength;
this.maxFrameLength = maxFrameLength;
iv = new byte[IV_LENGTH]; iv = new byte[IV_LENGTH];
aad = new byte[AAD_LENGTH]; aad = new byte[AAD_LENGTH];
ciphertext = new byte[maxFrameLength]; ciphertext = new byte[frameLength];
frameNumber = 0L; frameNumber = 0L;
writeTag = true;
}
/** Constructor for the responder's side of a connection. */
OutgoingEncryptionLayer(OutputStream out, long capacity,
AuthenticatedCipher frameCipher, ErasableKey frameKey,
int frameLength) {
this.out = out;
this.capacity = capacity;
this.frameCipher = frameCipher;
this.frameKey = frameKey;
this.frameLength = frameLength;
tagCipher = null;
tagKey = null;
iv = new byte[IV_LENGTH];
aad = new byte[AAD_LENGTH];
ciphertext = new byte[frameLength];
frameNumber = 0L;
writeTag = false;
} }
public void writeFrame(byte[] frame, int payloadLength, int paddingLength, public void writeFrame(byte[] frame, int payloadLength, int paddingLength,
boolean lastFrame) throws IOException { boolean lastFrame) throws IOException {
int plaintextLength = HEADER_LENGTH + payloadLength + paddingLength; int plaintextLength = HEADER_LENGTH + payloadLength + paddingLength;
int ciphertextLength = plaintextLength + MAC_LENGTH; int ciphertextLength = plaintextLength + MAC_LENGTH;
if(ciphertextLength > maxFrameLength) if(ciphertextLength > frameLength)
throw new IllegalArgumentException(); throw new IllegalArgumentException();
if(!lastFrame && ciphertextLength < maxFrameLength) if(!lastFrame && ciphertextLength < frameLength)
throw new IllegalArgumentException(); 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 payload or padding, don't write a tag or an empty frame

View File

@@ -75,7 +75,7 @@ public class FrameReadWriteTest extends BriarTestCase {
ByteArrayOutputStream out = new ByteArrayOutputStream(); ByteArrayOutputStream out = new ByteArrayOutputStream();
FrameWriter encryptionOut = new OutgoingEncryptionLayer(out, FrameWriter encryptionOut = new OutgoingEncryptionLayer(out,
Long.MAX_VALUE, tagCipher, frameCipher, tagCopy, frameCopy, Long.MAX_VALUE, tagCipher, frameCipher, tagCopy, frameCopy,
true, FRAME_LENGTH); FRAME_LENGTH);
ConnectionWriter writer = new ConnectionWriterImpl(encryptionOut, ConnectionWriter writer = new ConnectionWriterImpl(encryptionOut,
FRAME_LENGTH); FRAME_LENGTH);
OutputStream out1 = writer.getOutputStream(); OutputStream out1 = writer.getOutputStream();
@@ -88,7 +88,7 @@ public class FrameReadWriteTest extends BriarTestCase {
// Read the tag and the frames back // Read the tag and the frames back
ByteArrayInputStream in = new ByteArrayInputStream(output); ByteArrayInputStream in = new ByteArrayInputStream(output);
FrameReader encryptionIn = new IncomingEncryptionLayer(in, tagCipher, FrameReader encryptionIn = new IncomingEncryptionLayer(in, tagCipher,
frameCipher, tagKey, frameKey, true, FRAME_LENGTH); frameCipher, tagKey, frameKey, FRAME_LENGTH);
ConnectionReader reader = new ConnectionReaderImpl(encryptionIn, ConnectionReader reader = new ConnectionReaderImpl(encryptionIn,
FRAME_LENGTH); FRAME_LENGTH);
InputStream in1 = reader.getInputStream(); InputStream in1 = reader.getInputStream();