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