Skip to content
Snippets Groups Projects
Commit 33099384 authored by akwizgran's avatar akwizgran
Browse files

Massive refactoring to use pseudonyms instead of nicknames for contacts.

The invitation and private messaging UIs are currently broken. Some key
rotation bugs were fixed; others may have been created (unit tests
needed). An encoding for private keys was added. Pseudonyms were moved
out of the messaging package and ratings were moved in.
parent 4a40de95
No related branches found
No related tags found
No related merge requests found
Showing
with 155 additions and 86 deletions
package net.sf.briar.api.messaging;
package net.sf.briar.api;
import java.util.Arrays;
......
......
package net.sf.briar.api.messaging;
package net.sf.briar.api;
import java.util.Arrays;
......
......
......@@ -9,75 +9,91 @@ import javax.crypto.Cipher;
public interface CryptoComponent {
ErasableKey generateSecretKey();
MessageDigest getMessageDigest();
PseudoRandom getPseudoRandom(int seed1, int seed2);
SecureRandom getSecureRandom();
Signature getSignature();
KeyPair generateAgreementKeyPair();
KeyParser getAgreementKeyParser();
KeyPair generateSignatureKeyPair();
KeyParser getSignatureKeyParser();
/** Generates a random invitation code. */
int generateInvitationCode();
/**
* Derives a tag key from the given temporary secret.
* @param alice indicates whether the key is for connections initiated by
* Alice or Bob.
* 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.
*/
ErasableKey deriveTagKey(byte[] secret, boolean alice);
int[] deriveConfirmationCodes(byte[] secret);
/**
* 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.
* Derives two nonces from the given master secret. The first nonce is for
* Alice to sign; the second is for Bob to sign.
*/
ErasableKey deriveFrameKey(byte[] secret, long connection, boolean alice,
boolean initiator);
byte[][] deriveInvitationNonces(byte[] secret);
/**
* Derives an initial shared secret from two public keys and one of the
* 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.
*/
byte[] deriveInitialSecret(byte[] theirPublicKey, KeyPair ourKeyPair,
byte[] deriveMasterSecret(byte[] theirPublicKey, KeyPair ourKeyPair,
boolean alice) throws GeneralSecurityException;
/**
* Generates a random invitation code.
* Derives an initial secret for the given transport from the given master
* secret.
*/
int generateInvitationCode();
byte[] deriveInitialSecret(byte[] secret, int transportIndex);
/**
* 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.
* 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.
*/
int[] deriveConfirmationCodes(byte[] secret);
byte[] deriveNextSecret(byte[] secret, long period);
/**
* Derives a temporary secret for the given period from the previous
* period's temporary secret.
* Derives a tag key from the given temporary secret.
* @param alice indicates whether the key is for connections initiated by
* Alice or Bob.
*/
byte[] deriveNextSecret(byte[] secret, long period);
/** Encodes the pseudo-random tag that is used to recognise a connection. */
void encodeTag(byte[] tag, Cipher tagCipher, ErasableKey tagKey,
long connection);
KeyPair generateAgreementKeyPair();
KeyParser getAgreementKeyParser();
KeyPair generateSignatureKeyPair();
KeyParser getSignatureKeyParser();
ErasableKey generateSecretKey();
MessageDigest getMessageDigest();
PseudoRandom getPseudoRandom(int seed1, int seed2);
ErasableKey deriveTagKey(byte[] secret, boolean alice);
SecureRandom getSecureRandom();
/**
* 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);
/**
* Returns a cipher for generating the pseudo-random tags that are used to
* recognise connections.
*/
Cipher getTagCipher();
/** Returns a cipher for encrypting and authenticating connections. */
AuthenticatedCipher getFrameCipher();
Signature getSignature();
/** Encodes the pseudo-random tag that is used to recognise a connection. */
void encodeTag(byte[] tag, Cipher tagCipher, ErasableKey tagKey,
long connection);
/**
* Encrypts the given plaintext so it can be written to temporary storage.
......
......
package net.sf.briar.api.crypto;
import net.sf.briar.api.ContactId;
import net.sf.briar.api.messaging.TransportId;
import net.sf.briar.api.TransportId;
import net.sf.briar.api.transport.ConnectionContext;
import net.sf.briar.api.transport.Endpoint;
......
......
package net.sf.briar.api.crypto;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
public interface KeyParser {
PublicKey parsePublicKey(byte[] encodedKey) throws InvalidKeySpecException;
PrivateKey parsePrivateKey(byte[] encodedKey)
throws InvalidKeySpecException;
}
package net.sf.briar.api.crypto;
/**
* Encapsulates a password. Implementations may keep the password encrypted in
* memory to reduce the chances of writing it to the swapfile in plaintext.
*/
public interface Password {
/**
* Returns the password as a character array, which should be filled with
* zeroes as soon as it has been used.
*/
char[] getPassword();
}
package net.sf.briar.api.crypto;
/** A deterministic PRNG. */
public interface PseudoRandom {
byte[] nextBytes(int bytes);
......
......
package net.sf.briar.api.db;
/**
* Thrown when a duplicate contact is added to the database. This exception may
* occur due to concurrent updates and does not indicate a database error.
*/
public class ContactExistsException extends DbException {
private static final long serialVersionUID = -6658762011691502411L;
}
......@@ -4,28 +4,29 @@ import java.io.IOException;
import java.util.Collection;
import java.util.Map;
import net.sf.briar.api.Author;
import net.sf.briar.api.AuthorId;
import net.sf.briar.api.Contact;
import net.sf.briar.api.ContactId;
import net.sf.briar.api.Rating;
import net.sf.briar.api.LocalAuthor;
import net.sf.briar.api.TransportConfig;
import net.sf.briar.api.TransportId;
import net.sf.briar.api.TransportProperties;
import net.sf.briar.api.db.event.DatabaseListener;
import net.sf.briar.api.messaging.Ack;
import net.sf.briar.api.messaging.AuthorId;
import net.sf.briar.api.messaging.Group;
import net.sf.briar.api.messaging.GroupId;
import net.sf.briar.api.messaging.LocalAuthor;
import net.sf.briar.api.messaging.LocalGroup;
import net.sf.briar.api.messaging.Message;
import net.sf.briar.api.messaging.MessageId;
import net.sf.briar.api.messaging.Offer;
import net.sf.briar.api.messaging.Rating;
import net.sf.briar.api.messaging.Request;
import net.sf.briar.api.messaging.RetentionAck;
import net.sf.briar.api.messaging.RetentionUpdate;
import net.sf.briar.api.messaging.SubscriptionAck;
import net.sf.briar.api.messaging.SubscriptionUpdate;
import net.sf.briar.api.messaging.TransportAck;
import net.sf.briar.api.messaging.TransportId;
import net.sf.briar.api.messaging.TransportUpdate;
import net.sf.briar.api.transport.Endpoint;
import net.sf.briar.api.transport.TemporarySecret;
......@@ -53,9 +54,10 @@ public interface DatabaseComponent {
void removeListener(DatabaseListener d);
/**
* Stores a contact with the given name and returns an ID for the contact.
* Stores a contact with the given pseudonym, associated with the given
* local pseudonym, and returns an ID for the contact.
*/
ContactId addContact(String name) throws DbException;
ContactId addContact(Author remote, AuthorId local) throws DbException;
/** Stores an endpoint. */
void addEndpoint(Endpoint ep) throws DbException;
......@@ -85,7 +87,7 @@ public interface DatabaseComponent {
* Stores a transport and returns true if the transport was not previously
* in the database.
*/
boolean addTransport(TransportId t) throws DbException;
boolean addTransport(TransportId t, long maxLatency) throws DbException;
/**
* Generates an acknowledgement for the given contact, or returns null if
......@@ -176,12 +178,19 @@ public interface DatabaseComponent {
/** Returns the group with the given ID, if the user subscribes to it. */
Group getGroup(GroupId g) throws DbException;
/** Returns the pseudonym with the given ID. */
LocalAuthor getLocalAuthor(AuthorId a) throws DbException;
/** Returns all pseudonyms that the user can use to sign messages. */
Collection<LocalAuthor> getLocalAuthors() throws DbException;
/** Returns all restricted groups to which the user can post messages. */
Collection<LocalGroup> getLocalGroups() throws DbException;
/** Returns the local transport properties for all transports. */
Map<TransportId, TransportProperties> getLocalProperties()
throws DbException;
/** Returns the local transport properties for the given transport. */
TransportProperties getLocalProperties(TransportId t) throws DbException;
......@@ -222,6 +231,9 @@ public interface DatabaseComponent {
/** Returns the set of groups to which the user subscribes. */
Collection<Group> getSubscriptions() throws DbException;
/** Returns the maximum latencies of all local transports. */
Map<TransportId, Long> getTransportLatencies() throws DbException;
/** Returns the number of unread messages in each subscribed group. */
Map<GroupId, Integer> getUnreadMessageCounts() throws DbException;
......@@ -317,6 +329,13 @@ public interface DatabaseComponent {
*/
boolean setReadFlag(MessageId m, boolean read) throws DbException;
/**
* Sets the remote transport properties for the given contact, replacing
* any existing properties.
*/
void setRemoteProperties(ContactId c,
Map<TransportId, TransportProperties> p) throws DbException;
/** Records the given messages as having been seen by the given contact. */
void setSeen(ContactId c, Collection<MessageId> seen) throws DbException;
......
......
......@@ -2,13 +2,11 @@ package net.sf.briar.api.db;
import java.io.File;
import net.sf.briar.api.crypto.Password;
public interface DatabaseConfig {
File getDataDirectory();
Password getPassword();
char[] getPassword();
long getMaxSize();
}
package net.sf.briar.api.db;
import net.sf.briar.api.Rating;
import net.sf.briar.api.messaging.Author;
import net.sf.briar.api.Author;
import net.sf.briar.api.messaging.GroupId;
import net.sf.briar.api.messaging.MessageId;
import net.sf.briar.api.messaging.Rating;
public class GroupMessageHeader extends MessageHeader {
......
......
package net.sf.briar.api.db.event;
import net.sf.briar.api.Rating;
import net.sf.briar.api.messaging.AuthorId;
import net.sf.briar.api.AuthorId;
import net.sf.briar.api.messaging.Rating;
public class RatingChangedEvent extends DatabaseEvent {
......
......
package net.sf.briar.api.db.event;
import net.sf.briar.api.ContactId;
import net.sf.briar.api.messaging.TransportId;
import net.sf.briar.api.TransportId;
/**
* An event that is broadcast when a contact's remote transport properties
......
......
package net.sf.briar.api.db.event;
import net.sf.briar.api.messaging.TransportId;
import net.sf.briar.api.TransportId;
/** An event that is broadcast when a transport is added. */
/** An event that is broadcast when a transport is added to the database. */
public class TransportAddedEvent extends DatabaseEvent {
private final TransportId transportId;
private final long maxLatency;
public TransportAddedEvent(TransportId transportId) {
public TransportAddedEvent(TransportId transportId, long maxLatency) {
this.transportId = transportId;
this.maxLatency = maxLatency;
}
public TransportId getTransportId() {
return transportId;
}
public long getMaxLatency() {
return maxLatency;
}
}
package net.sf.briar.api.db.event;
import net.sf.briar.api.messaging.TransportId;
import net.sf.briar.api.TransportId;
/** An event that is broadcast when a transport is removed. */
public class TransportRemovedEvent extends DatabaseEvent {
......
......
......@@ -9,7 +9,10 @@ public interface InvitationListener {
/** Called if a connection is established and key agreement succeeds. */
void connectionSucceeded(int localCode, int remoteCode);
/** Called if a connection cannot be established. */
/**
* Called if a connection cannot be established. This indicates that the
* protocol has ended unsuccessfully.
*/
void connectionFailed();
/**
......@@ -20,7 +23,21 @@ public interface InvitationListener {
/**
* Informs the local peer that the remote peer's confirmation check did
* not succeed, or the connection was lost during confirmation.
* not succeed, or the connection was lost during confirmation. This
* indicates that the protocol has ended unsuccessfully.
*/
void remoteConfirmationFailed();
/**
* Informs the local peer of the name used by the remote peer. Called if
* the exchange of pseudonyms succeeds. This indicates that the protocol
* has ended successfully.
*/
void pseudonymExchangeSucceeded(String remoteName);
/**
* Called if the exchange of pseudonyms fails. This indicates that the
* protocol has ended unsuccessfully.
*/
void pseudonymExchangeFailed();
}
......@@ -7,12 +7,13 @@ public class InvitationState {
private final boolean connectionFailed;
private final boolean localCompared, remoteCompared;
private final boolean localMatched, remoteMatched;
private final String contactName;
public InvitationState(int localInvitationCode, int remoteInvitationCode,
int localConfirmationCode, int remoteConfirmationCode,
boolean connectionFailed, boolean localCompared,
boolean remoteCompared, boolean localMatched,
boolean remoteMatched) {
boolean remoteMatched, String contactName) {
this.localInvitationCode = localInvitationCode;
this.remoteInvitationCode = remoteInvitationCode;
this.localConfirmationCode = localConfirmationCode;
......@@ -22,6 +23,7 @@ public class InvitationState {
this.remoteCompared = remoteCompared;
this.localMatched = localMatched;
this.remoteMatched = remoteMatched;
this.contactName = contactName;
}
public int getLocalInvitationCode() {
......@@ -59,4 +61,8 @@ public class InvitationState {
public boolean getRemoteMatched() {
return remoteMatched;
}
public String getContactName() {
return contactName;
}
}
package net.sf.briar.api.invitation;
import net.sf.briar.api.AuthorId;
/** Creates tasks for exchanging invitations with remote peers. */
public interface InvitationTaskFactory {
/** Creates a task using the given invitation codes. */
InvitationTask createTask(int localCode, int remoteCode);
/** Creates a task using the given pseudonym and invitation codes. */
InvitationTask createTask(AuthorId localAuthorId, int localCode,
int remoteCode);
}
......@@ -29,8 +29,9 @@ public class Group {
}
/**
* If the group is restricted, returns the public key that is used to
* authorise all messages sent to the group. Otherwise returns null.
* If the group is restricted, returns the public key used to verify the
* signatures on all messages sent to the group. If the group is
* unrestricted, returns null.
*/
public byte[] getPublicKey() {
return publicKey;
......
......
......@@ -2,6 +2,8 @@ package net.sf.briar.api.messaging;
import java.util.Arrays;
import net.sf.briar.api.UniqueId;
/**
* Type-safe wrapper for a byte array that uniquely identifies a {@link Group}.
*/
......
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment