Refactor KeyManager and TagRecogniser. #55

This commit is contained in:
akwizgran
2015-02-12 09:11:24 +00:00
parent 878a70620d
commit 9868feeb2a
60 changed files with 2123 additions and 3840 deletions

View File

@@ -1,23 +1,13 @@
package org.briarproject.invitation;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.GeneralSecurityException;
import java.util.Map;
import java.util.logging.Logger;
import org.briarproject.api.Author;
import org.briarproject.api.AuthorFactory;
import org.briarproject.api.LocalAuthor;
import org.briarproject.api.TransportId;
import org.briarproject.api.TransportProperties;
import org.briarproject.api.crypto.CryptoComponent;
import org.briarproject.api.crypto.KeyManager;
import org.briarproject.api.crypto.PseudoRandom;
import org.briarproject.api.crypto.SecretKey;
import org.briarproject.api.data.Reader;
import org.briarproject.api.data.ReaderFactory;
import org.briarproject.api.data.Writer;
@@ -29,9 +19,20 @@ import org.briarproject.api.plugins.ConnectionManager;
import org.briarproject.api.plugins.duplex.DuplexPlugin;
import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
import org.briarproject.api.system.Clock;
import org.briarproject.api.transport.KeyManager;
import org.briarproject.api.transport.StreamReaderFactory;
import org.briarproject.api.transport.StreamWriterFactory;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.GeneralSecurityException;
import java.util.Map;
import java.util.logging.Logger;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
/** A connection thread for the peer being Alice in the invitation protocol. */
class AliceConnector extends Connector {
@@ -49,9 +50,9 @@ class AliceConnector extends Connector {
Map<TransportId, TransportProperties> 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
@@ -71,7 +72,7 @@ class AliceConnector extends Connector {
OutputStream out;
Reader r;
Writer w;
byte[] secret;
SecretKey master;
try {
in = conn.getReader().getInputStream();
out = conn.getWriter().getOutputStream();
@@ -82,7 +83,7 @@ class AliceConnector extends Connector {
byte[] hash = receivePublicKeyHash(r);
sendPublicKey(w);
byte[] key = receivePublicKey(r);
secret = deriveMasterSecret(hash, key, true);
master = deriveMasterSecret(hash, key, true);
} catch (IOException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
group.keyAgreementFailed();
@@ -96,8 +97,8 @@ class AliceConnector extends Connector {
}
// The key agreement succeeded - derive the confirmation codes
if (LOG.isLoggable(INFO)) LOG.info(pluginName + " agreement succeeded");
int[] codes = crypto.deriveConfirmationCodes(secret);
int aliceCode = codes[0], bobCode = codes[1];
int aliceCode = crypto.deriveConfirmationCode(master, true);
int bobCode = crypto.deriveConfirmationCode(master, false);
group.keyAgreementSucceeded(aliceCode, bobCode);
// Exchange confirmation results
boolean localMatched, remoteMatched;
@@ -130,19 +131,22 @@ class AliceConnector extends Connector {
// Confirmation succeeded - upgrade to a secure connection
if (LOG.isLoggable(INFO))
LOG.info(pluginName + " confirmation succeeded");
// Derive the header keys
SecretKey aliceHeaderKey = crypto.deriveInvitationKey(master, true);
SecretKey bobHeaderKey = crypto.deriveInvitationKey(master, false);
// Create the readers
InputStream streamReader =
streamReaderFactory.createInvitationStreamReader(in,
secret, false); // Bob's stream
bobHeaderKey);
r = readerFactory.createReader(streamReader);
// Create the writers
OutputStream streamWriter =
streamWriterFactory.createInvitationStreamWriter(out,
secret, true); // Alice's stream
aliceHeaderKey);
w = writerFactory.createWriter(streamWriter);
// Derive the invitation nonces
byte[][] nonces = crypto.deriveInvitationNonces(secret);
byte[] aliceNonce = nonces[0], bobNonce = nonces[1];
byte[] aliceNonce = crypto.deriveSignatureNonce(master, true);
byte[] bobNonce = crypto.deriveSignatureNonce(master, false);
// Exchange pseudonyms, signed nonces, timestamps and transports
Author remoteAuthor;
long remoteTimestamp;
@@ -171,11 +175,11 @@ class AliceConnector extends Connector {
tryToClose(conn, true);
return;
}
// The epoch is the minimum of the peers' timestamps
long epoch = Math.min(localTimestamp, remoteTimestamp);
// The agreed timestamp is the minimum of the peers' timestamps
long timestamp = Math.min(localTimestamp, remoteTimestamp);
// Add the contact and store the transports
try {
addContact(remoteAuthor, remoteProps, secret, epoch, true);
addContact(remoteAuthor, remoteProps, master, timestamp, true);
} catch (DbException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
tryToClose(conn, true);
@@ -190,4 +194,4 @@ class AliceConnector extends Connector {
LOG.info(pluginName + " pseudonym exchange succeeded");
group.pseudonymExchangeSucceeded(remoteAuthor);
}
}
}

View File

@@ -1,23 +1,13 @@
package org.briarproject.invitation;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.GeneralSecurityException;
import java.util.Map;
import java.util.logging.Logger;
import org.briarproject.api.Author;
import org.briarproject.api.AuthorFactory;
import org.briarproject.api.LocalAuthor;
import org.briarproject.api.TransportId;
import org.briarproject.api.TransportProperties;
import org.briarproject.api.crypto.CryptoComponent;
import org.briarproject.api.crypto.KeyManager;
import org.briarproject.api.crypto.PseudoRandom;
import org.briarproject.api.crypto.SecretKey;
import org.briarproject.api.data.Reader;
import org.briarproject.api.data.ReaderFactory;
import org.briarproject.api.data.Writer;
@@ -29,9 +19,20 @@ import org.briarproject.api.plugins.ConnectionManager;
import org.briarproject.api.plugins.duplex.DuplexPlugin;
import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
import org.briarproject.api.system.Clock;
import org.briarproject.api.transport.KeyManager;
import org.briarproject.api.transport.StreamReaderFactory;
import org.briarproject.api.transport.StreamWriterFactory;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.GeneralSecurityException;
import java.util.Map;
import java.util.logging.Logger;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
/** A connection thread for the peer being Bob in the invitation protocol. */
class BobConnector extends Connector {
@@ -49,9 +50,9 @@ class BobConnector extends Connector {
Map<TransportId, TransportProperties> 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
@@ -65,7 +66,7 @@ class BobConnector extends Connector {
OutputStream out;
Reader r;
Writer w;
byte[] secret;
SecretKey master;
try {
in = conn.getReader().getInputStream();
out = conn.getWriter().getOutputStream();
@@ -82,7 +83,7 @@ class BobConnector extends Connector {
sendPublicKeyHash(w);
byte[] key = receivePublicKey(r);
sendPublicKey(w);
secret = deriveMasterSecret(hash, key, false);
master = deriveMasterSecret(hash, key, false);
} catch (IOException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
group.keyAgreementFailed();
@@ -96,8 +97,8 @@ class BobConnector extends Connector {
}
// The key agreement succeeded - derive the confirmation codes
if (LOG.isLoggable(INFO)) LOG.info(pluginName + " agreement succeeded");
int[] codes = crypto.deriveConfirmationCodes(secret);
int aliceCode = codes[0], bobCode = codes[1];
int aliceCode = crypto.deriveConfirmationCode(master, true);
int bobCode = crypto.deriveConfirmationCode(master, false);
group.keyAgreementSucceeded(bobCode, aliceCode);
// Exchange confirmation results
boolean localMatched, remoteMatched;
@@ -130,19 +131,22 @@ class BobConnector extends Connector {
// Confirmation succeeded - upgrade to a secure connection
if (LOG.isLoggable(INFO))
LOG.info(pluginName + " confirmation succeeded");
// Derive the header keys
SecretKey aliceHeaderKey = crypto.deriveInvitationKey(master, true);
SecretKey bobHeaderKey = crypto.deriveInvitationKey(master, false);
// Create the readers
InputStream streamReader =
streamReaderFactory.createInvitationStreamReader(in,
secret, true); // Alice's stream
aliceHeaderKey);
r = readerFactory.createReader(streamReader);
// Create the writers
OutputStream streamWriter =
streamWriterFactory.createInvitationStreamWriter(out,
secret, false); // Bob's stream
bobHeaderKey);
w = writerFactory.createWriter(streamWriter);
// Derive the nonces
byte[][] nonces = crypto.deriveInvitationNonces(secret);
byte[] aliceNonce = nonces[0], bobNonce = nonces[1];
byte[] aliceNonce = crypto.deriveSignatureNonce(master, true);
byte[] bobNonce = crypto.deriveSignatureNonce(master, false);
// Exchange pseudonyms, signed nonces, timestamps and transports
Author remoteAuthor;
long remoteTimestamp;
@@ -171,11 +175,11 @@ class BobConnector extends Connector {
tryToClose(conn, true);
return;
}
// The epoch is the minimum of the peers' timestamps
long epoch = Math.min(localTimestamp, remoteTimestamp);
// The agreed timestamp is the minimum of the peers' timestamps
long timestamp = Math.min(localTimestamp, remoteTimestamp);
// Add the contact and store the transports
try {
addContact(remoteAuthor, remoteProps, secret, epoch, false);
addContact(remoteAuthor, remoteProps, master, timestamp, false);
} catch (DbException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
tryToClose(conn, true);

View File

@@ -1,5 +1,46 @@
package org.briarproject.invitation;
import org.briarproject.api.Author;
import org.briarproject.api.AuthorFactory;
import org.briarproject.api.ContactId;
import org.briarproject.api.FormatException;
import org.briarproject.api.LocalAuthor;
import org.briarproject.api.TransportId;
import org.briarproject.api.TransportProperties;
import org.briarproject.api.crypto.CryptoComponent;
import org.briarproject.api.crypto.KeyPair;
import org.briarproject.api.crypto.KeyParser;
import org.briarproject.api.crypto.MessageDigest;
import org.briarproject.api.crypto.PseudoRandom;
import org.briarproject.api.crypto.SecretKey;
import org.briarproject.api.crypto.Signature;
import org.briarproject.api.data.Reader;
import org.briarproject.api.data.ReaderFactory;
import org.briarproject.api.data.Writer;
import org.briarproject.api.data.WriterFactory;
import org.briarproject.api.db.DatabaseComponent;
import org.briarproject.api.db.DbException;
import org.briarproject.api.messaging.Group;
import org.briarproject.api.messaging.GroupFactory;
import org.briarproject.api.plugins.ConnectionManager;
import org.briarproject.api.plugins.duplex.DuplexPlugin;
import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
import org.briarproject.api.system.Clock;
import org.briarproject.api.transport.KeyManager;
import org.briarproject.api.transport.StreamReaderFactory;
import org.briarproject.api.transport.StreamWriterFactory;
import org.briarproject.api.transport.TransportKeys;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.logging.Logger;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static org.briarproject.api.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
@@ -9,50 +50,9 @@ import static org.briarproject.api.TransportPropertyConstants.MAX_PROPERTIES_PER
import static org.briarproject.api.TransportPropertyConstants.MAX_PROPERTY_LENGTH;
import static org.briarproject.api.TransportPropertyConstants.MAX_TRANSPORT_ID_LENGTH;
import static org.briarproject.api.invitation.InvitationConstants.CONNECTION_TIMEOUT;
import static org.briarproject.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.logging.Logger;
import org.briarproject.api.Author;
import org.briarproject.api.AuthorFactory;
import org.briarproject.api.ContactId;
import org.briarproject.api.FormatException;
import org.briarproject.api.LocalAuthor;
import org.briarproject.api.TransportId;
import org.briarproject.api.TransportProperties;
import org.briarproject.api.crypto.CryptoComponent;
import org.briarproject.api.crypto.KeyManager;
import org.briarproject.api.crypto.KeyPair;
import org.briarproject.api.crypto.KeyParser;
import org.briarproject.api.crypto.MessageDigest;
import org.briarproject.api.crypto.PseudoRandom;
import org.briarproject.api.crypto.Signature;
import org.briarproject.api.data.Reader;
import org.briarproject.api.data.ReaderFactory;
import org.briarproject.api.data.Writer;
import org.briarproject.api.data.WriterFactory;
import org.briarproject.api.db.DatabaseComponent;
import org.briarproject.api.db.DbException;
import org.briarproject.api.db.NoSuchTransportException;
import org.briarproject.api.messaging.Group;
import org.briarproject.api.messaging.GroupFactory;
import org.briarproject.api.plugins.ConnectionManager;
import org.briarproject.api.plugins.duplex.DuplexPlugin;
import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
import org.briarproject.api.system.Clock;
import org.briarproject.api.transport.Endpoint;
import org.briarproject.api.transport.StreamReaderFactory;
import org.briarproject.api.transport.StreamWriterFactory;
// FIXME: This class has way too many dependencies
abstract class Connector extends Thread {
private static final Logger LOG =
@@ -152,8 +152,8 @@ abstract class Connector extends Thread {
return b;
}
protected byte[] deriveMasterSecret(byte[] hash, byte[] key, boolean alice)
throws GeneralSecurityException {
protected SecretKey deriveMasterSecret(byte[] hash, byte[] key,
boolean alice) throws GeneralSecurityException {
// Check that the hash matches the key
if (!Arrays.equals(hash, messageDigest.digest(key))) {
if (LOG.isLoggable(INFO))
@@ -271,39 +271,34 @@ abstract class Connector extends Thread {
}
protected void addContact(Author remoteAuthor,
Map<TransportId, TransportProperties> remoteProps, byte[] secret,
long epoch, boolean alice) throws DbException {
Map<TransportId, TransportProperties> remoteProps, SecretKey master,
long timestamp, boolean alice) throws DbException {
// Add the contact to the database
contactId = db.addContact(remoteAuthor, localAuthor.getId());
// Create and store the inbox group
byte[] salt = crypto.deriveGroupSalt(secret);
byte[] salt = crypto.deriveGroupSalt(master);
Group inbox = groupFactory.createGroup("Inbox", salt);
db.addGroup(inbox);
db.setInboxGroup(contactId, inbox);
// Store the remote transport properties
db.setRemoteProperties(contactId, remoteProps);
// Create an endpoint for each transport shared with the contact
List<TransportId> ids = new ArrayList<TransportId>();
// Derive transport keys for each transport shared with the contact
Map<TransportId, Integer> latencies = db.getTransportLatencies();
for (TransportId id : localProps.keySet()) {
if (latencies.containsKey(id) && remoteProps.containsKey(id))
ids.add(id);
}
// Assign indices to the transports deterministically and derive keys
Collections.sort(ids, TransportIdComparator.INSTANCE);
int size = ids.size();
for (int i = 0; i < size; i++) {
TransportId id = ids.get(i);
Endpoint ep = new Endpoint(contactId, id, epoch, alice);
int maxLatency = latencies.get(id);
try {
db.addEndpoint(ep);
} catch (NoSuchTransportException e) {
continue;
List<TransportKeys> keys = new ArrayList<TransportKeys>();
for (TransportId t : localProps.keySet()) {
if (remoteProps.containsKey(t) && latencies.containsKey(t)) {
// Work out what rotation period the timestamp belongs to
long latency = latencies.get(t);
long rotationPeriodLength = latency + MAX_CLOCK_DIFFERENCE;
long rotationPeriod = timestamp / rotationPeriodLength;
// Derive the transport keys
TransportKeys k = crypto.deriveTransportKeys(t, master,
rotationPeriod, alice);
db.addTransportKeys(contactId, k);
keys.add(k);
}
byte[] initialSecret = crypto.deriveInitialSecret(secret, i);
keyManager.endpointAdded(ep, maxLatency, initialSecret);
}
keyManager.contactAdded(contactId, keys);
}
protected void tryToClose(DuplexTransportConnection conn,
@@ -322,16 +317,4 @@ abstract class Connector extends Thread {
TransportId t = plugin.getId();
connectionManager.manageOutgoingConnection(contactId, t, conn);
}
private static class TransportIdComparator
implements Comparator<TransportId> {
private static final TransportIdComparator INSTANCE =
new TransportIdComparator();
public int compare(TransportId t1, TransportId t2) {
String s1 = t1.getString(), s2 = t2.getString();
return String.CASE_INSENSITIVE_ORDER.compare(s1, s2);
}
}
}

View File

@@ -1,19 +1,5 @@
package org.briarproject.invitation;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.logging.Level.WARNING;
import static org.briarproject.api.invitation.InvitationConstants.CONFIRMATION_TIMEOUT;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Logger;
import org.briarproject.api.Author;
import org.briarproject.api.AuthorFactory;
import org.briarproject.api.AuthorId;
@@ -21,7 +7,6 @@ import org.briarproject.api.LocalAuthor;
import org.briarproject.api.TransportId;
import org.briarproject.api.TransportProperties;
import org.briarproject.api.crypto.CryptoComponent;
import org.briarproject.api.crypto.KeyManager;
import org.briarproject.api.crypto.PseudoRandom;
import org.briarproject.api.data.ReaderFactory;
import org.briarproject.api.data.WriterFactory;
@@ -35,9 +20,24 @@ import org.briarproject.api.plugins.ConnectionManager;
import org.briarproject.api.plugins.PluginManager;
import org.briarproject.api.plugins.duplex.DuplexPlugin;
import org.briarproject.api.system.Clock;
import org.briarproject.api.transport.KeyManager;
import org.briarproject.api.transport.StreamReaderFactory;
import org.briarproject.api.transport.StreamWriterFactory;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Logger;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.logging.Level.WARNING;
import static org.briarproject.api.invitation.InvitationConstants.CONFIRMATION_TIMEOUT;
/** A task consisting of one or more parallel connection attempts. */
class ConnectorGroup extends Thread implements InvitationTask {

View File

@@ -5,7 +5,6 @@ import javax.inject.Inject;
import org.briarproject.api.AuthorFactory;
import org.briarproject.api.AuthorId;
import org.briarproject.api.crypto.CryptoComponent;
import org.briarproject.api.crypto.KeyManager;
import org.briarproject.api.data.ReaderFactory;
import org.briarproject.api.data.WriterFactory;
import org.briarproject.api.db.DatabaseComponent;
@@ -15,6 +14,7 @@ import org.briarproject.api.messaging.GroupFactory;
import org.briarproject.api.plugins.ConnectionManager;
import org.briarproject.api.plugins.PluginManager;
import org.briarproject.api.system.Clock;
import org.briarproject.api.transport.KeyManager;
import org.briarproject.api.transport.StreamReaderFactory;
import org.briarproject.api.transport.StreamWriterFactory;