Fixed key derivation issues, moved tag encoding into crypto component.

This commit is contained in:
akwizgran
2012-10-24 20:05:18 +01:00
parent 5628342c58
commit d940c637c2
16 changed files with 103 additions and 82 deletions

View File

@@ -1,6 +1,8 @@
package net.sf.briar.crypto;
import static javax.crypto.Cipher.ENCRYPT_MODE;
import static net.sf.briar.api.plugins.InvitationConstants.CODE_BITS;
import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
import static net.sf.briar.util.ByteUtils.MAX_32_BIT_UNSIGNED;
import java.security.GeneralSecurityException;
@@ -210,6 +212,23 @@ class CryptoComponentImpl implements CryptoComponent {
return counterModeKdf(secret, ROTATE, period);
}
public void encodeTag(byte[] tag, Cipher tagCipher, ErasableKey tagKey,
long connection) {
if(tag.length < TAG_LENGTH) throw new IllegalArgumentException();
if(connection < 0 || connection > MAX_32_BIT_UNSIGNED)
throw new IllegalArgumentException();
for(int i = 0; i < TAG_LENGTH; i++) tag[i] = 0;
ByteUtils.writeUint32(connection, tag, 0);
try {
tagCipher.init(ENCRYPT_MODE, tagKey);
int encrypted = tagCipher.doFinal(tag, 0, TAG_LENGTH, tag);
if(encrypted != TAG_LENGTH) throw new IllegalArgumentException();
} catch(GeneralSecurityException e) {
// Unsuitable cipher or key
throw new IllegalArgumentException(e);
}
}
public int generateInvitationCode() {
int codeBytes = (int) Math.ceil(CODE_BITS / 8.0);
byte[] random = new byte[codeBytes];

View File

@@ -34,12 +34,12 @@ class IncomingDuplexConnection extends DuplexConnection {
@Override
protected ConnectionReader createConnectionReader() throws IOException {
return connReaderFactory.createConnectionReader(
transport.getInputStream(), ctx, true);
transport.getInputStream(), ctx, true, true);
}
@Override
protected ConnectionWriter createConnectionWriter() throws IOException {
return connWriterFactory.createConnectionWriter(
transport.getOutputStream(), Long.MAX_VALUE, ctx, false);
transport.getOutputStream(), Long.MAX_VALUE, ctx, true, false);
}
}

View File

@@ -34,12 +34,12 @@ class OutgoingDuplexConnection extends DuplexConnection {
@Override
protected ConnectionReader createConnectionReader() throws IOException {
return connReaderFactory.createConnectionReader(
transport.getInputStream(), ctx, false);
transport.getInputStream(), ctx, false, false);
}
@Override
protected ConnectionWriter createConnectionWriter() throws IOException {
return connWriterFactory.createConnectionWriter(
transport.getOutputStream(), Long.MAX_VALUE, ctx, true);
transport.getOutputStream(), Long.MAX_VALUE, ctx, false, true);
}
}

View File

