diff options
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.java | 83 |
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); + } } } } |