Make it possible to deserialize SenderKeyDistributionMessages
This commit is contained in:
parent
aa1c41c980
commit
bf9c8708e0
|
@ -1,7 +1,12 @@
|
||||||
package org.whispersystems.libaxolotl.protocol;
|
package org.whispersystems.libaxolotl.protocol;
|
||||||
|
|
||||||
import com.google.protobuf.ByteString;
|
import com.google.protobuf.ByteString;
|
||||||
|
import com.google.protobuf.InvalidProtocolBufferException;
|
||||||
|
|
||||||
|
import org.whispersystems.libaxolotl.InvalidKeyException;
|
||||||
|
import org.whispersystems.libaxolotl.InvalidMessageException;
|
||||||
|
import org.whispersystems.libaxolotl.LegacyMessageException;
|
||||||
|
import org.whispersystems.libaxolotl.ecc.Curve;
|
||||||
import org.whispersystems.libaxolotl.ecc.ECPublicKey;
|
import org.whispersystems.libaxolotl.ecc.ECPublicKey;
|
||||||
import org.whispersystems.libaxolotl.util.ByteUtil;
|
import org.whispersystems.libaxolotl.util.ByteUtil;
|
||||||
|
|
||||||
|
@ -15,17 +20,52 @@ public class SenderKeyDistributionMessage implements CiphertextMessage {
|
||||||
|
|
||||||
public SenderKeyDistributionMessage(int id, int iteration, byte[] chainKey, ECPublicKey signatureKey) {
|
public SenderKeyDistributionMessage(int id, int iteration, byte[] chainKey, ECPublicKey signatureKey) {
|
||||||
byte[] version = {ByteUtil.intsToByteHighAndLow(CURRENT_VERSION, CURRENT_VERSION)};
|
byte[] version = {ByteUtil.intsToByteHighAndLow(CURRENT_VERSION, CURRENT_VERSION)};
|
||||||
|
byte[] protobuf = WhisperProtos.SenderKeyDistributionMessage.newBuilder()
|
||||||
this.id = id;
|
|
||||||
this.iteration = iteration;
|
|
||||||
this.chainKey = chainKey;
|
|
||||||
this.signatureKey = signatureKey;
|
|
||||||
this.serialized = WhisperProtos.SenderKeyDistributionMessage.newBuilder()
|
|
||||||
.setId(id)
|
.setId(id)
|
||||||
.setIteration(iteration)
|
.setIteration(iteration)
|
||||||
.setChainKey(ByteString.copyFrom(chainKey))
|
.setChainKey(ByteString.copyFrom(chainKey))
|
||||||
.setSigningKey(ByteString.copyFrom(signatureKey.serialize()))
|
.setSigningKey(ByteString.copyFrom(signatureKey.serialize()))
|
||||||
.build().toByteArray();
|
.build().toByteArray();
|
||||||
|
|
||||||
|
this.id = id;
|
||||||
|
this.iteration = iteration;
|
||||||
|
this.chainKey = chainKey;
|
||||||
|
this.signatureKey = signatureKey;
|
||||||
|
this.serialized = ByteUtil.combine(version, protobuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SenderKeyDistributionMessage(byte[] serialized) throws LegacyMessageException, InvalidMessageException {
|
||||||
|
try {
|
||||||
|
byte[][] messageParts = ByteUtil.split(serialized, 1, serialized.length - 1);
|
||||||
|
byte version = messageParts[0][0];
|
||||||
|
byte[] message = messageParts[1];
|
||||||
|
|
||||||
|
if (ByteUtil.highBitsToInt(version) < CiphertextMessage.CURRENT_VERSION) {
|
||||||
|
throw new LegacyMessageException("Legacy message: " + ByteUtil.highBitsToInt(version));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ByteUtil.highBitsToInt(version) > CURRENT_VERSION) {
|
||||||
|
throw new InvalidMessageException("Unknown version: " + ByteUtil.highBitsToInt(version));
|
||||||
|
}
|
||||||
|
|
||||||
|
WhisperProtos.SenderKeyDistributionMessage distributionMessage = WhisperProtos.SenderKeyDistributionMessage.parseFrom(message);
|
||||||
|
|
||||||
|
if (!distributionMessage.hasId() ||
|
||||||
|
!distributionMessage.hasIteration() ||
|
||||||
|
!distributionMessage.hasChainKey() ||
|
||||||
|
!distributionMessage.hasSigningKey())
|
||||||
|
{
|
||||||
|
throw new InvalidMessageException("Incomplete message.");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.serialized = serialized;
|
||||||
|
this.id = distributionMessage.getId();
|
||||||
|
this.iteration = distributionMessage.getIteration();
|
||||||
|
this.chainKey = distributionMessage.getChainKey().toByteArray();
|
||||||
|
this.signatureKey = Curve.decodePoint(distributionMessage.getSigningKey().toByteArray(), 0);
|
||||||
|
} catch (InvalidProtocolBufferException | InvalidKeyException e) {
|
||||||
|
throw new InvalidMessageException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -30,9 +30,9 @@ public class GroupCipherTest extends TestCase {
|
||||||
GroupCipher aliceGroupCipher = new GroupCipher(aliceStore, GROUP_SENDER);
|
GroupCipher aliceGroupCipher = new GroupCipher(aliceStore, GROUP_SENDER);
|
||||||
GroupCipher bobGroupCipher = new GroupCipher(bobStore, GROUP_SENDER);
|
GroupCipher bobGroupCipher = new GroupCipher(bobStore, GROUP_SENDER);
|
||||||
|
|
||||||
SenderKeyDistributionMessage aliceDistributionMessage = aliceSessionBuilder.create(GROUP_SENDER);
|
SenderKeyDistributionMessage sentAliceDistributionMessage = aliceSessionBuilder.create(GROUP_SENDER);
|
||||||
|
SenderKeyDistributionMessage receivedAliceDistributionMessage = new SenderKeyDistributionMessage(sentAliceDistributionMessage.serialize());
|
||||||
bobSessionBuilder.process(GROUP_SENDER, aliceDistributionMessage);
|
bobSessionBuilder.process(GROUP_SENDER, receivedAliceDistributionMessage);
|
||||||
|
|
||||||
byte[] ciphertextFromAlice = aliceGroupCipher.encrypt("smert ze smert".getBytes());
|
byte[] ciphertextFromAlice = aliceGroupCipher.encrypt("smert ze smert".getBytes());
|
||||||
byte[] plaintextFromAlice = bobGroupCipher.decrypt(ciphertextFromAlice);
|
byte[] plaintextFromAlice = bobGroupCipher.decrypt(ciphertextFromAlice);
|
||||||
|
@ -54,10 +54,12 @@ public class GroupCipherTest extends TestCase {
|
||||||
GroupCipher aliceGroupCipher = new GroupCipher(aliceStore, aliceName);
|
GroupCipher aliceGroupCipher = new GroupCipher(aliceStore, aliceName);
|
||||||
GroupCipher bobGroupCipher = new GroupCipher(bobStore, aliceName);
|
GroupCipher bobGroupCipher = new GroupCipher(bobStore, aliceName);
|
||||||
|
|
||||||
SenderKeyDistributionMessage aliceDistributionMessage =
|
SenderKeyDistributionMessage sentAliceDistributionMessage =
|
||||||
aliceSessionBuilder.create(aliceName);
|
aliceSessionBuilder.create(aliceName);
|
||||||
|
SenderKeyDistributionMessage receivedAliceDistributionMessage =
|
||||||
|
new SenderKeyDistributionMessage(sentAliceDistributionMessage.serialize());
|
||||||
|
|
||||||
bobSessionBuilder.process(aliceName, aliceDistributionMessage);
|
bobSessionBuilder.process(aliceName, receivedAliceDistributionMessage);
|
||||||
|
|
||||||
byte[] ciphertextFromAlice = aliceGroupCipher.encrypt("smert ze smert".getBytes());
|
byte[] ciphertextFromAlice = aliceGroupCipher.encrypt("smert ze smert".getBytes());
|
||||||
byte[] ciphertextFromAlice2 = aliceGroupCipher.encrypt("smert ze smert2".getBytes());
|
byte[] ciphertextFromAlice2 = aliceGroupCipher.encrypt("smert ze smert2".getBytes());
|
||||||
|
@ -80,6 +82,40 @@ public class GroupCipherTest extends TestCase {
|
||||||
assertTrue(new String(plaintextFromAlice3).equals("smert ze smert3"));
|
assertTrue(new String(plaintextFromAlice3).equals("smert ze smert3"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testLateJoin() throws NoSessionException, InvalidMessageException, LegacyMessageException, DuplicateMessageException {
|
||||||
|
InMemorySenderKeyStore aliceStore = new InMemorySenderKeyStore();
|
||||||
|
InMemorySenderKeyStore bobStore = new InMemorySenderKeyStore();
|
||||||
|
|
||||||
|
GroupSessionBuilder aliceSessionBuilder = new GroupSessionBuilder(aliceStore);
|
||||||
|
|
||||||
|
|
||||||
|
SenderKeyName aliceName = GROUP_SENDER;
|
||||||
|
|
||||||
|
GroupCipher aliceGroupCipher = new GroupCipher(aliceStore, aliceName);
|
||||||
|
|
||||||
|
|
||||||
|
SenderKeyDistributionMessage aliceDistributionMessage = aliceSessionBuilder.create(aliceName);
|
||||||
|
// Send off to some people.
|
||||||
|
|
||||||
|
for (int i=0;i<100;i++) {
|
||||||
|
aliceGroupCipher.encrypt("up the punks up the punks up the punks".getBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now Bob Joins.
|
||||||
|
GroupSessionBuilder bobSessionBuilder = new GroupSessionBuilder(bobStore);
|
||||||
|
GroupCipher bobGroupCipher = new GroupCipher(bobStore, aliceName);
|
||||||
|
|
||||||
|
|
||||||
|
SenderKeyDistributionMessage distributionMessageToBob = aliceSessionBuilder.create(aliceName);
|
||||||
|
bobSessionBuilder.process(aliceName, new SenderKeyDistributionMessage(distributionMessageToBob.serialize()));
|
||||||
|
|
||||||
|
byte[] ciphertext = aliceGroupCipher.encrypt("welcome to the group".getBytes());
|
||||||
|
byte[] plaintext = bobGroupCipher.decrypt(ciphertext);
|
||||||
|
|
||||||
|
assertEquals(new String(plaintext), "welcome to the group");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public void testOutOfOrder()
|
public void testOutOfOrder()
|
||||||
throws LegacyMessageException, DuplicateMessageException, InvalidMessageException, NoSessionException
|
throws LegacyMessageException, DuplicateMessageException, InvalidMessageException, NoSessionException
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue