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,13 +1,14 @@
package org.briarproject.api.android;
import org.briarproject.api.ContactId;
import org.briarproject.api.lifecycle.Service;
import org.briarproject.api.messaging.GroupId;
/**
* Manages notifications for private messages and group posts. All methods must
* be called from the Android UI thread.
*/
public interface AndroidNotificationManager {
public interface AndroidNotificationManager extends Service {
public void showPrivateMessageNotification(ContactId c);

View File

@@ -1,5 +1,8 @@
package org.briarproject.api.crypto;
import org.briarproject.api.TransportId;
import org.briarproject.api.transport.TransportKeys;
import java.security.GeneralSecurityException;
import java.security.SecureRandom;
@@ -26,56 +29,50 @@ public interface CryptoComponent {
/** Generates a random invitation code. */
int generateInvitationCode();
/**
* Derives two confirmation codes from the given master 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 two nonces from the given master secret. The first nonce is for
* Alice to sign; the second is for Bob to sign.
*/
byte[][] deriveInvitationNonces(byte[] secret);
/**
* Derives a shared master secret from two public keys and one of the
* corresponding private keys.
* @param alice indicates whether the private key belongs to Alice or Bob.
* @param alice whether the private key belongs to Alice or Bob.
*/
byte[] deriveMasterSecret(byte[] theirPublicKey, KeyPair ourKeyPair,
SecretKey deriveMasterSecret(byte[] theirPublicKey, KeyPair ourKeyPair,
boolean alice) throws GeneralSecurityException;
/** Derives a group salt from the given master secret. */
byte[] deriveGroupSalt(byte[] secret);
/**
* Derives a confirmation code from the given master secret.
* @param alice whether the code is for use by Alice or Bob.
*/
int deriveConfirmationCode(SecretKey master, boolean alice);
/**
* Derives an initial secret for the given transport from the given master
* Derives a header key for an invitation stream from the given master
* secret.
* @param alice whether the key is for use by Alice or Bob.
*/
byte[] deriveInitialSecret(byte[] secret, int transportIndex);
SecretKey deriveInvitationKey(SecretKey master, boolean alice);
/**
* Derives a temporary secret for the given period from the given secret,
* which is either the initial shared secret or the previous period's
* temporary secret.
* Derives a nonce from the given master secret for one of the parties to
* sign.
* @param alice whether the nonce is for use by Alice or Bob.
*/
byte[] deriveNextSecret(byte[] secret, long period);
byte[] deriveSignatureNonce(SecretKey master, boolean alice);
/** Derives a group salt from the given master secret. */
byte[] deriveGroupSalt(SecretKey master);
/**
* Derives a tag key from the given temporary secret.
* @param alice indicates whether the key is for streams initiated by
* Alice or Bob.
* Derives initial transport keys for the given transport in the given
* rotation period from the given master secret.
* @param alice whether the keys are for use by Alice or Bob.
*/
SecretKey deriveTagKey(byte[] secret, boolean alice);
TransportKeys deriveTransportKeys(TransportId t, SecretKey master,
long rotationPeriod, boolean alice);
/**
* Derives a frame key from the given temporary secret and stream number.
* @param alice indicates whether the key is for a stream initiated by
* Alice or Bob.
* Rotates the given transport keys to the given rotation period. If the
* keys are for a future rotation period they are not rotated.
*/
SecretKey deriveFrameKey(byte[] secret, long streamNumber, boolean alice);
TransportKeys rotateTransportKeys(TransportKeys k, long rotationPeriod);
/** Encodes the pseudo-random tag that is used to recognise a stream. */
void encodeTag(byte[] tag, SecretKey tagKey, long streamNumber);

View File

@@ -1,21 +0,0 @@
package org.briarproject.api.crypto;
import org.briarproject.api.ContactId;
import org.briarproject.api.TransportId;
import org.briarproject.api.lifecycle.Service;
import org.briarproject.api.transport.Endpoint;
import org.briarproject.api.transport.StreamContext;
public interface KeyManager extends Service {
/**
* Returns a {@link org.briarproject.api.transport.StreamContext
* StreamContext} for sending data to the given contact over the given
* transport, or null if an error occurs or the contact does not support
* the transport.
*/
StreamContext getStreamContext(ContactId c, TransportId t);
/** Called whenever an endpoint has been added. */
void endpointAdded(Endpoint ep, int maxLatency, byte[] initialSecret);
}

View File

@@ -13,5 +13,5 @@ public interface StreamDecrypterFactory {
* Creates a {@link StreamDecrypter} for decrypting an invitation stream.
*/
StreamDecrypter createInvitationStreamDecrypter(InputStream in,
byte[] secret, boolean alice);
SecretKey headerKey);
}

View File

@@ -13,5 +13,5 @@ public interface StreamEncrypterFactory {
* Creates a {@link StreamEncrypter} for encrypting an invitation stream.
*/
StreamEncrypter createInvitationStreamEncrypter(OutputStream out,
byte[] secret, boolean alice);
SecretKey headerKey);
}

View File

@@ -1,9 +1,5 @@
package org.briarproject.api.db;
import java.io.IOException;
import java.util.Collection;
import java.util.Map;
import org.briarproject.api.Author;
import org.briarproject.api.AuthorId;
import org.briarproject.api.Contact;
@@ -26,8 +22,11 @@ import org.briarproject.api.messaging.SubscriptionAck;
import org.briarproject.api.messaging.SubscriptionUpdate;
import org.briarproject.api.messaging.TransportAck;
import org.briarproject.api.messaging.TransportUpdate;
import org.briarproject.api.transport.Endpoint;
import org.briarproject.api.transport.TemporarySecret;
import org.briarproject.api.transport.TransportKeys;
import java.io.IOException;
import java.util.Collection;
import java.util.Map;
/**
* Encapsulates the database implementation and exposes high-level operations
@@ -47,9 +46,6 @@ public interface DatabaseComponent {
*/
ContactId addContact(Author remote, AuthorId local) throws DbException;
/** Stores an endpoint. */
void addEndpoint(Endpoint ep) throws DbException;
/**
* Subscribes to a group, or returns false if the user already has the
* maximum number of public subscriptions.
@@ -62,18 +58,17 @@ public interface DatabaseComponent {
/** Stores a local message. */
void addLocalMessage(Message m) throws DbException;
/**
* Stores the given temporary secrets and deletes any secrets that have
* been made obsolete.
*/
void addSecrets(Collection<TemporarySecret> secrets) throws DbException;
/**
* Stores a transport and returns true if the transport was not previously
* in the database.
*/
boolean addTransport(TransportId t, int maxLatency) throws DbException;
/**
* Stores the given transport keys for a newly added contact.
*/
void addTransportKeys(ContactId c, TransportKeys k) throws DbException;
/**
* Returns an acknowledgement for the given contact, or null if there are
* no messages to acknowledge.
@@ -214,16 +209,17 @@ public interface DatabaseComponent {
Map<ContactId, TransportProperties> getRemoteProperties(TransportId t)
throws DbException;
/** Returns all temporary secrets. */
Collection<TemporarySecret> getSecrets() throws DbException;
/** Returns all settings. */
Settings getSettings() throws DbException;
/** Returns all contacts who subscribe to the given group. */
Collection<Contact> getSubscribers(GroupId g) throws DbException;
/** Returns the maximum latencies of all supported transports. */
/** Returns all transport keys for the given transport. */
Map<ContactId, TransportKeys> getTransportKeys(TransportId t)
throws DbException;
/** Returns the maximum latencies in milliseconds of all transports. */
Map<TransportId, Integer> getTransportLatencies() throws DbException;
/** Returns the number of unread messages in each subscribed group. */
@@ -233,11 +229,10 @@ public interface DatabaseComponent {
Collection<ContactId> getVisibility(GroupId g) throws DbException;
/**
* Increments the outgoing stream counter for the given endpoint in the
* given rotation period and returns the old value, or -1 if the counter
* does not exist.
* Increments the outgoing stream counter for the given contact and
* transport in the given rotation period .
*/
long incrementStreamCounter(ContactId c, TransportId t, long period)
void incrementStreamCounter(ContactId c, TransportId t, long rotationPeriod)
throws DbException;
/**
@@ -310,18 +305,11 @@ public interface DatabaseComponent {
*/
void removeTransport(TransportId t) throws DbException;
/**
* Sets the reordering window for the given endpoint in the given rotation
* period.
*/
void setReorderingWindow(ContactId c, TransportId t, long period,
long centre, byte[] bitmap) throws DbException;
/**
* Makes a group visible to the given contact, adds it to the contact's
* subscriptions, and sets it as the inbox group for the contact.
*/
public void setInboxGroup(ContactId c, Group g) throws DbException;
void setInboxGroup(ContactId c, Group g) throws DbException;
/**
* Marks a message as read or unread.
@@ -335,6 +323,13 @@ public interface DatabaseComponent {
void setRemoteProperties(ContactId c,
Map<TransportId, TransportProperties> p) throws DbException;
/**
* Sets the reordering window for the given contact and transport in the
* given rotation period.
*/
void setReorderingWindow(ContactId c, TransportId t, long rotationPeriod,
long base, byte[] bitmap) throws DbException;
/**
* Makes a group visible to the given set of contacts and invisible to any
* other current or future contacts.
@@ -347,4 +342,10 @@ public interface DatabaseComponent {
* to future contacts.
*/
void setVisibleToAll(GroupId g, boolean all) throws DbException;
/**
* Stores the given transport keys, deleting any keys they have replaced.
*/
void updateTransportKeys(Map<ContactId, TransportKeys> keys)
throws DbException;
}

View File

@@ -28,7 +28,7 @@ public interface Message {
/** Returns the message's content type. */
String getContentType();
/** Returns the message's timestamp. */
/** Returns the message's timestamp in milliseconds since the Unix epoch. */
long getTimestamp();
/** Returns the serialised message. */

View File

@@ -1,36 +0,0 @@
package org.briarproject.api.transport;
import org.briarproject.api.ContactId;
import org.briarproject.api.TransportId;
public class Endpoint {
protected final ContactId contactId;
protected final TransportId transportId;
private final long epoch;
private final boolean alice;
public Endpoint(ContactId contactId, TransportId transportId, long epoch,
boolean alice) {
this.contactId = contactId;
this.transportId = transportId;
this.epoch = epoch;
this.alice = alice;
}
public ContactId getContactId() {
return contactId;
}
public TransportId getTransportId() {
return transportId;
}
public long getEpoch() {
return epoch;
}
public boolean getAlice() {
return alice;
}
}

View File

@@ -0,0 +1,51 @@
package org.briarproject.api.transport;
import org.briarproject.api.crypto.SecretKey;
import static org.briarproject.api.transport.TransportConstants.REORDERING_WINDOW_SIZE;
/**
* Contains transport keys for receiving streams from a given contact over a
* given transport in a given rotation period.
*/
public class IncomingKeys {
private final SecretKey tagKey, headerKey;
private final long rotationPeriod, windowBase;
private final byte[] windowBitmap;
public IncomingKeys(SecretKey tagKey, SecretKey headerKey,
long rotationPeriod) {
this(tagKey, headerKey, rotationPeriod, 0,
new byte[REORDERING_WINDOW_SIZE / 8]);
}
public IncomingKeys(SecretKey tagKey, SecretKey headerKey,
long rotationPeriod, long windowBase, byte[] windowBitmap) {
this.tagKey = tagKey;
this.headerKey = headerKey;
this.rotationPeriod = rotationPeriod;
this.windowBase = windowBase;
this.windowBitmap = windowBitmap;
}
public SecretKey getTagKey() {
return tagKey;
}
public SecretKey getHeaderKey() {
return headerKey;
}
public long getRotationPeriod() {
return rotationPeriod;
}
public long getWindowBase() {
return windowBase;
}
public byte[] getWindowBitmap() {
return windowBitmap;
}
}

View File

@@ -0,0 +1,36 @@
package org.briarproject.api.transport;
import org.briarproject.api.ContactId;
import org.briarproject.api.TransportId;
import org.briarproject.api.db.DbException;
import org.briarproject.api.lifecycle.Service;
import java.util.Collection;
/**
* Responsible for managing transport keys and recognising the pseudo-random
* tags of incoming streams.
*/
public interface KeyManager extends Service {
/**
* Informs the key manager that a new contact has been added.
* {@link StreamContext StreamContexts} for the contact can be created
* after this method has returned.
*/
void contactAdded(ContactId c, Collection<TransportKeys> keys);
/**
* Returns a {@link StreamContext} for sending a stream to the given
* contact over the given transport, or null if an error occurs or the
* contact does not support the transport.
*/
StreamContext getStreamContext(ContactId c, TransportId t);
/**
* Looks up the given tag and returns a {@link StreamContext} for reading
* from the corresponding stream if the tag was expected, or null if the
* tag was unexpected.
*/
StreamContext recogniseTag(TransportId t, byte[] tag) throws DbException;
}

View File

@@ -0,0 +1,42 @@
package org.briarproject.api.transport;
import org.briarproject.api.crypto.SecretKey;
/**
* Contains transport keys for sending streams to a given contact over a given
* transport in a given rotation period.
*/
public class OutgoingKeys {
private final SecretKey tagKey, headerKey;
private final long rotationPeriod, streamCounter;
public OutgoingKeys(SecretKey tagKey, SecretKey headerKey,
long rotationPeriod) {
this(tagKey, headerKey, rotationPeriod, 0);
}
public OutgoingKeys(SecretKey tagKey, SecretKey headerKey,
long rotationPeriod, long streamCounter) {
this.tagKey = tagKey;
this.headerKey = headerKey;
this.rotationPeriod = rotationPeriod;
this.streamCounter = streamCounter;
}
public SecretKey getTagKey() {
return tagKey;
}
public SecretKey getHeaderKey() {
return headerKey;
}
public long getRotationPeriod() {
return rotationPeriod;
}
public long getStreamCounter() {
return streamCounter;
}
}

View File

@@ -2,22 +2,22 @@ package org.briarproject.api.transport;
import org.briarproject.api.ContactId;
import org.briarproject.api.TransportId;
import org.briarproject.api.crypto.SecretKey;
public class StreamContext {
private final ContactId contactId;
private final TransportId transportId;
private final byte[] secret;
private final SecretKey tagKey, headerKey;
private final long streamNumber;
private final boolean alice;
public StreamContext(ContactId contactId, TransportId transportId,
byte[] secret, long streamNumber, boolean alice) {
SecretKey tagKey, SecretKey headerKey, long streamNumber) {
this.contactId = contactId;
this.transportId = transportId;
this.secret = secret;
this.tagKey = tagKey;
this.headerKey = headerKey;
this.streamNumber = streamNumber;
this.alice = alice;
}
public ContactId getContactId() {
@@ -28,15 +28,15 @@ public class StreamContext {
return transportId;
}
public byte[] getSecret() {
return secret;
public SecretKey getTagKey() {
return tagKey;
}
public SecretKey getHeaderKey() {
return headerKey;
}
public long getStreamNumber() {
return streamNumber;
}
public boolean getAlice() {
return alice;
}
}

View File

@@ -2,6 +2,8 @@ package org.briarproject.api.transport;
import java.io.InputStream;
import org.briarproject.api.crypto.SecretKey;
public interface StreamReaderFactory {
/**
@@ -15,5 +17,5 @@ public interface StreamReaderFactory {
* invitation stream.
*/
InputStream createInvitationStreamReader(InputStream in,
byte[] secret, boolean alice);
SecretKey headerKey);
}

View File

@@ -2,6 +2,8 @@ package org.briarproject.api.transport;
import java.io.OutputStream;
import org.briarproject.api.crypto.SecretKey;
public interface StreamWriterFactory {
/**
@@ -15,5 +17,5 @@ public interface StreamWriterFactory {
* invitation stream.
*/
OutputStream createInvitationStreamWriter(OutputStream out,
byte[] secret, boolean alice);
SecretKey headerKey);
}

View File

@@ -1,26 +0,0 @@
package org.briarproject.api.transport;
import org.briarproject.api.ContactId;
import org.briarproject.api.TransportId;
import org.briarproject.api.db.DbException;
/** Keeps track of expected tags and uses them to recognise incoming streams. */
public interface TagRecogniser {
/**
* Looks up the given tag and returns a {@link StreamContext} for reading
* from the stream if the tag was expected, or null if the tag was
* unexpected.
*/
StreamContext recogniseTag(TransportId t, byte[] tag) throws DbException;
void addSecret(TemporarySecret s);
void removeSecret(ContactId c, TransportId t, long period);
void removeSecrets(ContactId c);
void removeSecrets(TransportId t);
void removeSecrets();
}

View File

@@ -1,73 +0,0 @@
package org.briarproject.api.transport;
import static org.briarproject.api.transport.TransportConstants.REORDERING_WINDOW_SIZE;
import org.briarproject.api.ContactId;
import org.briarproject.api.TransportId;
public class TemporarySecret extends Endpoint {
private final long period, outgoing, centre;
private final byte[] secret, bitmap;
/** Creates a temporary secret with the given reordering window. */
public TemporarySecret(ContactId contactId, TransportId transportId,
long epoch, boolean alice, long period, byte[] secret,
long outgoing, long centre, byte[] bitmap) {
super(contactId, transportId, epoch, alice);
this.period = period;
this.secret = secret;
this.outgoing = outgoing;
this.centre = centre;
this.bitmap = bitmap;
}
/** Creates a temporary secret with a new reordering window. */
public TemporarySecret(ContactId contactId, TransportId transportId,
long epoch, boolean alice, long period, byte[] secret) {
this(contactId, transportId, epoch, alice, period, secret, 0, 0,
new byte[REORDERING_WINDOW_SIZE / 8]);
}
/** Creates a temporary secret derived from the given endpoint. */
public TemporarySecret(Endpoint ep, long period, byte[] secret) {
this(ep.getContactId(), ep.getTransportId(), ep.getEpoch(),
ep.getAlice(), period, secret);
}
public long getPeriod() {
return period;
}
public byte[] getSecret() {
return secret;
}
public long getOutgoingStreamCounter() {
return outgoing;
}
public long getWindowCentre() {
return centre;
}
public byte[] getWindowBitmap() {
return bitmap;
}
@Override
public int hashCode() {
int periodHashCode = (int) (period ^ (period >>> 32));
return contactId.hashCode() ^ transportId.hashCode() ^ periodHashCode;
}
@Override
public boolean equals(Object o) {
if (o instanceof TemporarySecret) {
TemporarySecret s = (TemporarySecret) o;
return contactId.equals(s.contactId) &&
transportId.equals(s.transportId) && period == s.period;
}
return false;
}
}

View File

@@ -28,8 +28,8 @@ public interface TransportConstants {
*/
int MIN_STREAM_LENGTH = 64 * 1024; // 64 KiB
/** The maximum difference between two communicating devices' clocks. */
int MAX_CLOCK_DIFFERENCE = 60 * 60 * 1000; // 1 hour
/** The maximum difference in milliseconds between two peers' clocks. */
int MAX_CLOCK_DIFFERENCE = 24 * 60 * 60 * 1000; // 24 hours
/** The size of the reordering window. */
int REORDERING_WINDOW_SIZE = 32;

View File

@@ -0,0 +1,44 @@
package org.briarproject.api.transport;
import org.briarproject.api.TransportId;
/** Keys for communicating with a given contact over a given transport. */
public class TransportKeys {
private final TransportId transportId;
private final IncomingKeys inPrev, inCurr, inNext;
private final OutgoingKeys outCurr;
public TransportKeys(TransportId transportId, IncomingKeys inPrev,
IncomingKeys inCurr, IncomingKeys inNext, OutgoingKeys outCurr) {
this.transportId = transportId;
this.inPrev = inPrev;
this.inCurr = inCurr;
this.inNext = inNext;
this.outCurr = outCurr;
}
public TransportId getTransportId() {
return transportId;
}
public IncomingKeys getPreviousIncomingKeys() {
return inPrev;
}
public IncomingKeys getCurrentIncomingKeys() {
return inCurr;
}
public IncomingKeys getNextIncomingKeys() {
return inNext;
}
public OutgoingKeys getCurrentOutgoingKeys() {
return outCurr;
}
public long getRotationPeriod() {
return outCurr.getRotationPeriod();
}
}