Commit e779210c authored by akwizgran's avatar akwizgran

First stage of key rotation refactoring. Some tests are failing.

parent eb360475
package net.sf.briar.api;
import net.sf.briar.api.protocol.TransportId;
public class ContactTransport extends TemporarySecret {
private final long epoch, clockDiff, latency;
private final boolean alice;
public ContactTransport(ContactId contactId, TransportId transportId,
long epoch, long clockDiff, long latency, boolean alice,
long period, byte[] secret, long outgoing, long centre,
byte[] bitmap) {
super(contactId, transportId, period, secret, outgoing, centre, bitmap);
this.epoch = epoch;
this.clockDiff = clockDiff;
this.latency = latency;
this.alice = alice;
}
public long getEpoch() {
return epoch;
}
public long getClockDifference() {
return clockDiff;
}
public long getLatency() {
return latency;
}
public boolean getAlice() {
return alice;
}
}
package net.sf.briar.api;
import net.sf.briar.api.protocol.TransportId;
public class TemporarySecret {
protected final ContactId contactId;
protected final TransportId transportId;
protected final long period, outgoing, centre;
protected final byte[] secret, bitmap;
public TemporarySecret(ContactId contactId, TransportId transportId,
long period, byte[] secret, long outgoing, long centre,
byte[] bitmap) {
this.contactId = contactId;
this.transportId = transportId;
this.period = period;
this.secret = secret;
this.outgoing = outgoing;
this.centre = centre;
this.bitmap = bitmap;
}
public ContactId getContactId() {
return contactId;
}
public TransportId getTransportId() {
return transportId;
}
public long getPeriod() {
return period;
}
public byte[] getSecret() {
return secret;
}
public long getOutgoingConnectionCounter() {
return outgoing;
}
public long getWindowCentre() {
return centre;
}
public byte[] getWindowBitmap() {
return bitmap;
}
}
......@@ -9,16 +9,49 @@ import javax.crypto.Cipher;
public interface CryptoComponent {
ErasableKey deriveTagKey(byte[] secret, boolean initiator);
ErasableKey deriveFrameKey(byte[] secret, boolean initiator);
byte[][] deriveInitialSecrets(byte[] ourPublicKey, byte[] theirPublicKey,
PrivateKey ourPrivateKey, int invitationCode, boolean initiator);
int deriveConfirmationCode(byte[] secret);
byte[] deriveNextSecret(byte[] secret, int index, long connection);
/**
* Derives a tag key from the given temporary secret.
* @param alice Indicates whether the key is for connections initiated by
* Alice or Bob.
*/
ErasableKey deriveTagKey(byte[] secret, boolean alice);
/**
* Derives a frame key from the given temporary secret and connection
* number.
* @param alice Indicates whether the key is for a connection initiated by
* Alice or Bob.
* @param initiator Indicates whether the key is for the initiator's or the
* responder's side of the connection.
*/
ErasableKey deriveFrameKey(byte[] secret, long connection, boolean alice,
boolean initiator);
/**
* Derives an initial shared secret from two public keys and one of the
* corresponding private keys.
* @param alice Indicates whether the private key belongs to Alice or Bob.
*/
byte[] deriveInitialSecret(byte[] ourPublicKey, byte[] theirPublicKey,
PrivateKey ourPrivateKey, boolean alice);
/**
* Generates a random invitation code.
*/
int generateInvitationCode();
/**
* Derives two confirmation codes from the given initial shared secret. The
* first code is for Alice to give to Bob; the second is for Bob to give to
* Alice.
*/
int[] deriveConfirmationCodes(byte[] secret);
/**
* Derives a temporary secret for the given period from the previous
* period's temporary secret.
*/
byte[] deriveNextSecret(byte[] secret, long period);
KeyPair generateAgreementKeyPair();
......
package net.sf.briar.api.crypto;
import net.sf.briar.api.ContactId;
import net.sf.briar.api.protocol.TransportId;
import net.sf.briar.api.transport.ConnectionContext;
public interface KeyManager {
/**
* Returns a connection context for connecting to the given contact over
* the given transport, or null if the contact does not support the
* transport.
*/
ConnectionContext getConnectionContext(ContactId c, TransportId t);
}
......@@ -5,7 +5,9 @@ import java.util.Collection;
import java.util.Map;
import net.sf.briar.api.ContactId;
import net.sf.briar.api.ContactTransport;
import net.sf.briar.api.Rating;
import net.sf.briar.api.TemporarySecret;
import net.sf.briar.api.TransportConfig;
import net.sf.briar.api.TransportProperties;
import net.sf.briar.api.db.event.DatabaseListener;
......@@ -22,10 +24,7 @@ import net.sf.briar.api.protocol.Request;
import net.sf.briar.api.protocol.SubscriptionUpdate;
import net.sf.briar.api.protocol.Transport;
import net.sf.briar.api.protocol.TransportId;
import net.sf.briar.api.protocol.TransportIndex;
import net.sf.briar.api.protocol.TransportUpdate;
import net.sf.briar.api.transport.ConnectionContext;
import net.sf.briar.api.transport.ConnectionWindow;
/**
* Encapsulates the database implementation and exposes high-level operations
......@@ -50,10 +49,9 @@ public interface DatabaseComponent {
void removeListener(DatabaseListener d);
/**
* Adds a new contact to the database with the given secrets and returns an
* ID for the contact.
* Adds a new contact to the database and returns an ID for the contact.
*/
ContactId addContact(byte[] inSecret, byte[] outSecret) throws DbException;
ContactId addContact() throws DbException;
/** Adds a locally generated group message to the database. */
void addLocalGroupMessage(Message m) throws DbException;
......@@ -62,10 +60,10 @@ public interface DatabaseComponent {
void addLocalPrivateMessage(Message m, ContactId c) throws DbException;
/**
* Allocates and returns a local index for the given transport. Returns
* null if all indices have been allocated.
* Stores the given temporary secrets and deletes any secrets that have
* been made obsolete.
*/
TransportIndex addTransport(TransportId t) throws DbException;
void addSecrets(Collection<TemporarySecret> secrets) throws DbException;
/**
* Generates an acknowledgement for the given contact. Returns null if
......@@ -101,7 +99,7 @@ public interface DatabaseComponent {
* an update is not due.
*/
SubscriptionUpdate generateSubscriptionUpdate(ContactId c)
throws DbException;
throws DbException;
/**
* Generates a transport update for the given contact. Returns null if an
......@@ -112,28 +110,11 @@ public interface DatabaseComponent {
/** Returns the configuration for the given transport. */
TransportConfig getConfig(TransportId t) throws DbException;
/**
* Returns an outgoing connection context for the given contact and
* transport.
*/
ConnectionContext getConnectionContext(ContactId c, TransportIndex i)
throws DbException;
/**
* Returns the connection reordering window for the given contact and
* transport.
*/
ConnectionWindow getConnectionWindow(ContactId c, TransportIndex i)
throws DbException;
/** Returns the IDs of all contacts. */
Collection<ContactId> getContacts() throws DbException;
/**
* Returns the local index for the given transport, or null if no index
* has been allocated.
*/
TransportIndex getLocalIndex(TransportId t) throws DbException;
/** Returns all contact transports. */
Collection<ContactTransport> getContactTransports() throws DbException;
/** Returns the local transport properties for the given transport. */
TransportProperties getLocalProperties(TransportId t) throws DbException;
......@@ -147,16 +128,9 @@ public interface DatabaseComponent {
/** Returns the user's rating for the given author. */
Rating getRating(AuthorId a) throws DbException;
/**
* Returns the given contact's index for the given transport, or null if
* the contact does not support the transport.
*/
TransportIndex getRemoteIndex(ContactId c, TransportId t)
throws DbException;
/** Returns all remote transport properties for the given transport. */
Map<ContactId, TransportProperties> getRemoteProperties(TransportId t)
throws DbException;
throws DbException;
/** Returns the set of groups to which the user subscribes. */
Collection<Group> getSubscriptions() throws DbException;
......@@ -170,6 +144,13 @@ public interface DatabaseComponent {
/** Returns true if any messages are sendable to the given contact. */
boolean hasSendableMessages(ContactId c) throws DbException;
/**
* Increments the outgoing connection counter for the given contact
* transport in the given rotation period.
*/
void incrementConnectionCounter(ContactId c, TransportId t, long period)
throws DbException;
/** Processes an acknowledgement from the given contact. */
void receiveAck(ContactId c, Ack a) throws DbException;
......@@ -188,11 +169,11 @@ public interface DatabaseComponent {
/** Processes a subscription update from the given contact. */
void receiveSubscriptionUpdate(ContactId c, SubscriptionUpdate s)
throws DbException;
throws DbException;
/** Processes a transport update from the given contact. */
void receiveTransportUpdate(ContactId c, TransportUpdate t)
throws DbException;
throws DbException;
/** Removes a contact (and all associated state) from the database. */
void removeContact(ContactId c) throws DbException;
......@@ -204,18 +185,18 @@ public interface DatabaseComponent {
void setConfig(TransportId t, TransportConfig c) throws DbException;
/**
* Sets the connection reordering window for the given contact and
* transport.
* Sets the connection reordering window for the given contact transport
* in the given rotation period.
*/
void setConnectionWindow(ContactId c, TransportIndex i,
ConnectionWindow w) throws DbException;
void setConnectionWindow(ContactId c, TransportId t, long period,
long centre, byte[] bitmap) throws DbException;
/**
* Sets the local transport properties for the given transport, replacing
* any existing properties for that transport.
*/
void setLocalProperties(TransportId t, TransportProperties p)
throws DbException;
throws DbException;
/** Records the user's rating for the given author. */
void setRating(AuthorId a, Rating r) throws DbException;
......@@ -228,7 +209,7 @@ public interface DatabaseComponent {
* to any other contacts.
*/
void setVisibility(GroupId g, Collection<ContactId> visible)
throws DbException;
throws DbException;
/** Subscribes to the given group. */
void subscribe(Group g) throws DbException;
......
......@@ -7,8 +7,4 @@ package net.sf.briar.api.db;
public class NoSuchContactException extends DbException {
private static final long serialVersionUID = -7048538231308207386L;
public NoSuchContactException() {
super();
}
}
package net.sf.briar.api.db;
/**
* Thrown when a database operation is attempted for a contact transport that
* is not in the database.
*/
public class NoSuchContactTransportException extends DbException {
private static final long serialVersionUID = -6274982612759573100L;
}
package net.sf.briar.api.db.event;
import net.sf.briar.api.protocol.TransportId;
/** An event that is broadcast when a transport is added. */
public class TransportAddedEvent extends DatabaseEvent {
private final TransportId transportId;
public TransportAddedEvent(TransportId transportId) {
this.transportId = transportId;
}
public TransportId getTransportId() {
return transportId;
}
}
package net.sf.briar.api.plugins;
public interface IncomingInvitationCallback extends InvitationCallback {
int enterInvitationCode();
}
package net.sf.briar.api.plugins;
public interface InvitationCallback {
boolean isCancelled();
int enterConfirmationCode(int code);
void showProgress(String... message);
void showFailure(String... message);
void showSuccess();
}
package net.sf.briar.api.plugins;
import net.sf.briar.api.plugins.duplex.DuplexPlugin;
public interface InvitationStarter {
void startIncomingInvitation(DuplexPlugin plugin,
IncomingInvitationCallback callback);
void startOutgoingInvitation(DuplexPlugin plugin,
OutgoingInvitationCallback callback);
}
package net.sf.briar.api.plugins;
public interface OutgoingInvitationCallback extends InvitationCallback {
void showInvitationCode(int code);
}
......@@ -8,29 +8,21 @@ public class Transport extends TreeMap<String, String> {
private static final long serialVersionUID = 4900420175715429560L;
private final TransportId id;
private final TransportIndex index;
public Transport(TransportId id, TransportIndex index,
Map<String, String> p) {
public Transport(TransportId id, Map<String, String> p) {
super(p);
this.id = id;
this.index = index;
}
public Transport(TransportId id, TransportIndex index) {
public Transport(TransportId id) {
super();
this.id = id;
this.index = index;
}
public TransportId getId() {
return id;
}
public TransportIndex getIndex() {
return index;
}
@Override
public int hashCode() {
return id.hashCode();
......@@ -40,7 +32,7 @@ public class Transport extends TreeMap<String, String> {
public boolean equals(Object o) {
if(o instanceof Transport) {
Transport t = (Transport) o;
return id.equals(t.id) && index.equals(t.index) && super.equals(o);
return id.equals(t.id) && super.equals(o);
}
return false;
}
......
package net.sf.briar.api.protocol;
/**
* Type-safe wrapper for an integer that uniquely identifies a transport plugin
* within the scope of a single node.
*/
public class TransportIndex {
private final int index;
public TransportIndex(int index) {
if(index < 0 || index >= ProtocolConstants.MAX_TRANSPORTS)
throw new IllegalArgumentException();
this.index = index;
}
public int getInt() {
return index;
}
@Override
public boolean equals(Object o) {
if(o instanceof TransportIndex)
return index == ((TransportIndex) o).index;
return false;
}
@Override
public int hashCode() {
return index;
}
}
......@@ -3,14 +3,12 @@ package net.sf.briar.api.protocol.duplex;
import net.sf.briar.api.ContactId;
import net.sf.briar.api.plugins.duplex.DuplexTransportConnection;
import net.sf.briar.api.protocol.TransportId;
import net.sf.briar.api.protocol.TransportIndex;
import net.sf.briar.api.transport.ConnectionContext;
public interface DuplexConnectionFactory {
void createIncomingConnection(ConnectionContext ctx, TransportId t,
DuplexTransportConnection d);
void createIncomingConnection(ConnectionContext ctx, DuplexTransportConnection d);
void createOutgoingConnection(ContactId c, TransportId t, TransportIndex i,
void createOutgoingConnection(ContactId c, TransportId t,
DuplexTransportConnection d);
}
......@@ -4,14 +4,12 @@ import net.sf.briar.api.ContactId;
import net.sf.briar.api.plugins.simplex.SimplexTransportReader;
import net.sf.briar.api.plugins.simplex.SimplexTransportWriter;
import net.sf.briar.api.protocol.TransportId;
import net.sf.briar.api.protocol.TransportIndex;
import net.sf.briar.api.transport.ConnectionContext;
public interface SimplexConnectionFactory {
void createIncomingConnection(ConnectionContext ctx, TransportId t,
SimplexTransportReader r);
void createIncomingConnection(ConnectionContext ctx, SimplexTransportReader r);
void createOutgoingConnection(ContactId c, TransportId t, TransportIndex i,
void createOutgoingConnection(ContactId c, TransportId t,
SimplexTransportWriter w);
}
package net.sf.briar.api.transport;
import net.sf.briar.api.ContactId;
import net.sf.briar.api.protocol.TransportIndex;
import net.sf.briar.api.protocol.TransportId;
public interface ConnectionContext {
public class ConnectionContext {
ContactId getContactId();
private final ContactId contactId;
private final TransportId transportId;
private final byte[] tag, secret;
private final long connection;
private final boolean alice;
TransportIndex getTransportIndex();
public ConnectionContext(ContactId contactId, TransportId transportId,
byte[] tag, byte[] secret, long connection, boolean alice) {
this.contactId = contactId;
this.transportId = transportId;
this.tag = tag;
this.secret = secret;
this.connection = connection;
this.alice = alice;
}
long getConnectionNumber();
public ContactId getContactId() {
return contactId;
}
byte[] getSecret();
public TransportId getTransportId() {
return transportId;
}
public byte[] getTag() {
return tag;
}
public byte[] getSecret() {
return secret;
}
public long getConnectionNumber() {
return connection;
}
public boolean getAlice() {
return alice;
}
}
package net.sf.briar.api.transport;
import net.sf.briar.api.ContactId;
import net.sf.briar.api.protocol.TransportIndex;
public interface ConnectionContextFactory {
ConnectionContext createConnectionContext(ContactId c, TransportIndex i,
long connection, byte[] secret);
ConnectionContext createNextConnectionContext(ContactId c, TransportIndex i,
long connection, byte[] previousSecret);
}
......@@ -5,17 +5,16 @@ import net.sf.briar.api.plugins.duplex.DuplexTransportConnection;
import net.sf.briar.api.plugins.simplex.SimplexTransportReader;
import net.sf.briar.api.plugins.simplex.SimplexTransportWriter;
import net.sf.briar.api.protocol.TransportId;
import net.sf.briar.api.protocol.TransportIndex;
public interface ConnectionDispatcher {
void dispatchReader(TransportId t, SimplexTransportReader r);
void dispatchWriter(ContactId c, TransportId t, TransportIndex i,
void dispatchWriter(ContactId c, TransportId t,
SimplexTransportWriter w);
void dispatchIncomingConnection(TransportId t, DuplexTransportConnection d);
void dispatchOutgoingConnection(ContactId c, TransportId t,
TransportIndex i, DuplexTransportConnection d);
DuplexTransportConnection d);
}
......@@ -8,6 +8,6 @@ public interface ConnectionReaderFactory {
* Creates a connection reader for a simplex connection or one side of a
* duplex connection. The secret is erased before this method returns.
*/
ConnectionReader createConnectionReader(InputStream in, byte[] secret,
boolean initiator);
ConnectionReader createConnectionReader(InputStream in,
ConnectionContext ctx, boolean initiator);
}
package net.sf.briar.api.transport;
import java.util.Map;
import java.util.Set;
public interface ConnectionWindow {
boolean isSeen(long connection);
byte[] setSeen(long connection);
void setSeen(long connection);
Map<Long, byte[]> getUnseen();
void erase();
Set<Long> getUnseen();
}
package net.sf.briar.api.transport;
import java.util.Map;