Rename axolotl terminology.

1) ephemeralKey -> ratchetKey

2) Have the caller specify Alice/Bob orientation.

3) Reorganize verification tag.

4) Remove verification tag from key exchange messages, replace
   with signatures in both directions.
This commit is contained in:
Moxie Marlinspike 2014-07-23 01:00:32 -07:00
parent 82bd75fb75
commit 641ac9aed9
18 changed files with 962 additions and 828 deletions

View File

@ -5,8 +5,8 @@ option java_outer_classname = "StorageProtos";
message SessionStructure {
message Chain {
optional bytes senderEphemeral = 1;
optional bytes senderEphemeralPrivate = 2;
optional bytes senderRatchetKey = 1;
optional bytes senderRatchetKeyPrivate = 2;
message ChainKey {
optional uint32 index = 1;
@ -28,8 +28,8 @@ message SessionStructure {
optional uint32 sequence = 1;
optional bytes localBaseKey = 2;
optional bytes localBaseKeyPrivate = 3;
optional bytes localEphemeralKey = 4;
optional bytes localEphemeralKeyPrivate = 5;
optional bytes localRatchetKey = 4;
optional bytes localRatchetKeyPrivate = 5;
optional bytes localIdentityKey = 7;
optional bytes localIdentityKeyPrivate = 8;
}

View File

@ -4,7 +4,7 @@ option java_package = "org.whispersystems.libaxolotl.protocol";
option java_outer_classname = "WhisperProtos";
message WhisperMessage {
optional bytes ephemeralKey = 1;
optional bytes ratchetKey = 1;
optional uint32 counter = 2;
optional uint32 previousCounter = 3;
optional bytes ciphertext = 4;
@ -23,8 +23,7 @@ message PreKeyWhisperMessage {
message KeyExchangeMessage {
optional uint32 id = 1;
optional bytes baseKey = 2;
optional bytes ephemeralKey = 3;
optional bytes ratchetKey = 3;
optional bytes identityKey = 4;
optional bytes baseKeySignature = 5;
optional bytes verification = 6;
}

View File

@ -154,7 +154,8 @@ public class SessionBuilderTest extends AndroidTestCase {
PreKeyBundle bobPreKey = new PreKeyBundle(bobIdentityKeyStore.getLocalRegistrationId(), 1,
31337, bobPreKeyPair.getPublicKey(),
22, bobSignedPreKeyPair.getPublicKey(), bobSignedPreKeySignature,
22, bobSignedPreKeyPair.getPublicKey(),
bobSignedPreKeySignature,
bobIdentityKeyStore.getIdentityKeyPair().getPublicKey());
aliceSessionBuilder.process(bobPreKey);

View File

@ -15,6 +15,8 @@ import org.whispersystems.libaxolotl.ecc.ECKeyPair;
import org.whispersystems.libaxolotl.ecc.ECPublicKey;
import org.whispersystems.libaxolotl.protocol.CiphertextMessage;
import org.whispersystems.libaxolotl.protocol.WhisperMessage;
import org.whispersystems.libaxolotl.ratchet.AliceAxolotlParameters;
import org.whispersystems.libaxolotl.ratchet.BobAxolotlParameters;
import org.whispersystems.libaxolotl.ratchet.RatchetingSession;
import org.whispersystems.libaxolotl.state.IdentityKeyStore;
import org.whispersystems.libaxolotl.state.PreKeyStore;
@ -31,7 +33,6 @@ import java.util.Collections;
import java.util.List;
import java.util.Random;
import static org.whispersystems.libaxolotl.ratchet.RatchetingSession.AxolotlParameters;
public class SessionCipherTest extends AndroidTestCase {
@ -149,30 +150,23 @@ public class SessionCipherTest extends AndroidTestCase {
ECKeyPair bobBaseKey = Curve.generateKeyPair(true);
ECKeyPair bobEphemeralKey = bobBaseKey;
AxolotlParameters aliceParameters =
AxolotlParameters.newBuilder()
.setOurIdentityKey(aliceIdentityKey)
.setOurBaseKey(aliceBaseKey)
.setOurEphemeralKey(aliceEphemeralKey)
.setOurPreKey(Optional.<ECKeyPair>absent())
.setTheirIdentityKey(bobIdentityKey.getPublicKey())
.setTheirBaseKey(bobBaseKey.getPublicKey())
.setTheirEphemeralKey(bobEphemeralKey.getPublicKey())
.setTheirPreKey(Optional.<ECPublicKey>absent())
.create();
AxolotlParameters bobParameters =
RatchetingSession.AxolotlParameters.newBuilder()
.setOurIdentityKey(bobIdentityKey)
.setOurBaseKey(bobBaseKey)
.setOurEphemeralKey(bobEphemeralKey)
.setOurPreKey(Optional.<ECKeyPair>absent())
.setTheirIdentityKey(aliceIdentityKey.getPublicKey())
.setTheirBaseKey(aliceBaseKey.getPublicKey())
.setTheirEphemeralKey(aliceEphemeralKey.getPublicKey())
.setTheirPreKey(Optional.<ECPublicKey>absent())
.create();
AliceAxolotlParameters aliceParameters = AliceAxolotlParameters.newBuilder()
.setOurIdentityKey(aliceIdentityKey)
.setOurBaseKey(aliceBaseKey)
.setTheirIdentityKey(bobIdentityKey.getPublicKey())
.setTheirSignedPreKey(bobEphemeralKey.getPublicKey())
.setTheirRatchetKey(bobEphemeralKey.getPublicKey())
.setTheirOneTimePreKey(Optional.<ECPublicKey>absent())
.create();
BobAxolotlParameters bobParameters = BobAxolotlParameters.newBuilder()
.setOurIdentityKey(bobIdentityKey)
.setOurOneTimePreKey(Optional.<ECKeyPair>absent())
.setOurRatchetKey(bobEphemeralKey)
.setOurSignedPreKey(bobBaseKey)
.setTheirBaseKey(aliceBaseKey.getPublicKey())
.setTheirIdentityKey(aliceIdentityKey.getPublicKey())
.create();
RatchetingSession.initializeSession(aliceSessionState, 2, aliceParameters);
RatchetingSession.initializeSession(bobSessionState, 2, bobParameters);
@ -197,33 +191,25 @@ public class SessionCipherTest extends AndroidTestCase {
ECKeyPair bobPreKey = Curve.generateKeyPair(true);
AxolotlParameters aliceParameters =
AxolotlParameters.newBuilder()
.setOurIdentityKey(aliceIdentityKey)
.setOurBaseKey(aliceBaseKey)
.setOurEphemeralKey(aliceEphemeralKey)
.setOurPreKey(Optional.of(alicePreKey))
.setTheirIdentityKey(bobIdentityKey.getPublicKey())
.setTheirBaseKey(bobBaseKey.getPublicKey())
.setTheirEphemeralKey(bobEphemeralKey.getPublicKey())
.setTheirPreKey(Optional.of(bobPreKey.getPublicKey()))
.create();
AxolotlParameters bobParameters =
AxolotlParameters.newBuilder()
.setOurIdentityKey(bobIdentityKey)
.setOurBaseKey(bobBaseKey)
.setOurEphemeralKey(bobEphemeralKey)
.setOurPreKey(Optional.of(bobPreKey))
.setTheirIdentityKey(aliceIdentityKey.getPublicKey())
.setTheirBaseKey(aliceBaseKey.getPublicKey())
.setTheirEphemeralKey(aliceEphemeralKey.getPublicKey())
.setTheirPreKey(Optional.of(alicePreKey.getPublicKey()))
.create();
AliceAxolotlParameters aliceParameters = AliceAxolotlParameters.newBuilder()
.setOurBaseKey(aliceBaseKey)
.setOurIdentityKey(aliceIdentityKey)
.setTheirOneTimePreKey(Optional.<ECPublicKey>absent())
.setTheirRatchetKey(bobEphemeralKey.getPublicKey())
.setTheirSignedPreKey(bobBaseKey.getPublicKey())
.setTheirIdentityKey(bobIdentityKey.getPublicKey())
.create();
BobAxolotlParameters bobParameters = BobAxolotlParameters.newBuilder()
.setOurRatchetKey(bobEphemeralKey)
.setOurSignedPreKey(bobBaseKey)
.setOurOneTimePreKey(Optional.<ECKeyPair>absent())
.setOurIdentityKey(bobIdentityKey)
.setTheirIdentityKey(aliceIdentityKey.getPublicKey())
.setTheirBaseKey(aliceBaseKey.getPublicKey())
.create();
RatchetingSession.initializeSession(aliceSessionState, 3, aliceParameters);
RatchetingSession.initializeSession(bobSessionState, 3, bobParameters);
}
}

View File

@ -9,14 +9,14 @@ import org.whispersystems.libaxolotl.ecc.Curve;
import org.whispersystems.libaxolotl.ecc.ECKeyPair;
import org.whispersystems.libaxolotl.ecc.ECPrivateKey;
import org.whispersystems.libaxolotl.ecc.ECPublicKey;
import org.whispersystems.libaxolotl.ratchet.AliceAxolotlParameters;
import org.whispersystems.libaxolotl.ratchet.BobAxolotlParameters;
import org.whispersystems.libaxolotl.ratchet.RatchetingSession;
import org.whispersystems.libaxolotl.state.SessionState;
import org.whispersystems.libaxolotl.util.guava.Optional;
import java.util.Arrays;
import static org.whispersystems.libaxolotl.ratchet.RatchetingSession.AxolotlParameters;
public class RatchetingSessionTest extends AndroidTestCase {
public void testRatchetingSessionAsBob() throws InvalidKeyException {
@ -108,20 +108,17 @@ public class RatchetingSessionTest extends AndroidTestCase {
ECPublicKey aliceEphemeralPublicKey = Curve.decodePoint(aliceEphemeralPublic, 0);
IdentityKey aliceIdentityPublicKey = new IdentityKey(aliceIdentityPublic, 0);
AxolotlParameters parameters = AxolotlParameters.newBuilder()
.setOurBaseKey(bobBaseKey)
.setOurEphemeralKey(bobEphemeralKey)
.setOurIdentityKey(bobIdentityKey)
.setOurPreKey(Optional.<ECKeyPair>absent())
.setTheirBaseKey(aliceBasePublicKey)
.setTheirEphemeralKey(aliceEphemeralPublicKey)
.setTheirIdentityKey(aliceIdentityPublicKey)
.setTheirPreKey(Optional.<ECPublicKey>absent())
.create();
BobAxolotlParameters parameters = BobAxolotlParameters.newBuilder()
.setOurIdentityKey(bobIdentityKey)
.setOurSignedPreKey(bobBaseKey)
.setOurRatchetKey(bobEphemeralKey)
.setOurOneTimePreKey(Optional.<ECKeyPair>absent())
.setTheirIdentityKey(aliceIdentityPublicKey)
.setTheirBaseKey(aliceBasePublicKey)
.create();
SessionState session = new SessionState();
RatchetingSession.initializeSession(session, 2, parameters);
assertTrue(session.getLocalIdentityKey().equals(bobIdentityKey.getPublicKey()));
@ -217,16 +214,14 @@ public class RatchetingSessionTest extends AndroidTestCase {
SessionState session = new SessionState();
AxolotlParameters parameters = AxolotlParameters.newBuilder()
.setOurBaseKey(aliceBaseKey)
.setOurEphemeralKey(aliceEphemeralKey)
.setOurIdentityKey(aliceIdentityKey)
.setOurPreKey(Optional.<ECKeyPair>absent())
.setTheirBaseKey(bobBasePublicKey)
.setTheirEphemeralKey(bobEphemeralPublicKey)
.setTheirIdentityKey(bobIdentityKey)
.setTheirPreKey(Optional.<ECPublicKey>absent())
.create();
AliceAxolotlParameters parameters = AliceAxolotlParameters.newBuilder()
.setOurBaseKey(aliceBaseKey)
.setOurIdentityKey(aliceIdentityKey)
.setTheirIdentityKey(bobIdentityKey)
.setTheirSignedPreKey(bobBasePublicKey)
.setTheirRatchetKey(bobEphemeralPublicKey)
.setTheirOneTimePreKey(Optional.<ECPublicKey>absent())
.create();
RatchetingSession.initializeSession(session, 2, parameters);

View File

@ -3,6 +3,7 @@ package org.whispersystems.test.ratchet;
import android.test.AndroidTestCase;
import android.util.Log;
import org.whispersystems.libaxolotl.IdentityKey;
import org.whispersystems.libaxolotl.InvalidKeyException;
import org.whispersystems.libaxolotl.ecc.Curve;
import org.whispersystems.libaxolotl.ecc.ECPublicKey;
@ -65,8 +66,8 @@ public class VerifyKeyTest extends AndroidTestCase {
(byte)0x79, (byte)0x00, (byte)0xef, (byte)0x1b, (byte)0x40,
(byte)0x0f, (byte)0xdc};
byte[] expectedTag = {(byte)0x2f, (byte)0x77, (byte)0xaf, (byte)0xad, (byte)0x5b,
(byte)0x96, (byte)0xf5, (byte)0x3c};
byte[] expectedTag = {(byte)0xd3, (byte)0x62, (byte)0x84, (byte)0x3c,
(byte)0x9d, (byte)0x59, (byte)0x8c, (byte)0x6f};
ECPublicKey aliceBaseKey = Curve.decodePoint(aliceBaseKeyBytes, 0);
ECPublicKey alicePreKey = aliceBaseKey;
@ -77,9 +78,11 @@ public class VerifyKeyTest extends AndroidTestCase {
ECPublicKey bobIdentityKey = Curve.decodePoint(bobIdentityKeyBytes, 0);
VerifyKey verifyKey = new VerifyKey(key);
byte[] verification = verifyKey.generateVerification(aliceBaseKey, Optional.of(alicePreKey),
aliceIdentityKey, bobBaseKey,
Optional.of(bobPreKey), bobIdentityKey);
byte[] verification = verifyKey.generateVerification(new IdentityKey(aliceIdentityKey),
new IdentityKey(bobIdentityKey),
aliceBaseKey, bobBaseKey,
Optional.of(bobPreKey));
assertTrue(MessageDigest.isEqual(verification, expectedTag));
}

View File

@ -8,7 +8,10 @@ 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.AliceAxolotlParameters;
import org.whispersystems.libaxolotl.ratchet.BobAxolotlParameters;
import org.whispersystems.libaxolotl.ratchet.RatchetingSession;
import org.whispersystems.libaxolotl.ratchet.SymmetricAxolotlParameters;
import org.whispersystems.libaxolotl.state.IdentityKeyStore;
import org.whispersystems.libaxolotl.state.PreKeyBundle;
import org.whispersystems.libaxolotl.state.PreKeyStore;
@ -22,8 +25,6 @@ import org.whispersystems.libaxolotl.util.guava.Optional;
import java.security.MessageDigest;
import static org.whispersystems.libaxolotl.ratchet.RatchetingSession.AxolotlParameters;
/**
* SessionBuilder is responsible for setting up encrypted sessions.
* Once a session has been established, {@link org.whispersystems.libaxolotl.SessionCipher}
@ -120,21 +121,22 @@ public class SessionBuilder {
return false;
}
boolean simultaneousInitiate = sessionRecord.getSessionState().hasUnacknowledgedPreKeyMessage();
boolean simultaneousInitiate = sessionRecord.getSessionState().hasUnacknowledgedPreKeyMessage();
ECKeyPair ourSignedPreKey = signedPreKeyStore.loadSignedPreKey(message.getSignedPreKeyId()).getKeyPair();
AxolotlParameters.Builder parameters = AxolotlParameters.newBuilder();
BobAxolotlParameters.Builder parameters = BobAxolotlParameters.newBuilder();
parameters.setTheirBaseKey(message.getBaseKey());
parameters.setTheirEphemeralKey(message.getWhisperMessage().getSenderEphemeral());
parameters.setTheirPreKey(Optional.of(message.getBaseKey()));
parameters.setTheirIdentityKey(message.getIdentityKey());
parameters.setTheirBaseKey(message.getBaseKey())
.setTheirIdentityKey(message.getIdentityKey())
.setOurIdentityKey(identityKeyStore.getIdentityKeyPair())
.setOurSignedPreKey(ourSignedPreKey)
.setOurRatchetKey(ourSignedPreKey);
parameters.setOurBaseKey(signedPreKeyStore.loadSignedPreKey(message.getSignedPreKeyId()).getKeyPair());
parameters.setOurEphemeralKey(parameters.getOurBaseKey());
parameters.setOurIdentityKey(identityKeyStore.getIdentityKeyPair());
if (message.getPreKeyId() >= 0) parameters.setOurPreKey(Optional.of(preKeyStore.loadPreKey(message.getPreKeyId()).getKeyPair()));
else parameters.setOurPreKey(Optional.<ECKeyPair>absent());
if (message.getPreKeyId() >= 0) {
parameters.setOurOneTimePreKey(Optional.of(preKeyStore.loadPreKey(message.getPreKeyId()).getKeyPair()));
} else {
parameters.setOurOneTimePreKey(Optional.<ECKeyPair>absent());
}
if (!simultaneousInitiate) sessionRecord.reset();
else sessionRecord.archiveCurrentState();
@ -171,19 +173,18 @@ public class SessionBuilder {
return false;
}
SessionRecord sessionRecord = sessionStore.loadSession(recipientId, deviceId);
boolean simultaneousInitiate = sessionRecord.getSessionState().hasUnacknowledgedPreKeyMessage();
AxolotlParameters.Builder parameters = RatchetingSession.AxolotlParameters.newBuilder();
SessionRecord sessionRecord = sessionStore.loadSession(recipientId, deviceId);
ECKeyPair ourPreKey = preKeyStore.loadPreKey(message.getPreKeyId()).getKeyPair();
boolean simultaneousInitiate = sessionRecord.getSessionState().hasUnacknowledgedPreKeyMessage();
parameters.setTheirBaseKey(message.getBaseKey());
parameters.setTheirEphemeralKey(message.getWhisperMessage().getSenderEphemeral());
parameters.setTheirPreKey(Optional.<ECPublicKey>absent());
parameters.setTheirIdentityKey(message.getIdentityKey());
BobAxolotlParameters.Builder parameters = BobAxolotlParameters.newBuilder();
parameters.setOurBaseKey(preKeyStore.loadPreKey(message.getPreKeyId()).getKeyPair());
parameters.setOurEphemeralKey(parameters.getOurBaseKey());
parameters.setOurPreKey(Optional.<ECKeyPair>absent());
parameters.setOurIdentityKey(identityKeyStore.getIdentityKeyPair());
parameters.setOurIdentityKey(identityKeyStore.getIdentityKeyPair())
.setOurSignedPreKey(ourPreKey)
.setOurRatchetKey(ourPreKey)
.setOurOneTimePreKey(Optional.<ECKeyPair>absent())
.setTheirIdentityKey(message.getIdentityKey())
.setTheirBaseKey(message.getBaseKey());
if (!simultaneousInitiate) sessionRecord.reset();
else sessionRecord.archiveCurrentState();
@ -195,12 +196,12 @@ public class SessionBuilder {
if (simultaneousInitiate) sessionRecord.getSessionState().setNeedsRefresh(true);
sessionStore.storeSession(recipientId, deviceId, sessionRecord);
if (message.getPreKeyId() != Medium.MAX_VALUE) {
preKeyStore.removePreKey(message.getPreKeyId());
}
sessionStore.storeSession(recipientId, deviceId, sessionRecord);
return true;
}
@ -233,20 +234,21 @@ public class SessionBuilder {
throw new InvalidKeyException("Both signed and unsigned prekeys are absent!");
}
SessionRecord sessionRecord = sessionStore.loadSession(recipientId, deviceId);
AxolotlParameters.Builder parameters = AxolotlParameters.newBuilder();
ECKeyPair ourBaseKey = Curve.generateKeyPair(true);
SessionRecord sessionRecord = sessionStore.loadSession(recipientId, deviceId);
ECKeyPair ourBaseKey = Curve.generateKeyPair(true);
ECPublicKey theirSignedPreKey = preKey.getSignedPreKey() != null ? preKey.getSignedPreKey() :
preKey.getPreKey();
parameters.setOurIdentityKey(identityKeyStore.getIdentityKeyPair());
parameters.setOurBaseKey(ourBaseKey);
parameters.setOurEphemeralKey(Curve.generateKeyPair(true));
parameters.setOurPreKey(Optional.of(parameters.getOurBaseKey()));
AliceAxolotlParameters.Builder parameters = AliceAxolotlParameters.newBuilder();
parameters.setTheirIdentityKey(preKey.getIdentityKey());
if (preKey.getSignedPreKey() == null) parameters.setTheirBaseKey(preKey.getPreKey());
else parameters.setTheirBaseKey(preKey.getSignedPreKey());
parameters.setTheirEphemeralKey(parameters.getTheirBaseKey());
parameters.setTheirPreKey(Optional.fromNullable(preKey.getPreKey()));
parameters.setOurBaseKey(ourBaseKey)
.setOurIdentityKey(identityKeyStore.getIdentityKeyPair())
.setTheirIdentityKey(preKey.getIdentityKey())
.setTheirSignedPreKey(theirSignedPreKey)
.setTheirRatchetKey(theirSignedPreKey)
.setTheirOneTimePreKey(preKey.getSignedPreKey() != null ?
Optional.fromNullable(preKey.getPreKey()) :
Optional.<ECPublicKey>absent());
if (sessionRecord.getSessionState().getNeedsRefresh()) sessionRecord.archiveCurrentState();
else sessionRecord.reset();
@ -288,9 +290,8 @@ public class SessionBuilder {
}
private KeyExchangeMessage processInitiate(KeyExchangeMessage message) throws InvalidKeyException {
AxolotlParameters.Builder parameters = AxolotlParameters.newBuilder();
int flags = KeyExchangeMessage.RESPONSE_FLAG;
SessionRecord sessionRecord = sessionStore.loadSession(recipientId, deviceId);
int flags = KeyExchangeMessage.RESPONSE_FLAG;
SessionRecord sessionRecord = sessionStore.loadSession(recipientId, deviceId);
if (message.getVersion() >= 3 &&
!Curve.verifySignature(message.getIdentityKey().getPublicKey(),
@ -300,41 +301,42 @@ public class SessionBuilder {
throw new InvalidKeyException("Bad signature!");
}
SymmetricAxolotlParameters.Builder builder = SymmetricAxolotlParameters.newBuilder();
if (!sessionRecord.getSessionState().hasPendingKeyExchange()) {
Log.w(TAG, "We don't have a pending initiate...");
parameters.setOurBaseKey(Curve.generateKeyPair(true));
parameters.setOurEphemeralKey(Curve.generateKeyPair(true));
parameters.setOurIdentityKey(identityKeyStore.getIdentityKeyPair());
parameters.setOurPreKey(Optional.<ECKeyPair>absent());
builder.setOurIdentityKey(identityKeyStore.getIdentityKeyPair())
.setOurBaseKey(Curve.generateKeyPair(true))
.setOurRatchetKey(Curve.generateKeyPair(true));
} else {
Log.w(TAG, "We already have a pending initiate, responding as simultaneous initiate...");
parameters.setOurBaseKey(sessionRecord.getSessionState().getPendingKeyExchangeBaseKey());
parameters.setOurEphemeralKey(sessionRecord.getSessionState().getPendingKeyExchangeEphemeralKey());
parameters.setOurIdentityKey(sessionRecord.getSessionState().getPendingKeyExchangeIdentityKey());
parameters.setOurPreKey(Optional.<ECKeyPair>absent());
builder.setOurIdentityKey(sessionRecord.getSessionState().getPendingKeyExchangeIdentityKey())
.setOurBaseKey(sessionRecord.getSessionState().getPendingKeyExchangeBaseKey())
.setOurRatchetKey(sessionRecord.getSessionState().getPendingKeyExchangeRatchetKey());
flags |= KeyExchangeMessage.SIMULTAENOUS_INITIATE_FLAG;
}
parameters.setTheirBaseKey(message.getBaseKey());
parameters.setTheirEphemeralKey(message.getEphemeralKey());
parameters.setTheirPreKey(Optional.<ECPublicKey>absent());
parameters.setTheirIdentityKey(message.getIdentityKey());
builder.setTheirBaseKey(message.getBaseKey())
.setTheirRatchetKey(message.getRatchetKey())
.setTheirIdentityKey(message.getIdentityKey());
SymmetricAxolotlParameters parameters = builder.create();
sessionRecord.reset();
RatchetingSession.initializeSession(sessionRecord.getSessionState(),
Math.min(message.getMaxVersion(), CiphertextMessage.CURRENT_VERSION),
parameters.create());
parameters);
sessionStore.storeSession(recipientId, deviceId, sessionRecord);
identityKeyStore.saveIdentity(recipientId, message.getIdentityKey());
byte[] baseKeySignature = Curve.calculateSignature(parameters.getOurIdentityKey().getPrivateKey(),
parameters.getOurBaseKey().getPublicKey().serialize());
return new KeyExchangeMessage(sessionRecord.getSessionState().getSessionVersion(),
message.getSequence(), flags,
parameters.getOurBaseKey().getPublicKey(), null,
parameters.getOurEphemeralKey().getPublicKey(),
parameters.getOurIdentityKey().getPublicKey(),
sessionRecord.getSessionState().getVerification());
parameters.getOurBaseKey().getPublicKey(),
baseKeySignature, parameters.getOurRatchetKey().getPublicKey(),
parameters.getOurIdentityKey().getPublicKey());
}
private void processResponse(KeyExchangeMessage message)
@ -351,29 +353,27 @@ public class SessionBuilder {
else return;
}
AxolotlParameters parameters =
AxolotlParameters.newBuilder()
.setOurBaseKey(sessionRecord.getSessionState().getPendingKeyExchangeBaseKey())
.setOurEphemeralKey(sessionRecord.getSessionState().getPendingKeyExchangeEphemeralKey())
.setOurPreKey(Optional.<ECKeyPair>absent())
.setOurIdentityKey(sessionRecord.getSessionState().getPendingKeyExchangeIdentityKey())
.setTheirBaseKey(message.getBaseKey())
.setTheirEphemeralKey(message.getEphemeralKey())
.setTheirPreKey(Optional.<ECPublicKey>absent())
.setTheirIdentityKey(message.getIdentityKey())
.create();
SymmetricAxolotlParameters.Builder parameters = SymmetricAxolotlParameters.newBuilder();
parameters.setOurBaseKey(sessionRecord.getSessionState().getPendingKeyExchangeBaseKey())
.setOurRatchetKey(sessionRecord.getSessionState().getPendingKeyExchangeRatchetKey())
.setOurIdentityKey(sessionRecord.getSessionState().getPendingKeyExchangeIdentityKey())
.setTheirBaseKey(message.getBaseKey())
.setTheirRatchetKey(message.getRatchetKey())
.setTheirIdentityKey(message.getIdentityKey());
sessionRecord.reset();
RatchetingSession.initializeSession(sessionRecord.getSessionState(),
Math.min(message.getMaxVersion(), CiphertextMessage.CURRENT_VERSION),
parameters);
parameters.create());
if (sessionRecord.getSessionState().getSessionVersion() >= 3 &&
!MessageDigest.isEqual(message.getVerificationTag(),
sessionRecord.getSessionState().getVerification()))
!Curve.verifySignature(message.getIdentityKey().getPublicKey(),
message.getBaseKey().serialize(),
message.getBaseKeySignature()))
{
throw new InvalidKeyException("Verification tag doesn't match!");
throw new InvalidKeyException("Base key signature doesn't match!");
}
sessionStore.storeSession(recipientId, deviceId, sessionRecord);
@ -387,18 +387,23 @@ public class SessionBuilder {
* @return the KeyExchangeMessage to deliver.
*/
public KeyExchangeMessage process() {
int sequence = KeyHelper.getRandomSequence(65534) + 1;
int flags = KeyExchangeMessage.INITIATE_FLAG;
ECKeyPair baseKey = Curve.generateKeyPair(true);
ECKeyPair ephemeralKey = Curve.generateKeyPair(true);
IdentityKeyPair identityKey = identityKeyStore.getIdentityKeyPair();
SessionRecord sessionRecord = sessionStore.loadSession(recipientId, deviceId);
try {
int sequence = KeyHelper.getRandomSequence(65534) + 1;
int flags = KeyExchangeMessage.INITIATE_FLAG;
ECKeyPair baseKey = Curve.generateKeyPair(true);
ECKeyPair ratchetKey = Curve.generateKeyPair(true);
IdentityKeyPair identityKey = identityKeyStore.getIdentityKeyPair();
byte[] baseKeySignature = Curve.calculateSignature(identityKey.getPrivateKey(), baseKey.getPublicKey().serialize());
SessionRecord sessionRecord = sessionStore.loadSession(recipientId, deviceId);
sessionRecord.getSessionState().setPendingKeyExchange(sequence, baseKey, ephemeralKey, identityKey);
sessionStore.storeSession(recipientId, deviceId, sessionRecord);
sessionRecord.getSessionState().setPendingKeyExchange(sequence, baseKey, ratchetKey, identityKey);
sessionStore.storeSession(recipientId, deviceId, sessionRecord);
return new KeyExchangeMessage(2, sequence, flags, baseKey.getPublicKey(), null,
ephemeralKey.getPublicKey(), identityKey.getPublicKey(), null);
return new KeyExchangeMessage(2, sequence, flags, baseKey.getPublicKey(), baseKeySignature,
ratchetKey.getPublicKey(), identityKey.getPublicKey());
} catch (InvalidKeyException e) {
throw new AssertionError(e);
}
}

View File

@ -98,7 +98,7 @@ public class SessionCipher {
SessionState sessionState = sessionRecord.getSessionState();
ChainKey chainKey = sessionState.getSenderChainKey();
MessageKeys messageKeys = chainKey.getMessageKeys();
ECPublicKey senderEphemeral = sessionState.getSenderEphemeral();
ECPublicKey senderEphemeral = sessionState.getSenderRatchetKey();
int previousCounter = sessionState.getPreviousCounter();
int sessionVersion = sessionState.getSessionVersion();
@ -223,7 +223,7 @@ public class SessionCipher {
sessionState.getSessionVersion()));
}
ECPublicKey theirEphemeral = ciphertextMessage.getSenderEphemeral();
ECPublicKey theirEphemeral = ciphertextMessage.getSenderRatchetKey();
int counter = ciphertextMessage.getCounter();
ChainKey chainKey = getOrCreateChainKey(sessionState, theirEphemeral);
MessageKeys messageKeys = getOrCreateMessageKeys(sessionState, theirEphemeral,
@ -254,7 +254,7 @@ public class SessionCipher {
return sessionState.getReceiverChainKey(theirEphemeral);
} else {
RootKey rootKey = sessionState.getRootKey();
ECKeyPair ourEphemeral = sessionState.getSenderEphemeralPair();
ECKeyPair ourEphemeral = sessionState.getSenderRatchetKeyPair();
Pair<RootKey, ChainKey> receiverChain = rootKey.createChain(theirEphemeral, ourEphemeral);
ECKeyPair ourNewEphemeral = Curve.generateKeyPair(true);
Pair<RootKey, ChainKey> senderChain = receiverChain.first().createChain(theirEphemeral, ourNewEphemeral);

View File

@ -29,15 +29,14 @@ public class KeyExchangeMessage {
private final ECPublicKey baseKey;
private final byte[] baseKeySignature;
private final ECPublicKey ephemeralKey;
private final ECPublicKey ratchetKey;
private final IdentityKey identityKey;
private final byte[] verificationTag;
private final byte[] serialized;
public KeyExchangeMessage(int messageVersion, int sequence, int flags,
ECPublicKey baseKey, byte[] baseKeySignature,
ECPublicKey ephemeralKey,
IdentityKey identityKey, byte[] verificationTag)
ECPublicKey ratchetKey,
IdentityKey identityKey)
{
this.supportedVersion = CiphertextMessage.CURRENT_VERSION;
this.version = messageVersion;
@ -45,25 +44,21 @@ public class KeyExchangeMessage {
this.flags = flags;
this.baseKey = baseKey;
this.baseKeySignature = baseKeySignature;
this.ephemeralKey = ephemeralKey;
this.ratchetKey = ratchetKey;
this.identityKey = identityKey;
this.verificationTag = verificationTag;
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()));
Builder builder = WhisperProtos.KeyExchangeMessage
.newBuilder()
.setId((sequence << 5) | flags)
.setBaseKey(ByteString.copyFrom(baseKey.serialize()))
.setRatchetKey(ByteString.copyFrom(ratchetKey.serialize()))
.setIdentityKey(ByteString.copyFrom(identityKey.serialize()));
if (messageVersion >= 3 && baseKeySignature != null) {
if (messageVersion >= 3) {
builder.setBaseKeySignature(ByteString.copyFrom(baseKeySignature));
}
if (messageVersion >=3 && verificationTag != null) {
builder.setVerification(ByteString.copyFrom(verificationTag));
}
this.serialized = ByteUtil.combine(version, builder.build().toByteArray());
}
@ -86,9 +81,8 @@ public class KeyExchangeMessage {
WhisperProtos.KeyExchangeMessage message = WhisperProtos.KeyExchangeMessage.parseFrom(parts[1]);
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()))
!message.hasRatchetKey() || !message.hasIdentityKey() ||
(this.version >=3 && !message.hasBaseKeySignature()))
{
throw new InvalidMessageException("Some required fields missing!");
}
@ -98,8 +92,7 @@ public class KeyExchangeMessage {
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.ratchetKey = Curve.decodePoint(message.getRatchetKey().toByteArray(), 0);
this.identityKey = new IdentityKey(message.getIdentityKey().toByteArray(), 0);
} catch (InvalidKeyException | IOException e) {
throw new InvalidMessageException(e);
@ -118,12 +111,8 @@ public class KeyExchangeMessage {
return baseKeySignature;
}
public byte[] getVerificationTag() {
return verificationTag;
}
public ECPublicKey getEphemeralKey() {
return ephemeralKey;
public ECPublicKey getRatchetKey() {
return ratchetKey;
}
public IdentityKey getIdentityKey() {

View File

@ -38,7 +38,7 @@ public class WhisperMessage implements CiphertextMessage {
private static final int MAC_LENGTH = 8;
private final int messageVersion;
private final ECPublicKey senderEphemeral;
private final ECPublicKey senderRatchetKey;
private final int counter;
private final int previousCounter;
private final byte[] ciphertext;
@ -63,44 +63,44 @@ public class WhisperMessage implements CiphertextMessage {
if (!whisperMessage.hasCiphertext() ||
!whisperMessage.hasCounter() ||
!whisperMessage.hasEphemeralKey())
!whisperMessage.hasRatchetKey())
{
throw new InvalidMessageException("Incomplete message.");
}
this.serialized = serialized;
this.senderEphemeral = Curve.decodePoint(whisperMessage.getEphemeralKey().toByteArray(), 0);
this.messageVersion = ByteUtil.highBitsToInt(version);
this.counter = whisperMessage.getCounter();
this.previousCounter = whisperMessage.getPreviousCounter();
this.ciphertext = whisperMessage.getCiphertext().toByteArray();
this.serialized = serialized;
this.senderRatchetKey = Curve.decodePoint(whisperMessage.getRatchetKey().toByteArray(), 0);
this.messageVersion = ByteUtil.highBitsToInt(version);
this.counter = whisperMessage.getCounter();
this.previousCounter = whisperMessage.getPreviousCounter();
this.ciphertext = whisperMessage.getCiphertext().toByteArray();
} catch (InvalidProtocolBufferException | InvalidKeyException | ParseException e) {
throw new InvalidMessageException(e);
}
}
public WhisperMessage(int messageVersion, SecretKeySpec macKey, ECPublicKey senderEphemeral,
public WhisperMessage(int messageVersion, SecretKeySpec macKey, ECPublicKey senderRatchetKey,
int counter, int previousCounter, byte[] ciphertext)
{
byte[] version = {ByteUtil.intsToByteHighAndLow(messageVersion, CURRENT_VERSION)};
byte[] message = WhisperProtos.WhisperMessage.newBuilder()
.setEphemeralKey(ByteString.copyFrom(senderEphemeral.serialize()))
.setRatchetKey(ByteString.copyFrom(senderRatchetKey.serialize()))
.setCounter(counter)
.setPreviousCounter(previousCounter)
.setCiphertext(ByteString.copyFrom(ciphertext))
.build().toByteArray();
byte[] mac = getMac(macKey, ByteUtil.combine(version, message));
this.serialized = ByteUtil.combine(version, message, mac);
this.senderEphemeral = senderEphemeral;
this.counter = counter;
this.previousCounter = previousCounter;
this.ciphertext = ciphertext;
this.messageVersion = messageVersion;
this.serialized = ByteUtil.combine(version, message, mac);
this.senderRatchetKey = senderRatchetKey;
this.counter = counter;
this.previousCounter = previousCounter;
this.ciphertext = ciphertext;
this.messageVersion = messageVersion;
}
public ECPublicKey getSenderEphemeral() {
return senderEphemeral;
public ECPublicKey getSenderRatchetKey() {
return senderRatchetKey;
}
public int getMessageVersion() {

View File

@ -11,15 +11,15 @@ public final class WhisperProtos {
public interface WhisperMessageOrBuilder
extends com.google.protobuf.MessageOrBuilder {
// optional bytes ephemeralKey = 1;
// optional bytes ratchetKey = 1;
/**
* <code>optional bytes ephemeralKey = 1;</code>
* <code>optional bytes ratchetKey = 1;</code>
*/
boolean hasEphemeralKey();
boolean hasRatchetKey();
/**
* <code>optional bytes ephemeralKey = 1;</code>
* <code>optional bytes ratchetKey = 1;</code>
*/
com.google.protobuf.ByteString getEphemeralKey();
com.google.protobuf.ByteString getRatchetKey();
// optional uint32 counter = 2;
/**
@ -104,7 +104,7 @@ public final class WhisperProtos {
}
case 10: {
bitField0_ |= 0x00000001;
ephemeralKey_ = input.readBytes();
ratchetKey_ = input.readBytes();
break;
}
case 16: {
@ -162,20 +162,20 @@ public final class WhisperProtos {
}
private int bitField0_;
// optional bytes ephemeralKey = 1;
public static final int EPHEMERALKEY_FIELD_NUMBER = 1;
private com.google.protobuf.ByteString ephemeralKey_;
// optional bytes ratchetKey = 1;
public static final int RATCHETKEY_FIELD_NUMBER = 1;
private com.google.protobuf.ByteString ratchetKey_;
/**
* <code>optional bytes ephemeralKey = 1;</code>
* <code>optional bytes ratchetKey = 1;</code>
*/
public boolean hasEphemeralKey() {
public boolean hasRatchetKey() {
return ((bitField0_ & 0x00000001) == 0x00000001);
}
/**
* <code>optional bytes ephemeralKey = 1;</code>
* <code>optional bytes ratchetKey = 1;</code>
*/
public com.google.protobuf.ByteString getEphemeralKey() {
return ephemeralKey_;
public com.google.protobuf.ByteString getRatchetKey() {
return ratchetKey_;
}
// optional uint32 counter = 2;
@ -227,7 +227,7 @@ public final class WhisperProtos {
}
private void initFields() {
ephemeralKey_ = com.google.protobuf.ByteString.EMPTY;
ratchetKey_ = com.google.protobuf.ByteString.EMPTY;
counter_ = 0;
previousCounter_ = 0;
ciphertext_ = com.google.protobuf.ByteString.EMPTY;
@ -245,7 +245,7 @@ public final class WhisperProtos {
throws java.io.IOException {
getSerializedSize();
if (((bitField0_ & 0x00000001) == 0x00000001)) {
output.writeBytes(1, ephemeralKey_);
output.writeBytes(1, ratchetKey_);
}
if (((bitField0_ & 0x00000002) == 0x00000002)) {
output.writeUInt32(2, counter_);
@ -267,7 +267,7 @@ public final class WhisperProtos {
size = 0;
if (((bitField0_ & 0x00000001) == 0x00000001)) {
size += com.google.protobuf.CodedOutputStream
.computeBytesSize(1, ephemeralKey_);
.computeBytesSize(1, ratchetKey_);
}
if (((bitField0_ & 0x00000002) == 0x00000002)) {
size += com.google.protobuf.CodedOutputStream
@ -397,7 +397,7 @@ public final class WhisperProtos {
public Builder clear() {
super.clear();
ephemeralKey_ = com.google.protobuf.ByteString.EMPTY;
ratchetKey_ = com.google.protobuf.ByteString.EMPTY;
bitField0_ = (bitField0_ & ~0x00000001);
counter_ = 0;
bitField0_ = (bitField0_ & ~0x00000002);
@ -436,7 +436,7 @@ public final class WhisperProtos {
if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
to_bitField0_ |= 0x00000001;
}
result.ephemeralKey_ = ephemeralKey_;
result.ratchetKey_ = ratchetKey_;
if (((from_bitField0_ & 0x00000002) == 0x00000002)) {
to_bitField0_ |= 0x00000002;
}
@ -465,8 +465,8 @@ public final class WhisperProtos {
public Builder mergeFrom(org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage other) {
if (other == org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage.getDefaultInstance()) return this;
if (other.hasEphemeralKey()) {
setEphemeralKey(other.getEphemeralKey());
if (other.hasRatchetKey()) {
setRatchetKey(other.getRatchetKey());
}
if (other.hasCounter()) {
setCounter(other.getCounter());
@ -504,38 +504,38 @@ public final class WhisperProtos {
}
private int bitField0_;
// optional bytes ephemeralKey = 1;
private com.google.protobuf.ByteString ephemeralKey_ = com.google.protobuf.ByteString.EMPTY;
// optional bytes ratchetKey = 1;
private com.google.protobuf.ByteString ratchetKey_ = com.google.protobuf.ByteString.EMPTY;
/**
* <code>optional bytes ephemeralKey = 1;</code>
* <code>optional bytes ratchetKey = 1;</code>
*/
public boolean hasEphemeralKey() {
public boolean hasRatchetKey() {
return ((bitField0_ & 0x00000001) == 0x00000001);
}
/**
* <code>optional bytes ephemeralKey = 1;</code>
* <code>optional bytes ratchetKey = 1;</code>
*/
public com.google.protobuf.ByteString getEphemeralKey() {
return ephemeralKey_;
public com.google.protobuf.ByteString getRatchetKey() {
return ratchetKey_;
}
/**
* <code>optional bytes ephemeralKey = 1;</code>
* <code>optional bytes ratchetKey = 1;</code>
*/
public Builder setEphemeralKey(com.google.protobuf.ByteString value) {
public Builder setRatchetKey(com.google.protobuf.ByteString value) {
if (value == null) {
throw new NullPointerException();
}
bitField0_ |= 0x00000001;
ephemeralKey_ = value;
ratchetKey_ = value;
onChanged();
return this;
}
/**
* <code>optional bytes ephemeralKey = 1;</code>
* <code>optional bytes ratchetKey = 1;</code>
*/
public Builder clearEphemeralKey() {
public Builder clearRatchetKey() {
bitField0_ = (bitField0_ & ~0x00000001);
ephemeralKey_ = getDefaultInstance().getEphemeralKey();
ratchetKey_ = getDefaultInstance().getRatchetKey();
onChanged();
return this;
}
@ -1602,15 +1602,15 @@ public final class WhisperProtos {
*/
com.google.protobuf.ByteString getBaseKey();
// optional bytes ephemeralKey = 3;
// optional bytes ratchetKey = 3;
/**
* <code>optional bytes ephemeralKey = 3;</code>
* <code>optional bytes ratchetKey = 3;</code>
*/
boolean hasEphemeralKey();
boolean hasRatchetKey();
/**
* <code>optional bytes ephemeralKey = 3;</code>
* <code>optional bytes ratchetKey = 3;</code>
*/
com.google.protobuf.ByteString getEphemeralKey();
com.google.protobuf.ByteString getRatchetKey();
// optional bytes identityKey = 4;
/**
@ -1625,22 +1625,20 @@ public final class WhisperProtos {
// optional bytes baseKeySignature = 5;
/**
* <code>optional bytes baseKeySignature = 5;</code>
*
* <pre>
* optional bytes verification = 6;
* </pre>
*/
boolean hasBaseKeySignature();
/**
* <code>optional bytes baseKeySignature = 5;</code>
*
* <pre>
* optional bytes verification = 6;
* </pre>
*/
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}
@ -1705,7 +1703,7 @@ public final class WhisperProtos {
}
case 26: {
bitField0_ |= 0x00000004;
ephemeralKey_ = input.readBytes();
ratchetKey_ = input.readBytes();
break;
}
case 34: {
@ -1718,11 +1716,6 @@ public final class WhisperProtos {
baseKeySignature_ = input.readBytes();
break;
}
case 50: {
bitField0_ |= 0x00000020;
verification_ = input.readBytes();
break;
}
}
}
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
@ -1795,20 +1788,20 @@ public final class WhisperProtos {
return baseKey_;
}
// optional bytes ephemeralKey = 3;
public static final int EPHEMERALKEY_FIELD_NUMBER = 3;
private com.google.protobuf.ByteString ephemeralKey_;
// optional bytes ratchetKey = 3;
public static final int RATCHETKEY_FIELD_NUMBER = 3;
private com.google.protobuf.ByteString ratchetKey_;
/**
* <code>optional bytes ephemeralKey = 3;</code>
* <code>optional bytes ratchetKey = 3;</code>
*/
public boolean hasEphemeralKey() {
public boolean hasRatchetKey() {
return ((bitField0_ & 0x00000004) == 0x00000004);
}
/**
* <code>optional bytes ephemeralKey = 3;</code>
* <code>optional bytes ratchetKey = 3;</code>
*/
public com.google.protobuf.ByteString getEphemeralKey() {
return ephemeralKey_;
public com.google.protobuf.ByteString getRatchetKey() {
return ratchetKey_;
}
// optional bytes identityKey = 4;
@ -1832,40 +1825,31 @@ public final class WhisperProtos {
private com.google.protobuf.ByteString baseKeySignature_;
/**
* <code>optional bytes baseKeySignature = 5;</code>
*
* <pre>
* optional bytes verification = 6;
* </pre>
*/
public boolean hasBaseKeySignature() {
return ((bitField0_ & 0x00000010) == 0x00000010);
}
/**
* <code>optional bytes baseKeySignature = 5;</code>
*
* <pre>
* optional bytes verification = 6;
* </pre>
*/
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() {
id_ = 0;
baseKey_ = com.google.protobuf.ByteString.EMPTY;
ephemeralKey_ = com.google.protobuf.ByteString.EMPTY;
ratchetKey_ = 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() {
@ -1886,7 +1870,7 @@ public final class WhisperProtos {
output.writeBytes(2, baseKey_);
}
if (((bitField0_ & 0x00000004) == 0x00000004)) {
output.writeBytes(3, ephemeralKey_);
output.writeBytes(3, ratchetKey_);
}
if (((bitField0_ & 0x00000008) == 0x00000008)) {
output.writeBytes(4, identityKey_);
@ -1894,9 +1878,6 @@ public final class WhisperProtos {
if (((bitField0_ & 0x00000010) == 0x00000010)) {
output.writeBytes(5, baseKeySignature_);
}
if (((bitField0_ & 0x00000020) == 0x00000020)) {
output.writeBytes(6, verification_);
}
getUnknownFields().writeTo(output);
}
@ -1916,7 +1897,7 @@ public final class WhisperProtos {
}
if (((bitField0_ & 0x00000004) == 0x00000004)) {
size += com.google.protobuf.CodedOutputStream
.computeBytesSize(3, ephemeralKey_);
.computeBytesSize(3, ratchetKey_);
}
if (((bitField0_ & 0x00000008) == 0x00000008)) {
size += com.google.protobuf.CodedOutputStream
@ -1926,10 +1907,6 @@ public final class WhisperProtos {
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;
@ -2050,14 +2027,12 @@ public final class WhisperProtos {
bitField0_ = (bitField0_ & ~0x00000001);
baseKey_ = com.google.protobuf.ByteString.EMPTY;
bitField0_ = (bitField0_ & ~0x00000002);
ephemeralKey_ = com.google.protobuf.ByteString.EMPTY;
ratchetKey_ = com.google.protobuf.ByteString.EMPTY;
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;
}
@ -2097,7 +2072,7 @@ public final class WhisperProtos {
if (((from_bitField0_ & 0x00000004) == 0x00000004)) {
to_bitField0_ |= 0x00000004;
}
result.ephemeralKey_ = ephemeralKey_;
result.ratchetKey_ = ratchetKey_;
if (((from_bitField0_ & 0x00000008) == 0x00000008)) {
to_bitField0_ |= 0x00000008;
}
@ -2106,10 +2081,6 @@ public final class WhisperProtos {
to_bitField0_ |= 0x00000010;
}
result.baseKeySignature_ = baseKeySignature_;
if (((from_bitField0_ & 0x00000020) == 0x00000020)) {
to_bitField0_ |= 0x00000020;
}
result.verification_ = verification_;
result.bitField0_ = to_bitField0_;
onBuilt();
return result;
@ -2132,8 +2103,8 @@ public final class WhisperProtos {
if (other.hasBaseKey()) {
setBaseKey(other.getBaseKey());
}
if (other.hasEphemeralKey()) {
setEphemeralKey(other.getEphemeralKey());
if (other.hasRatchetKey()) {
setRatchetKey(other.getRatchetKey());
}
if (other.hasIdentityKey()) {
setIdentityKey(other.getIdentityKey());
@ -2141,9 +2112,6 @@ public final class WhisperProtos {
if (other.hasBaseKeySignature()) {
setBaseKeySignature(other.getBaseKeySignature());
}
if (other.hasVerification()) {
setVerification(other.getVerification());
}
this.mergeUnknownFields(other.getUnknownFields());
return this;
}
@ -2240,38 +2208,38 @@ public final class WhisperProtos {
return this;
}
// optional bytes ephemeralKey = 3;
private com.google.protobuf.ByteString ephemeralKey_ = com.google.protobuf.ByteString.EMPTY;
// optional bytes ratchetKey = 3;
private com.google.protobuf.ByteString ratchetKey_ = com.google.protobuf.ByteString.EMPTY;
/**
* <code>optional bytes ephemeralKey = 3;</code>
* <code>optional bytes ratchetKey = 3;</code>
*/
public boolean hasEphemeralKey() {
public boolean hasRatchetKey() {
return ((bitField0_ & 0x00000004) == 0x00000004);
}
/**
* <code>optional bytes ephemeralKey = 3;</code>
* <code>optional bytes ratchetKey = 3;</code>
*/
public com.google.protobuf.ByteString getEphemeralKey() {
return ephemeralKey_;
public com.google.protobuf.ByteString getRatchetKey() {
return ratchetKey_;
}
/**
* <code>optional bytes ephemeralKey = 3;</code>
* <code>optional bytes ratchetKey = 3;</code>
*/
public Builder setEphemeralKey(com.google.protobuf.ByteString value) {
public Builder setRatchetKey(com.google.protobuf.ByteString value) {
if (value == null) {
throw new NullPointerException();
}
bitField0_ |= 0x00000004;
ephemeralKey_ = value;
ratchetKey_ = value;
onChanged();
return this;
}
/**
* <code>optional bytes ephemeralKey = 3;</code>
* <code>optional bytes ratchetKey = 3;</code>
*/
public Builder clearEphemeralKey() {
public Builder clearRatchetKey() {
bitField0_ = (bitField0_ & ~0x00000004);
ephemeralKey_ = getDefaultInstance().getEphemeralKey();
ratchetKey_ = getDefaultInstance().getRatchetKey();
onChanged();
return this;
}
@ -2316,18 +2284,30 @@ public final class WhisperProtos {
private com.google.protobuf.ByteString baseKeySignature_ = com.google.protobuf.ByteString.EMPTY;
/**
* <code>optional bytes baseKeySignature = 5;</code>
*
* <pre>
* optional bytes verification = 6;
* </pre>
*/
public boolean hasBaseKeySignature() {
return ((bitField0_ & 0x00000010) == 0x00000010);
}
/**
* <code>optional bytes baseKeySignature = 5;</code>
*
* <pre>
* optional bytes verification = 6;
* </pre>
*/
public com.google.protobuf.ByteString getBaseKeySignature() {
return baseKeySignature_;
}
/**
* <code>optional bytes baseKeySignature = 5;</code>
*
* <pre>
* optional bytes verification = 6;
* </pre>
*/
public Builder setBaseKeySignature(com.google.protobuf.ByteString value) {
if (value == null) {
@ -2340,6 +2320,10 @@ public final class WhisperProtos {
}
/**
* <code>optional bytes baseKeySignature = 5;</code>
*
* <pre>
* optional bytes verification = 6;
* </pre>
*/
public Builder clearBaseKeySignature() {
bitField0_ = (bitField0_ & ~0x00000010);
@ -2348,42 +2332,6 @@ public final class WhisperProtos {
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)
}
@ -2420,18 +2368,18 @@ public final class WhisperProtos {
static {
java.lang.String[] descriptorData = {
"\n\031WhisperTextProtocol.proto\022\ntextsecure\"" +
"d\n\016WhisperMessage\022\024\n\014ephemeralKey\030\001 \001(\014\022" +
"\017\n\007counter\030\002 \001(\r\022\027\n\017previousCounter\030\003 \001(" +
"\r\022\022\n\nciphertext\030\004 \001(\014\"\245\001\n\024PreKeyWhisperM" +
"essage\022\026\n\016registrationId\030\005 \001(\r\022\020\n\010preKey" +
"Id\030\001 \001(\r\022\026\n\016signedPreKeyId\030\006 \001(\r\022\017\n\007base" +
"Key\030\002 \001(\014\022\023\n\013identityKey\030\003 \001(\014\022\024\n\014verifi" +
"cation\030\007 \001(\014\022\017\n\007message\030\004 \001(\014\"\214\001\n\022KeyExc" +
"hangeMessage\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\014verifi" +
"cation\030\006 \001(\014B7\n&org.whispersystems.libax" +
"olotl.protocolB\rWhisperProtos"
"b\n\016WhisperMessage\022\022\n\nratchetKey\030\001 \001(\014\022\017\n" +
"\007counter\030\002 \001(\r\022\027\n\017previousCounter\030\003 \001(\r\022" +
"\022\n\nciphertext\030\004 \001(\014\"\245\001\n\024PreKeyWhisperMes" +
"sage\022\026\n\016registrationId\030\005 \001(\r\022\020\n\010preKeyId" +
"\030\001 \001(\r\022\026\n\016signedPreKeyId\030\006 \001(\r\022\017\n\007baseKe" +
"y\030\002 \001(\014\022\023\n\013identityKey\030\003 \001(\014\022\024\n\014verifica" +
"tion\030\007 \001(\014\022\017\n\007message\030\004 \001(\014\"t\n\022KeyExchan" +
"geMessage\022\n\n\002id\030\001 \001(\r\022\017\n\007baseKey\030\002 \001(\014\022\022" +
"\n\nratchetKey\030\003 \001(\014\022\023\n\013identityKey\030\004 \001(\014\022",
"\030\n\020baseKeySignature\030\005 \001(\014B7\n&org.whisper" +
"systems.libaxolotl.protocolB\rWhisperProt" +
"os"
};
com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
@ -2443,7 +2391,7 @@ public final class WhisperProtos {
internal_static_textsecure_WhisperMessage_fieldAccessorTable = new
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
internal_static_textsecure_WhisperMessage_descriptor,
new java.lang.String[] { "EphemeralKey", "Counter", "PreviousCounter", "Ciphertext", });
new java.lang.String[] { "RatchetKey", "Counter", "PreviousCounter", "Ciphertext", });
internal_static_textsecure_PreKeyWhisperMessage_descriptor =
getDescriptor().getMessageTypes().get(1);
internal_static_textsecure_PreKeyWhisperMessage_fieldAccessorTable = new
@ -2455,7 +2403,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", "BaseKeySignature", "Verification", });
new java.lang.String[] { "Id", "BaseKey", "RatchetKey", "IdentityKey", "BaseKeySignature", });
return null;
}
};

View File

@ -0,0 +1,109 @@
package org.whispersystems.libaxolotl.ratchet;
import org.whispersystems.libaxolotl.IdentityKey;
import org.whispersystems.libaxolotl.IdentityKeyPair;
import org.whispersystems.libaxolotl.ecc.ECKeyPair;
import org.whispersystems.libaxolotl.ecc.ECPublicKey;
import org.whispersystems.libaxolotl.util.guava.Optional;
public class AliceAxolotlParameters {
private final IdentityKeyPair ourIdentityKey;
private final ECKeyPair ourBaseKey;
private final IdentityKey theirIdentityKey;
private final ECPublicKey theirSignedPreKey;
private final Optional<ECPublicKey> theirOneTimePreKey;
private final ECPublicKey theirRatchetKey;
private AliceAxolotlParameters(IdentityKeyPair ourIdentityKey, ECKeyPair ourBaseKey,
IdentityKey theirIdentityKey, ECPublicKey theirSignedPreKey,
ECPublicKey theirRatchetKey, Optional<ECPublicKey> theirOneTimePreKey)
{
this.ourIdentityKey = ourIdentityKey;
this.ourBaseKey = ourBaseKey;
this.theirIdentityKey = theirIdentityKey;
this.theirSignedPreKey = theirSignedPreKey;
this.theirRatchetKey = theirRatchetKey;
this.theirOneTimePreKey = theirOneTimePreKey;
if (ourIdentityKey == null || ourBaseKey == null || theirIdentityKey == null ||
theirSignedPreKey == null || theirRatchetKey == null || theirOneTimePreKey == null)
{
throw new IllegalArgumentException("Null values!");
}
}
public IdentityKeyPair getOurIdentityKey() {
return ourIdentityKey;
}
public ECKeyPair getOurBaseKey() {
return ourBaseKey;
}
public IdentityKey getTheirIdentityKey() {
return theirIdentityKey;
}
public ECPublicKey getTheirSignedPreKey() {
return theirSignedPreKey;
}
public Optional<ECPublicKey> getTheirOneTimePreKey() {
return theirOneTimePreKey;
}
public static Builder newBuilder() {
return new Builder();
}
public ECPublicKey getTheirRatchetKey() {
return theirRatchetKey;
}
public static class Builder {
private IdentityKeyPair ourIdentityKey;
private ECKeyPair ourBaseKey;
private IdentityKey theirIdentityKey;
private ECPublicKey theirSignedPreKey;
private ECPublicKey theirRatchetKey;
private Optional<ECPublicKey> theirOneTimePreKey;
public Builder setOurIdentityKey(IdentityKeyPair ourIdentityKey) {
this.ourIdentityKey = ourIdentityKey;
return this;
}
public Builder setOurBaseKey(ECKeyPair ourBaseKey) {
this.ourBaseKey = ourBaseKey;
return this;
}
public Builder setTheirRatchetKey(ECPublicKey theirRatchetKey) {
this.theirRatchetKey = theirRatchetKey;
return this;
}
public Builder setTheirIdentityKey(IdentityKey theirIdentityKey) {
this.theirIdentityKey = theirIdentityKey;
return this;
}
public Builder setTheirSignedPreKey(ECPublicKey theirSignedPreKey) {
this.theirSignedPreKey = theirSignedPreKey;
return this;
}
public Builder setTheirOneTimePreKey(Optional<ECPublicKey> theirOneTimePreKey) {
this.theirOneTimePreKey = theirOneTimePreKey;
return this;
}
public AliceAxolotlParameters create() {
return new AliceAxolotlParameters(ourIdentityKey, ourBaseKey, theirIdentityKey,
theirSignedPreKey, theirRatchetKey, theirOneTimePreKey);
}
}
}

View File

@ -0,0 +1,109 @@
package org.whispersystems.libaxolotl.ratchet;
import org.whispersystems.libaxolotl.IdentityKey;
import org.whispersystems.libaxolotl.IdentityKeyPair;
import org.whispersystems.libaxolotl.ecc.ECKeyPair;
import org.whispersystems.libaxolotl.ecc.ECPublicKey;
import org.whispersystems.libaxolotl.util.guava.Optional;
public class BobAxolotlParameters {
private final IdentityKeyPair ourIdentityKey;
private final ECKeyPair ourSignedPreKey;
private final Optional<ECKeyPair> ourOneTimePreKey;
private final ECKeyPair ourRatchetKey;
private final IdentityKey theirIdentityKey;
private final ECPublicKey theirBaseKey;
BobAxolotlParameters(IdentityKeyPair ourIdentityKey, ECKeyPair ourSignedPreKey,
ECKeyPair ourRatchetKey, Optional<ECKeyPair> ourOneTimePreKey,
IdentityKey theirIdentityKey, ECPublicKey theirBaseKey)
{
this.ourIdentityKey = ourIdentityKey;
this.ourSignedPreKey = ourSignedPreKey;
this.ourRatchetKey = ourRatchetKey;
this.ourOneTimePreKey = ourOneTimePreKey;
this.theirIdentityKey = theirIdentityKey;
this.theirBaseKey = theirBaseKey;
if (ourIdentityKey == null || ourSignedPreKey == null || ourRatchetKey == null ||
ourOneTimePreKey == null || theirIdentityKey == null || theirBaseKey == null)
{
throw new IllegalArgumentException("Null value!");
}
}
public IdentityKeyPair getOurIdentityKey() {
return ourIdentityKey;
}
public ECKeyPair getOurSignedPreKey() {
return ourSignedPreKey;
}
public Optional<ECKeyPair> getOurOneTimePreKey() {
return ourOneTimePreKey;
}
public IdentityKey getTheirIdentityKey() {
return theirIdentityKey;
}
public ECPublicKey getTheirBaseKey() {
return theirBaseKey;
}
public static Builder newBuilder() {
return new Builder();
}
public ECKeyPair getOurRatchetKey() {
return ourRatchetKey;
}
public static class Builder {
private IdentityKeyPair ourIdentityKey;
private ECKeyPair ourSignedPreKey;
private Optional<ECKeyPair> ourOneTimePreKey;
private ECKeyPair ourRatchetKey;
private IdentityKey theirIdentityKey;
private ECPublicKey theirBaseKey;
public Builder setOurIdentityKey(IdentityKeyPair ourIdentityKey) {
this.ourIdentityKey = ourIdentityKey;
return this;
}
public Builder setOurSignedPreKey(ECKeyPair ourSignedPreKey) {
this.ourSignedPreKey = ourSignedPreKey;
return this;
}
public Builder setOurOneTimePreKey(Optional<ECKeyPair> ourOneTimePreKey) {
this.ourOneTimePreKey = ourOneTimePreKey;
return this;
}
public Builder setTheirIdentityKey(IdentityKey theirIdentityKey) {
this.theirIdentityKey = theirIdentityKey;
return this;
}
public Builder setTheirBaseKey(ECPublicKey theirBaseKey) {
this.theirBaseKey = theirBaseKey;
return this;
}
public Builder setOurRatchetKey(ECKeyPair ourRatchetKey) {
this.ourRatchetKey = ourRatchetKey;
return this;
}
public BobAxolotlParameters create() {
return new BobAxolotlParameters(ourIdentityKey, ourSignedPreKey, ourRatchetKey,
ourOneTimePreKey, theirIdentityKey, theirBaseKey);
}
}
}

View File

@ -16,8 +16,6 @@
*/
package org.whispersystems.libaxolotl.ratchet;
import org.whispersystems.libaxolotl.IdentityKey;
import org.whispersystems.libaxolotl.IdentityKeyPair;
import org.whispersystems.libaxolotl.InvalidKeyException;
import org.whispersystems.libaxolotl.ecc.Curve;
import org.whispersystems.libaxolotl.ecc.ECKeyPair;
@ -37,288 +35,176 @@ public class RatchetingSession {
public static void initializeSession(SessionState sessionState,
int sessionVersion,
AxolotlParameters parameters)
SymmetricAxolotlParameters parameters)
throws InvalidKeyException
{
if (isAlice(parameters)) initializeSessionAsAlice(sessionState, sessionVersion, parameters);
else initializeSessionAsBob(sessionState, sessionVersion, parameters);
if (isAlice(parameters.getOurBaseKey().getPublicKey(), parameters.getTheirBaseKey())) {
AliceAxolotlParameters.Builder aliceParameters = AliceAxolotlParameters.newBuilder();
sessionState.setSessionVersion(sessionVersion);
}
aliceParameters.setOurBaseKey(parameters.getOurBaseKey())
.setOurIdentityKey(parameters.getOurIdentityKey())
.setTheirRatchetKey(parameters.getTheirRatchetKey())
.setTheirIdentityKey(parameters.getTheirIdentityKey())
.setTheirSignedPreKey(parameters.getTheirBaseKey())
.setTheirOneTimePreKey(Optional.<ECPublicKey>absent());
private static void initializeSessionAsAlice(SessionState sessionState,
int sessionVersion,
AxolotlParameters parameters)
throws InvalidKeyException
{
sessionState.setRemoteIdentityKey(parameters.getTheirIdentityKey());
sessionState.setLocalIdentityKey(parameters.getOurIdentityKey().getPublicKey());
RatchetingSession.initializeSession(sessionState, sessionVersion, aliceParameters.create());
} else {
BobAxolotlParameters.Builder bobParameters = BobAxolotlParameters.newBuilder();
ECKeyPair sendingKey = Curve.generateKeyPair(true);
DHEResult result = calculate4DHE(true, sessionVersion, parameters);
bobParameters.setOurIdentityKey(parameters.getOurIdentityKey())
.setOurRatchetKey(parameters.getOurRatchetKey())
.setOurSignedPreKey(parameters.getOurBaseKey())
.setOurOneTimePreKey(Optional.<ECKeyPair>absent())
.setTheirBaseKey(parameters.getTheirBaseKey())
.setTheirIdentityKey(parameters.getTheirIdentityKey());
Pair<RootKey, ChainKey> sendingChain = result.getRootKey().createChain(parameters.getTheirEphemeralKey(), sendingKey);
sessionState.addReceiverChain(parameters.getTheirEphemeralKey(), result.getChainKey());
sessionState.setSenderChain(sendingKey, sendingChain.second());
sessionState.setRootKey(sendingChain.first());
if (sessionVersion >= 3) {
sessionState.setVerification(calculateVerificationTag(true, result.getVerifyKey(), parameters));
RatchetingSession.initializeSession(sessionState, sessionVersion, bobParameters.create());
}
}
private static void initializeSessionAsBob(SessionState sessionState,
int sessionVersion,
AxolotlParameters parameters)
throws InvalidKeyException
{
sessionState.setRemoteIdentityKey(parameters.getTheirIdentityKey());
sessionState.setLocalIdentityKey(parameters.getOurIdentityKey().getPublicKey());
DHEResult result = calculate4DHE(false, sessionVersion, parameters);
sessionState.setSenderChain(parameters.getOurEphemeralKey(), result.getChainKey());
sessionState.setRootKey(result.getRootKey());
if (sessionVersion >= 3) {
sessionState.setVerification(calculateVerificationTag(false, result.getVerifyKey(), parameters));
}
}
private static DHEResult calculate4DHE(boolean isAlice, int sessionVersion, AxolotlParameters parameters)
public static void initializeSession(SessionState sessionState,
int sessionVersion,
AliceAxolotlParameters parameters)
throws InvalidKeyException
{
try {
HKDF kdf = HKDF.createFor(sessionVersion);
byte[] discontinuity = new byte[32];
ByteArrayOutputStream secrets = new ByteArrayOutputStream();
sessionState.setSessionVersion(sessionVersion);
sessionState.setRemoteIdentityKey(parameters.getTheirIdentityKey());
sessionState.setLocalIdentityKey(parameters.getOurIdentityKey().getPublicKey());
ECKeyPair sendingRatchetKey = Curve.generateKeyPair(true);
ByteArrayOutputStream secrets = new ByteArrayOutputStream();
if (sessionVersion >= 3) {
Arrays.fill(discontinuity, (byte) 0xFF);
secrets.write(discontinuity);
secrets.write(getDiscontinuityBytes());
}
if (isAlice) {
secrets.write(Curve.calculateAgreement(parameters.getTheirBaseKey(),
parameters.getOurIdentityKey().getPrivateKey()));
secrets.write(Curve.calculateAgreement(parameters.getTheirIdentityKey().getPublicKey(),
parameters.getOurBaseKey().getPrivateKey()));
} else {
secrets.write(Curve.calculateAgreement(parameters.getTheirIdentityKey().getPublicKey(),
parameters.getOurBaseKey().getPrivateKey()));
secrets.write(Curve.calculateAgreement(parameters.getTheirBaseKey(),
parameters.getOurIdentityKey().getPrivateKey()));
}
secrets.write(Curve.calculateAgreement(parameters.getTheirBaseKey(),
secrets.write(Curve.calculateAgreement(parameters.getTheirSignedPreKey(),
parameters.getOurIdentityKey().getPrivateKey()));
secrets.write(Curve.calculateAgreement(parameters.getTheirIdentityKey().getPublicKey(),
parameters.getOurBaseKey().getPrivateKey()));
secrets.write(Curve.calculateAgreement(parameters.getTheirSignedPreKey(),
parameters.getOurBaseKey().getPrivateKey()));
if (sessionVersion >= 3 && parameters.getTheirPreKey().isPresent() && parameters.getOurPreKey().isPresent()) {
secrets.write(Curve.calculateAgreement(parameters.getTheirPreKey().get(), parameters.getOurPreKey().get().getPrivateKey()));
if (sessionVersion >= 3 & parameters.getTheirOneTimePreKey().isPresent()) {
secrets.write(Curve.calculateAgreement(parameters.getTheirOneTimePreKey().get(),
parameters.getOurBaseKey().getPrivateKey()));
}
byte[] derivedSecretBytes = kdf.deriveSecrets(secrets.toByteArray(), "WhisperText".getBytes(), 96);
byte[][] derivedSecrets = ByteUtil.split(derivedSecretBytes, 32, 32, 32);
DerivedKeys derivedKeys = calculateDerivedKeys(sessionVersion, secrets.toByteArray());
Pair<RootKey, ChainKey> sendingChain = derivedKeys.getRootKey().createChain(parameters.getTheirRatchetKey(), sendingRatchetKey);
return new DHEResult(new RootKey(kdf, derivedSecrets[0]),
new ChainKey(kdf, derivedSecrets[1], 0),
new VerifyKey(derivedSecrets[2]));
sessionState.addReceiverChain(parameters.getTheirRatchetKey(), derivedKeys.getChainKey());
sessionState.setSenderChain(sendingRatchetKey, sendingChain.second());
sessionState.setRootKey(sendingChain.first());
} catch (IOException | ParseException e) {
if (sessionVersion >= 3) {
sessionState.setVerification(calculateVerificationTag(derivedKeys.getVerifyKey(), parameters));
}
} catch (IOException e) {
throw new AssertionError(e);
}
}
private static byte[] calculateVerificationTag(boolean isAlice, VerifyKey verifyKey,
AxolotlParameters parameters)
public static void initializeSession(SessionState sessionState,
int sessionVersion,
BobAxolotlParameters parameters)
throws InvalidKeyException
{
if (isAlice) {
return verifyKey.generateVerification(parameters.getOurBaseKey().getPublicKey(),
getPublicKey(parameters.getOurPreKey()),
parameters.getOurIdentityKey().getPublicKey().getPublicKey(),
parameters.getTheirBaseKey(),
parameters.getTheirPreKey(),
parameters.getTheirIdentityKey().getPublicKey());
try {
sessionState.setSessionVersion(sessionVersion);
sessionState.setRemoteIdentityKey(parameters.getTheirIdentityKey());
sessionState.setLocalIdentityKey(parameters.getOurIdentityKey().getPublicKey());
ByteArrayOutputStream secrets = new ByteArrayOutputStream();
if (sessionVersion >= 3) {
secrets.write(getDiscontinuityBytes());
}
secrets.write(Curve.calculateAgreement(parameters.getTheirIdentityKey().getPublicKey(),
parameters.getOurSignedPreKey().getPrivateKey()));
secrets.write(Curve.calculateAgreement(parameters.getTheirBaseKey(),
parameters.getOurIdentityKey().getPrivateKey()));
secrets.write(Curve.calculateAgreement(parameters.getTheirBaseKey(),
parameters.getOurSignedPreKey().getPrivateKey()));
if (sessionVersion >= 3 && parameters.getOurOneTimePreKey().isPresent()) {
secrets.write(Curve.calculateAgreement(parameters.getTheirBaseKey(),
parameters.getOurOneTimePreKey().get().getPrivateKey()));
}
DerivedKeys derivedKeys = calculateDerivedKeys(sessionVersion, secrets.toByteArray());
sessionState.setSenderChain(parameters.getOurRatchetKey(), derivedKeys.getChainKey());
sessionState.setRootKey(derivedKeys.getRootKey());
if (sessionVersion >= 3) {
sessionState.setVerification(calculateVerificationTag(derivedKeys.getVerifyKey(), parameters));
}
} catch (IOException e) {
throw new AssertionError(e);
}
}
private static byte[] calculateVerificationTag(VerifyKey verifyKey, AliceAxolotlParameters parameters) {
return verifyKey.generateVerification(parameters.getOurIdentityKey().getPublicKey(),
parameters.getTheirIdentityKey(),
parameters.getOurBaseKey().getPublicKey(),
parameters.getTheirSignedPreKey(),
parameters.getTheirOneTimePreKey());
}
private static byte[] calculateVerificationTag(VerifyKey verifyKey, BobAxolotlParameters parameters) {
Optional<ECPublicKey> ourOneTimePreKey;
if (parameters.getOurOneTimePreKey().isPresent()) {
ourOneTimePreKey = Optional.of(parameters.getOurOneTimePreKey().get().getPublicKey());
} else {
return verifyKey.generateVerification(parameters.getTheirBaseKey(),
parameters.getTheirPreKey(),
parameters.getTheirIdentityKey().getPublicKey(),
parameters.getOurBaseKey().getPublicKey(),
getPublicKey(parameters.getOurPreKey()),
parameters.getOurIdentityKey().getPublicKey().getPublicKey());
ourOneTimePreKey = Optional.absent();
}
return verifyKey.generateVerification(parameters.getTheirIdentityKey(),
parameters.getOurIdentityKey().getPublicKey(),
parameters.getTheirBaseKey(),
parameters.getOurSignedPreKey().getPublicKey(),
ourOneTimePreKey);
}
private static byte[] getDiscontinuityBytes() {
byte[] discontinuity = new byte[32];
Arrays.fill(discontinuity, (byte) 0xFF);
return discontinuity;
}
private static DerivedKeys calculateDerivedKeys(int sessionVersion, byte[] masterSecret) {
try {
HKDF kdf = HKDF.createFor(sessionVersion);
byte[] derivedSecretBytes = kdf.deriveSecrets(masterSecret, "WhisperText".getBytes(), 96);
byte[][] derivedSecrets = ByteUtil.split(derivedSecretBytes, 32, 32, 32);
return new DerivedKeys(new RootKey(kdf, derivedSecrets[0]),
new ChainKey(kdf, derivedSecrets[1], 0),
new VerifyKey(derivedSecrets[2]));
} catch (ParseException e) {
throw new AssertionError(e);
}
}
private static boolean isAlice(AxolotlParameters parameters)
{
if (parameters.getOurEphemeralKey().equals(parameters.getOurBaseKey())) {
return false;
}
if (parameters.getTheirEphemeralKey().equals(parameters.getTheirBaseKey())) {
return true;
}
return isLowEnd(parameters.getOurBaseKey().getPublicKey(), parameters.getTheirBaseKey());
}
private static boolean isLowEnd(ECPublicKey ourKey, ECPublicKey theirKey) {
private static boolean isAlice(ECPublicKey ourKey, ECPublicKey theirKey) {
return ourKey.compareTo(theirKey) < 0;
}
private static Optional<ECPublicKey> getPublicKey(Optional<ECKeyPair> keyPair) {
if (keyPair.isPresent()) return Optional.of(keyPair.get().getPublicKey());
else return Optional.absent();
}
public static class AxolotlParameters {
private final ECKeyPair ourBaseKey;
private final ECKeyPair ourEphemeralKey;
private final Optional<ECKeyPair> ourPreKey;
private final IdentityKeyPair ourIdentityKey;
private final ECPublicKey theirBaseKey;
private final ECPublicKey theirEphemeralKey;
private final Optional<ECPublicKey> theirPreKey;
private final IdentityKey theirIdentityKey;
public AxolotlParameters(ECKeyPair ourBaseKey, ECKeyPair ourEphemeralKey,
Optional<ECKeyPair> ourPreKey, IdentityKeyPair ourIdentityKey,
ECPublicKey theirBaseKey, ECPublicKey theirEphemeralKey,
Optional<ECPublicKey> theirPreKey, IdentityKey theirIdentityKey)
{
this.ourBaseKey = ourBaseKey;
this.ourEphemeralKey = ourEphemeralKey;
this.ourPreKey = ourPreKey;
this.ourIdentityKey = ourIdentityKey;
this.theirBaseKey = theirBaseKey;
this.theirEphemeralKey = theirEphemeralKey;
this.theirPreKey = theirPreKey;
this.theirIdentityKey = theirIdentityKey;
}
public ECKeyPair getOurBaseKey() {
return ourBaseKey;
}
public ECKeyPair getOurEphemeralKey() {
return ourEphemeralKey;
}
public Optional<ECKeyPair> getOurPreKey() {
return ourPreKey;
}
public IdentityKeyPair getOurIdentityKey() {
return ourIdentityKey;
}
public ECPublicKey getTheirBaseKey() {
return theirBaseKey;
}
public ECPublicKey getTheirEphemeralKey() {
return theirEphemeralKey;
}
public Optional<ECPublicKey> getTheirPreKey() {
return theirPreKey;
}
public IdentityKey getTheirIdentityKey() {
return theirIdentityKey;
}
public static Builder newBuilder() {
return new Builder();
}
public static class Builder {
private ECKeyPair ourBaseKey;
private ECKeyPair ourEphemeralKey;
private Optional<ECKeyPair> ourPreKey;
private IdentityKeyPair ourIdentityKey;
private ECPublicKey theirBaseKey;
private ECPublicKey theirEphemeralKey;
private Optional<ECPublicKey> theirPreKey;
private IdentityKey theirIdentityKey;
public Builder setOurBaseKey(ECKeyPair ourBaseKey) {
this.ourBaseKey = ourBaseKey;
return this;
}
public ECKeyPair getOurBaseKey() {
return ourBaseKey;
}
public Builder setOurEphemeralKey(ECKeyPair ourEphemeralKey) {
this.ourEphemeralKey = ourEphemeralKey;
return this;
}
public ECKeyPair getOurEphemeralKey() {
return ourEphemeralKey;
}
public Builder setOurPreKey(Optional<ECKeyPair> ourPreKey) {
this.ourPreKey = ourPreKey;
return this;
}
public Builder setOurIdentityKey(IdentityKeyPair ourIdentityKey) {
this.ourIdentityKey = ourIdentityKey;
return this;
}
public IdentityKeyPair getOurIdentityKey() {
return ourIdentityKey;
}
public Builder setTheirBaseKey(ECPublicKey theirBaseKey) {
this.theirBaseKey = theirBaseKey;
return this;
}
public ECPublicKey getTheirBaseKey() {
return theirBaseKey;
}
public Builder setTheirEphemeralKey(ECPublicKey theirEphemeralKey) {
this.theirEphemeralKey = theirEphemeralKey;
return this;
}
public Builder setTheirPreKey(Optional<ECPublicKey> theirPreKey) {
this.theirPreKey = theirPreKey;
return this;
}
public Builder setTheirIdentityKey(IdentityKey theirIdentityKey) {
this.theirIdentityKey = theirIdentityKey;
return this;
}
public AxolotlParameters create() {
if (ourBaseKey == null || ourEphemeralKey == null || ourPreKey == null || ourIdentityKey == null ||
theirBaseKey == null || theirEphemeralKey == null || theirPreKey == null || theirIdentityKey == null)
{
throw new IllegalArgumentException("All parameters not specified!");
}
return new AxolotlParameters(ourBaseKey, ourEphemeralKey, ourPreKey, ourIdentityKey,
theirBaseKey, theirEphemeralKey, theirPreKey, theirIdentityKey);
}
}
}
private static class DHEResult {
private static class DerivedKeys {
private final RootKey rootKey;
private final ChainKey chainKey;
private final VerifyKey verifyKey;
private DHEResult(RootKey rootKey, ChainKey chainKey, VerifyKey verifyKey) {
private DerivedKeys(RootKey rootKey, ChainKey chainKey, VerifyKey verifyKey) {
this.rootKey = rootKey;
this.chainKey = chainKey;
this.verifyKey = verifyKey;
@ -336,5 +222,4 @@ public class RatchetingSession {
return verifyKey;
}
}
}

View File

@ -0,0 +1,108 @@
package org.whispersystems.libaxolotl.ratchet;
import org.whispersystems.libaxolotl.IdentityKey;
import org.whispersystems.libaxolotl.IdentityKeyPair;
import org.whispersystems.libaxolotl.ecc.ECKeyPair;
import org.whispersystems.libaxolotl.ecc.ECPublicKey;
public class SymmetricAxolotlParameters {
private final ECKeyPair ourBaseKey;
private final ECKeyPair ourRatchetKey;
private final IdentityKeyPair ourIdentityKey;
private final ECPublicKey theirBaseKey;
private final ECPublicKey theirRatchetKey;
private final IdentityKey theirIdentityKey;
SymmetricAxolotlParameters(ECKeyPair ourBaseKey, ECKeyPair ourRatchetKey,
IdentityKeyPair ourIdentityKey, ECPublicKey theirBaseKey,
ECPublicKey theirRatchetKey, IdentityKey theirIdentityKey)
{
this.ourBaseKey = ourBaseKey;
this.ourRatchetKey = ourRatchetKey;
this.ourIdentityKey = ourIdentityKey;
this.theirBaseKey = theirBaseKey;
this.theirRatchetKey = theirRatchetKey;
this.theirIdentityKey = theirIdentityKey;
if (ourBaseKey == null || ourRatchetKey == null || ourIdentityKey == null ||
theirBaseKey == null || theirRatchetKey == null || theirIdentityKey == null)
{
throw new IllegalArgumentException("Null values!");
}
}
public ECKeyPair getOurBaseKey() {
return ourBaseKey;
}
public ECKeyPair getOurRatchetKey() {
return ourRatchetKey;
}
public IdentityKeyPair getOurIdentityKey() {
return ourIdentityKey;
}
public ECPublicKey getTheirBaseKey() {
return theirBaseKey;
}
public ECPublicKey getTheirRatchetKey() {
return theirRatchetKey;
}
public IdentityKey getTheirIdentityKey() {
return theirIdentityKey;
}
public static Builder newBuilder() {
return new Builder();
}
public static class Builder {
private ECKeyPair ourBaseKey;
private ECKeyPair ourRatchetKey;
private IdentityKeyPair ourIdentityKey;
private ECPublicKey theirBaseKey;
private ECPublicKey theirRatchetKey;
private IdentityKey theirIdentityKey;
public Builder setOurBaseKey(ECKeyPair ourBaseKey) {
this.ourBaseKey = ourBaseKey;
return this;
}
public Builder setOurRatchetKey(ECKeyPair ourRatchetKey) {
this.ourRatchetKey = ourRatchetKey;
return this;
}
public Builder setOurIdentityKey(IdentityKeyPair ourIdentityKey) {
this.ourIdentityKey = ourIdentityKey;
return this;
}
public Builder setTheirBaseKey(ECPublicKey theirBaseKey) {
this.theirBaseKey = theirBaseKey;
return this;
}
public Builder setTheirRatchetKey(ECPublicKey theirRatchetKey) {
this.theirRatchetKey = theirRatchetKey;
return this;
}
public Builder setTheirIdentityKey(IdentityKey theirIdentityKey) {
this.theirIdentityKey = theirIdentityKey;
return this;
}
public SymmetricAxolotlParameters create() {
return new SymmetricAxolotlParameters(ourBaseKey, ourRatchetKey, ourIdentityKey,
theirBaseKey, theirRatchetKey, theirIdentityKey);
}
}
}

View File

@ -1,5 +1,6 @@
package org.whispersystems.libaxolotl.ratchet;
import org.whispersystems.libaxolotl.IdentityKey;
import org.whispersystems.libaxolotl.ecc.ECPublicKey;
import org.whispersystems.libaxolotl.util.ByteUtil;
import org.whispersystems.libaxolotl.util.guava.Optional;
@ -24,29 +25,26 @@ public class VerifyKey {
return key;
}
public byte[] generateVerification(ECPublicKey aliceBaseKey,
Optional<ECPublicKey> alicePreKey,
ECPublicKey aliceIdentityKey,
ECPublicKey bobBaseKey,
Optional<ECPublicKey> bobPreKey,
ECPublicKey bobIdentityKey)
public byte[] generateVerification(IdentityKey aliceIdentity,
IdentityKey bobIdentity,
ECPublicKey aliceBaseKey,
ECPublicKey bobSignedPreKey,
Optional<ECPublicKey> bobOneTimePreKey)
{
try {
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(key, "HmacSHA256"));
mac.update(VERIFICATION_INFO);
mac.update(aliceIdentity.getPublicKey().serialize());
mac.update(bobIdentity.getPublicKey().serialize());
mac.update(aliceBaseKey.serialize());
mac.update(aliceIdentityKey.serialize());
mac.update(bobBaseKey.serialize());
mac.update(bobIdentityKey.serialize());
mac.update(bobSignedPreKey.serialize());
if (alicePreKey.isPresent() && bobPreKey.isPresent()) {
mac.update(alicePreKey.get().serialize());
mac.update(bobPreKey.get().serialize());
if (bobOneTimePreKey.isPresent()) {
mac.update(bobOneTimePreKey.get().serialize());
}
return ByteUtil.trim(mac.doFinal(), 8);
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
throw new AssertionError(e);

View File

@ -32,11 +32,10 @@ import org.whispersystems.libaxolotl.kdf.HKDF;
import org.whispersystems.libaxolotl.ratchet.ChainKey;
import org.whispersystems.libaxolotl.ratchet.MessageKeys;
import org.whispersystems.libaxolotl.ratchet.RootKey;
import org.whispersystems.libaxolotl.ratchet.VerifyKey;
import org.whispersystems.libaxolotl.util.Pair;
import org.whispersystems.libaxolotl.state.StorageProtos.SessionStructure.Chain;
import org.whispersystems.libaxolotl.state.StorageProtos.SessionStructure.PendingKeyExchange;
import org.whispersystems.libaxolotl.state.StorageProtos.SessionStructure.PendingPreKey;
import org.whispersystems.libaxolotl.util.Pair;
import java.util.Iterator;
import java.util.LinkedList;
@ -159,18 +158,18 @@ public class SessionState {
.build();
}
public ECPublicKey getSenderEphemeral() {
public ECPublicKey getSenderRatchetKey() {
try {
return Curve.decodePoint(sessionStructure.getSenderChain().getSenderEphemeral().toByteArray(), 0);
return Curve.decodePoint(sessionStructure.getSenderChain().getSenderRatchetKey().toByteArray(), 0);
} catch (InvalidKeyException e) {
throw new AssertionError(e);
}
}
public ECKeyPair getSenderEphemeralPair() {
ECPublicKey publicKey = getSenderEphemeral();
public ECKeyPair getSenderRatchetKeyPair() {
ECPublicKey publicKey = getSenderRatchetKey();
ECPrivateKey privateKey = Curve.decodePrivatePoint(sessionStructure.getSenderChain()
.getSenderEphemeralPrivate()
.getSenderRatchetKeyPrivate()
.toByteArray());
return new ECKeyPair(publicKey, privateKey);
@ -190,9 +189,9 @@ public class SessionState {
for (Chain receiverChain : receiverChains) {
try {
ECPublicKey chainSenderEphemeral = Curve.decodePoint(receiverChain.getSenderEphemeral().toByteArray(), 0);
ECPublicKey chainSenderRatchetKey = Curve.decodePoint(receiverChain.getSenderRatchetKey().toByteArray(), 0);
if (chainSenderEphemeral.equals(senderEphemeral)) {
if (chainSenderRatchetKey.equals(senderEphemeral)) {
return new Pair<>(receiverChain,index);
}
} catch (InvalidKeyException e) {
@ -218,7 +217,7 @@ public class SessionState {
}
}
public void addReceiverChain(ECPublicKey senderEphemeral, ChainKey chainKey) {
public void addReceiverChain(ECPublicKey senderRatchetKey, ChainKey chainKey) {
Chain.ChainKey chainKeyStructure = Chain.ChainKey.newBuilder()
.setKey(ByteString.copyFrom(chainKey.getKey()))
.setIndex(chainKey.getIndex())
@ -226,7 +225,7 @@ public class SessionState {
Chain chain = Chain.newBuilder()
.setChainKey(chainKeyStructure)
.setSenderEphemeral(ByteString.copyFrom(senderEphemeral.serialize()))
.setSenderRatchetKey(ByteString.copyFrom(senderRatchetKey.serialize()))
.build();
this.sessionStructure = this.sessionStructure.toBuilder().addReceiverChains(chain).build();
@ -238,15 +237,15 @@ public class SessionState {
}
}
public void setSenderChain(ECKeyPair senderEphemeralPair, ChainKey chainKey) {
public void setSenderChain(ECKeyPair senderRatchetKeyPair, ChainKey chainKey) {
Chain.ChainKey chainKeyStructure = Chain.ChainKey.newBuilder()
.setKey(ByteString.copyFrom(chainKey.getKey()))
.setIndex(chainKey.getIndex())
.build();
Chain senderChain = Chain.newBuilder()
.setSenderEphemeral(ByteString.copyFrom(senderEphemeralPair.getPublicKey().serialize()))
.setSenderEphemeralPrivate(ByteString.copyFrom(senderEphemeralPair.getPrivateKey().serialize()))
.setSenderRatchetKey(ByteString.copyFrom(senderRatchetKeyPair.getPublicKey().serialize()))
.setSenderRatchetKeyPrivate(ByteString.copyFrom(senderRatchetKeyPair.getPrivateKey().serialize()))
.setChainKey(chainKeyStructure)
.build();
@ -363,7 +362,7 @@ public class SessionState {
public void setPendingKeyExchange(int sequence,
ECKeyPair ourBaseKey,
ECKeyPair ourEphemeralKey,
ECKeyPair ourRatchetKey,
IdentityKeyPair ourIdentityKey)
{
PendingKeyExchange structure =
@ -371,8 +370,8 @@ public class SessionState {
.setSequence(sequence)
.setLocalBaseKey(ByteString.copyFrom(ourBaseKey.getPublicKey().serialize()))
.setLocalBaseKeyPrivate(ByteString.copyFrom(ourBaseKey.getPrivateKey().serialize()))
.setLocalEphemeralKey(ByteString.copyFrom(ourEphemeralKey.getPublicKey().serialize()))
.setLocalEphemeralKeyPrivate(ByteString.copyFrom(ourEphemeralKey.getPrivateKey().serialize()))
.setLocalRatchetKey(ByteString.copyFrom(ourRatchetKey.getPublicKey().serialize()))
.setLocalRatchetKeyPrivate(ByteString.copyFrom(ourRatchetKey.getPrivateKey().serialize()))
.setLocalIdentityKey(ByteString.copyFrom(ourIdentityKey.getPublicKey().serialize()))
.setLocalIdentityKeyPrivate(ByteString.copyFrom(ourIdentityKey.getPrivateKey().serialize()))
.build();
@ -397,12 +396,12 @@ public class SessionState {
return new ECKeyPair(publicKey, privateKey);
}
public ECKeyPair getPendingKeyExchangeEphemeralKey() throws InvalidKeyException {
public ECKeyPair getPendingKeyExchangeRatchetKey() throws InvalidKeyException {
ECPublicKey publicKey = Curve.decodePoint(sessionStructure.getPendingKeyExchange()
.getLocalEphemeralKey().toByteArray(), 0);
.getLocalRatchetKey().toByteArray(), 0);
ECPrivateKey privateKey = Curve.decodePrivatePoint(sessionStructure.getPendingKeyExchange()
.getLocalEphemeralKeyPrivate()
.getLocalRatchetKeyPrivate()
.toByteArray());
return new ECKeyPair(publicKey, privateKey);

View File

@ -371,25 +371,25 @@ public final class StorageProtos {
public interface ChainOrBuilder
extends com.google.protobuf.MessageOrBuilder {
// optional bytes senderEphemeral = 1;
// optional bytes senderRatchetKey = 1;
/**
* <code>optional bytes senderEphemeral = 1;</code>
* <code>optional bytes senderRatchetKey = 1;</code>
*/
boolean hasSenderEphemeral();
boolean hasSenderRatchetKey();
/**
* <code>optional bytes senderEphemeral = 1;</code>
* <code>optional bytes senderRatchetKey = 1;</code>
*/
com.google.protobuf.ByteString getSenderEphemeral();
com.google.protobuf.ByteString getSenderRatchetKey();
// optional bytes senderEphemeralPrivate = 2;
// optional bytes senderRatchetKeyPrivate = 2;
/**
* <code>optional bytes senderEphemeralPrivate = 2;</code>
* <code>optional bytes senderRatchetKeyPrivate = 2;</code>
*/
boolean hasSenderEphemeralPrivate();
boolean hasSenderRatchetKeyPrivate();
/**
* <code>optional bytes senderEphemeralPrivate = 2;</code>
* <code>optional bytes senderRatchetKeyPrivate = 2;</code>
*/
com.google.protobuf.ByteString getSenderEphemeralPrivate();
com.google.protobuf.ByteString getSenderRatchetKeyPrivate();
// optional .textsecure.SessionStructure.Chain.ChainKey chainKey = 3;
/**
@ -483,12 +483,12 @@ public final class StorageProtos {
}
case 10: {
bitField0_ |= 0x00000001;
senderEphemeral_ = input.readBytes();
senderRatchetKey_ = input.readBytes();
break;
}
case 18: {
bitField0_ |= 0x00000002;
senderEphemeralPrivate_ = input.readBytes();
senderRatchetKeyPrivate_ = input.readBytes();
break;
}
case 26: {
@ -1599,36 +1599,36 @@ public final class StorageProtos {
}
private int bitField0_;
// optional bytes senderEphemeral = 1;
public static final int SENDEREPHEMERAL_FIELD_NUMBER = 1;
private com.google.protobuf.ByteString senderEphemeral_;
// optional bytes senderRatchetKey = 1;
public static final int SENDERRATCHETKEY_FIELD_NUMBER = 1;
private com.google.protobuf.ByteString senderRatchetKey_;
/**
* <code>optional bytes senderEphemeral = 1;</code>
* <code>optional bytes senderRatchetKey = 1;</code>
*/
public boolean hasSenderEphemeral() {
public boolean hasSenderRatchetKey() {
return ((bitField0_ & 0x00000001) == 0x00000001);
}
/**
* <code>optional bytes senderEphemeral = 1;</code>
* <code>optional bytes senderRatchetKey = 1;</code>
*/
public com.google.protobuf.ByteString getSenderEphemeral() {
return senderEphemeral_;
public com.google.protobuf.ByteString getSenderRatchetKey() {
return senderRatchetKey_;
}
// optional bytes senderEphemeralPrivate = 2;
public static final int SENDEREPHEMERALPRIVATE_FIELD_NUMBER = 2;
private com.google.protobuf.ByteString senderEphemeralPrivate_;
// optional bytes senderRatchetKeyPrivate = 2;
public static final int SENDERRATCHETKEYPRIVATE_FIELD_NUMBER = 2;
private com.google.protobuf.ByteString senderRatchetKeyPrivate_;
/**
* <code>optional bytes senderEphemeralPrivate = 2;</code>
* <code>optional bytes senderRatchetKeyPrivate = 2;</code>
*/
public boolean hasSenderEphemeralPrivate() {
public boolean hasSenderRatchetKeyPrivate() {
return ((bitField0_ & 0x00000002) == 0x00000002);
}
/**
* <code>optional bytes senderEphemeralPrivate = 2;</code>
* <code>optional bytes senderRatchetKeyPrivate = 2;</code>
*/
public com.google.protobuf.ByteString getSenderEphemeralPrivate() {
return senderEphemeralPrivate_;
public com.google.protobuf.ByteString getSenderRatchetKeyPrivate() {
return senderRatchetKeyPrivate_;
}
// optional .textsecure.SessionStructure.Chain.ChainKey chainKey = 3;
@ -1690,8 +1690,8 @@ public final class StorageProtos {
}
private void initFields() {
senderEphemeral_ = com.google.protobuf.ByteString.EMPTY;
senderEphemeralPrivate_ = com.google.protobuf.ByteString.EMPTY;
senderRatchetKey_ = com.google.protobuf.ByteString.EMPTY;
senderRatchetKeyPrivate_ = com.google.protobuf.ByteString.EMPTY;
chainKey_ = org.whispersystems.libaxolotl.state.StorageProtos.SessionStructure.Chain.ChainKey.getDefaultInstance();
messageKeys_ = java.util.Collections.emptyList();
}
@ -1708,10 +1708,10 @@ public final class StorageProtos {
throws java.io.IOException {
getSerializedSize();
if (((bitField0_ & 0x00000001) == 0x00000001)) {
output.writeBytes(1, senderEphemeral_);
output.writeBytes(1, senderRatchetKey_);
}
if (((bitField0_ & 0x00000002) == 0x00000002)) {
output.writeBytes(2, senderEphemeralPrivate_);
output.writeBytes(2, senderRatchetKeyPrivate_);
}
if (((bitField0_ & 0x00000004) == 0x00000004)) {
output.writeMessage(3, chainKey_);
@ -1730,11 +1730,11 @@ public final class StorageProtos {
size = 0;
if (((bitField0_ & 0x00000001) == 0x00000001)) {
size += com.google.protobuf.CodedOutputStream
.computeBytesSize(1, senderEphemeral_);
.computeBytesSize(1, senderRatchetKey_);
}
if (((bitField0_ & 0x00000002) == 0x00000002)) {
size += com.google.protobuf.CodedOutputStream
.computeBytesSize(2, senderEphemeralPrivate_);
.computeBytesSize(2, senderRatchetKeyPrivate_);
}
if (((bitField0_ & 0x00000004) == 0x00000004)) {
size += com.google.protobuf.CodedOutputStream
@ -1862,9 +1862,9 @@ public final class StorageProtos {
public Builder clear() {
super.clear();
senderEphemeral_ = com.google.protobuf.ByteString.EMPTY;
senderRatchetKey_ = com.google.protobuf.ByteString.EMPTY;
bitField0_ = (bitField0_ & ~0x00000001);
senderEphemeralPrivate_ = com.google.protobuf.ByteString.EMPTY;
senderRatchetKeyPrivate_ = com.google.protobuf.ByteString.EMPTY;
bitField0_ = (bitField0_ & ~0x00000002);
if (chainKeyBuilder_ == null) {
chainKey_ = org.whispersystems.libaxolotl.state.StorageProtos.SessionStructure.Chain.ChainKey.getDefaultInstance();
@ -1909,11 +1909,11 @@ public final class StorageProtos {
if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
to_bitField0_ |= 0x00000001;
}
result.senderEphemeral_ = senderEphemeral_;
result.senderRatchetKey_ = senderRatchetKey_;
if (((from_bitField0_ & 0x00000002) == 0x00000002)) {
to_bitField0_ |= 0x00000002;
}
result.senderEphemeralPrivate_ = senderEphemeralPrivate_;
result.senderRatchetKeyPrivate_ = senderRatchetKeyPrivate_;
if (((from_bitField0_ & 0x00000004) == 0x00000004)) {
to_bitField0_ |= 0x00000004;
}
@ -1947,11 +1947,11 @@ public final class StorageProtos {
public Builder mergeFrom(org.whispersystems.libaxolotl.state.StorageProtos.SessionStructure.Chain other) {
if (other == org.whispersystems.libaxolotl.state.StorageProtos.SessionStructure.Chain.getDefaultInstance()) return this;
if (other.hasSenderEphemeral()) {
setSenderEphemeral(other.getSenderEphemeral());
if (other.hasSenderRatchetKey()) {
setSenderRatchetKey(other.getSenderRatchetKey());
}
if (other.hasSenderEphemeralPrivate()) {
setSenderEphemeralPrivate(other.getSenderEphemeralPrivate());
if (other.hasSenderRatchetKeyPrivate()) {
setSenderRatchetKeyPrivate(other.getSenderRatchetKeyPrivate());
}
if (other.hasChainKey()) {
mergeChainKey(other.getChainKey());
@ -2009,74 +2009,74 @@ public final class StorageProtos {
}
private int bitField0_;
// optional bytes senderEphemeral = 1;
private com.google.protobuf.ByteString senderEphemeral_ = com.google.protobuf.ByteString.EMPTY;
// optional bytes senderRatchetKey = 1;
private com.google.protobuf.ByteString senderRatchetKey_ = com.google.protobuf.ByteString.EMPTY;
/**
* <code>optional bytes senderEphemeral = 1;</code>
* <code>optional bytes senderRatchetKey = 1;</code>
*/
public boolean hasSenderEphemeral() {
public boolean hasSenderRatchetKey() {
return ((bitField0_ & 0x00000001) == 0x00000001);
}
/**
* <code>optional bytes senderEphemeral = 1;</code>
* <code>optional bytes senderRatchetKey = 1;</code>
*/
public com.google.protobuf.ByteString getSenderEphemeral() {
return senderEphemeral_;
public com.google.protobuf.ByteString getSenderRatchetKey() {
return senderRatchetKey_;
}
/**
* <code>optional bytes senderEphemeral = 1;</code>
* <code>optional bytes senderRatchetKey = 1;</code>
*/
public Builder setSenderEphemeral(com.google.protobuf.ByteString value) {
public Builder setSenderRatchetKey(com.google.protobuf.ByteString value) {
if (value == null) {
throw new NullPointerException();
}
bitField0_ |= 0x00000001;
senderEphemeral_ = value;
senderRatchetKey_ = value;
onChanged();
return this;
}
/**
* <code>optional bytes senderEphemeral = 1;</code>
* <code>optional bytes senderRatchetKey = 1;</code>
*/
public Builder clearSenderEphemeral() {
public Builder clearSenderRatchetKey() {
bitField0_ = (bitField0_ & ~0x00000001);
senderEphemeral_ = getDefaultInstance().getSenderEphemeral();
senderRatchetKey_ = getDefaultInstance().getSenderRatchetKey();
onChanged();
return this;
}
// optional bytes senderEphemeralPrivate = 2;
private com.google.protobuf.ByteString senderEphemeralPrivate_ = com.google.protobuf.ByteString.EMPTY;
// optional bytes senderRatchetKeyPrivate = 2;
private com.google.protobuf.ByteString senderRatchetKeyPrivate_ = com.google.protobuf.ByteString.EMPTY;
/**
* <code>optional bytes senderEphemeralPrivate = 2;</code>
* <code>optional bytes senderRatchetKeyPrivate = 2;</code>
*/
public boolean hasSenderEphemeralPrivate() {
public boolean hasSenderRatchetKeyPrivate() {
return ((bitField0_ & 0x00000002) == 0x00000002);
}
/**
* <code>optional bytes senderEphemeralPrivate = 2;</code>
* <code>optional bytes senderRatchetKeyPrivate = 2;</code>
*/
public com.google.protobuf.ByteString getSenderEphemeralPrivate() {
return senderEphemeralPrivate_;
public com.google.protobuf.ByteString getSenderRatchetKeyPrivate() {
return senderRatchetKeyPrivate_;
}
/**
* <code>optional bytes senderEphemeralPrivate = 2;</code>
* <code>optional bytes senderRatchetKeyPrivate = 2;</code>
*/
public Builder setSenderEphemeralPrivate(com.google.protobuf.ByteString value) {
public Builder setSenderRatchetKeyPrivate(com.google.protobuf.ByteString value) {
if (value == null) {
throw new NullPointerException();
}
bitField0_ |= 0x00000002;
senderEphemeralPrivate_ = value;
senderRatchetKeyPrivate_ = value;
onChanged();
return this;
}
/**
* <code>optional bytes senderEphemeralPrivate = 2;</code>
* <code>optional bytes senderRatchetKeyPrivate = 2;</code>
*/
public Builder clearSenderEphemeralPrivate() {
public Builder clearSenderRatchetKeyPrivate() {
bitField0_ = (bitField0_ & ~0x00000002);
senderEphemeralPrivate_ = getDefaultInstance().getSenderEphemeralPrivate();
senderRatchetKeyPrivate_ = getDefaultInstance().getSenderRatchetKeyPrivate();
onChanged();
return this;
}
@ -2482,25 +2482,25 @@ public final class StorageProtos {
*/
com.google.protobuf.ByteString getLocalBaseKeyPrivate();
// optional bytes localEphemeralKey = 4;
// optional bytes localRatchetKey = 4;
/**
* <code>optional bytes localEphemeralKey = 4;</code>
* <code>optional bytes localRatchetKey = 4;</code>
*/
boolean hasLocalEphemeralKey();
boolean hasLocalRatchetKey();
/**
* <code>optional bytes localEphemeralKey = 4;</code>
* <code>optional bytes localRatchetKey = 4;</code>
*/
com.google.protobuf.ByteString getLocalEphemeralKey();
com.google.protobuf.ByteString getLocalRatchetKey();
// optional bytes localEphemeralKeyPrivate = 5;
// optional bytes localRatchetKeyPrivate = 5;
/**
* <code>optional bytes localEphemeralKeyPrivate = 5;</code>
* <code>optional bytes localRatchetKeyPrivate = 5;</code>
*/
boolean hasLocalEphemeralKeyPrivate();
boolean hasLocalRatchetKeyPrivate();
/**
* <code>optional bytes localEphemeralKeyPrivate = 5;</code>
* <code>optional bytes localRatchetKeyPrivate = 5;</code>
*/
com.google.protobuf.ByteString getLocalEphemeralKeyPrivate();
com.google.protobuf.ByteString getLocalRatchetKeyPrivate();
// optional bytes localIdentityKey = 7;
/**
@ -2590,12 +2590,12 @@ public final class StorageProtos {
}
case 34: {
bitField0_ |= 0x00000008;
localEphemeralKey_ = input.readBytes();
localRatchetKey_ = input.readBytes();
break;
}
case 42: {
bitField0_ |= 0x00000010;
localEphemeralKeyPrivate_ = input.readBytes();
localRatchetKeyPrivate_ = input.readBytes();
break;
}
case 58: {
@ -2696,36 +2696,36 @@ public final class StorageProtos {
return localBaseKeyPrivate_;
}
// optional bytes localEphemeralKey = 4;
public static final int LOCALEPHEMERALKEY_FIELD_NUMBER = 4;
private com.google.protobuf.ByteString localEphemeralKey_;
// optional bytes localRatchetKey = 4;
public static final int LOCALRATCHETKEY_FIELD_NUMBER = 4;
private com.google.protobuf.ByteString localRatchetKey_;
/**
* <code>optional bytes localEphemeralKey = 4;</code>
* <code>optional bytes localRatchetKey = 4;</code>
*/
public boolean hasLocalEphemeralKey() {
public boolean hasLocalRatchetKey() {
return ((bitField0_ & 0x00000008) == 0x00000008);
}
/**
* <code>optional bytes localEphemeralKey = 4;</code>
* <code>optional bytes localRatchetKey = 4;</code>
*/
public com.google.protobuf.ByteString getLocalEphemeralKey() {
return localEphemeralKey_;
public com.google.protobuf.ByteString getLocalRatchetKey() {
return localRatchetKey_;
}
// optional bytes localEphemeralKeyPrivate = 5;
public static final int LOCALEPHEMERALKEYPRIVATE_FIELD_NUMBER = 5;
private com.google.protobuf.ByteString localEphemeralKeyPrivate_;
// optional bytes localRatchetKeyPrivate = 5;
public static final int LOCALRATCHETKEYPRIVATE_FIELD_NUMBER = 5;
private com.google.protobuf.ByteString localRatchetKeyPrivate_;
/**
* <code>optional bytes localEphemeralKeyPrivate = 5;</code>
* <code>optional bytes localRatchetKeyPrivate = 5;</code>
*/
public boolean hasLocalEphemeralKeyPrivate() {
public boolean hasLocalRatchetKeyPrivate() {
return ((bitField0_ & 0x00000010) == 0x00000010);
}
/**
* <code>optional bytes localEphemeralKeyPrivate = 5;</code>
* <code>optional bytes localRatchetKeyPrivate = 5;</code>
*/
public com.google.protobuf.ByteString getLocalEphemeralKeyPrivate() {
return localEphemeralKeyPrivate_;
public com.google.protobuf.ByteString getLocalRatchetKeyPrivate() {
return localRatchetKeyPrivate_;
}
// optional bytes localIdentityKey = 7;
@ -2764,8 +2764,8 @@ public final class StorageProtos {
sequence_ = 0;
localBaseKey_ = com.google.protobuf.ByteString.EMPTY;
localBaseKeyPrivate_ = com.google.protobuf.ByteString.EMPTY;
localEphemeralKey_ = com.google.protobuf.ByteString.EMPTY;
localEphemeralKeyPrivate_ = com.google.protobuf.ByteString.EMPTY;
localRatchetKey_ = com.google.protobuf.ByteString.EMPTY;
localRatchetKeyPrivate_ = com.google.protobuf.ByteString.EMPTY;
localIdentityKey_ = com.google.protobuf.ByteString.EMPTY;
localIdentityKeyPrivate_ = com.google.protobuf.ByteString.EMPTY;
}
@ -2791,10 +2791,10 @@ public final class StorageProtos {
output.writeBytes(3, localBaseKeyPrivate_);
}
if (((bitField0_ & 0x00000008) == 0x00000008)) {
output.writeBytes(4, localEphemeralKey_);
output.writeBytes(4, localRatchetKey_);
}
if (((bitField0_ & 0x00000010) == 0x00000010)) {
output.writeBytes(5, localEphemeralKeyPrivate_);
output.writeBytes(5, localRatchetKeyPrivate_);
}
if (((bitField0_ & 0x00000020) == 0x00000020)) {
output.writeBytes(7, localIdentityKey_);
@ -2825,11 +2825,11 @@ public final class StorageProtos {
}
if (((bitField0_ & 0x00000008) == 0x00000008)) {
size += com.google.protobuf.CodedOutputStream
.computeBytesSize(4, localEphemeralKey_);
.computeBytesSize(4, localRatchetKey_);
}
if (((bitField0_ & 0x00000010) == 0x00000010)) {
size += com.google.protobuf.CodedOutputStream
.computeBytesSize(5, localEphemeralKeyPrivate_);
.computeBytesSize(5, localRatchetKeyPrivate_);
}
if (((bitField0_ & 0x00000020) == 0x00000020)) {
size += com.google.protobuf.CodedOutputStream
@ -2961,9 +2961,9 @@ public final class StorageProtos {
bitField0_ = (bitField0_ & ~0x00000002);
localBaseKeyPrivate_ = com.google.protobuf.ByteString.EMPTY;
bitField0_ = (bitField0_ & ~0x00000004);
localEphemeralKey_ = com.google.protobuf.ByteString.EMPTY;
localRatchetKey_ = com.google.protobuf.ByteString.EMPTY;
bitField0_ = (bitField0_ & ~0x00000008);
localEphemeralKeyPrivate_ = com.google.protobuf.ByteString.EMPTY;
localRatchetKeyPrivate_ = com.google.protobuf.ByteString.EMPTY;
bitField0_ = (bitField0_ & ~0x00000010);
localIdentityKey_ = com.google.protobuf.ByteString.EMPTY;
bitField0_ = (bitField0_ & ~0x00000020);
@ -3012,11 +3012,11 @@ public final class StorageProtos {
if (((from_bitField0_ & 0x00000008) == 0x00000008)) {
to_bitField0_ |= 0x00000008;
}
result.localEphemeralKey_ = localEphemeralKey_;
result.localRatchetKey_ = localRatchetKey_;
if (((from_bitField0_ & 0x00000010) == 0x00000010)) {
to_bitField0_ |= 0x00000010;
}
result.localEphemeralKeyPrivate_ = localEphemeralKeyPrivate_;
result.localRatchetKeyPrivate_ = localRatchetKeyPrivate_;
if (((from_bitField0_ & 0x00000020) == 0x00000020)) {
to_bitField0_ |= 0x00000020;
}
@ -3050,11 +3050,11 @@ public final class StorageProtos {
if (other.hasLocalBaseKeyPrivate()) {
setLocalBaseKeyPrivate(other.getLocalBaseKeyPrivate());
}
if (other.hasLocalEphemeralKey()) {
setLocalEphemeralKey(other.getLocalEphemeralKey());
if (other.hasLocalRatchetKey()) {
setLocalRatchetKey(other.getLocalRatchetKey());
}
if (other.hasLocalEphemeralKeyPrivate()) {
setLocalEphemeralKeyPrivate(other.getLocalEphemeralKeyPrivate());
if (other.hasLocalRatchetKeyPrivate()) {
setLocalRatchetKeyPrivate(other.getLocalRatchetKeyPrivate());
}
if (other.hasLocalIdentityKey()) {
setLocalIdentityKey(other.getLocalIdentityKey());
@ -3194,74 +3194,74 @@ public final class StorageProtos {
return this;
}
// optional bytes localEphemeralKey = 4;
private com.google.protobuf.ByteString localEphemeralKey_ = com.google.protobuf.ByteString.EMPTY;
// optional bytes localRatchetKey = 4;
private com.google.protobuf.ByteString localRatchetKey_ = com.google.protobuf.ByteString.EMPTY;
/**
* <code>optional bytes localEphemeralKey = 4;</code>
* <code>optional bytes localRatchetKey = 4;</code>
*/
public boolean hasLocalEphemeralKey() {
public boolean hasLocalRatchetKey() {
return ((bitField0_ & 0x00000008) == 0x00000008);
}
/**
* <code>optional bytes localEphemeralKey = 4;</code>
* <code>optional bytes localRatchetKey = 4;</code>
*/
public com.google.protobuf.ByteString getLocalEphemeralKey() {
return localEphemeralKey_;
public com.google.protobuf.ByteString getLocalRatchetKey() {
return localRatchetKey_;
}
/**
* <code>optional bytes localEphemeralKey = 4;</code>
* <code>optional bytes localRatchetKey = 4;</code>
*/
public Builder setLocalEphemeralKey(com.google.protobuf.ByteString value) {
public Builder setLocalRatchetKey(com.google.protobuf.ByteString value) {
if (value == null) {
throw new NullPointerException();
}
bitField0_ |= 0x00000008;
localEphemeralKey_ = value;
localRatchetKey_ = value;
onChanged();
return this;
}
/**
* <code>optional bytes localEphemeralKey = 4;</code>
* <code>optional bytes localRatchetKey = 4;</code>
*/
public Builder clearLocalEphemeralKey() {
public Builder clearLocalRatchetKey() {
bitField0_ = (bitField0_ & ~0x00000008);
localEphemeralKey_ = getDefaultInstance().getLocalEphemeralKey();
localRatchetKey_ = getDefaultInstance().getLocalRatchetKey();
onChanged();
return this;
}
// optional bytes localEphemeralKeyPrivate = 5;
private com.google.protobuf.ByteString localEphemeralKeyPrivate_ = com.google.protobuf.ByteString.EMPTY;
// optional bytes localRatchetKeyPrivate = 5;
private com.google.protobuf.ByteString localRatchetKeyPrivate_ = com.google.protobuf.ByteString.EMPTY;
/**
* <code>optional bytes localEphemeralKeyPrivate = 5;</code>
* <code>optional bytes localRatchetKeyPrivate = 5;</code>
*/
public boolean hasLocalEphemeralKeyPrivate() {
public boolean hasLocalRatchetKeyPrivate() {
return ((bitField0_ & 0x00000010) == 0x00000010);
}
/**
* <code>optional bytes localEphemeralKeyPrivate = 5;</code>
* <code>optional bytes localRatchetKeyPrivate = 5;</code>
*/
public com.google.protobuf.ByteString getLocalEphemeralKeyPrivate() {
return localEphemeralKeyPrivate_;
public com.google.protobuf.ByteString getLocalRatchetKeyPrivate() {
return localRatchetKeyPrivate_;
}
/**
* <code>optional bytes localEphemeralKeyPrivate = 5;</code>
* <code>optional bytes localRatchetKeyPrivate = 5;</code>
*/
public Builder setLocalEphemeralKeyPrivate(com.google.protobuf.ByteString value) {
public Builder setLocalRatchetKeyPrivate(com.google.protobuf.ByteString value) {
if (value == null) {
throw new NullPointerException();
}
bitField0_ |= 0x00000010;
localEphemeralKeyPrivate_ = value;
localRatchetKeyPrivate_ = value;
onChanged();
return this;
}
/**
* <code>optional bytes localEphemeralKeyPrivate = 5;</code>
* <code>optional bytes localRatchetKeyPrivate = 5;</code>
*/
public Builder clearLocalEphemeralKeyPrivate() {
public Builder clearLocalRatchetKeyPrivate() {
bitField0_ = (bitField0_ & ~0x00000010);
localEphemeralKeyPrivate_ = getDefaultInstance().getLocalEphemeralKeyPrivate();
localRatchetKeyPrivate_ = getDefaultInstance().getLocalRatchetKeyPrivate();
onChanged();
return this;
}
@ -8333,7 +8333,7 @@ public final class StorageProtos {
static {
java.lang.String[] descriptorData = {
"\n\032LocalStorageProtocol.proto\022\ntextsecure" +
"\"\337\010\n\020SessionStructure\022\026\n\016sessionVersion\030" +
"\"\335\010\n\020SessionStructure\022\026\n\016sessionVersion\030" +
"\001 \001(\r\022\033\n\023localIdentityPublic\030\002 \001(\014\022\034\n\024re" +
"moteIdentityPublic\030\003 \001(\014\022\017\n\007rootKey\030\004 \001(" +
"\014\022\027\n\017previousCounter\030\005 \001(\r\0227\n\013senderChai" +
@ -8346,33 +8346,33 @@ public final class StorageProtos {
"gPreKey\022\034\n\024remoteRegistrationId\030\n \001(\r\022\033\n" +
"\023localRegistrationId\030\013 \001(\r\022\024\n\014needsRefre" +
"sh\030\014 \001(\010\022\024\n\014aliceBaseKey\030\r \001(\014\022\024\n\014verifi" +
"cation\030\016 \001(\014\032\253\002\n\005Chain\022\027\n\017senderEphemera" +
"l\030\001 \001(\014\022\036\n\026senderEphemeralPrivate\030\002 \001(\014\022" +
"=\n\010chainKey\030\003 \001(\0132+.textsecure.SessionSt" +
"ructure.Chain.ChainKey\022B\n\013messageKeys\030\004 " +
"\003(\0132-.textsecure.SessionStructure.Chain." +
"MessageKey\032&\n\010ChainKey\022\r\n\005index\030\001 \001(\r\022\013\n",
"\003key\030\002 \001(\014\032>\n\nMessageKey\022\r\n\005index\030\001 \001(\r\022" +
"\021\n\tcipherKey\030\002 \001(\014\022\016\n\006macKey\030\003 \001(\014\032\321\001\n\022P" +
"endingKeyExchange\022\020\n\010sequence\030\001 \001(\r\022\024\n\014l" +
"ocalBaseKey\030\002 \001(\014\022\033\n\023localBaseKeyPrivate" +
"\030\003 \001(\014\022\031\n\021localEphemeralKey\030\004 \001(\014\022 \n\030loc" +
"alEphemeralKeyPrivate\030\005 \001(\014\022\030\n\020localIden" +
"tityKey\030\007 \001(\014\022\037\n\027localIdentityKeyPrivate" +
"\030\010 \001(\014\032J\n\rPendingPreKey\022\020\n\010preKeyId\030\001 \001(" +
"\r\022\026\n\016signedPreKeyId\030\003 \001(\005\022\017\n\007baseKey\030\002 \001" +
"(\014\"\177\n\017RecordStructure\0224\n\016currentSession\030",
"\001 \001(\0132\034.textsecure.SessionStructure\0226\n\020p" +
"reviousSessions\030\002 \003(\0132\034.textsecure.Sessi" +
"onStructure\"J\n\025PreKeyRecordStructure\022\n\n\002" +
"cation\030\016 \001(\014\032\255\002\n\005Chain\022\030\n\020senderRatchetK" +
"ey\030\001 \001(\014\022\037\n\027senderRatchetKeyPrivate\030\002 \001(" +
"\014\022=\n\010chainKey\030\003 \001(\0132+.textsecure.Session" +
"Structure.Chain.ChainKey\022B\n\013messageKeys\030" +
"\004 \003(\0132-.textsecure.SessionStructure.Chai" +
"n.MessageKey\032&\n\010ChainKey\022\r\n\005index\030\001 \001(\r\022",
"\013\n\003key\030\002 \001(\014\032>\n\nMessageKey\022\r\n\005index\030\001 \001(" +
"\r\022\021\n\tcipherKey\030\002 \001(\014\022\016\n\006macKey\030\003 \001(\014\032\315\001\n" +
"\022PendingKeyExchange\022\020\n\010sequence\030\001 \001(\r\022\024\n" +
"\014localBaseKey\030\002 \001(\014\022\033\n\023localBaseKeyPriva" +
"te\030\003 \001(\014\022\027\n\017localRatchetKey\030\004 \001(\014\022\036\n\026loc" +
"alRatchetKeyPrivate\030\005 \001(\014\022\030\n\020localIdenti" +
"tyKey\030\007 \001(\014\022\037\n\027localIdentityKeyPrivate\030\010" +
" \001(\014\032J\n\rPendingPreKey\022\020\n\010preKeyId\030\001 \001(\r\022" +
"\026\n\016signedPreKeyId\030\003 \001(\005\022\017\n\007baseKey\030\002 \001(\014" +
"\"\177\n\017RecordStructure\0224\n\016currentSession\030\001 ",
"\001(\0132\034.textsecure.SessionStructure\0226\n\020pre" +
"viousSessions\030\002 \003(\0132\034.textsecure.Session" +
"Structure\"J\n\025PreKeyRecordStructure\022\n\n\002id" +
"\030\001 \001(\r\022\021\n\tpublicKey\030\002 \001(\014\022\022\n\nprivateKey\030" +
"\003 \001(\014\"v\n\033SignedPreKeyRecordStructure\022\n\n\002" +
"id\030\001 \001(\r\022\021\n\tpublicKey\030\002 \001(\014\022\022\n\nprivateKe" +
"y\030\003 \001(\014\"v\n\033SignedPreKeyRecordStructure\022\n" +
"\n\002id\030\001 \001(\r\022\021\n\tpublicKey\030\002 \001(\014\022\022\n\nprivate" +
"Key\030\003 \001(\014\022\021\n\tsignature\030\004 \001(\014\022\021\n\ttimestam" +
"p\030\005 \001(\006\"A\n\030IdentityKeyPairStructure\022\021\n\tp" +
"ublicKey\030\001 \001(\014\022\022\n\nprivateKey\030\002 \001(\014B4\n#or" +
"g.whispersystems.libaxolotl.stateB\rStora",
"geProtos"
"y\030\003 \001(\014\022\021\n\tsignature\030\004 \001(\014\022\021\n\ttimestamp\030" +
"\005 \001(\006\"A\n\030IdentityKeyPairStructure\022\021\n\tpub" +
"licKey\030\001 \001(\014\022\022\n\nprivateKey\030\002 \001(\014B4\n#org." +
"whispersystems.libaxolotl.stateB\rStorage",
"Protos"
};
com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
@ -8390,7 +8390,7 @@ public final class StorageProtos {
internal_static_textsecure_SessionStructure_Chain_fieldAccessorTable = new
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
internal_static_textsecure_SessionStructure_Chain_descriptor,
new java.lang.String[] { "SenderEphemeral", "SenderEphemeralPrivate", "ChainKey", "MessageKeys", });
new java.lang.String[] { "SenderRatchetKey", "SenderRatchetKeyPrivate", "ChainKey", "MessageKeys", });
internal_static_textsecure_SessionStructure_Chain_ChainKey_descriptor =
internal_static_textsecure_SessionStructure_Chain_descriptor.getNestedTypes().get(0);
internal_static_textsecure_SessionStructure_Chain_ChainKey_fieldAccessorTable = new
@ -8408,7 +8408,7 @@ public final class StorageProtos {
internal_static_textsecure_SessionStructure_PendingKeyExchange_fieldAccessorTable = new
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
internal_static_textsecure_SessionStructure_PendingKeyExchange_descriptor,
new java.lang.String[] { "Sequence", "LocalBaseKey", "LocalBaseKeyPrivate", "LocalEphemeralKey", "LocalEphemeralKeyPrivate", "LocalIdentityKey", "LocalIdentityKeyPrivate", });
new java.lang.String[] { "Sequence", "LocalBaseKey", "LocalBaseKeyPrivate", "LocalRatchetKey", "LocalRatchetKeyPrivate", "LocalIdentityKey", "LocalIdentityKeyPrivate", });
internal_static_textsecure_SessionStructure_PendingPreKey_descriptor =
internal_static_textsecure_SessionStructure_descriptor.getNestedTypes().get(2);
internal_static_textsecure_SessionStructure_PendingPreKey_fieldAccessorTable = new