From 47f136904c0206d5535bc16fa2c9775eb147f84a Mon Sep 17 00:00:00 2001 From: ameba23 Date: Mon, 28 Jun 2021 09:55:41 +0200 Subject: [PATCH] Create HandshakeKeyExchange client and module --- .../HandshakeKeyExchangeManager.java | 22 ++ .../HandshakeKeyExchangeConstants.java | 13 + .../HandshakeKeyExchangeManagerImpl.java | 235 ++++++++++++++++++ .../HandshakeKeyExchangeModule.java | 23 ++ .../HandshakeKeyExchangeValidator.java | 31 +++ 5 files changed, 324 insertions(+) create mode 100644 briar-api/src/main/java/org/briarproject/briar/api/handshakekeyexchange/HandshakeKeyExchangeManager.java create mode 100644 briar-core/src/main/java/org/briarproject/briar/handshakekeyexchange/HandshakeKeyExchangeConstants.java create mode 100644 briar-core/src/main/java/org/briarproject/briar/handshakekeyexchange/HandshakeKeyExchangeManagerImpl.java create mode 100644 briar-core/src/main/java/org/briarproject/briar/handshakekeyexchange/HandshakeKeyExchangeModule.java create mode 100644 briar-core/src/main/java/org/briarproject/briar/handshakekeyexchange/HandshakeKeyExchangeValidator.java diff --git a/briar-api/src/main/java/org/briarproject/briar/api/handshakekeyexchange/HandshakeKeyExchangeManager.java b/briar-api/src/main/java/org/briarproject/briar/api/handshakekeyexchange/HandshakeKeyExchangeManager.java new file mode 100644 index 000000000..c6da01697 --- /dev/null +++ b/briar-api/src/main/java/org/briarproject/briar/api/handshakekeyexchange/HandshakeKeyExchangeManager.java @@ -0,0 +1,22 @@ +package org.briarproject.briar.api.handshakekeyexchange; + +import org.briarproject.bramble.api.sync.ClientId; +import org.briarproject.briar.api.conversation.ConversationManager; + +public interface HandshakeKeyExchangeManager extends ConversationManager.ConversationClient { + + /** + * The unique ID of the client. + */ + ClientId CLIENT_ID = new ClientId("org.briarproject.briar.handshakekeyexchange"); + + /** + * The current major version of the handshake key exchange client. + */ + int MAJOR_VERSION = 0; + + /** + * The current minor version of the handshake key exchange client. + */ + int MINOR_VERSION = 0; +} diff --git a/briar-core/src/main/java/org/briarproject/briar/handshakekeyexchange/HandshakeKeyExchangeConstants.java b/briar-core/src/main/java/org/briarproject/briar/handshakekeyexchange/HandshakeKeyExchangeConstants.java new file mode 100644 index 000000000..8b4aa7ed4 --- /dev/null +++ b/briar-core/src/main/java/org/briarproject/briar/handshakekeyexchange/HandshakeKeyExchangeConstants.java @@ -0,0 +1,13 @@ +package org.briarproject.briar.handshakekeyexchange; + +public interface HandshakeKeyExchangeConstants { + + // Group metadata keys + String GROUP_KEY_CONTACT_ID = "contactId"; + + // Message metadata keys + String MSG_KEY_TIMESTAMP = "timestamp"; + String MSG_KEY_MESSAGE_TYPE = "messageType"; + String MSG_KEY_LOCAL = "local"; + String MSG_KEY_VERSION = "version"; +} diff --git a/briar-core/src/main/java/org/briarproject/briar/handshakekeyexchange/HandshakeKeyExchangeManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/handshakekeyexchange/HandshakeKeyExchangeManagerImpl.java new file mode 100644 index 000000000..3240ed458 --- /dev/null +++ b/briar-core/src/main/java/org/briarproject/briar/handshakekeyexchange/HandshakeKeyExchangeManagerImpl.java @@ -0,0 +1,235 @@ +package org.briarproject.briar.handshakekeyexchange; + +import org.briarproject.bramble.api.FormatException; +import org.briarproject.bramble.api.client.ClientHelper; +import org.briarproject.bramble.api.client.ContactGroupFactory; +import org.briarproject.bramble.api.contact.Contact; +import org.briarproject.bramble.api.contact.ContactId; +import org.briarproject.bramble.api.contact.ContactManager; +import org.briarproject.bramble.api.crypto.AgreementPublicKey; +import org.briarproject.bramble.api.crypto.PublicKey; +import org.briarproject.bramble.api.data.BdfDictionary; +import org.briarproject.bramble.api.data.BdfEntry; +import org.briarproject.bramble.api.data.BdfList; +import org.briarproject.bramble.api.data.MetadataParser; +import org.briarproject.bramble.api.db.DatabaseComponent; +import org.briarproject.bramble.api.db.DbException; +import org.briarproject.bramble.api.db.Transaction; +import org.briarproject.bramble.api.identity.Identity; +import org.briarproject.bramble.api.identity.IdentityManager; +import org.briarproject.bramble.api.lifecycle.LifecycleManager; +import org.briarproject.bramble.api.sync.Group; +import org.briarproject.bramble.api.sync.GroupId; +import org.briarproject.bramble.api.sync.Message; +import org.briarproject.bramble.api.sync.MessageId; +import org.briarproject.bramble.api.system.Clock; +import org.briarproject.bramble.api.versioning.ClientVersion; +import org.briarproject.bramble.api.versioning.ClientVersioningManager; +import org.briarproject.briar.api.client.MessageTracker; +import org.briarproject.briar.api.conversation.ConversationManager; +import org.briarproject.briar.api.conversation.ConversationMessageHeader; +import org.briarproject.briar.api.conversation.DeletionResult; +import org.briarproject.briar.api.handshakekeyexchange.HandshakeKeyExchangeManager; +import org.briarproject.briar.client.ConversationClientImpl; + +import java.util.Collection; +import java.util.Map; +import java.util.Set; +import java.util.logging.Logger; + +import javax.inject.Inject; + +import static java.util.logging.Logger.getLogger; +import static org.briarproject.briar.handshakekeyexchange.HandshakeKeyExchangeConstants.GROUP_KEY_CONTACT_ID; +import static org.briarproject.briar.handshakekeyexchange.HandshakeKeyExchangeConstants.MSG_KEY_LOCAL; +import static org.briarproject.briar.handshakekeyexchange.HandshakeKeyExchangeConstants.MSG_KEY_TIMESTAMP; + +public class HandshakeKeyExchangeManagerImpl extends ConversationClientImpl + implements + HandshakeKeyExchangeManager, LifecycleManager.OpenDatabaseHook, + ContactManager.ContactHook { + + private final ClientVersioningManager clientVersioningManager; + private final ContactGroupFactory contactGroupFactory; + private final ContactManager contactManager; + private final IdentityManager identityManager; + private final Group localGroup; + private final Clock clock; + private PublicKey handshakePublicKey; + private static final Logger LOG = + getLogger(HandshakeKeyExchangeManager.class.getName()); + + + @Inject + protected HandshakeKeyExchangeManagerImpl ( + DatabaseComponent db, + ClientHelper clientHelper, + MetadataParser metadataParser, + MessageTracker messageTracker, + ClientVersioningManager clientVersioningManager, + ContactGroupFactory contactGroupFactory, + ContactManager contactManager, + IdentityManager identityManager, + Clock clock + ) { + super(db, clientHelper, metadataParser, messageTracker); + this.clientVersioningManager = clientVersioningManager; + this.contactGroupFactory = contactGroupFactory; + this.contactManager = contactManager; + this.identityManager = identityManager; + this.clock = clock; + localGroup = contactGroupFactory.createLocalGroup(CLIENT_ID, MAJOR_VERSION); + } + + @Override + public void onDatabaseOpened(Transaction txn) throws DbException { + if (db.containsGroup(txn, localGroup.getId())) return; + db.addGroup(txn, localGroup); + + // Get our own handshake public key + handshakePublicKey = identityManager.getHandshakeKeys(txn).getPublic(); + + // Set things up for any pre-existing contacts + for (Contact c : db.getContacts(txn)) addingContact(txn, c); + } + + @Override + public Group getContactGroup(Contact c) { + return contactGroupFactory.createContactGroup(CLIENT_ID, + MAJOR_VERSION, c); + } + + @Override + public Collection getMessageHeaders( + Transaction txn, ContactId contactId) throws DbException { + return null; + } + + @Override + public Set getMessageIds(Transaction txn, ContactId contactId) + throws DbException { + Contact contact = db.getContact(txn, contactId); + GroupId contactGroupId = getContactGroup(contact).getId(); + try { + Map messages = clientHelper + .getMessageMetadataAsDictionary(txn, contactGroupId); + return messages.keySet(); + } catch (FormatException e) { + throw new DbException(e); + } + } + + @Override + public void setReadFlag(GroupId g, MessageId m, boolean read) + throws DbException { + + } + + @Override + public DeletionResult deleteAllMessages(Transaction txn, ContactId c) + throws DbException { + GroupId g = getContactGroup(db.getContact(txn, c)).getId(); + for (MessageId messageId : db.getMessageIds(txn, g)) { + db.deleteMessage(txn, messageId); + db.deleteMessageMetadata(txn, messageId); + } + messageTracker.initializeGroupCount(txn, g); + return new DeletionResult(); + } + + + @Override + public DeletionResult deleteMessages(Transaction txn, ContactId c, + Set messageIds) throws DbException { + for (MessageId m : messageIds) { + db.deleteMessage(txn, m); + db.deleteMessageMetadata(txn, m); + } + return new DeletionResult(); + } + + @Override + protected boolean incomingMessage(Transaction txn, Message m, BdfList body, + BdfDictionary meta) throws DbException, FormatException { + LOG.info("Incoming HandshakeKeyExchange message"); + ContactId contactId = getContactId(txn, m.getGroupId()); + Contact c = contactManager.getContact(txn, contactId); + if (c.getHandshakePublicKey() != null) { + LOG.info("Already have public key - ignoring message"); + return false; + } + PublicKey handshakePublicKey = new AgreementPublicKey(body.getRaw(0)); + return false; + } + + private ContactId getContactId(Transaction txn, GroupId g) + throws DbException { + try { + BdfDictionary meta = + clientHelper.getGroupMetadataAsDictionary(txn, g); + return new ContactId(meta.getLong( + HandshakeKeyExchangeConstants.GROUP_KEY_CONTACT_ID).intValue()); + } catch (FormatException e) { + throw new DbException(e); + } + } + + @Override + public void addingContact(Transaction txn, Contact c) throws DbException { + // Create a group to share with the contact + Group g = getContactGroup(c); + db.addGroup(txn, g); + // Apply the client's visibility to the contact group + Group.Visibility client = + clientVersioningManager.getClientVisibility(txn, + c.getId(), CLIENT_ID, MAJOR_VERSION); + db.setGroupVisibility(txn, c.getId(), g.getId(), client); + // Attach the contact ID to the group + setContactId(txn, g.getId(), c.getId()); + + if (c.getHandshakePublicKey() == null) { + sendHandshakePublicKey(txn, c); + } + } + + private void sendHandshakePublicKey(Transaction txn, Contact c) + throws DbException { + Group group = getContactGroup(c); + GroupId g = group.getId(); + if (!db.containsGroup(txn, g)) db.addGroup(txn, group); + long timestamp = clock.currentTimeMillis(); + + BdfList bodyList = new BdfList(); + bodyList.add(handshakePublicKey); + try { + byte[] body = clientHelper.toByteArray(bodyList); + Message m = clientHelper.createMessage(g, timestamp, body); + + BdfDictionary meta = BdfDictionary.of( + new BdfEntry(MSG_KEY_LOCAL, true), + new BdfEntry(MSG_KEY_TIMESTAMP, timestamp) + ); + clientHelper.addLocalMessage(txn, m, meta, true, false); + } catch (FormatException e) { + throw new DbException(); + } + +// messageTracker.trackOutgoingMessage(txn, m); + } + + @Override + public void removingContact(Transaction txn, Contact c) throws DbException { + db.removeGroup(txn, getContactGroup(c)); + } + + private void setContactId(Transaction txn, GroupId g, ContactId c) + throws DbException { + BdfDictionary d = new BdfDictionary(); + d.put(GROUP_KEY_CONTACT_ID, c.getInt()); + try { + clientHelper.mergeGroupMetadata(txn, g, d); + } catch (FormatException e) { + throw new AssertionError(e); + } + } +} diff --git a/briar-core/src/main/java/org/briarproject/briar/handshakekeyexchange/HandshakeKeyExchangeModule.java b/briar-core/src/main/java/org/briarproject/briar/handshakekeyexchange/HandshakeKeyExchangeModule.java new file mode 100644 index 000000000..011b4a7c4 --- /dev/null +++ b/briar-core/src/main/java/org/briarproject/briar/handshakekeyexchange/HandshakeKeyExchangeModule.java @@ -0,0 +1,23 @@ +package org.briarproject.briar.handshakekeyexchange; + +import org.briarproject.briar.api.handshakekeyexchange.HandshakeKeyExchangeManager; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import dagger.Module; +import dagger.Provides; + +@Module +public class HandshakeKeyExchangeModule { + public static class EagerSingletons { + @Inject + HandshakeKeyExchangeManager handshakeKeyExchangeManager; + } + + @Provides + @Singleton + HandshakeKeyExchangeManager handshakeKeyExchangeManager(HandshakeKeyExchangeManagerImpl handshakeKeyExchangeManager) { + return handshakeKeyExchangeManager; + } +} diff --git a/briar-core/src/main/java/org/briarproject/briar/handshakekeyexchange/HandshakeKeyExchangeValidator.java b/briar-core/src/main/java/org/briarproject/briar/handshakekeyexchange/HandshakeKeyExchangeValidator.java new file mode 100644 index 000000000..a030013a2 --- /dev/null +++ b/briar-core/src/main/java/org/briarproject/briar/handshakekeyexchange/HandshakeKeyExchangeValidator.java @@ -0,0 +1,31 @@ +package org.briarproject.briar.handshakekeyexchange; + +import org.briarproject.bramble.api.FormatException; +import org.briarproject.bramble.api.client.BdfMessageContext; +import org.briarproject.bramble.api.client.BdfMessageValidator; +import org.briarproject.bramble.api.client.ClientHelper; +import org.briarproject.bramble.api.data.BdfList; +import org.briarproject.bramble.api.data.MetadataEncoder; +import org.briarproject.bramble.api.sync.Group; +import org.briarproject.bramble.api.sync.InvalidMessageException; +import org.briarproject.bramble.api.sync.Message; +import org.briarproject.bramble.api.system.Clock; + +import javax.inject.Inject; + +public class HandshakeKeyExchangeValidator extends BdfMessageValidator { + + @Inject + protected HandshakeKeyExchangeValidator( + ClientHelper clientHelper, + MetadataEncoder metadataEncoder, + Clock clock) { + super(clientHelper, metadataEncoder, clock); + } + + @Override + protected BdfMessageContext validateMessage(Message m, Group g, + BdfList body) throws InvalidMessageException, FormatException { + return null; + } +}