aboutsummaryrefslogtreecommitdiffstats
path: root/java/src/main/java/org/whispersystems/libaxolotl/groups/GroupSessionBuilder.java
diff options
context:
space:
mode:
Diffstat (limited to 'java/src/main/java/org/whispersystems/libaxolotl/groups/GroupSessionBuilder.java')
-rw-r--r--java/src/main/java/org/whispersystems/libaxolotl/groups/GroupSessionBuilder.java83
1 files changed, 72 insertions, 11 deletions
diff --git a/java/src/main/java/org/whispersystems/libaxolotl/groups/GroupSessionBuilder.java b/java/src/main/java/org/whispersystems/libaxolotl/groups/GroupSessionBuilder.java
index 8b73484b..ee02fffd 100644
--- a/java/src/main/java/org/whispersystems/libaxolotl/groups/GroupSessionBuilder.java
+++ b/java/src/main/java/org/whispersystems/libaxolotl/groups/GroupSessionBuilder.java
@@ -1,9 +1,44 @@
+/**
+ * Copyright (C) 2014-2015 Open Whisper Systems
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
package org.whispersystems.libaxolotl.groups;
-import org.whispersystems.libaxolotl.ecc.ECKeyPair;
+import org.whispersystems.libaxolotl.InvalidKeyException;
+import org.whispersystems.libaxolotl.InvalidKeyIdException;
import org.whispersystems.libaxolotl.groups.state.SenderKeyRecord;
+import org.whispersystems.libaxolotl.groups.state.SenderKeyState;
import org.whispersystems.libaxolotl.groups.state.SenderKeyStore;
import org.whispersystems.libaxolotl.protocol.SenderKeyDistributionMessage;
+import org.whispersystems.libaxolotl.util.KeyHelper;
+
+/**
+ * GroupSessionBuilder is responsible for setting up group SenderKey encrypted sessions.
+ *
+ * Once a session has been established, {@link org.whispersystems.libaxolotl.groups.GroupCipher}
+ * can be used to encrypt/decrypt messages in that session.
+ * <p>
+ * The built sessions are unidirectional: they can be used either for sending or for receiving,
+ * but not both.
+ *
+ * Sessions are constructed per (groupId + senderId + deviceId) tuple. Remote logical users
+ * are identified by their senderId, and each logical recipientId can have multiple physical
+ * devices.
+ *
+ * @author Moxie Marlinspike
+ */
public class GroupSessionBuilder {
@@ -13,26 +48,52 @@ public class GroupSessionBuilder {
this.senderKeyStore = senderKeyStore;
}
- public void process(String sender, SenderKeyDistributionMessage senderKeyDistributionMessage) {
+ /**
+ * Construct a group session for receiving messages from senderKeyName.
+ *
+ * @param senderKeyName The (groupId, senderId, deviceId) tuple associated with the SenderKeyDistributionMessage.
+ * @param senderKeyDistributionMessage A received SenderKeyDistributionMessage.
+ */
+ public void process(SenderKeyName senderKeyName, SenderKeyDistributionMessage senderKeyDistributionMessage) {
synchronized (GroupCipher.LOCK) {
- SenderKeyRecord senderKeyRecord = senderKeyStore.loadSenderKey(sender);
+ SenderKeyRecord senderKeyRecord = senderKeyStore.loadSenderKey(senderKeyName);
senderKeyRecord.addSenderKeyState(senderKeyDistributionMessage.getId(),
senderKeyDistributionMessage.getIteration(),
senderKeyDistributionMessage.getChainKey(),
senderKeyDistributionMessage.getSignatureKey());
- senderKeyStore.storeSenderKey(sender, senderKeyRecord);
+ senderKeyStore.storeSenderKey(senderKeyName, senderKeyRecord);
}
}
- public SenderKeyDistributionMessage process(String groupId, int keyId, int iteration,
- byte[] chainKey, ECKeyPair signatureKey)
- {
+ /**
+ * Construct a group session for sending messages.
+ *
+ * @param senderKeyName The (groupId, senderId, deviceId) tuple. In this case, 'senderId' should be the caller.
+ * @return A SenderKeyDistributionMessage that is individually distributed to each member of the group.
+ */
+ public SenderKeyDistributionMessage create(SenderKeyName senderKeyName) {
synchronized (GroupCipher.LOCK) {
- SenderKeyRecord senderKeyRecord = senderKeyStore.loadSenderKey(groupId);
- senderKeyRecord.setSenderKeyState(keyId, iteration, chainKey, signatureKey);
- senderKeyStore.storeSenderKey(groupId, senderKeyRecord);
+ try {
+ SenderKeyRecord senderKeyRecord = senderKeyStore.loadSenderKey(senderKeyName);
+
+ if (senderKeyRecord.isEmpty()) {
+ senderKeyRecord.setSenderKeyState(KeyHelper.generateSenderKeyId(),
+ 0,
+ KeyHelper.generateSenderKey(),
+ KeyHelper.generateSenderSigningKey());
+ senderKeyStore.storeSenderKey(senderKeyName, senderKeyRecord);
+ }
+
+ SenderKeyState state = senderKeyRecord.getSenderKeyState();
+
+ return new SenderKeyDistributionMessage(state.getKeyId(),
+ state.getSenderChainKey().getIteration(),
+ state.getSenderChainKey().getSeed(),
+ state.getSigningKeyPublic());
- return new SenderKeyDistributionMessage(keyId, iteration, chainKey, signatureKey.getPublicKey());
+ } catch (InvalidKeyIdException | InvalidKeyException e) {
+ throw new AssertionError(e);
+ }
}
}
}