org.whispersystems.libaxolotl.groups.GroupSessionBuilder Maven / Gradle / Ivy
/**
* 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 .
*/
package org.whispersystems.libaxolotl.groups;
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.
*
* 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 {
private final SenderKeyStore senderKeyStore;
public GroupSessionBuilder(SenderKeyStore senderKeyStore) {
this.senderKeyStore = senderKeyStore;
}
/**
* 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(senderKeyName);
senderKeyRecord.addSenderKeyState(senderKeyDistributionMessage.getId(),
senderKeyDistributionMessage.getIteration(),
senderKeyDistributionMessage.getChainKey(),
senderKeyDistributionMessage.getSignatureKey());
senderKeyStore.storeSenderKey(senderKeyName, senderKeyRecord);
}
}
/**
* 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) {
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());
} catch (InvalidKeyIdException | InvalidKeyException e) {
throw new AssertionError(e);
}
}
}
}