diff --git a/libaxolotl/protobuf/WhisperTextProtocol.proto b/libaxolotl/protobuf/WhisperTextProtocol.proto
index cc278ea748..68435211a7 100644
--- a/libaxolotl/protobuf/WhisperTextProtocol.proto
+++ b/libaxolotl/protobuf/WhisperTextProtocol.proto
@@ -21,8 +21,10 @@ message PreKeyWhisperMessage {
}
message KeyExchangeMessage {
- optional uint32 id = 1;
- optional bytes baseKey = 2;
- optional bytes ephemeralKey = 3;
- optional bytes identityKey = 4;
+ optional uint32 id = 1;
+ optional bytes baseKey = 2;
+ optional bytes ephemeralKey = 3;
+ optional bytes identityKey = 4;
+ optional bytes baseKeySignature = 5;
+ optional bytes verification = 6;
}
\ No newline at end of file
diff --git a/libaxolotl/src/androidTest/java/org/whispersystems/test/SessionBuilderTest.java b/libaxolotl/src/androidTest/java/org/whispersystems/test/SessionBuilderTest.java
index cb00031667..ac5de16646 100644
--- a/libaxolotl/src/androidTest/java/org/whispersystems/test/SessionBuilderTest.java
+++ b/libaxolotl/src/androidTest/java/org/whispersystems/test/SessionBuilderTest.java
@@ -501,7 +501,7 @@ public class SessionBuilderTest extends AndroidTestCase {
}
- public void testBasicKeyExchange() throws InvalidKeyException, LegacyMessageException, InvalidMessageException, DuplicateMessageException, UntrustedIdentityException, StaleKeyExchangeException {
+ public void testBasicKeyExchange() throws InvalidKeyException, LegacyMessageException, InvalidMessageException, DuplicateMessageException, UntrustedIdentityException, StaleKeyExchangeException, InvalidVersionException {
SessionStore aliceSessionStore = new InMemorySessionStore();
PreKeyStore alicePreKeyStore = new InMemoryPreKeyStore();
DeviceKeyStore aliceDeviceKeyStore = new InMemoryDeviceKeyStore();
@@ -520,13 +520,16 @@ public class SessionBuilderTest extends AndroidTestCase {
bobIdentityKeyStore,
ALICE_RECIPIENT_ID, 1);
- KeyExchangeMessage aliceKeyExchangeMessage = aliceSessionBuilder.process();
- KeyExchangeMessage bobKeyExchangeMessage = bobSessionBuilder.process(aliceKeyExchangeMessage);
-
- assertTrue(bobKeyExchangeMessage != null);
+ KeyExchangeMessage aliceKeyExchangeMessage = aliceSessionBuilder.process();
assertTrue(aliceKeyExchangeMessage != null);
- KeyExchangeMessage response = aliceSessionBuilder.process(bobKeyExchangeMessage);
+ byte[] aliceKeyExchangeMessageBytes = aliceKeyExchangeMessage.serialize();
+ KeyExchangeMessage bobKeyExchangeMessage = bobSessionBuilder.process(new KeyExchangeMessage(aliceKeyExchangeMessageBytes));
+
+ assertTrue(bobKeyExchangeMessage != null);
+
+ byte[] bobKeyExchangeMessageBytes = bobKeyExchangeMessage.serialize();
+ KeyExchangeMessage response = aliceSessionBuilder.process(new KeyExchangeMessage(bobKeyExchangeMessageBytes));
assertTrue(response == null);
assertTrue(aliceSessionStore.containsSession(BOB_RECIPIENT_ID, 1));
diff --git a/libaxolotl/src/main/java/org/whispersystems/libaxolotl/SessionBuilder.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/SessionBuilder.java
index e0de65519e..9241a42758 100644
--- a/libaxolotl/src/main/java/org/whispersystems/libaxolotl/SessionBuilder.java
+++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/SessionBuilder.java
@@ -5,10 +5,10 @@ import android.util.Log;
import org.whispersystems.libaxolotl.ecc.Curve;
import org.whispersystems.libaxolotl.ecc.ECKeyPair;
import org.whispersystems.libaxolotl.ecc.ECPublicKey;
+import org.whispersystems.libaxolotl.protocol.CiphertextMessage;
import org.whispersystems.libaxolotl.protocol.KeyExchangeMessage;
import org.whispersystems.libaxolotl.protocol.PreKeyWhisperMessage;
import org.whispersystems.libaxolotl.ratchet.RatchetingSession;
-import org.whispersystems.libaxolotl.state.DeviceKeyRecord;
import org.whispersystems.libaxolotl.state.DeviceKeyStore;
import org.whispersystems.libaxolotl.state.IdentityKeyStore;
import org.whispersystems.libaxolotl.state.PreKeyBundle;
@@ -149,7 +149,6 @@ public class SessionBuilder {
sessionRecord.getSessionState().setLocalRegistrationId(identityKeyStore.getLocalRegistrationId());
sessionRecord.getSessionState().setRemoteRegistrationId(message.getRegistrationId());
sessionRecord.getSessionState().setAliceBaseKey(theirBaseKey.serialize());
- sessionRecord.getSessionState().setSessionVersion(message.getMessageVersion());
if (simultaneousInitiate) sessionRecord.getSessionState().setNeedsRefresh(true);
@@ -197,7 +196,6 @@ public class SessionBuilder {
sessionRecord.getSessionState().setLocalRegistrationId(identityKeyStore.getLocalRegistrationId());
sessionRecord.getSessionState().setRemoteRegistrationId(message.getRegistrationId());
- sessionRecord.getSessionState().setSessionVersion(message.getMessageVersion());
if (simultaneousInitiate) sessionRecord.getSessionState().setNeedsRefresh(true);
@@ -277,31 +275,71 @@ public class SessionBuilder {
}
KeyExchangeMessage responseMessage = null;
- SessionRecord sessionRecord = sessionStore.loadSession(recipientId, deviceId);
- Log.w(TAG, "Received key exchange with sequence: " + message.getSequence());
+ if (message.isInitiate()) responseMessage = processInitiate(message);
+ else processResponse(message);
- if (message.isInitiate()) {
- Log.w(TAG, "KeyExchange is an initiate.");
- responseMessage = processInitiate(sessionRecord, message);
+ return responseMessage;
+ }
+
+ private KeyExchangeMessage processInitiate(KeyExchangeMessage message) throws InvalidKeyException {
+ ECKeyPair ourBaseKey, ourEphemeralKey;
+ IdentityKeyPair ourIdentityKey;
+
+ int flags = KeyExchangeMessage.RESPONSE_FLAG;
+ SessionRecord sessionRecord = sessionStore.loadSession(recipientId, deviceId);
+
+ if (message.getVersion() >= 3 &&
+ !Curve.verifySignature(message.getIdentityKey().getPublicKey(),
+ message.getBaseKey().serialize(),
+ message.getBaseKeySignature()))
+ {
+ throw new InvalidKeyException("Bad signature!");
}
- if (message.isResponse()) {
- SessionState sessionState = sessionRecord.getSessionState();
- boolean hasPendingKeyExchange = sessionState.hasPendingKeyExchange();
- boolean isSimultaneousInitiateResponse = message.isResponseForSimultaneousInitiate();
-
- if ((!hasPendingKeyExchange || sessionState.getPendingKeyExchangeSequence() != message.getSequence()) &&
- !isSimultaneousInitiateResponse)
- {
- throw new StaleKeyExchangeException();
- }
+ if (!sessionRecord.getSessionState().hasPendingKeyExchange()) {
+ Log.w(TAG, "We don't have a pending initiate...");
+ ourBaseKey = Curve.generateKeyPair(true);
+ ourEphemeralKey = Curve.generateKeyPair(true);
+ ourIdentityKey = identityKeyStore.getIdentityKeyPair();
+ } else {
+ Log.w(TAG, "We already have a pending initiate, responding as simultaneous initiate...");
+ ourBaseKey = sessionRecord.getSessionState().getPendingKeyExchangeBaseKey();
+ ourEphemeralKey = sessionRecord.getSessionState().getPendingKeyExchangeEphemeralKey();
+ ourIdentityKey = sessionRecord.getSessionState().getPendingKeyExchangeIdentityKey();
+ flags |= KeyExchangeMessage.SIMULTAENOUS_INITIATE_FLAG;
}
- if (message.getSequence() != sessionRecord.getSessionState().getPendingKeyExchangeSequence()) {
- Log.w("KeyExchangeProcessor", "No matching sequence for response. " +
- "Is simultaneous initiate response: " + message.isResponseForSimultaneousInitiate());
- return responseMessage;
+ sessionRecord.reset();
+
+ RatchetingSession.initializeSession(sessionRecord.getSessionState(),
+ Math.min(message.getMaxVersion(), CiphertextMessage.CURRENT_VERSION),
+ ourBaseKey, message.getBaseKey(),
+ ourEphemeralKey, message.getEphemeralKey(),
+ ourBaseKey, message.getBaseKey(),
+ ourIdentityKey, message.getIdentityKey());
+
+ sessionStore.storeSession(recipientId, deviceId, sessionRecord);
+ identityKeyStore.saveIdentity(recipientId, message.getIdentityKey());
+
+ return new KeyExchangeMessage(sessionRecord.getSessionState().getSessionVersion(),
+ message.getSequence(), flags, ourBaseKey.getPublicKey(), null,
+ ourEphemeralKey.getPublicKey(), ourIdentityKey.getPublicKey(),
+ sessionRecord.getSessionState().getVerification());
+ }
+
+ private void processResponse(KeyExchangeMessage message)
+ throws StaleKeyExchangeException, InvalidKeyException
+ {
+ SessionRecord sessionRecord = sessionStore.loadSession(recipientId, deviceId);
+ SessionState sessionState = sessionRecord.getSessionState();
+ boolean hasPendingKeyExchange = sessionState.hasPendingKeyExchange();
+ boolean isSimultaneousInitiateResponse = message.isResponseForSimultaneousInitiate();
+
+ if (!hasPendingKeyExchange || sessionState.getPendingKeyExchangeSequence() != message.getSequence()) {
+ Log.w(TAG, "No matching sequence for response. Is simultaneous initiate response: " + isSimultaneousInitiateResponse);
+ if (!isSimultaneousInitiateResponse) throw new StaleKeyExchangeException();
+ else return;
}
ECKeyPair ourBaseKey = sessionRecord.getSessionState().getPendingKeyExchangeBaseKey();
@@ -311,51 +349,22 @@ public class SessionBuilder {
sessionRecord.reset();
RatchetingSession.initializeSession(sessionRecord.getSessionState(),
- 2,
+ Math.min(message.getMaxVersion(), CiphertextMessage.CURRENT_VERSION),
ourBaseKey, message.getBaseKey(),
ourEphemeralKey, message.getEphemeralKey(),
- null, null,
+ ourBaseKey, message.getBaseKey(),
ourIdentityKey, message.getIdentityKey());
- sessionRecord.getSessionState().setSessionVersion(message.getVersion());
- sessionStore.storeSession(recipientId, deviceId, sessionRecord);
-
- identityKeyStore.saveIdentity(recipientId, message.getIdentityKey());
-
- return responseMessage;
- }
-
- private KeyExchangeMessage processInitiate(SessionRecord sessionRecord, KeyExchangeMessage message)
- throws InvalidKeyException
- {
- ECKeyPair ourBaseKey, ourEphemeralKey;
- IdentityKeyPair ourIdentityKey;
-
- int flags = KeyExchangeMessage.RESPONSE_FLAG;
-
- if (!sessionRecord.getSessionState().hasPendingKeyExchange()) {
- Log.w(TAG, "We don't have a pending initiate...");
- ourBaseKey = Curve.generateKeyPair(true);
- ourEphemeralKey = Curve.generateKeyPair(true);
- ourIdentityKey = identityKeyStore.getIdentityKeyPair();
-
- sessionRecord.getSessionState().setPendingKeyExchange(message.getSequence(), ourBaseKey,
- ourEphemeralKey, ourIdentityKey);
- } else {
- Log.w(TAG, "We already have a pending initiate, responding as simultaneous initiate...");
- ourBaseKey = sessionRecord.getSessionState().getPendingKeyExchangeBaseKey();
- ourEphemeralKey = sessionRecord.getSessionState().getPendingKeyExchangeEphemeralKey();
- ourIdentityKey = sessionRecord.getSessionState().getPendingKeyExchangeIdentityKey();
- flags |= KeyExchangeMessage.SIMULTAENOUS_INITIATE_FLAG;
-
- sessionRecord.getSessionState().setPendingKeyExchange(message.getSequence(), ourBaseKey,
- ourEphemeralKey, ourIdentityKey);
+ if (sessionRecord.getSessionState().getSessionVersion() >= 3 &&
+ !MessageDigest.isEqual(message.getVerificationTag(),
+ sessionRecord.getSessionState().getVerification()))
+ {
+ throw new InvalidKeyException("Verification tag doesn't match!");
}
- return new KeyExchangeMessage(message.getSequence(),
- flags, ourBaseKey.getPublicKey(),
- ourEphemeralKey.getPublicKey(),
- ourIdentityKey.getPublicKey());
+ sessionStore.storeSession(recipientId, deviceId, sessionRecord);
+ identityKeyStore.saveIdentity(recipientId, message.getIdentityKey());
+
}
/**
@@ -374,10 +383,10 @@ public class SessionBuilder {
sessionRecord.getSessionState().setPendingKeyExchange(sequence, baseKey, ephemeralKey, identityKey);
sessionStore.storeSession(recipientId, deviceId, sessionRecord);
- return new KeyExchangeMessage(sequence, flags,
- baseKey.getPublicKey(),
+ return new KeyExchangeMessage(2, sequence, flags,
+ baseKey.getPublicKey(), null,
ephemeralKey.getPublicKey(),
- identityKey.getPublicKey());
+ identityKey.getPublicKey(), null);
}
diff --git a/libaxolotl/src/main/java/org/whispersystems/libaxolotl/protocol/KeyExchangeMessage.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/protocol/KeyExchangeMessage.java
index 561664fccb..97babda5f3 100644
--- a/libaxolotl/src/main/java/org/whispersystems/libaxolotl/protocol/KeyExchangeMessage.java
+++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/protocol/KeyExchangeMessage.java
@@ -14,6 +14,8 @@ import org.whispersystems.libaxolotl.util.ByteUtil;
import java.io.IOException;
+import static org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage.Builder;
+
public class KeyExchangeMessage {
public static final int INITIATE_FLAG = 0x01;
@@ -26,31 +28,43 @@ public class KeyExchangeMessage {
private final int flags;
private final ECPublicKey baseKey;
+ private final byte[] baseKeySignature;
private final ECPublicKey ephemeralKey;
private final IdentityKey identityKey;
+ private final byte[] verificationTag;
private final byte[] serialized;
- public KeyExchangeMessage(int sequence, int flags,
- ECPublicKey baseKey, ECPublicKey ephemeralKey,
- IdentityKey identityKey)
+ public KeyExchangeMessage(int messageVersion, int sequence, int flags,
+ ECPublicKey baseKey, byte[] baseKeySignature,
+ ECPublicKey ephemeralKey,
+ IdentityKey identityKey, byte[] verificationTag)
{
- this.supportedVersion = 2;
- this.version = 2;
+ this.supportedVersion = CiphertextMessage.CURRENT_VERSION;
+ this.version = messageVersion;
this.sequence = sequence;
this.flags = flags;
this.baseKey = baseKey;
+ this.baseKeySignature = baseKeySignature;
this.ephemeralKey = ephemeralKey;
this.identityKey = identityKey;
+ this.verificationTag = verificationTag;
- byte[] version = {ByteUtil.intsToByteHighAndLow(this.version, this.supportedVersion)};
- byte[] message = WhisperProtos.KeyExchangeMessage.newBuilder()
- .setId((sequence << 5) | flags)
- .setBaseKey(ByteString.copyFrom(baseKey.serialize()))
- .setEphemeralKey(ByteString.copyFrom(ephemeralKey.serialize()))
- .setIdentityKey(ByteString.copyFrom(identityKey.serialize()))
- .build().toByteArray();
+ byte[] version = {ByteUtil.intsToByteHighAndLow(this.version, this.supportedVersion)};
+ Builder builder = WhisperProtos.KeyExchangeMessage.newBuilder()
+ .setId((sequence << 5) | flags)
+ .setBaseKey(ByteString.copyFrom(baseKey.serialize()))
+ .setEphemeralKey(ByteString.copyFrom(ephemeralKey.serialize()))
+ .setIdentityKey(ByteString.copyFrom(identityKey.serialize()));
- this.serialized = ByteUtil.combine(version, message);
+ if (messageVersion >= 3 && baseKeySignature != null) {
+ builder.setBaseKeySignature(ByteString.copyFrom(baseKeySignature));
+ }
+
+ if (messageVersion >=3 && verificationTag != null) {
+ builder.setVerification(ByteString.copyFrom(verificationTag));
+ }
+
+ this.serialized = ByteUtil.combine(version, builder.build().toByteArray());
}
public KeyExchangeMessage(byte[] serialized)
@@ -71,18 +85,22 @@ public class KeyExchangeMessage {
WhisperProtos.KeyExchangeMessage message = WhisperProtos.KeyExchangeMessage.parseFrom(parts[1]);
- if (!message.hasId() || !message.hasBaseKey() ||
- !message.hasEphemeralKey() || !message.hasIdentityKey())
+ if (!message.hasId() || !message.hasBaseKey() ||
+ !message.hasEphemeralKey() || !message.hasIdentityKey() ||
+ (this.version >=3 && (((message.getId() & 0x1f) & INITIATE_FLAG) != 0) && !message.hasBaseKeySignature()) ||
+ (this.version >=3 && (((message.getId() & 0x1f) & RESPONSE_FLAG) != 0) && !message.hasVerification()))
{
throw new InvalidMessageException("Some required fields missing!");
}
- this.sequence = message.getId() >> 5;
- this.flags = message.getId() & 0x1f;
- this.serialized = serialized;
- this.baseKey = Curve.decodePoint(message.getBaseKey().toByteArray(), 0);
- this.ephemeralKey = Curve.decodePoint(message.getEphemeralKey().toByteArray(), 0);
- this.identityKey = new IdentityKey(message.getIdentityKey().toByteArray(), 0);
+ this.sequence = message.getId() >> 5;
+ this.flags = message.getId() & 0x1f;
+ this.serialized = serialized;
+ this.baseKey = Curve.decodePoint(message.getBaseKey().toByteArray(), 0);
+ this.baseKeySignature = message.getBaseKeySignature().toByteArray();
+ this.verificationTag = message.getVerification().toByteArray();
+ this.ephemeralKey = Curve.decodePoint(message.getEphemeralKey().toByteArray(), 0);
+ this.identityKey = new IdentityKey(message.getIdentityKey().toByteArray(), 0);
} catch (InvalidKeyException | IOException e) {
throw new InvalidMessageException(e);
}
@@ -96,6 +114,14 @@ public class KeyExchangeMessage {
return baseKey;
}
+ public byte[] getBaseKeySignature() {
+ return baseKeySignature;
+ }
+
+ public byte[] getVerificationTag() {
+ return verificationTag;
+ }
+
public ECPublicKey getEphemeralKey() {
return ephemeralKey;
}
diff --git a/libaxolotl/src/main/java/org/whispersystems/libaxolotl/protocol/WhisperProtos.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/protocol/WhisperProtos.java
index 6765827afc..355fc2b773 100644
--- a/libaxolotl/src/main/java/org/whispersystems/libaxolotl/protocol/WhisperProtos.java
+++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/protocol/WhisperProtos.java
@@ -1621,6 +1621,26 @@ public final class WhisperProtos {
* optional bytes identityKey = 4;
*/
com.google.protobuf.ByteString getIdentityKey();
+
+ // optional bytes baseKeySignature = 5;
+ /**
+ * optional bytes baseKeySignature = 5;
+ */
+ boolean hasBaseKeySignature();
+ /**
+ * optional bytes baseKeySignature = 5;
+ */
+ com.google.protobuf.ByteString getBaseKeySignature();
+
+ // optional bytes verification = 6;
+ /**
+ * optional bytes verification = 6;
+ */
+ boolean hasVerification();
+ /**
+ * optional bytes verification = 6;
+ */
+ com.google.protobuf.ByteString getVerification();
}
/**
* Protobuf type {@code textsecure.KeyExchangeMessage}
@@ -1693,6 +1713,16 @@ public final class WhisperProtos {
identityKey_ = input.readBytes();
break;
}
+ case 42: {
+ bitField0_ |= 0x00000010;
+ baseKeySignature_ = input.readBytes();
+ break;
+ }
+ case 50: {
+ bitField0_ |= 0x00000020;
+ verification_ = input.readBytes();
+ break;
+ }
}
}
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
@@ -1797,11 +1827,45 @@ public final class WhisperProtos {
return identityKey_;
}
+ // optional bytes baseKeySignature = 5;
+ public static final int BASEKEYSIGNATURE_FIELD_NUMBER = 5;
+ private com.google.protobuf.ByteString baseKeySignature_;
+ /**
+ * optional bytes baseKeySignature = 5;
+ */
+ public boolean hasBaseKeySignature() {
+ return ((bitField0_ & 0x00000010) == 0x00000010);
+ }
+ /**
+ * optional bytes baseKeySignature = 5;
+ */
+ public com.google.protobuf.ByteString getBaseKeySignature() {
+ return baseKeySignature_;
+ }
+
+ // optional bytes verification = 6;
+ public static final int VERIFICATION_FIELD_NUMBER = 6;
+ private com.google.protobuf.ByteString verification_;
+ /**
+ * optional bytes verification = 6;
+ */
+ public boolean hasVerification() {
+ return ((bitField0_ & 0x00000020) == 0x00000020);
+ }
+ /**
+ * optional bytes verification = 6;
+ */
+ public com.google.protobuf.ByteString getVerification() {
+ return verification_;
+ }
+
private void initFields() {
id_ = 0;
baseKey_ = com.google.protobuf.ByteString.EMPTY;
ephemeralKey_ = com.google.protobuf.ByteString.EMPTY;
identityKey_ = com.google.protobuf.ByteString.EMPTY;
+ baseKeySignature_ = com.google.protobuf.ByteString.EMPTY;
+ verification_ = com.google.protobuf.ByteString.EMPTY;
}
private byte memoizedIsInitialized = -1;
public final boolean isInitialized() {
@@ -1827,6 +1891,12 @@ public final class WhisperProtos {
if (((bitField0_ & 0x00000008) == 0x00000008)) {
output.writeBytes(4, identityKey_);
}
+ if (((bitField0_ & 0x00000010) == 0x00000010)) {
+ output.writeBytes(5, baseKeySignature_);
+ }
+ if (((bitField0_ & 0x00000020) == 0x00000020)) {
+ output.writeBytes(6, verification_);
+ }
getUnknownFields().writeTo(output);
}
@@ -1852,6 +1922,14 @@ public final class WhisperProtos {
size += com.google.protobuf.CodedOutputStream
.computeBytesSize(4, identityKey_);
}
+ if (((bitField0_ & 0x00000010) == 0x00000010)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeBytesSize(5, baseKeySignature_);
+ }
+ if (((bitField0_ & 0x00000020) == 0x00000020)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeBytesSize(6, verification_);
+ }
size += getUnknownFields().getSerializedSize();
memoizedSerializedSize = size;
return size;
@@ -1976,6 +2054,10 @@ public final class WhisperProtos {
bitField0_ = (bitField0_ & ~0x00000004);
identityKey_ = com.google.protobuf.ByteString.EMPTY;
bitField0_ = (bitField0_ & ~0x00000008);
+ baseKeySignature_ = com.google.protobuf.ByteString.EMPTY;
+ bitField0_ = (bitField0_ & ~0x00000010);
+ verification_ = com.google.protobuf.ByteString.EMPTY;
+ bitField0_ = (bitField0_ & ~0x00000020);
return this;
}
@@ -2020,6 +2102,14 @@ public final class WhisperProtos {
to_bitField0_ |= 0x00000008;
}
result.identityKey_ = identityKey_;
+ if (((from_bitField0_ & 0x00000010) == 0x00000010)) {
+ to_bitField0_ |= 0x00000010;
+ }
+ result.baseKeySignature_ = baseKeySignature_;
+ if (((from_bitField0_ & 0x00000020) == 0x00000020)) {
+ to_bitField0_ |= 0x00000020;
+ }
+ result.verification_ = verification_;
result.bitField0_ = to_bitField0_;
onBuilt();
return result;
@@ -2048,6 +2138,12 @@ public final class WhisperProtos {
if (other.hasIdentityKey()) {
setIdentityKey(other.getIdentityKey());
}
+ if (other.hasBaseKeySignature()) {
+ setBaseKeySignature(other.getBaseKeySignature());
+ }
+ if (other.hasVerification()) {
+ setVerification(other.getVerification());
+ }
this.mergeUnknownFields(other.getUnknownFields());
return this;
}
@@ -2216,6 +2312,78 @@ public final class WhisperProtos {
return this;
}
+ // optional bytes baseKeySignature = 5;
+ private com.google.protobuf.ByteString baseKeySignature_ = com.google.protobuf.ByteString.EMPTY;
+ /**
+ * optional bytes baseKeySignature = 5;
+ */
+ public boolean hasBaseKeySignature() {
+ return ((bitField0_ & 0x00000010) == 0x00000010);
+ }
+ /**
+ * optional bytes baseKeySignature = 5;
+ */
+ public com.google.protobuf.ByteString getBaseKeySignature() {
+ return baseKeySignature_;
+ }
+ /**
+ * optional bytes baseKeySignature = 5;
+ */
+ public Builder setBaseKeySignature(com.google.protobuf.ByteString value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ bitField0_ |= 0x00000010;
+ baseKeySignature_ = value;
+ onChanged();
+ return this;
+ }
+ /**
+ * optional bytes baseKeySignature = 5;
+ */
+ public Builder clearBaseKeySignature() {
+ bitField0_ = (bitField0_ & ~0x00000010);
+ baseKeySignature_ = getDefaultInstance().getBaseKeySignature();
+ onChanged();
+ return this;
+ }
+
+ // optional bytes verification = 6;
+ private com.google.protobuf.ByteString verification_ = com.google.protobuf.ByteString.EMPTY;
+ /**
+ * optional bytes verification = 6;
+ */
+ public boolean hasVerification() {
+ return ((bitField0_ & 0x00000020) == 0x00000020);
+ }
+ /**
+ * optional bytes verification = 6;
+ */
+ public com.google.protobuf.ByteString getVerification() {
+ return verification_;
+ }
+ /**
+ * optional bytes verification = 6;
+ */
+ public Builder setVerification(com.google.protobuf.ByteString value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ bitField0_ |= 0x00000020;
+ verification_ = value;
+ onChanged();
+ return this;
+ }
+ /**
+ * optional bytes verification = 6;
+ */
+ public Builder clearVerification() {
+ bitField0_ = (bitField0_ & ~0x00000020);
+ verification_ = getDefaultInstance().getVerification();
+ onChanged();
+ return this;
+ }
+
// @@protoc_insertion_point(builder_scope:textsecure.KeyExchangeMessage)
}
@@ -2258,11 +2426,12 @@ public final class WhisperProtos {
"essage\022\026\n\016registrationId\030\005 \001(\r\022\020\n\010preKey" +
"Id\030\001 \001(\r\022\023\n\013deviceKeyId\030\006 \001(\r\022\017\n\007baseKey" +
"\030\002 \001(\014\022\023\n\013identityKey\030\003 \001(\014\022\024\n\014verificat" +
- "ion\030\007 \001(\014\022\017\n\007message\030\004 \001(\014\"\\\n\022KeyExchang" +
- "eMessage\022\n\n\002id\030\001 \001(\r\022\017\n\007baseKey\030\002 \001(\014\022\024\n" +
- "\014ephemeralKey\030\003 \001(\014\022\023\n\013identityKey\030\004 \001(\014",
- "B7\n&org.whispersystems.libaxolotl.protoc" +
- "olB\rWhisperProtos"
+ "ion\030\007 \001(\014\022\017\n\007message\030\004 \001(\014\"\214\001\n\022KeyExchan" +
+ "geMessage\022\n\n\002id\030\001 \001(\r\022\017\n\007baseKey\030\002 \001(\014\022\024" +
+ "\n\014ephemeralKey\030\003 \001(\014\022\023\n\013identityKey\030\004 \001(",
+ "\014\022\030\n\020baseKeySignature\030\005 \001(\014\022\024\n\014verificat" +
+ "ion\030\006 \001(\014B7\n&org.whispersystems.libaxolo" +
+ "tl.protocolB\rWhisperProtos"
};
com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
@@ -2286,7 +2455,7 @@ public final class WhisperProtos {
internal_static_textsecure_KeyExchangeMessage_fieldAccessorTable = new
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
internal_static_textsecure_KeyExchangeMessage_descriptor,
- new java.lang.String[] { "Id", "BaseKey", "EphemeralKey", "IdentityKey", });
+ new java.lang.String[] { "Id", "BaseKey", "EphemeralKey", "IdentityKey", "BaseKeySignature", "Verification", });
return null;
}
};