@@ -65,7 +65,7 @@ class IncomingSimplexConnection {
connRegistry.registerConnection(contactId, transportId);
try {
ConnectionReader conn = connFactory.createConnectionReader(
transport.getInputStream(), ctx, true);
transport.getInputStream(), ctx, true, true);
InputStream in = conn.getInputStream();
ProtocolReader reader = protoFactory.createProtocolReader(in);
// Read packets until EOF

View File

@@ -59,7 +59,7 @@ class OutgoingSimplexConnection {
try {
ConnectionWriter conn = connFactory.createConnectionWriter(
transport.getOutputStream(), transport.getCapacity(),
ctx, true);
ctx, false, true);
OutputStream out = conn.getOutputStream();
ProtocolWriter writer = protoFactory.createProtocolWriter(out,
transport.shouldFlush());

View File

@@ -22,12 +22,13 @@ class ConnectionReaderFactoryImpl implements ConnectionReaderFactory {
}
public ConnectionReader createConnectionReader(InputStream in,
ConnectionContext ctx, boolean initiator) {
ConnectionContext ctx, boolean incoming, boolean initiator) {
byte[] secret = ctx.getSecret();
long connection = ctx.getConnectionNumber();
boolean alice = ctx.getAlice();
ErasableKey frameKey = crypto.deriveFrameKey(secret, connection, alice,
initiator);
boolean weAreAlice = ctx.getAlice();
boolean initiatorIsAlice = incoming ? !weAreAlice : weAreAlice;
ErasableKey frameKey = crypto.deriveFrameKey(secret, connection,
initiatorIsAlice, initiator);
FrameReader encryption = new IncomingEncryptionLayer(in,
crypto.getFrameCipher(), frameKey, MAX_FRAME_LENGTH);
return new ConnectionReaderImpl(encryption, MAX_FRAME_LENGTH);

View File

@@ -26,18 +26,20 @@ class ConnectionWriterFactoryImpl implements ConnectionWriterFactory {
}
public ConnectionWriter createConnectionWriter(OutputStream out,
long capacity, ConnectionContext ctx, boolean initiator) {
long capacity, ConnectionContext ctx, boolean incoming,
boolean initiator) {
byte[] secret = ctx.getSecret();
long connection = ctx.getConnectionNumber();
boolean alice = ctx.getAlice();
ErasableKey frameKey = crypto.deriveFrameKey(secret, connection, alice,
initiator);
boolean weAreAlice = ctx.getAlice();
boolean initiatorIsAlice = incoming ? !weAreAlice : weAreAlice;
ErasableKey frameKey = crypto.deriveFrameKey(secret, connection,
initiatorIsAlice, initiator);
FrameWriter encryption;
if(initiator) {
byte[] tag = new byte[TAG_LENGTH];
Cipher tagCipher = crypto.getTagCipher();
ErasableKey tagKey = crypto.deriveTagKey(secret, alice);
TagEncoder.encodeTag(tag, tagCipher, tagKey, connection);
ErasableKey tagKey = crypto.deriveTagKey(secret, initiatorIsAlice);
crypto.encodeTag(tag, tagCipher, tagKey, connection);
encryption = new OutgoingEncryptionLayer(out, capacity,
crypto.getFrameCipher(), frameKey, MAX_FRAME_LENGTH, tag);
} else {

View File

@@ -1,32 +0,0 @@
package net.sf.briar.transport;
import static javax.crypto.Cipher.ENCRYPT_MODE;
import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
import static net.sf.briar.util.ByteUtils.MAX_32_BIT_UNSIGNED;
import java.security.GeneralSecurityException;
import javax.crypto.Cipher;
import net.sf.briar.api.crypto.ErasableKey;
import net.sf.briar.util.ByteUtils;
class TagEncoder {
static void encodeTag(byte[] tag, Cipher tagCipher, ErasableKey tagKey,
long connection) {
if(tag.length < TAG_LENGTH) throw new IllegalArgumentException();
if(connection < 0 || connection > MAX_32_BIT_UNSIGNED)
throw new IllegalArgumentException();
for(int i = 0; i < TAG_LENGTH; i++) tag[i] = 0;
ByteUtils.writeUint32(connection, tag, 0);
try {
tagCipher.init(ENCRYPT_MODE, tagKey);
int encrypted = tagCipher.doFinal(tag, 0, TAG_LENGTH, tag);
if(encrypted != TAG_LENGTH) throw new IllegalArgumentException();
} catch(GeneralSecurityException e) {
// Unsuitable cipher or key
throw new IllegalArgumentException(e);
}
}
}

View File

@@ -51,10 +51,10 @@ class TransportConnectionRecogniser {
boolean alice = ctx.getAlice();
// Update the connection window and the expected tags
Cipher cipher = crypto.getTagCipher();
ErasableKey key = crypto.deriveTagKey(secret, alice);
ErasableKey key = crypto.deriveTagKey(secret, !alice);
for(long connection1 : window.setSeen(connection)) {
byte[] tag1 = new byte[TAG_LENGTH];
TagEncoder.encodeTag(tag1, cipher, key, connection1);
crypto.encodeTag(tag1, cipher, key, connection1);
if(connection1 <= connection) {
WindowContext old = tagMap.remove(new Bytes(tag1));
assert old != null;
@@ -84,11 +84,11 @@ class TransportConnectionRecogniser {
byte[] bitmap = s.getWindowBitmap();
// Create the connection window and the expected tags
Cipher cipher = crypto.getTagCipher();
ErasableKey key = crypto.deriveTagKey(secret, alice);
ErasableKey key = crypto.deriveTagKey(secret, !alice);
ConnectionWindow window = new ConnectionWindow(centre, bitmap);
for(long connection : window.getUnseen()) {
byte[] tag = new byte[TAG_LENGTH];
TagEncoder.encodeTag(tag, cipher, key, connection);
crypto.encodeTag(tag, cipher, key, connection);
ConnectionContext ctx = new ConnectionContext(contactId,
transportId, secret.clone(), connection, alice);
WindowContext wctx = new WindowContext(window, ctx, period);
@@ -113,10 +113,10 @@ class TransportConnectionRecogniser {
private void removeSecret(RemovalContext rctx) {
// Remove the expected tags
Cipher cipher = crypto.getTagCipher();
ErasableKey key = crypto.deriveTagKey(rctx.secret, rctx.alice);
ErasableKey key = crypto.deriveTagKey(rctx.secret, !rctx.alice);
byte[] tag = new byte[TAG_LENGTH];
for(long connection : rctx.window.getUnseen()) {
TagEncoder.encodeTag(tag, cipher, key, connection);
crypto.encodeTag(tag, cipher, key, connection);
WindowContext old = tagMap.remove(new Bytes(tag));
assert old != null;
ByteUtils.erase(old.context.getSecret());