From 752f2dcf69eb1c47a58bfea3ee5afcca847ab692 Mon Sep 17 00:00:00 2001 From: Moxie Marlinspike Date: Wed, 11 Feb 2015 13:39:10 -0800 Subject: [PATCH] Update GroupSessionBuilder and GroupSessionCipher interfaces. --- .../libaxolotl/groups/GroupCipher.java | 46 +++++++++- .../groups/GroupSessionBuilder.java | 83 ++++++++++++++++--- .../libaxolotl/groups/SenderKeyName.java | 68 +++++++++++++++ .../groups/ratchet/SenderChainKey.java | 26 ++++++ .../groups/ratchet/SenderMessageKey.java | 23 +++++ .../groups/state/SenderKeyRecord.java | 26 ++++++ .../groups/state/SenderKeyState.java | 21 +++++ .../groups/state/SenderKeyStore.java | 46 +++++++++- .../libaxolotl/groups/GroupCipherTest.java | 44 ++++------ .../groups/InMemorySenderKeyStore.java | 10 +-- 10 files changed, 344 insertions(+), 49 deletions(-) create mode 100644 java/src/main/java/org/whispersystems/libaxolotl/groups/SenderKeyName.java diff --git a/java/src/main/java/org/whispersystems/libaxolotl/groups/GroupCipher.java b/java/src/main/java/org/whispersystems/libaxolotl/groups/GroupCipher.java index 43dac752e..778ca916a 100644 --- a/java/src/main/java/org/whispersystems/libaxolotl/groups/GroupCipher.java +++ b/java/src/main/java/org/whispersystems/libaxolotl/groups/GroupCipher.java @@ -1,3 +1,19 @@ +/** + * 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.DuplicateMessageException; @@ -22,18 +38,35 @@ import javax.crypto.NoSuchPaddingException; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; +/** + * The main entry point for axolotl group encrypt/decrypt operations. + * + * Once a session has been established with {@link org.whispersystems.libaxolotl.groups.GroupSessionBuilder} + * and a {@link org.whispersystems.libaxolotl.protocol.SenderKeyDistributionMessage} has been + * distributed to each member of the group, this class can be used for all subsequent encrypt/decrypt + * operations within that session (ie: until group membership changes). + * + * @author Moxie Marlinspike + */ public class GroupCipher { static final Object LOCK = new Object(); private final SenderKeyStore senderKeyStore; - private final String senderKeyId; + private final SenderKeyName senderKeyId; - public GroupCipher(SenderKeyStore senderKeyStore, String senderKeyId) { + public GroupCipher(SenderKeyStore senderKeyStore, SenderKeyName senderKeyId) { this.senderKeyStore = senderKeyStore; this.senderKeyId = senderKeyId; } + /** + * Encrypt a message. + * + * @param paddedPlaintext The plaintext message bytes, optionally padded. + * @return Ciphertext. + * @throws NoSessionException + */ public byte[] encrypt(byte[] paddedPlaintext) throws NoSessionException { synchronized (LOCK) { try { @@ -58,6 +91,15 @@ public class GroupCipher { } } + /** + * Decrypt a SenderKey group message. + * + * @param senderKeyMessageBytes The received ciphertext. + * @return Plaintext + * @throws LegacyMessageException + * @throws InvalidMessageException + * @throws DuplicateMessageException + */ public byte[] decrypt(byte[] senderKeyMessageBytes) throws LegacyMessageException, InvalidMessageException, DuplicateMessageException { 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 8b73484b2..ee02fffd4 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 . + */ 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. + *

+ * 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); - return new SenderKeyDistributionMessage(keyId, iteration, chainKey, signatureKey.getPublicKey()); + 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); + } } } } diff --git a/java/src/main/java/org/whispersystems/libaxolotl/groups/SenderKeyName.java b/java/src/main/java/org/whispersystems/libaxolotl/groups/SenderKeyName.java new file mode 100644 index 000000000..ce4325ffa --- /dev/null +++ b/java/src/main/java/org/whispersystems/libaxolotl/groups/SenderKeyName.java @@ -0,0 +1,68 @@ +/** + * 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; + +/** + * A representation of a (groupId + senderId + deviceId) tuple. + */ +public class SenderKeyName { + + private final String groupId; + private final long senderId; + private final int deviceId; + + public SenderKeyName(String groupId, long senderId, int deviceId) { + this.groupId = groupId; + this.senderId = senderId; + this.deviceId = deviceId; + } + + public String getGroupId() { + return groupId; + } + + public long getSenderId() { + return senderId; + } + + public int getDeviceId() { + return deviceId; + } + + public String serialize() { + return groupId + "::" + String.valueOf(senderId) + "::" + String.valueOf(deviceId); + } + + @Override + public boolean equals(Object other) { + if (other == null) return false; + if (!(other instanceof SenderKeyName)) return false; + + SenderKeyName that = (SenderKeyName)other; + + return + this.groupId.equals(that.groupId) && + this.senderId == that.senderId && + this.deviceId == that.deviceId; + } + + @Override + public int hashCode() { + return this.groupId.hashCode() ^ (int)this.senderId ^ this.deviceId; + } + +} diff --git a/java/src/main/java/org/whispersystems/libaxolotl/groups/ratchet/SenderChainKey.java b/java/src/main/java/org/whispersystems/libaxolotl/groups/ratchet/SenderChainKey.java index 71375923b..304c4667b 100644 --- a/java/src/main/java/org/whispersystems/libaxolotl/groups/ratchet/SenderChainKey.java +++ b/java/src/main/java/org/whispersystems/libaxolotl/groups/ratchet/SenderChainKey.java @@ -1,3 +1,19 @@ +/** + * 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.ratchet; import java.security.InvalidKeyException; @@ -6,6 +22,16 @@ import java.security.NoSuchAlgorithmException; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; +/** + * Each SenderKey is a "chain" of keys, each derived from the previous. + * + * At any given point in time, the state of a SenderKey can be represented + * as the current chain key value, along with its iteration count. From there, + * subsequent iterations can be derived, as well as individual message keys from + * each chain key. + * + * @author Moxie Marlinspike + */ public class SenderChainKey { private static final byte[] MESSAGE_KEY_SEED = {0x01}; diff --git a/java/src/main/java/org/whispersystems/libaxolotl/groups/ratchet/SenderMessageKey.java b/java/src/main/java/org/whispersystems/libaxolotl/groups/ratchet/SenderMessageKey.java index 8808a8e8f..cdee444db 100644 --- a/java/src/main/java/org/whispersystems/libaxolotl/groups/ratchet/SenderMessageKey.java +++ b/java/src/main/java/org/whispersystems/libaxolotl/groups/ratchet/SenderMessageKey.java @@ -1,8 +1,31 @@ +/** + * 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.ratchet; import org.whispersystems.libaxolotl.kdf.HKDFv3; import org.whispersystems.libaxolotl.util.ByteUtil; +/** + * The final symmetric material (IV and Cipher Key) used for encrypting + * individual SenderKey messages. + * + * @author Moxie Marlinspike + */ public class SenderMessageKey { private final int iteration; diff --git a/java/src/main/java/org/whispersystems/libaxolotl/groups/state/SenderKeyRecord.java b/java/src/main/java/org/whispersystems/libaxolotl/groups/state/SenderKeyRecord.java index bb1ba952a..f023b10f8 100644 --- a/java/src/main/java/org/whispersystems/libaxolotl/groups/state/SenderKeyRecord.java +++ b/java/src/main/java/org/whispersystems/libaxolotl/groups/state/SenderKeyRecord.java @@ -1,3 +1,19 @@ +/** + * 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.state; import org.whispersystems.libaxolotl.InvalidKeyIdException; @@ -11,6 +27,12 @@ import java.util.List; import static org.whispersystems.libaxolotl.state.StorageProtos.SenderKeyRecordStructure; +/** + * A durable representation of a set of SenderKeyStates for a specific + * SenderKeyName. + * + * @author Moxie Marlisnpike + */ public class SenderKeyRecord { private List senderKeyStates = new LinkedList<>(); @@ -25,6 +47,10 @@ public class SenderKeyRecord { } } + public boolean isEmpty() { + return senderKeyStates.isEmpty(); + } + public SenderKeyState getSenderKeyState() throws InvalidKeyIdException { if (!senderKeyStates.isEmpty()) { return senderKeyStates.get(0); diff --git a/java/src/main/java/org/whispersystems/libaxolotl/groups/state/SenderKeyState.java b/java/src/main/java/org/whispersystems/libaxolotl/groups/state/SenderKeyState.java index 80498ce0b..0b0f9a637 100644 --- a/java/src/main/java/org/whispersystems/libaxolotl/groups/state/SenderKeyState.java +++ b/java/src/main/java/org/whispersystems/libaxolotl/groups/state/SenderKeyState.java @@ -1,3 +1,19 @@ +/** + * 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.state; import com.google.protobuf.ByteString; @@ -17,6 +33,11 @@ import java.util.List; import static org.whispersystems.libaxolotl.state.StorageProtos.SenderKeyStateStructure; +/** + * Represents the state of an individual SenderKey ratchet. + * + * @author Moxie Marlinspike + */ public class SenderKeyState { private SenderKeyStateStructure senderKeyStateStructure; diff --git a/java/src/main/java/org/whispersystems/libaxolotl/groups/state/SenderKeyStore.java b/java/src/main/java/org/whispersystems/libaxolotl/groups/state/SenderKeyStore.java index da01b1f3d..42afb6282 100644 --- a/java/src/main/java/org/whispersystems/libaxolotl/groups/state/SenderKeyStore.java +++ b/java/src/main/java/org/whispersystems/libaxolotl/groups/state/SenderKeyStore.java @@ -1,6 +1,48 @@ +/** + * 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.state; +import org.whispersystems.libaxolotl.groups.SenderKeyName; + public interface SenderKeyStore { - public void storeSenderKey(String senderKeyId, SenderKeyRecord record); - public SenderKeyRecord loadSenderKey(String senderKeyId); + + /** + * Commit to storage the {@link org.whispersystems.libaxolotl.groups.state.SenderKeyRecord} for a + * given (groupId + senderId + deviceId) tuple. + * + * @param senderKeyName the (groupId + senderId + deviceId) tuple. + * @param record the current SenderKeyRecord for the specified senderKeyName. + */ + public void storeSenderKey(SenderKeyName senderKeyName, SenderKeyRecord record); + + /** + * Returns a copy of the {@link org.whispersystems.libaxolotl.groups.state.SenderKeyRecord} + * corresponding to the (groupId + senderId + deviceId) tuple, or a new SenderKeyRecord if + * one does not currently exist. + *

+ * It is important that implementations return a copy of the current durable information. The + * returned SenderKeyRecord may be modified, but those changes should not have an effect on the + * durable session state (what is returned by subsequent calls to this method) without the + * store method being called here first. + * + * @param senderKeyName The (groupId + senderId + deviceId) tuple. + * @return a copy of the SenderKeyRecord corresponding to the (groupId + senderId + deviceId tuple, or + * a new SenderKeyRecord if one does not currently exist. + */ + + public SenderKeyRecord loadSenderKey(SenderKeyName senderKeyName); } diff --git a/tests/src/test/java/org/whispersystems/libaxolotl/groups/GroupCipherTest.java b/tests/src/test/java/org/whispersystems/libaxolotl/groups/GroupCipherTest.java index 7c9892b02..b41adb58a 100644 --- a/tests/src/test/java/org/whispersystems/libaxolotl/groups/GroupCipherTest.java +++ b/tests/src/test/java/org/whispersystems/libaxolotl/groups/GroupCipherTest.java @@ -6,9 +6,7 @@ import org.whispersystems.libaxolotl.DuplicateMessageException; import org.whispersystems.libaxolotl.InvalidMessageException; import org.whispersystems.libaxolotl.LegacyMessageException; import org.whispersystems.libaxolotl.NoSessionException; -import org.whispersystems.libaxolotl.ecc.ECKeyPair; import org.whispersystems.libaxolotl.protocol.SenderKeyDistributionMessage; -import org.whispersystems.libaxolotl.util.KeyHelper; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; @@ -25,18 +23,13 @@ public class GroupCipherTest extends TestCase { GroupSessionBuilder aliceSessionBuilder = new GroupSessionBuilder(aliceStore); GroupSessionBuilder bobSessionBuilder = new GroupSessionBuilder(bobStore); - GroupCipher aliceGroupCipher = new GroupCipher(aliceStore, "groupWithBobInIt"); - GroupCipher bobGroupCipher = new GroupCipher(bobStore, "groupWithBobInIt::aliceUserName"); - - byte[] aliceSenderKey = KeyHelper.generateSenderKey(); - ECKeyPair aliceSenderSigningKey = KeyHelper.generateSenderSigningKey(); - int aliceSenderKeyId = KeyHelper.generateSenderKeyId(); + GroupCipher aliceGroupCipher = new GroupCipher(aliceStore, new SenderKeyName("cool group", 1111, 0)); + GroupCipher bobGroupCipher = new GroupCipher(bobStore, new SenderKeyName("cool group", 1111, 0)); SenderKeyDistributionMessage aliceDistributionMessage = - aliceSessionBuilder.process("groupWithBobInIt", aliceSenderKeyId, 0, - aliceSenderKey, aliceSenderSigningKey); + aliceSessionBuilder.create(new SenderKeyName("cool group", 1111, 0)); - bobSessionBuilder.process("groupWithBobInIt::aliceUserName", aliceDistributionMessage); + bobSessionBuilder.process(new SenderKeyName("cool group", 1111, 0), aliceDistributionMessage); byte[] ciphertextFromAlice = aliceGroupCipher.encrypt("smert ze smert".getBytes()); byte[] plaintextFromAlice = bobGroupCipher.decrypt(ciphertextFromAlice); @@ -53,18 +46,15 @@ public class GroupCipherTest extends TestCase { GroupSessionBuilder aliceSessionBuilder = new GroupSessionBuilder(aliceStore); GroupSessionBuilder bobSessionBuilder = new GroupSessionBuilder(bobStore); - GroupCipher aliceGroupCipher = new GroupCipher(aliceStore, "groupWithBobInIt"); - GroupCipher bobGroupCipher = new GroupCipher(bobStore, "groupWithBobInIt::aliceUserName"); + SenderKeyName aliceName = new SenderKeyName("cool group", 1111, 0); - byte[] aliceSenderKey = KeyHelper.generateSenderKey(); - ECKeyPair aliceSenderSigningKey = KeyHelper.generateSenderSigningKey(); - int aliceSenderKeyId = KeyHelper.generateSenderKeyId(); + GroupCipher aliceGroupCipher = new GroupCipher(aliceStore, aliceName); + GroupCipher bobGroupCipher = new GroupCipher(bobStore, aliceName); SenderKeyDistributionMessage aliceDistributionMessage = - aliceSessionBuilder.process("groupWithBobInIt", aliceSenderKeyId, 0, - aliceSenderKey, aliceSenderSigningKey); + aliceSessionBuilder.create(aliceName); - bobSessionBuilder.process("groupWithBobInIt::aliceUserName", aliceDistributionMessage); + bobSessionBuilder.process(aliceName, aliceDistributionMessage); byte[] ciphertextFromAlice = aliceGroupCipher.encrypt("smert ze smert".getBytes()); byte[] ciphertextFromAlice2 = aliceGroupCipher.encrypt("smert ze smert2".getBytes()); @@ -96,19 +86,15 @@ public class GroupCipherTest extends TestCase { GroupSessionBuilder aliceSessionBuilder = new GroupSessionBuilder(aliceStore); GroupSessionBuilder bobSessionBuilder = new GroupSessionBuilder(bobStore); - GroupCipher aliceGroupCipher = new GroupCipher(aliceStore, "groupWithBobInIt"); - GroupCipher bobGroupCipher = new GroupCipher(bobStore, "groupWithBobInIt::aliceUserName"); + SenderKeyName aliceName = new SenderKeyName("cool group", 1111, 0); - byte[] aliceSenderKey = KeyHelper.generateSenderKey(); - ECKeyPair aliceSenderSigningKey = KeyHelper.generateSenderSigningKey(); - int aliceSenderKeyId = KeyHelper.generateSenderKeyId(); + GroupCipher aliceGroupCipher = new GroupCipher(aliceStore, aliceName); + GroupCipher bobGroupCipher = new GroupCipher(bobStore, aliceName); SenderKeyDistributionMessage aliceDistributionMessage = - aliceSessionBuilder.process("groupWithBobInIt", aliceSenderKeyId, 0, - aliceSenderKey, aliceSenderSigningKey); - - bobSessionBuilder.process("groupWithBobInIt::aliceUserName", aliceDistributionMessage); + aliceSessionBuilder.create(aliceName); + bobSessionBuilder.process(aliceName, aliceDistributionMessage); ArrayList ciphertexts = new ArrayList<>(100); @@ -127,7 +113,7 @@ public class GroupCipherTest extends TestCase { public void testEncryptNoSession() { InMemorySenderKeyStore aliceStore = new InMemorySenderKeyStore(); - GroupCipher aliceGroupCipher = new GroupCipher(aliceStore, "groupWithBobInIt"); + GroupCipher aliceGroupCipher = new GroupCipher(aliceStore, new SenderKeyName("coolio groupio", 1111, 0)); try { aliceGroupCipher.encrypt("up the punks".getBytes()); throw new AssertionError("Should have failed!"); diff --git a/tests/src/test/java/org/whispersystems/libaxolotl/groups/InMemorySenderKeyStore.java b/tests/src/test/java/org/whispersystems/libaxolotl/groups/InMemorySenderKeyStore.java index c012566a1..fe4453987 100644 --- a/tests/src/test/java/org/whispersystems/libaxolotl/groups/InMemorySenderKeyStore.java +++ b/tests/src/test/java/org/whispersystems/libaxolotl/groups/InMemorySenderKeyStore.java @@ -9,17 +9,17 @@ import java.util.Map; public class InMemorySenderKeyStore implements SenderKeyStore { - private final Map store = new HashMap<>(); + private final Map store = new HashMap<>(); @Override - public void storeSenderKey(String senderKeyId, SenderKeyRecord record) { - store.put(senderKeyId, record); + public void storeSenderKey(SenderKeyName senderKeyName, SenderKeyRecord record) { + store.put(senderKeyName, record); } @Override - public SenderKeyRecord loadSenderKey(String senderKeyId) { + public SenderKeyRecord loadSenderKey(SenderKeyName senderKeyName) { try { - SenderKeyRecord record = store.get(senderKeyId); + SenderKeyRecord record = store.get(senderKeyName); if (record == null) { return new SenderKeyRecord();