mirror of
https://github.com/oxen-io/session-android.git
synced 2024-12-02 14:35:21 +00:00
Add V3 support for KeyExchangeMessage case.
1) V3 KeyExchangeMessages can now contain signatures and verification tags.
This commit is contained in:
parent
77ff9cece8
commit
64b40df15b
@ -25,4 +25,6 @@ message KeyExchangeMessage {
|
|||||||
optional bytes baseKey = 2;
|
optional bytes baseKey = 2;
|
||||||
optional bytes ephemeralKey = 3;
|
optional bytes ephemeralKey = 3;
|
||||||
optional bytes identityKey = 4;
|
optional bytes identityKey = 4;
|
||||||
|
optional bytes baseKeySignature = 5;
|
||||||
|
optional bytes verification = 6;
|
||||||
}
|
}
|
@ -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();
|
SessionStore aliceSessionStore = new InMemorySessionStore();
|
||||||
PreKeyStore alicePreKeyStore = new InMemoryPreKeyStore();
|
PreKeyStore alicePreKeyStore = new InMemoryPreKeyStore();
|
||||||
DeviceKeyStore aliceDeviceKeyStore = new InMemoryDeviceKeyStore();
|
DeviceKeyStore aliceDeviceKeyStore = new InMemoryDeviceKeyStore();
|
||||||
@ -521,12 +521,15 @@ public class SessionBuilderTest extends AndroidTestCase {
|
|||||||
ALICE_RECIPIENT_ID, 1);
|
ALICE_RECIPIENT_ID, 1);
|
||||||
|
|
||||||
KeyExchangeMessage aliceKeyExchangeMessage = aliceSessionBuilder.process();
|
KeyExchangeMessage aliceKeyExchangeMessage = aliceSessionBuilder.process();
|
||||||
KeyExchangeMessage bobKeyExchangeMessage = bobSessionBuilder.process(aliceKeyExchangeMessage);
|
|
||||||
|
|
||||||
assertTrue(bobKeyExchangeMessage != null);
|
|
||||||
assertTrue(aliceKeyExchangeMessage != null);
|
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(response == null);
|
||||||
assertTrue(aliceSessionStore.containsSession(BOB_RECIPIENT_ID, 1));
|
assertTrue(aliceSessionStore.containsSession(BOB_RECIPIENT_ID, 1));
|
||||||
|
@ -5,10 +5,10 @@ import android.util.Log;
|
|||||||
import org.whispersystems.libaxolotl.ecc.Curve;
|
import org.whispersystems.libaxolotl.ecc.Curve;
|
||||||
import org.whispersystems.libaxolotl.ecc.ECKeyPair;
|
import org.whispersystems.libaxolotl.ecc.ECKeyPair;
|
||||||
import org.whispersystems.libaxolotl.ecc.ECPublicKey;
|
import org.whispersystems.libaxolotl.ecc.ECPublicKey;
|
||||||
|
import org.whispersystems.libaxolotl.protocol.CiphertextMessage;
|
||||||
import org.whispersystems.libaxolotl.protocol.KeyExchangeMessage;
|
import org.whispersystems.libaxolotl.protocol.KeyExchangeMessage;
|
||||||
import org.whispersystems.libaxolotl.protocol.PreKeyWhisperMessage;
|
import org.whispersystems.libaxolotl.protocol.PreKeyWhisperMessage;
|
||||||
import org.whispersystems.libaxolotl.ratchet.RatchetingSession;
|
import org.whispersystems.libaxolotl.ratchet.RatchetingSession;
|
||||||
import org.whispersystems.libaxolotl.state.DeviceKeyRecord;
|
|
||||||
import org.whispersystems.libaxolotl.state.DeviceKeyStore;
|
import org.whispersystems.libaxolotl.state.DeviceKeyStore;
|
||||||
import org.whispersystems.libaxolotl.state.IdentityKeyStore;
|
import org.whispersystems.libaxolotl.state.IdentityKeyStore;
|
||||||
import org.whispersystems.libaxolotl.state.PreKeyBundle;
|
import org.whispersystems.libaxolotl.state.PreKeyBundle;
|
||||||
@ -149,7 +149,6 @@ public class SessionBuilder {
|
|||||||
sessionRecord.getSessionState().setLocalRegistrationId(identityKeyStore.getLocalRegistrationId());
|
sessionRecord.getSessionState().setLocalRegistrationId(identityKeyStore.getLocalRegistrationId());
|
||||||
sessionRecord.getSessionState().setRemoteRegistrationId(message.getRegistrationId());
|
sessionRecord.getSessionState().setRemoteRegistrationId(message.getRegistrationId());
|
||||||
sessionRecord.getSessionState().setAliceBaseKey(theirBaseKey.serialize());
|
sessionRecord.getSessionState().setAliceBaseKey(theirBaseKey.serialize());
|
||||||
sessionRecord.getSessionState().setSessionVersion(message.getMessageVersion());
|
|
||||||
|
|
||||||
if (simultaneousInitiate) sessionRecord.getSessionState().setNeedsRefresh(true);
|
if (simultaneousInitiate) sessionRecord.getSessionState().setNeedsRefresh(true);
|
||||||
|
|
||||||
@ -197,7 +196,6 @@ public class SessionBuilder {
|
|||||||
|
|
||||||
sessionRecord.getSessionState().setLocalRegistrationId(identityKeyStore.getLocalRegistrationId());
|
sessionRecord.getSessionState().setLocalRegistrationId(identityKeyStore.getLocalRegistrationId());
|
||||||
sessionRecord.getSessionState().setRemoteRegistrationId(message.getRegistrationId());
|
sessionRecord.getSessionState().setRemoteRegistrationId(message.getRegistrationId());
|
||||||
sessionRecord.getSessionState().setSessionVersion(message.getMessageVersion());
|
|
||||||
|
|
||||||
if (simultaneousInitiate) sessionRecord.getSessionState().setNeedsRefresh(true);
|
if (simultaneousInitiate) sessionRecord.getSessionState().setNeedsRefresh(true);
|
||||||
|
|
||||||
@ -277,31 +275,71 @@ public class SessionBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
KeyExchangeMessage responseMessage = null;
|
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()) {
|
return responseMessage;
|
||||||
Log.w(TAG, "KeyExchange is an initiate.");
|
|
||||||
responseMessage = processInitiate(sessionRecord, message);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (message.isResponse()) {
|
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 (!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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
SessionState sessionState = sessionRecord.getSessionState();
|
||||||
boolean hasPendingKeyExchange = sessionState.hasPendingKeyExchange();
|
boolean hasPendingKeyExchange = sessionState.hasPendingKeyExchange();
|
||||||
boolean isSimultaneousInitiateResponse = message.isResponseForSimultaneousInitiate();
|
boolean isSimultaneousInitiateResponse = message.isResponseForSimultaneousInitiate();
|
||||||
|
|
||||||
if ((!hasPendingKeyExchange || sessionState.getPendingKeyExchangeSequence() != message.getSequence()) &&
|
if (!hasPendingKeyExchange || sessionState.getPendingKeyExchangeSequence() != message.getSequence()) {
|
||||||
!isSimultaneousInitiateResponse)
|
Log.w(TAG, "No matching sequence for response. Is simultaneous initiate response: " + isSimultaneousInitiateResponse);
|
||||||
{
|
if (!isSimultaneousInitiateResponse) throw new StaleKeyExchangeException();
|
||||||
throw new StaleKeyExchangeException();
|
else return;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (message.getSequence() != sessionRecord.getSessionState().getPendingKeyExchangeSequence()) {
|
|
||||||
Log.w("KeyExchangeProcessor", "No matching sequence for response. " +
|
|
||||||
"Is simultaneous initiate response: " + message.isResponseForSimultaneousInitiate());
|
|
||||||
return responseMessage;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ECKeyPair ourBaseKey = sessionRecord.getSessionState().getPendingKeyExchangeBaseKey();
|
ECKeyPair ourBaseKey = sessionRecord.getSessionState().getPendingKeyExchangeBaseKey();
|
||||||
@ -311,51 +349,22 @@ public class SessionBuilder {
|
|||||||
sessionRecord.reset();
|
sessionRecord.reset();
|
||||||
|
|
||||||
RatchetingSession.initializeSession(sessionRecord.getSessionState(),
|
RatchetingSession.initializeSession(sessionRecord.getSessionState(),
|
||||||
2,
|
Math.min(message.getMaxVersion(), CiphertextMessage.CURRENT_VERSION),
|
||||||
ourBaseKey, message.getBaseKey(),
|
ourBaseKey, message.getBaseKey(),
|
||||||
ourEphemeralKey, message.getEphemeralKey(),
|
ourEphemeralKey, message.getEphemeralKey(),
|
||||||
null, null,
|
ourBaseKey, message.getBaseKey(),
|
||||||
ourIdentityKey, message.getIdentityKey());
|
ourIdentityKey, message.getIdentityKey());
|
||||||
|
|
||||||
sessionRecord.getSessionState().setSessionVersion(message.getVersion());
|
if (sessionRecord.getSessionState().getSessionVersion() >= 3 &&
|
||||||
sessionStore.storeSession(recipientId, deviceId, sessionRecord);
|
!MessageDigest.isEqual(message.getVerificationTag(),
|
||||||
|
sessionRecord.getSessionState().getVerification()))
|
||||||
|
{
|
||||||
|
throw new InvalidKeyException("Verification tag doesn't match!");
|
||||||
|
}
|
||||||
|
|
||||||
|
sessionStore.storeSession(recipientId, deviceId, sessionRecord);
|
||||||
identityKeyStore.saveIdentity(recipientId, message.getIdentityKey());
|
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new KeyExchangeMessage(message.getSequence(),
|
|
||||||
flags, ourBaseKey.getPublicKey(),
|
|
||||||
ourEphemeralKey.getPublicKey(),
|
|
||||||
ourIdentityKey.getPublicKey());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -374,10 +383,10 @@ public class SessionBuilder {
|
|||||||
sessionRecord.getSessionState().setPendingKeyExchange(sequence, baseKey, ephemeralKey, identityKey);
|
sessionRecord.getSessionState().setPendingKeyExchange(sequence, baseKey, ephemeralKey, identityKey);
|
||||||
sessionStore.storeSession(recipientId, deviceId, sessionRecord);
|
sessionStore.storeSession(recipientId, deviceId, sessionRecord);
|
||||||
|
|
||||||
return new KeyExchangeMessage(sequence, flags,
|
return new KeyExchangeMessage(2, sequence, flags,
|
||||||
baseKey.getPublicKey(),
|
baseKey.getPublicKey(), null,
|
||||||
ephemeralKey.getPublicKey(),
|
ephemeralKey.getPublicKey(),
|
||||||
identityKey.getPublicKey());
|
identityKey.getPublicKey(), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -14,6 +14,8 @@ import org.whispersystems.libaxolotl.util.ByteUtil;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import static org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage.Builder;
|
||||||
|
|
||||||
public class KeyExchangeMessage {
|
public class KeyExchangeMessage {
|
||||||
|
|
||||||
public static final int INITIATE_FLAG = 0x01;
|
public static final int INITIATE_FLAG = 0x01;
|
||||||
@ -26,31 +28,43 @@ public class KeyExchangeMessage {
|
|||||||
private final int flags;
|
private final int flags;
|
||||||
|
|
||||||
private final ECPublicKey baseKey;
|
private final ECPublicKey baseKey;
|
||||||
|
private final byte[] baseKeySignature;
|
||||||
private final ECPublicKey ephemeralKey;
|
private final ECPublicKey ephemeralKey;
|
||||||
private final IdentityKey identityKey;
|
private final IdentityKey identityKey;
|
||||||
|
private final byte[] verificationTag;
|
||||||
private final byte[] serialized;
|
private final byte[] serialized;
|
||||||
|
|
||||||
public KeyExchangeMessage(int sequence, int flags,
|
public KeyExchangeMessage(int messageVersion, int sequence, int flags,
|
||||||
ECPublicKey baseKey, ECPublicKey ephemeralKey,
|
ECPublicKey baseKey, byte[] baseKeySignature,
|
||||||
IdentityKey identityKey)
|
ECPublicKey ephemeralKey,
|
||||||
|
IdentityKey identityKey, byte[] verificationTag)
|
||||||
{
|
{
|
||||||
this.supportedVersion = 2;
|
this.supportedVersion = CiphertextMessage.CURRENT_VERSION;
|
||||||
this.version = 2;
|
this.version = messageVersion;
|
||||||
this.sequence = sequence;
|
this.sequence = sequence;
|
||||||
this.flags = flags;
|
this.flags = flags;
|
||||||
this.baseKey = baseKey;
|
this.baseKey = baseKey;
|
||||||
|
this.baseKeySignature = baseKeySignature;
|
||||||
this.ephemeralKey = ephemeralKey;
|
this.ephemeralKey = ephemeralKey;
|
||||||
this.identityKey = identityKey;
|
this.identityKey = identityKey;
|
||||||
|
this.verificationTag = verificationTag;
|
||||||
|
|
||||||
byte[] version = {ByteUtil.intsToByteHighAndLow(this.version, this.supportedVersion)};
|
byte[] version = {ByteUtil.intsToByteHighAndLow(this.version, this.supportedVersion)};
|
||||||
byte[] message = WhisperProtos.KeyExchangeMessage.newBuilder()
|
Builder builder = WhisperProtos.KeyExchangeMessage.newBuilder()
|
||||||
.setId((sequence << 5) | flags)
|
.setId((sequence << 5) | flags)
|
||||||
.setBaseKey(ByteString.copyFrom(baseKey.serialize()))
|
.setBaseKey(ByteString.copyFrom(baseKey.serialize()))
|
||||||
.setEphemeralKey(ByteString.copyFrom(ephemeralKey.serialize()))
|
.setEphemeralKey(ByteString.copyFrom(ephemeralKey.serialize()))
|
||||||
.setIdentityKey(ByteString.copyFrom(identityKey.serialize()))
|
.setIdentityKey(ByteString.copyFrom(identityKey.serialize()));
|
||||||
.build().toByteArray();
|
|
||||||
|
|
||||||
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)
|
public KeyExchangeMessage(byte[] serialized)
|
||||||
@ -72,7 +86,9 @@ public class KeyExchangeMessage {
|
|||||||
WhisperProtos.KeyExchangeMessage message = WhisperProtos.KeyExchangeMessage.parseFrom(parts[1]);
|
WhisperProtos.KeyExchangeMessage message = WhisperProtos.KeyExchangeMessage.parseFrom(parts[1]);
|
||||||
|
|
||||||
if (!message.hasId() || !message.hasBaseKey() ||
|
if (!message.hasId() || !message.hasBaseKey() ||
|
||||||
!message.hasEphemeralKey() || !message.hasIdentityKey())
|
!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!");
|
throw new InvalidMessageException("Some required fields missing!");
|
||||||
}
|
}
|
||||||
@ -81,6 +97,8 @@ public class KeyExchangeMessage {
|
|||||||
this.flags = message.getId() & 0x1f;
|
this.flags = message.getId() & 0x1f;
|
||||||
this.serialized = serialized;
|
this.serialized = serialized;
|
||||||
this.baseKey = Curve.decodePoint(message.getBaseKey().toByteArray(), 0);
|
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.ephemeralKey = Curve.decodePoint(message.getEphemeralKey().toByteArray(), 0);
|
||||||
this.identityKey = new IdentityKey(message.getIdentityKey().toByteArray(), 0);
|
this.identityKey = new IdentityKey(message.getIdentityKey().toByteArray(), 0);
|
||||||
} catch (InvalidKeyException | IOException e) {
|
} catch (InvalidKeyException | IOException e) {
|
||||||
@ -96,6 +114,14 @@ public class KeyExchangeMessage {
|
|||||||
return baseKey;
|
return baseKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public byte[] getBaseKeySignature() {
|
||||||
|
return baseKeySignature;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getVerificationTag() {
|
||||||
|
return verificationTag;
|
||||||
|
}
|
||||||
|
|
||||||
public ECPublicKey getEphemeralKey() {
|
public ECPublicKey getEphemeralKey() {
|
||||||
return ephemeralKey;
|
return ephemeralKey;
|
||||||
}
|
}
|
||||||
|
@ -1621,6 +1621,26 @@ public final class WhisperProtos {
|
|||||||
* <code>optional bytes identityKey = 4;</code>
|
* <code>optional bytes identityKey = 4;</code>
|
||||||
*/
|
*/
|
||||||
com.google.protobuf.ByteString getIdentityKey();
|
com.google.protobuf.ByteString getIdentityKey();
|
||||||
|
|
||||||
|
// optional bytes baseKeySignature = 5;
|
||||||
|
/**
|
||||||
|
* <code>optional bytes baseKeySignature = 5;</code>
|
||||||
|
*/
|
||||||
|
boolean hasBaseKeySignature();
|
||||||
|
/**
|
||||||
|
* <code>optional bytes baseKeySignature = 5;</code>
|
||||||
|
*/
|
||||||
|
com.google.protobuf.ByteString getBaseKeySignature();
|
||||||
|
|
||||||
|
// optional bytes verification = 6;
|
||||||
|
/**
|
||||||
|
* <code>optional bytes verification = 6;</code>
|
||||||
|
*/
|
||||||
|
boolean hasVerification();
|
||||||
|
/**
|
||||||
|
* <code>optional bytes verification = 6;</code>
|
||||||
|
*/
|
||||||
|
com.google.protobuf.ByteString getVerification();
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Protobuf type {@code textsecure.KeyExchangeMessage}
|
* Protobuf type {@code textsecure.KeyExchangeMessage}
|
||||||
@ -1693,6 +1713,16 @@ public final class WhisperProtos {
|
|||||||
identityKey_ = input.readBytes();
|
identityKey_ = input.readBytes();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 42: {
|
||||||
|
bitField0_ |= 0x00000010;
|
||||||
|
baseKeySignature_ = input.readBytes();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 50: {
|
||||||
|
bitField0_ |= 0x00000020;
|
||||||
|
verification_ = input.readBytes();
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
|
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
|
||||||
@ -1797,11 +1827,45 @@ public final class WhisperProtos {
|
|||||||
return identityKey_;
|
return identityKey_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// optional bytes baseKeySignature = 5;
|
||||||
|
public static final int BASEKEYSIGNATURE_FIELD_NUMBER = 5;
|
||||||
|
private com.google.protobuf.ByteString baseKeySignature_;
|
||||||
|
/**
|
||||||
|
* <code>optional bytes baseKeySignature = 5;</code>
|
||||||
|
*/
|
||||||
|
public boolean hasBaseKeySignature() {
|
||||||
|
return ((bitField0_ & 0x00000010) == 0x00000010);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* <code>optional bytes baseKeySignature = 5;</code>
|
||||||
|
*/
|
||||||
|
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_;
|
||||||
|
/**
|
||||||
|
* <code>optional bytes verification = 6;</code>
|
||||||
|
*/
|
||||||
|
public boolean hasVerification() {
|
||||||
|
return ((bitField0_ & 0x00000020) == 0x00000020);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* <code>optional bytes verification = 6;</code>
|
||||||
|
*/
|
||||||
|
public com.google.protobuf.ByteString getVerification() {
|
||||||
|
return verification_;
|
||||||
|
}
|
||||||
|
|
||||||
private void initFields() {
|
private void initFields() {
|
||||||
id_ = 0;
|
id_ = 0;
|
||||||
baseKey_ = com.google.protobuf.ByteString.EMPTY;
|
baseKey_ = com.google.protobuf.ByteString.EMPTY;
|
||||||
ephemeralKey_ = com.google.protobuf.ByteString.EMPTY;
|
ephemeralKey_ = com.google.protobuf.ByteString.EMPTY;
|
||||||
identityKey_ = 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;
|
private byte memoizedIsInitialized = -1;
|
||||||
public final boolean isInitialized() {
|
public final boolean isInitialized() {
|
||||||
@ -1827,6 +1891,12 @@ public final class WhisperProtos {
|
|||||||
if (((bitField0_ & 0x00000008) == 0x00000008)) {
|
if (((bitField0_ & 0x00000008) == 0x00000008)) {
|
||||||
output.writeBytes(4, identityKey_);
|
output.writeBytes(4, identityKey_);
|
||||||
}
|
}
|
||||||
|
if (((bitField0_ & 0x00000010) == 0x00000010)) {
|
||||||
|
output.writeBytes(5, baseKeySignature_);
|
||||||
|
}
|
||||||
|
if (((bitField0_ & 0x00000020) == 0x00000020)) {
|
||||||
|
output.writeBytes(6, verification_);
|
||||||
|
}
|
||||||
getUnknownFields().writeTo(output);
|
getUnknownFields().writeTo(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1852,6 +1922,14 @@ public final class WhisperProtos {
|
|||||||
size += com.google.protobuf.CodedOutputStream
|
size += com.google.protobuf.CodedOutputStream
|
||||||
.computeBytesSize(4, identityKey_);
|
.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();
|
size += getUnknownFields().getSerializedSize();
|
||||||
memoizedSerializedSize = size;
|
memoizedSerializedSize = size;
|
||||||
return size;
|
return size;
|
||||||
@ -1976,6 +2054,10 @@ public final class WhisperProtos {
|
|||||||
bitField0_ = (bitField0_ & ~0x00000004);
|
bitField0_ = (bitField0_ & ~0x00000004);
|
||||||
identityKey_ = com.google.protobuf.ByteString.EMPTY;
|
identityKey_ = com.google.protobuf.ByteString.EMPTY;
|
||||||
bitField0_ = (bitField0_ & ~0x00000008);
|
bitField0_ = (bitField0_ & ~0x00000008);
|
||||||
|
baseKeySignature_ = com.google.protobuf.ByteString.EMPTY;
|
||||||
|
bitField0_ = (bitField0_ & ~0x00000010);
|
||||||
|
verification_ = com.google.protobuf.ByteString.EMPTY;
|
||||||
|
bitField0_ = (bitField0_ & ~0x00000020);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2020,6 +2102,14 @@ public final class WhisperProtos {
|
|||||||
to_bitField0_ |= 0x00000008;
|
to_bitField0_ |= 0x00000008;
|
||||||
}
|
}
|
||||||
result.identityKey_ = identityKey_;
|
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_;
|
result.bitField0_ = to_bitField0_;
|
||||||
onBuilt();
|
onBuilt();
|
||||||
return result;
|
return result;
|
||||||
@ -2048,6 +2138,12 @@ public final class WhisperProtos {
|
|||||||
if (other.hasIdentityKey()) {
|
if (other.hasIdentityKey()) {
|
||||||
setIdentityKey(other.getIdentityKey());
|
setIdentityKey(other.getIdentityKey());
|
||||||
}
|
}
|
||||||
|
if (other.hasBaseKeySignature()) {
|
||||||
|
setBaseKeySignature(other.getBaseKeySignature());
|
||||||
|
}
|
||||||
|
if (other.hasVerification()) {
|
||||||
|
setVerification(other.getVerification());
|
||||||
|
}
|
||||||
this.mergeUnknownFields(other.getUnknownFields());
|
this.mergeUnknownFields(other.getUnknownFields());
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -2216,6 +2312,78 @@ public final class WhisperProtos {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// optional bytes baseKeySignature = 5;
|
||||||
|
private com.google.protobuf.ByteString baseKeySignature_ = com.google.protobuf.ByteString.EMPTY;
|
||||||
|
/**
|
||||||
|
* <code>optional bytes baseKeySignature = 5;</code>
|
||||||
|
*/
|
||||||
|
public boolean hasBaseKeySignature() {
|
||||||
|
return ((bitField0_ & 0x00000010) == 0x00000010);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* <code>optional bytes baseKeySignature = 5;</code>
|
||||||
|
*/
|
||||||
|
public com.google.protobuf.ByteString getBaseKeySignature() {
|
||||||
|
return baseKeySignature_;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* <code>optional bytes baseKeySignature = 5;</code>
|
||||||
|
*/
|
||||||
|
public Builder setBaseKeySignature(com.google.protobuf.ByteString value) {
|
||||||
|
if (value == null) {
|
||||||
|
throw new NullPointerException();
|
||||||
|
}
|
||||||
|
bitField0_ |= 0x00000010;
|
||||||
|
baseKeySignature_ = value;
|
||||||
|
onChanged();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* <code>optional bytes baseKeySignature = 5;</code>
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
/**
|
||||||
|
* <code>optional bytes verification = 6;</code>
|
||||||
|
*/
|
||||||
|
public boolean hasVerification() {
|
||||||
|
return ((bitField0_ & 0x00000020) == 0x00000020);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* <code>optional bytes verification = 6;</code>
|
||||||
|
*/
|
||||||
|
public com.google.protobuf.ByteString getVerification() {
|
||||||
|
return verification_;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* <code>optional bytes verification = 6;</code>
|
||||||
|
*/
|
||||||
|
public Builder setVerification(com.google.protobuf.ByteString value) {
|
||||||
|
if (value == null) {
|
||||||
|
throw new NullPointerException();
|
||||||
|
}
|
||||||
|
bitField0_ |= 0x00000020;
|
||||||
|
verification_ = value;
|
||||||
|
onChanged();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* <code>optional bytes verification = 6;</code>
|
||||||
|
*/
|
||||||
|
public Builder clearVerification() {
|
||||||
|
bitField0_ = (bitField0_ & ~0x00000020);
|
||||||
|
verification_ = getDefaultInstance().getVerification();
|
||||||
|
onChanged();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
// @@protoc_insertion_point(builder_scope:textsecure.KeyExchangeMessage)
|
// @@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" +
|
"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" +
|
"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" +
|
"\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" +
|
"ion\030\007 \001(\014\022\017\n\007message\030\004 \001(\014\"\214\001\n\022KeyExchan" +
|
||||||
"eMessage\022\n\n\002id\030\001 \001(\r\022\017\n\007baseKey\030\002 \001(\014\022\024\n" +
|
"geMessage\022\n\n\002id\030\001 \001(\r\022\017\n\007baseKey\030\002 \001(\014\022\024" +
|
||||||
"\014ephemeralKey\030\003 \001(\014\022\023\n\013identityKey\030\004 \001(\014",
|
"\n\014ephemeralKey\030\003 \001(\014\022\023\n\013identityKey\030\004 \001(",
|
||||||
"B7\n&org.whispersystems.libaxolotl.protoc" +
|
"\014\022\030\n\020baseKeySignature\030\005 \001(\014\022\024\n\014verificat" +
|
||||||
"olB\rWhisperProtos"
|
"ion\030\006 \001(\014B7\n&org.whispersystems.libaxolo" +
|
||||||
|
"tl.protocolB\rWhisperProtos"
|
||||||
};
|
};
|
||||||
com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
|
com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
|
||||||
new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
|
new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
|
||||||
@ -2286,7 +2455,7 @@ public final class WhisperProtos {
|
|||||||
internal_static_textsecure_KeyExchangeMessage_fieldAccessorTable = new
|
internal_static_textsecure_KeyExchangeMessage_fieldAccessorTable = new
|
||||||
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
|
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
|
||||||
internal_static_textsecure_KeyExchangeMessage_descriptor,
|
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;
|
return null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user