diff --git a/library/protobuf/LocalStorageProtocol.proto b/library/protobuf/LocalStorageProtocol.proto
new file mode 100644
index 0000000000..22378423d8
--- /dev/null
+++ b/library/protobuf/LocalStorageProtocol.proto
@@ -0,0 +1,54 @@
+package textsecure;
+
+option java_package = "org.whispersystems.textsecure.storage";
+option java_outer_classname = "StorageProtos";
+
+message SessionStructure {
+ message Chain {
+ optional bytes senderEphemeral = 1;
+ optional bytes senderEphemeralPrivate = 2;
+
+ message ChainKey {
+ optional uint32 index = 1;
+ optional bytes key = 2;
+ }
+
+ optional ChainKey chainKey = 3;
+
+ message MessageKey {
+ optional uint32 index = 1;
+ optional bytes cipherKey = 2;
+ optional bytes macKey = 3;
+ }
+
+ repeated MessageKey messageKeys = 4;
+ }
+
+ message PendingKeyExchange {
+ optional uint32 sequence = 1;
+ optional bytes localBaseKey = 2;
+ optional bytes localBaseKeyPrivate = 3;
+ optional bytes localEphemeralKey = 4;
+ optional bytes localEphemeralKeyPrivate = 5;
+ optional bytes localIdentityKey = 7;
+ optional bytes localIdentityKeyPrivate = 8;
+ }
+
+ message PendingPreKey {
+ optional uint32 preKeyId = 1;
+ optional bytes baseKey = 2;
+ }
+
+ optional uint32 sessionVersion = 1;
+ optional bytes localIdentityPublic = 2;
+ optional bytes remoteIdentityPublic = 3;
+
+ optional bytes rootKey = 4;
+ optional uint32 previousCounter = 5;
+
+ optional Chain senderChain = 6;
+ repeated Chain receiverChains = 7;
+
+ optional PendingKeyExchange pendingKeyExchange = 8;
+ optional PendingPreKey pendingPreKey = 9;
+}
\ No newline at end of file
diff --git a/library/protobuf/Makefile b/library/protobuf/Makefile
index 55640f5437..2354c14d61 100644
--- a/library/protobuf/Makefile
+++ b/library/protobuf/Makefile
@@ -1,3 +1,3 @@
all:
- protoc --java_out=../src/ IncomingPushMessageSignal.proto
+ protoc --java_out=../src/ IncomingPushMessageSignal.proto WhisperTextProtocol.proto LocalStorageProtocol.proto
diff --git a/library/protobuf/WhisperTextProtocol.proto b/library/protobuf/WhisperTextProtocol.proto
new file mode 100644
index 0000000000..f14625b96b
--- /dev/null
+++ b/library/protobuf/WhisperTextProtocol.proto
@@ -0,0 +1,25 @@
+package textsecure;
+
+option java_package = "org.whispersystems.textsecure.crypto.protocol";
+option java_outer_classname = "WhisperProtos";
+
+message WhisperMessage {
+ optional bytes ephemeralKey = 1;
+ optional uint32 counter = 2;
+ optional uint32 previousCounter = 3;
+ optional bytes ciphertext = 4;
+}
+
+message PreKeyWhisperMessage {
+ optional uint32 preKeyId = 1;
+ optional bytes baseKey = 2;
+ optional bytes identityKey = 3;
+ optional bytes message = 4; // WhisperMessage
+}
+
+message KeyExchangeMessage {
+ optional uint32 id = 1;
+ optional bytes baseKey = 2;
+ optional bytes ephemeralKey = 3;
+ optional bytes identityKey = 4;
+}
diff --git a/library/src/org/whispersystems/textsecure/crypto/IdentityKey.java b/library/src/org/whispersystems/textsecure/crypto/IdentityKey.java
index 742d716d58..26898a2a94 100644
--- a/library/src/org/whispersystems/textsecure/crypto/IdentityKey.java
+++ b/library/src/org/whispersystems/textsecure/crypto/IdentityKey.java
@@ -47,8 +47,7 @@ public class IdentityKey implements Parcelable, SerializableKey {
}
};
- public static final int SIZE = 1 + ECPublicKey.KEY_SIZE;
- private static final int CURRENT_VESION = 1;
+ public static final int NIST_SIZE = 1 + ECPublicKey.KEY_SIZE;
private ECPublicKey publicKey;
@@ -73,19 +72,22 @@ public class IdentityKey implements Parcelable, SerializableKey {
}
private void initializeFromSerialized(byte[] bytes, int offset) throws InvalidKeyException {
- int version = bytes[offset] & 0xff;
-
- if (version > CURRENT_VESION)
- throw new InvalidKeyException("Unsupported key version: " + version);
-
- this.publicKey = Curve.decodePoint(bytes, offset + 1);
+ if ((bytes[offset] & 0xff) == 1) {
+ this.publicKey = Curve.decodePoint(bytes, offset +1);
+ } else {
+ this.publicKey = Curve.decodePoint(bytes, offset);
+ }
}
public byte[] serialize() {
- byte[] versionBytes = {(byte)CURRENT_VESION};
- byte[] encodedKey = publicKey.serialize();
+ if (publicKey.getType() == Curve.NIST_TYPE) {
+ byte[] versionBytes = {0x01};
+ byte[] encodedKey = publicKey.serialize();
- return Util.combine(versionBytes, encodedKey);
+ return Util.combine(versionBytes, encodedKey);
+ } else {
+ return publicKey.serialize();
+ }
}
public String getFingerprint() {
diff --git a/library/src/org/whispersystems/textsecure/crypto/KeyUtil.java b/library/src/org/whispersystems/textsecure/crypto/KeyUtil.java
deleted file mode 100644
index e720d1b7a7..0000000000
--- a/library/src/org/whispersystems/textsecure/crypto/KeyUtil.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/**
- * Copyright (C) 2013 Open Whisper Systems
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.whispersystems.textsecure.crypto;
-
-import android.content.Context;
-import android.util.Log;
-
-import org.whispersystems.textsecure.crypto.ecc.Curve;
-import org.whispersystems.textsecure.storage.CanonicalRecipientAddress;
-import org.whispersystems.textsecure.storage.LocalKeyRecord;
-import org.whispersystems.textsecure.storage.RemoteKeyRecord;
-import org.whispersystems.textsecure.storage.SessionRecord;
-
-import java.security.NoSuchAlgorithmException;
-import java.security.SecureRandom;
-
-/**
- * Helper class for generating key pairs and calculating ECDH agreements.
- *
- * @author Moxie Marlinspike
- */
-
-public class KeyUtil {
-
- public static void abortSessionFor(Context context, CanonicalRecipientAddress recipient) {
- //XXX Obviously we should probably do something more thorough here eventually.
- Log.w("KeyUtil", "Aborting session, deleting keys...");
- LocalKeyRecord.delete(context, recipient);
- RemoteKeyRecord.delete(context, recipient);
- SessionRecord.delete(context, recipient);
- }
-
- public static boolean isSessionFor(Context context, CanonicalRecipientAddress recipient) {
- Log.w("KeyUtil", "Checking session...");
- return
- (LocalKeyRecord.hasRecord(context, recipient)) &&
- (RemoteKeyRecord.hasRecord(context, recipient)) &&
- (SessionRecord.hasSession(context, recipient));
- }
-
- public static boolean isNonPrekeySessionFor(Context context, MasterSecret masterSecret, CanonicalRecipientAddress recipient) {
- return isSessionFor(context, recipient) &&
- !(new SessionRecord(context, masterSecret, recipient).isPrekeyBundleRequired());
- }
-
- public static boolean isIdentityKeyFor(Context context,
- MasterSecret masterSecret,
- CanonicalRecipientAddress recipient)
- {
- return isSessionFor(context, recipient) &&
- new SessionRecord(context, masterSecret, recipient).getIdentityKey() != null;
- }
-
- public static LocalKeyRecord initializeRecordFor(Context context,
- MasterSecret masterSecret,
- CanonicalRecipientAddress recipient,
- int sessionVersion)
- {
- Log.w("KeyUtil", "Initializing local key pairs...");
- try {
- SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
- int initialId = secureRandom.nextInt(4094) + 1;
-
- KeyPair currentPair = new KeyPair(initialId, Curve.generateKeyPairForSession(sessionVersion), masterSecret);
- KeyPair nextPair = new KeyPair(initialId + 1, Curve.generateKeyPairForSession(sessionVersion), masterSecret);
- LocalKeyRecord record = new LocalKeyRecord(context, masterSecret, recipient);
-
- record.setCurrentKeyPair(currentPair);
- record.setNextKeyPair(nextPair);
- record.save();
-
- return record;
- } catch (NoSuchAlgorithmException e) {
- throw new AssertionError(e);
- }
- }
-
-}
diff --git a/library/src/org/whispersystems/textsecure/crypto/MessageCipher.java b/library/src/org/whispersystems/textsecure/crypto/MessageCipher.java
deleted file mode 100644
index 79755a54a4..0000000000
--- a/library/src/org/whispersystems/textsecure/crypto/MessageCipher.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/**
- * Copyright (C) 2011 Whisper Systems
- * Copyright (C) 2013 Open Whisper Systems
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.whispersystems.textsecure.crypto;
-
-import android.content.Context;
-
-import org.whispersystems.textsecure.crypto.SessionCipher.SessionCipherContext;
-import org.whispersystems.textsecure.crypto.protocol.CiphertextMessage;
-import org.whispersystems.textsecure.storage.CanonicalRecipientAddress;
-
-/**
- * Parses and serializes the encrypted message format.
- *
- * @author Moxie Marlinspike
- */
-
-public class MessageCipher {
-
- private final Context context;
- private final MasterSecret masterSecret;
- private final IdentityKeyPair localIdentityKey;
-
- public MessageCipher(Context context, MasterSecret masterSecret, IdentityKeyPair localIdentityKey) {
- this.context = context.getApplicationContext();
- this.masterSecret = masterSecret;
- this.localIdentityKey = localIdentityKey;
- }
-
- public CiphertextMessage encrypt(CanonicalRecipientAddress recipient, byte[] paddedBody) {
- synchronized (SessionCipher.CIPHER_LOCK) {
- SessionCipher sessionCipher = new SessionCipher();
- SessionCipherContext sessionContext = sessionCipher.getEncryptionContext(context, masterSecret, localIdentityKey, recipient);
- byte[] ciphertextBody = sessionCipher.encrypt(sessionContext, paddedBody);
-
- return new CiphertextMessage(sessionContext, ciphertextBody);
- }
- }
-
- public byte[] decrypt(CanonicalRecipientAddress recipient, byte[] ciphertext)
- throws InvalidMessageException
- {
- synchronized (SessionCipher.CIPHER_LOCK) {
- try {
- CiphertextMessage message = new CiphertextMessage(ciphertext);
-
- int messageVersion = message.getCurrentVersion();
- int senderKeyId = message.getSenderKeyId();
- int receiverKeyId = message.getReceiverKeyId();
- PublicKey nextRemoteKey = new PublicKey(message.getNextKeyBytes());
- int counter = message.getCounter();
- byte[] body = message.getBody();
-
- SessionCipher sessionCipher = new SessionCipher();
- SessionCipherContext sessionContext = sessionCipher.getDecryptionContext(context, masterSecret,
- localIdentityKey,
- recipient, senderKeyId,
- receiverKeyId,
- nextRemoteKey,
- counter,
- messageVersion);
-
- message.verifyMac(sessionContext);
-
- return sessionCipher.decrypt(sessionContext, body);
- } catch (InvalidKeyException e) {
- throw new InvalidMessageException(e);
- }
- }
- }
-}
diff --git a/library/src/org/whispersystems/textsecure/crypto/MessageMac.java b/library/src/org/whispersystems/textsecure/crypto/MessageMac.java
deleted file mode 100644
index 88b8506aa3..0000000000
--- a/library/src/org/whispersystems/textsecure/crypto/MessageMac.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/**
- * Copyright (C) 2011 Whisper Systems
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.whispersystems.textsecure.crypto;
-
-import java.security.InvalidKeyException;
-import java.security.NoSuchAlgorithmException;
-import java.util.Arrays;
-
-import javax.crypto.Mac;
-import javax.crypto.spec.SecretKeySpec;
-
-import org.whispersystems.textsecure.util.Hex;
-
-import android.util.Log;
-
-public class MessageMac {
-
- public static final int MAC_LENGTH = 10;
-
- public static byte[] calculateMac(byte[] message, int offset, int length, SecretKeySpec macKey) {
- try {
- Mac mac = Mac.getInstance("HmacSHA1");
- mac.init(macKey);
-
- assert(mac.getMacLength() >= MAC_LENGTH);
-
- mac.update(message, offset, length);
- byte[] macBytes = mac.doFinal();
- byte[] truncatedMacBytes = new byte[MAC_LENGTH];
- System.arraycopy(macBytes, 0, truncatedMacBytes, 0, truncatedMacBytes.length);
-
- return truncatedMacBytes;
- } catch (NoSuchAlgorithmException e) {
- throw new IllegalArgumentException(e);
- } catch (InvalidKeyException e) {
- throw new IllegalArgumentException(e);
- }
- }
-
- public static void verifyMac(byte[] message, int offset, int length,
- byte[] receivedMac, SecretKeySpec macKey)
- throws InvalidMacException
- {
- byte[] localMac = calculateMac(message, offset, length, macKey);
-
- Log.w("MessageMac", "Local Mac: " + Hex.toString(localMac));
- Log.w("MessageMac", "Remot Mac: " + Hex.toString(receivedMac));
-
- if (!Arrays.equals(localMac, receivedMac)) {
- throw new InvalidMacException("MAC on message does not match calculated MAC.");
- }
- }
-
-}
diff --git a/library/src/org/whispersystems/textsecure/crypto/SessionCipher.java b/library/src/org/whispersystems/textsecure/crypto/SessionCipher.java
index 758262610a..92c8cde72e 100644
--- a/library/src/org/whispersystems/textsecure/crypto/SessionCipher.java
+++ b/library/src/org/whispersystems/textsecure/crypto/SessionCipher.java
@@ -16,345 +16,31 @@
*/
package org.whispersystems.textsecure.crypto;
-import android.content.Context;
-import android.util.Log;
-import org.whispersystems.textsecure.crypto.ecc.ECPublicKey;
-import org.whispersystems.textsecure.crypto.kdf.DerivedSecrets;
+import android.content.Context;
+
import org.whispersystems.textsecure.crypto.protocol.CiphertextMessage;
import org.whispersystems.textsecure.storage.CanonicalRecipientAddress;
-import org.whispersystems.textsecure.storage.InvalidKeyIdException;
-import org.whispersystems.textsecure.storage.LocalKeyRecord;
-import org.whispersystems.textsecure.storage.RemoteKeyRecord;
-import org.whispersystems.textsecure.storage.SessionKey;
-import org.whispersystems.textsecure.storage.SessionRecord;
-import org.whispersystems.textsecure.util.Conversions;
+import org.whispersystems.textsecure.storage.SessionRecordV1;
+import org.whispersystems.textsecure.storage.SessionRecordV2;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.NoSuchAlgorithmException;
-import java.util.Arrays;
+public abstract class SessionCipher {
-import javax.crypto.BadPaddingException;
-import javax.crypto.Cipher;
-import javax.crypto.IllegalBlockSizeException;
-import javax.crypto.NoSuchPaddingException;
-import javax.crypto.spec.IvParameterSpec;
-import javax.crypto.spec.SecretKeySpec;
+ protected static final Object SESSION_LOCK = new Object();
-/**
- * This is where the session encryption magic happens. Implements a compressed version of the OTR protocol.
- *
- * @author Moxie Marlinspike
- */
+ public abstract CiphertextMessage encrypt(byte[] paddedMessage);
+ public abstract byte[] decrypt(byte[] decodedMessage) throws InvalidMessageException;
-public class SessionCipher {
-
- public static final Object CIPHER_LOCK = new Object();
-
- public static final int CIPHER_KEY_LENGTH = 16;
- public static final int MAC_KEY_LENGTH = 20;
-
- public SessionCipherContext getEncryptionContext(Context context,
- MasterSecret masterSecret,
- IdentityKeyPair localIdentityKey,
- CanonicalRecipientAddress recipient)
+ public static SessionCipher createFor(Context context, MasterSecret masterSecret,
+ CanonicalRecipientAddress recipient)
{
- try {
- KeyRecords records = getKeyRecords(context, masterSecret, recipient);
- int localKeyId = records.getLocalKeyRecord().getCurrentKeyPair().getId();
- int remoteKeyId = records.getRemoteKeyRecord().getCurrentRemoteKey().getId();
- int sessionVersion = records.getSessionRecord().getSessionVersion();
- SessionKey sessionKey = getSessionKey(masterSecret, Cipher.ENCRYPT_MODE, sessionVersion, localIdentityKey, records, localKeyId, remoteKeyId);
- PublicKey nextKey = records.getLocalKeyRecord().getNextKeyPair().getPublicKey();
- int counter = records.getSessionRecord().getCounter();
-
-
- return new SessionCipherContext(records, sessionKey, localKeyId, remoteKeyId,
- nextKey, counter, sessionVersion);
- } catch (InvalidKeyIdException e) {
- throw new IllegalArgumentException(e);
- } catch (InvalidKeyException e) {
- throw new IllegalArgumentException(e);
- }
- }
-
- public SessionCipherContext getDecryptionContext(Context context, MasterSecret masterSecret,
- IdentityKeyPair localIdentityKey,
- CanonicalRecipientAddress recipient,
- int senderKeyId, int recipientKeyId,
- PublicKey nextKey, int counter,
- int messageVersion)
- throws InvalidMessageException
- {
- try {
- KeyRecords records = getKeyRecords(context, masterSecret, recipient);
-
- if (messageVersion < records.getSessionRecord().getNegotiatedSessionVersion()) {
- throw new InvalidMessageException("Message version: " + messageVersion +
- " but negotiated session version: " +
- records.getSessionRecord().getNegotiatedSessionVersion());
- }
-
- SessionKey sessionKey = getSessionKey(masterSecret, Cipher.DECRYPT_MODE, messageVersion,
- localIdentityKey, records, recipientKeyId, senderKeyId);
-
- return new SessionCipherContext(records, sessionKey, senderKeyId,
- recipientKeyId, nextKey, counter,
- messageVersion);
- } catch (InvalidKeyIdException e) {
- throw new InvalidMessageException(e);
- } catch (InvalidKeyException e) {
- throw new InvalidMessageException(e);
- }
- }
-
- public byte[] encrypt(SessionCipherContext context, byte[] paddedMessageBody) {
- Log.w("SessionCipher", "Encrypting message...");
- try {
- byte[]cipherText = getCiphertext(paddedMessageBody, context.getSessionKey().getCipherKey(), context.getSessionRecord().getCounter());
-
- context.getSessionRecord().setSessionKey(context.getSessionKey());
- context.getSessionRecord().incrementCounter();
- context.getSessionRecord().save();
-
- return cipherText;
- } catch (IllegalBlockSizeException e) {
- throw new IllegalArgumentException(e);
- } catch (BadPaddingException e) {
- throw new IllegalArgumentException(e);
- }
- }
-
- public byte[] decrypt(SessionCipherContext context, byte[] decodedCiphertext)
- throws InvalidMessageException
- {
- Log.w("SessionCipher", "Decrypting message...");
- try {
- byte[] plaintextWithPadding = getPlaintext(decodedCiphertext,
- context.getSessionKey().getCipherKey(),
- context.getCounter());
-
- context.getRemoteKeyRecord().updateCurrentRemoteKey(context.getNextKey());
- context.getRemoteKeyRecord().save();
-
- context.getLocalKeyRecord().advanceKeyIfNecessary(context.getRecipientKeyId());
- context.getLocalKeyRecord().save();
-
- context.getSessionRecord().setSessionKey(context.getSessionKey());
- context.getSessionRecord().setPrekeyBundleRequired(false);
- context.getSessionRecord().save();
-
- return plaintextWithPadding;
- } catch (IllegalBlockSizeException e) {
- throw new InvalidMessageException("assert", e);
- } catch (BadPaddingException e) {
- throw new InvalidMessageException("assert", e);
- }
- }
-
- private byte[] getPlaintext(byte[] cipherText, SecretKeySpec key, int counter)
- throws IllegalBlockSizeException, BadPaddingException
- {
- Cipher cipher = getCipher(Cipher.DECRYPT_MODE, key, counter);
- return cipher.doFinal(cipherText);
- }
-
- private byte[] getCiphertext(byte[] message, SecretKeySpec key, int counter)
- throws IllegalBlockSizeException, BadPaddingException
- {
- Cipher cipher = getCipher(Cipher.ENCRYPT_MODE, key, counter);
- return cipher.doFinal(message);
- }
-
- private Cipher getCipher(int mode, SecretKeySpec key, int counter) {
- try {
- Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");
-
- byte[] ivBytes = new byte[16];
- Conversions.mediumToByteArray(ivBytes, 0, counter);
-
- IvParameterSpec iv = new IvParameterSpec(ivBytes);
- cipher.init(mode, key, iv);
-
- return cipher;
- } catch (NoSuchAlgorithmException e) {
- throw new IllegalArgumentException("AES Not Supported!");
- } catch (NoSuchPaddingException e) {
- throw new IllegalArgumentException("NoPadding Not Supported!");
- } catch (java.security.InvalidKeyException e) {
- Log.w("SessionCipher", e);
- throw new IllegalArgumentException("Invaid Key?");
- } catch (InvalidAlgorithmParameterException e) {
- Log.w("SessionCipher", e);
- throw new IllegalArgumentException("Bad IV?");
- }
- }
-
- private SessionKey getSessionKey(MasterSecret masterSecret, int mode,
- int messageVersion,
- IdentityKeyPair localIdentityKey,
- KeyRecords records,
- int localKeyId, int remoteKeyId)
- throws InvalidKeyIdException, InvalidKeyException
- {
- Log.w("SessionCipher", "Getting session key for local: " + localKeyId + " remote: " + remoteKeyId);
- SessionKey sessionKey = records.getSessionRecord().getSessionKey(mode, localKeyId, remoteKeyId);
-
- if (sessionKey != null)
- return sessionKey;
-
- DerivedSecrets derivedSecrets = calculateSharedSecret(messageVersion, mode, localIdentityKey,
- records, localKeyId, remoteKeyId);
-
- return new SessionKey(mode, localKeyId, remoteKeyId, derivedSecrets.getCipherKey(),
- derivedSecrets.getMacKey(), masterSecret);
- }
-
- private DerivedSecrets calculateSharedSecret(int messageVersion, int mode,
- IdentityKeyPair localIdentityKey,
- KeyRecords records,
- int localKeyId, int remoteKeyId)
- throws InvalidKeyIdException, InvalidKeyException
- {
- KeyPair localKeyPair = records.getLocalKeyRecord().getKeyPairForId(localKeyId);
- ECPublicKey remoteKey = records.getRemoteKeyRecord().getKeyForId(remoteKeyId).getKey();
- IdentityKey remoteIdentityKey = records.getSessionRecord().getIdentityKey();
- boolean isLowEnd = isLowEnd(records, localKeyId, remoteKeyId);
-
- isLowEnd = (mode == Cipher.ENCRYPT_MODE ? isLowEnd : !isLowEnd);
-
- if (isInitiallyExchangedKeys(records, localKeyId, remoteKeyId) &&
- messageVersion >= CiphertextMessage.DHE3_INTRODUCED_VERSION)
- {
- return SharedSecretCalculator.calculateSharedSecret(isLowEnd,
- localKeyPair, localKeyId, localIdentityKey,
- remoteKey, remoteKeyId, remoteIdentityKey);
+ if (SessionRecordV2.hasSession(context, masterSecret, recipient)) {
+ return new SessionCipherV2(context, masterSecret, recipient);
+ } else if (SessionRecordV1.hasSession(context, recipient)) {
+ return new SessionCipherV1(context, masterSecret, recipient);
} else {
- return SharedSecretCalculator.calculateSharedSecret(messageVersion, isLowEnd,
- localKeyPair, localKeyId,
- remoteKey, remoteKeyId);
+ throw new AssertionError("Attempt to initialize cipher for non-existing session.");
}
}
- private boolean isLowEnd(KeyRecords records, int localKeyId, int remoteKeyId)
- throws InvalidKeyIdException
- {
- ECPublicKey localPublic = records.getLocalKeyRecord().getKeyPairForId(localKeyId).getPublicKey().getKey();
- ECPublicKey remotePublic = records.getRemoteKeyRecord().getKeyForId(remoteKeyId).getKey();
-
- return localPublic.compareTo(remotePublic) < 0;
- }
-
- private boolean isInitiallyExchangedKeys(KeyRecords records, int localKeyId, int remoteKeyId)
- throws InvalidKeyIdException
- {
- byte[] localFingerprint = records.getSessionRecord().getLocalFingerprint();
- byte[] remoteFingerprint = records.getSessionRecord().getRemoteFingerprint();
-
- return Arrays.equals(localFingerprint, records.getLocalKeyRecord().getKeyPairForId(localKeyId).getPublicKey().getFingerprintBytes()) &&
- Arrays.equals(remoteFingerprint, records.getRemoteKeyRecord().getKeyForId(remoteKeyId).getFingerprintBytes());
- }
-
- private KeyRecords getKeyRecords(Context context, MasterSecret masterSecret,
- CanonicalRecipientAddress recipient)
- {
- LocalKeyRecord localKeyRecord = new LocalKeyRecord(context, masterSecret, recipient);
- RemoteKeyRecord remoteKeyRecord = new RemoteKeyRecord(context, recipient);
- SessionRecord sessionRecord = new SessionRecord(context, masterSecret, recipient);
- return new KeyRecords(localKeyRecord, remoteKeyRecord, sessionRecord);
- }
-
- private static class KeyRecords {
-
- private final LocalKeyRecord localKeyRecord;
- private final RemoteKeyRecord remoteKeyRecord;
- private final SessionRecord sessionRecord;
-
- public KeyRecords(LocalKeyRecord localKeyRecord, RemoteKeyRecord remoteKeyRecord, SessionRecord sessionRecord) {
- this.localKeyRecord = localKeyRecord;
- this.remoteKeyRecord = remoteKeyRecord;
- this.sessionRecord = sessionRecord;
- }
-
- private LocalKeyRecord getLocalKeyRecord() {
- return localKeyRecord;
- }
-
- private RemoteKeyRecord getRemoteKeyRecord() {
- return remoteKeyRecord;
- }
-
- private SessionRecord getSessionRecord() {
- return sessionRecord;
- }
- }
-
- public static class SessionCipherContext {
-
- private final LocalKeyRecord localKeyRecord;
- private final RemoteKeyRecord remoteKeyRecord;
- private final SessionRecord sessionRecord;
- private final SessionKey sessionKey;
- private final int senderKeyId;
- private final int recipientKeyId;
- private final PublicKey nextKey;
- private final int counter;
- private final int messageVersion;
-
- public SessionCipherContext(KeyRecords records,
- SessionKey sessionKey,
- int senderKeyId,
- int receiverKeyId,
- PublicKey nextKey,
- int counter,
- int messageVersion)
- {
- this.localKeyRecord = records.getLocalKeyRecord();
- this.remoteKeyRecord = records.getRemoteKeyRecord();
- this.sessionRecord = records.getSessionRecord();
- this.sessionKey = sessionKey;
- this.senderKeyId = senderKeyId;
- this.recipientKeyId = receiverKeyId;
- this.nextKey = nextKey;
- this.counter = counter;
- this.messageVersion = messageVersion;
- }
-
- public LocalKeyRecord getLocalKeyRecord() {
- return localKeyRecord;
- }
-
- public RemoteKeyRecord getRemoteKeyRecord() {
- return remoteKeyRecord;
- }
-
- public SessionRecord getSessionRecord() {
- return sessionRecord;
- }
-
- public SessionKey getSessionKey() {
- return sessionKey;
- }
-
- public PublicKey getNextKey() {
- return nextKey;
- }
-
- public int getCounter() {
- return counter;
- }
-
- public int getSenderKeyId() {
- return senderKeyId;
- }
-
- public int getRecipientKeyId() {
- return recipientKeyId;
- }
-
- public int getMessageVersion() {
- return messageVersion;
- }
- }
-
-}
+}
\ No newline at end of file
diff --git a/library/src/org/whispersystems/textsecure/crypto/SessionCipherV1.java b/library/src/org/whispersystems/textsecure/crypto/SessionCipherV1.java
new file mode 100644
index 0000000000..bebdf45872
--- /dev/null
+++ b/library/src/org/whispersystems/textsecure/crypto/SessionCipherV1.java
@@ -0,0 +1,325 @@
+package org.whispersystems.textsecure.crypto;
+
+import android.content.Context;
+import android.util.Log;
+
+import org.whispersystems.textsecure.crypto.ecc.Curve;
+import org.whispersystems.textsecure.crypto.ecc.ECPublicKey;
+import org.whispersystems.textsecure.crypto.kdf.DerivedSecrets;
+import org.whispersystems.textsecure.crypto.kdf.NKDF;
+import org.whispersystems.textsecure.crypto.protocol.CiphertextMessage;
+import org.whispersystems.textsecure.crypto.protocol.WhisperMessageV1;
+import org.whispersystems.textsecure.storage.CanonicalRecipientAddress;
+import org.whispersystems.textsecure.storage.InvalidKeyIdException;
+import org.whispersystems.textsecure.storage.LocalKeyRecord;
+import org.whispersystems.textsecure.storage.RemoteKeyRecord;
+import org.whispersystems.textsecure.storage.SessionKey;
+import org.whispersystems.textsecure.storage.SessionRecordV1;
+import org.whispersystems.textsecure.util.Conversions;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.NoSuchAlgorithmException;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+public class SessionCipherV1 extends SessionCipher {
+
+ private final Context context;
+ private final MasterSecret masterSecret;
+ private final CanonicalRecipientAddress recipient;
+
+ public SessionCipherV1(Context context, MasterSecret masterSecret,
+ CanonicalRecipientAddress recipient)
+ {
+ this.context = context;
+ this.masterSecret = masterSecret;
+ this.recipient = recipient;
+ }
+
+ public CiphertextMessage encrypt(byte[] paddedMessageBody) {
+ synchronized (SESSION_LOCK) {
+ SessionCipherContext encryptionContext = getEncryptionContext();
+ byte[] cipherText = getCiphertext(paddedMessageBody,
+ encryptionContext.getSessionKey().getCipherKey(),
+ encryptionContext.getSessionRecord().getCounter());
+
+ encryptionContext.getSessionRecord().setSessionKey(encryptionContext.getSessionKey());
+ encryptionContext.getSessionRecord().incrementCounter();
+ encryptionContext.getSessionRecord().save();
+
+ return new WhisperMessageV1(encryptionContext, cipherText);
+ }
+ }
+
+ public byte[] decrypt(byte[] decodedCiphertext) throws InvalidMessageException {
+ synchronized (SESSION_LOCK) {
+ WhisperMessageV1 message = new WhisperMessageV1(decodedCiphertext);
+ SessionCipherContext decryptionContext = getDecryptionContext(message);
+
+ message.verifyMac(decryptionContext);
+
+ byte[] plaintextWithPadding = getPlaintext(message.getBody(),
+ decryptionContext.getSessionKey().getCipherKey(),
+ decryptionContext.getCounter());
+
+ decryptionContext.getRemoteKeyRecord().updateCurrentRemoteKey(decryptionContext.getNextKey());
+ decryptionContext.getRemoteKeyRecord().save();
+
+ decryptionContext.getLocalKeyRecord().advanceKeyIfNecessary(decryptionContext.getRecipientKeyId());
+ decryptionContext.getLocalKeyRecord().save();
+
+ decryptionContext.getSessionRecord().setSessionKey(decryptionContext.getSessionKey());
+ decryptionContext.getSessionRecord().save();
+
+ return plaintextWithPadding;
+ }
+ }
+
+ private SessionCipherContext getEncryptionContext() {
+ try {
+ KeyRecords records = getKeyRecords(context, masterSecret, recipient);
+ int localKeyId = records.getLocalKeyRecord().getCurrentKeyPair().getId();
+ int remoteKeyId = records.getRemoteKeyRecord().getCurrentRemoteKey().getId();
+ int sessionVersion = records.getSessionRecord().getSessionVersion();
+ SessionKey sessionKey = getSessionKey(masterSecret, Cipher.ENCRYPT_MODE,
+ records, localKeyId, remoteKeyId);
+ PublicKey nextKey = records.getLocalKeyRecord().getNextKeyPair().getPublicKey();
+ int counter = records.getSessionRecord().getCounter();
+
+
+ return new SessionCipherContext(records, sessionKey, localKeyId, remoteKeyId,
+ nextKey, counter, sessionVersion);
+ } catch (InvalidKeyIdException e) {
+ throw new IllegalArgumentException(e);
+ } catch (InvalidKeyException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ public SessionCipherContext getDecryptionContext(WhisperMessageV1 message)
+ throws InvalidMessageException
+ {
+ try {
+ KeyRecords records = getKeyRecords(context, masterSecret, recipient);
+ int messageVersion = message.getCurrentVersion();
+ int recipientKeyId = message.getReceiverKeyId();
+ int senderKeyId = message.getSenderKeyId();
+ PublicKey nextKey = new PublicKey(message.getNextKeyBytes());
+ int counter = message.getCounter();
+
+ if (messageVersion < records.getSessionRecord().getSessionVersion()) {
+ throw new InvalidMessageException("Message version: " + messageVersion +
+ " but negotiated session version: " +
+ records.getSessionRecord().getSessionVersion());
+ }
+
+ SessionKey sessionKey = getSessionKey(masterSecret, Cipher.DECRYPT_MODE,
+ records, recipientKeyId, senderKeyId);
+
+ return new SessionCipherContext(records, sessionKey, senderKeyId,
+ recipientKeyId, nextKey, counter,
+ messageVersion);
+ } catch (InvalidKeyIdException e) {
+ throw new InvalidMessageException(e);
+ } catch (InvalidKeyException e) {
+ throw new InvalidMessageException(e);
+ }
+ }
+
+ private byte[] getCiphertext(byte[] message, SecretKeySpec key, int counter) {
+ try {
+ Cipher cipher = getCipher(Cipher.ENCRYPT_MODE, key, counter);
+ return cipher.doFinal(message);
+ } catch (IllegalBlockSizeException e) {
+ throw new AssertionError(e);
+ } catch (BadPaddingException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ private byte[] getPlaintext(byte[] cipherText, SecretKeySpec key, int counter) {
+ try {
+ Cipher cipher = getCipher(Cipher.DECRYPT_MODE, key, counter);
+ return cipher.doFinal(cipherText);
+ } catch (IllegalBlockSizeException e) {
+ throw new AssertionError(e);
+ } catch (BadPaddingException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ private Cipher getCipher(int mode, SecretKeySpec key, int counter) {
+ try {
+ Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");
+
+ byte[] ivBytes = new byte[16];
+ Conversions.mediumToByteArray(ivBytes, 0, counter);
+
+ IvParameterSpec iv = new IvParameterSpec(ivBytes);
+ cipher.init(mode, key, iv);
+
+ return cipher;
+ } catch (NoSuchAlgorithmException e) {
+ throw new IllegalArgumentException("AES Not Supported!");
+ } catch (NoSuchPaddingException e) {
+ throw new IllegalArgumentException("NoPadding Not Supported!");
+ } catch (java.security.InvalidKeyException e) {
+ Log.w("SessionCipher", e);
+ throw new IllegalArgumentException("Invaid Key?");
+ } catch (InvalidAlgorithmParameterException e) {
+ Log.w("SessionCipher", e);
+ throw new IllegalArgumentException("Bad IV?");
+ }
+ }
+
+ private SessionKey getSessionKey(MasterSecret masterSecret, int mode,
+ KeyRecords records,
+ int localKeyId, int remoteKeyId)
+ throws InvalidKeyIdException, InvalidKeyException
+ {
+ Log.w("SessionCipher", "Getting session key for local: " + localKeyId + " remote: " + remoteKeyId);
+ SessionKey sessionKey = records.getSessionRecord().getSessionKey(mode, localKeyId, remoteKeyId);
+
+ if (sessionKey != null)
+ return sessionKey;
+
+ DerivedSecrets derivedSecrets = calculateSharedSecret(mode, records, localKeyId, remoteKeyId);
+
+ return new SessionKey(mode, localKeyId, remoteKeyId, derivedSecrets.getCipherKey(),
+ derivedSecrets.getMacKey(), masterSecret);
+ }
+
+ private DerivedSecrets calculateSharedSecret(int mode, KeyRecords records,
+ int localKeyId, int remoteKeyId)
+ throws InvalidKeyIdException, InvalidKeyException
+ {
+ NKDF kdf = new NKDF();
+ KeyPair localKeyPair = records.getLocalKeyRecord().getKeyPairForId(localKeyId);
+ ECPublicKey remoteKey = records.getRemoteKeyRecord().getKeyForId(remoteKeyId).getKey();
+ byte[] sharedSecret = Curve.calculateAgreement(remoteKey, localKeyPair.getPrivateKey());
+ boolean isLowEnd = isLowEnd(records, localKeyId, remoteKeyId);
+
+ isLowEnd = (mode == Cipher.ENCRYPT_MODE ? isLowEnd : !isLowEnd);
+
+ return kdf.deriveSecrets(sharedSecret, isLowEnd);
+ }
+
+ private boolean isLowEnd(KeyRecords records, int localKeyId, int remoteKeyId)
+ throws InvalidKeyIdException
+ {
+ ECPublicKey localPublic = records.getLocalKeyRecord().getKeyPairForId(localKeyId).getPublicKey().getKey();
+ ECPublicKey remotePublic = records.getRemoteKeyRecord().getKeyForId(remoteKeyId).getKey();
+
+ return localPublic.compareTo(remotePublic) < 0;
+ }
+
+ private KeyRecords getKeyRecords(Context context, MasterSecret masterSecret,
+ CanonicalRecipientAddress recipient)
+ {
+ LocalKeyRecord localKeyRecord = new LocalKeyRecord(context, masterSecret, recipient);
+ RemoteKeyRecord remoteKeyRecord = new RemoteKeyRecord(context, recipient);
+ SessionRecordV1 sessionRecord = new SessionRecordV1(context, masterSecret, recipient);
+ return new KeyRecords(localKeyRecord, remoteKeyRecord, sessionRecord);
+ }
+
+ private static class KeyRecords {
+
+ private final LocalKeyRecord localKeyRecord;
+ private final RemoteKeyRecord remoteKeyRecord;
+ private final SessionRecordV1 sessionRecord;
+
+ public KeyRecords(LocalKeyRecord localKeyRecord,
+ RemoteKeyRecord remoteKeyRecord,
+ SessionRecordV1 sessionRecord)
+ {
+ this.localKeyRecord = localKeyRecord;
+ this.remoteKeyRecord = remoteKeyRecord;
+ this.sessionRecord = sessionRecord;
+ }
+
+ private LocalKeyRecord getLocalKeyRecord() {
+ return localKeyRecord;
+ }
+
+ private RemoteKeyRecord getRemoteKeyRecord() {
+ return remoteKeyRecord;
+ }
+
+ private SessionRecordV1 getSessionRecord() {
+ return sessionRecord;
+ }
+ }
+
+ public static class SessionCipherContext {
+
+ private final LocalKeyRecord localKeyRecord;
+ private final RemoteKeyRecord remoteKeyRecord;
+ private final SessionRecordV1 sessionRecord;
+ private final SessionKey sessionKey;
+ private final int senderKeyId;
+ private final int recipientKeyId;
+ private final PublicKey nextKey;
+ private final int counter;
+ private final int messageVersion;
+
+ public SessionCipherContext(KeyRecords records,
+ SessionKey sessionKey,
+ int senderKeyId,
+ int receiverKeyId,
+ PublicKey nextKey,
+ int counter,
+ int messageVersion)
+ {
+ this.localKeyRecord = records.getLocalKeyRecord();
+ this.remoteKeyRecord = records.getRemoteKeyRecord();
+ this.sessionRecord = records.getSessionRecord();
+ this.sessionKey = sessionKey;
+ this.senderKeyId = senderKeyId;
+ this.recipientKeyId = receiverKeyId;
+ this.nextKey = nextKey;
+ this.counter = counter;
+ this.messageVersion = messageVersion;
+ }
+
+ public LocalKeyRecord getLocalKeyRecord() {
+ return localKeyRecord;
+ }
+
+ public RemoteKeyRecord getRemoteKeyRecord() {
+ return remoteKeyRecord;
+ }
+
+ public SessionRecordV1 getSessionRecord() {
+ return sessionRecord;
+ }
+
+ public SessionKey getSessionKey() {
+ return sessionKey;
+ }
+
+ public PublicKey getNextKey() {
+ return nextKey;
+ }
+
+ public int getCounter() {
+ return counter;
+ }
+
+ public int getSenderKeyId() {
+ return senderKeyId;
+ }
+
+ public int getRecipientKeyId() {
+ return recipientKeyId;
+ }
+
+ public int getMessageVersion() {
+ return messageVersion;
+ }
+ }
+}
diff --git a/library/src/org/whispersystems/textsecure/crypto/SessionCipherV2.java b/library/src/org/whispersystems/textsecure/crypto/SessionCipherV2.java
new file mode 100644
index 0000000000..b5fd072681
--- /dev/null
+++ b/library/src/org/whispersystems/textsecure/crypto/SessionCipherV2.java
@@ -0,0 +1,201 @@
+package org.whispersystems.textsecure.crypto;
+
+import android.content.Context;
+import android.util.Log;
+import android.util.Pair;
+
+import org.whispersystems.textsecure.crypto.ecc.Curve;
+import org.whispersystems.textsecure.crypto.ecc.ECKeyPair;
+import org.whispersystems.textsecure.crypto.ecc.ECPublicKey;
+import org.whispersystems.textsecure.crypto.protocol.CiphertextMessage;
+import org.whispersystems.textsecure.crypto.protocol.PreKeyWhisperMessage;
+import org.whispersystems.textsecure.crypto.protocol.WhisperMessageV2;
+import org.whispersystems.textsecure.crypto.ratchet.ChainKey;
+import org.whispersystems.textsecure.crypto.ratchet.MessageKeys;
+import org.whispersystems.textsecure.crypto.ratchet.RootKey;
+import org.whispersystems.textsecure.storage.CanonicalRecipientAddress;
+import org.whispersystems.textsecure.storage.SessionRecordV2;
+import org.whispersystems.textsecure.util.Conversions;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.NoSuchAlgorithmException;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+public class SessionCipherV2 extends SessionCipher {
+
+ private final Context context;
+ private final MasterSecret masterSecret;
+ private final CanonicalRecipientAddress recipient;
+
+ public SessionCipherV2(Context context,
+ MasterSecret masterSecret,
+ CanonicalRecipientAddress recipient)
+ {
+ this.context = context;
+ this.masterSecret = masterSecret;
+ this.recipient = recipient;
+ }
+
+ @Override
+ public CiphertextMessage encrypt(byte[] paddedMessage) {
+ synchronized (SESSION_LOCK) {
+ SessionRecordV2 sessionRecord = getSessionRecord();
+ ChainKey chainKey = sessionRecord.getSenderChainKey();
+ MessageKeys messageKeys = chainKey.getMessageKeys();
+ ECPublicKey senderEphemeral = sessionRecord.getSenderEphemeral();
+ int previousCounter = sessionRecord.getPreviousCounter();
+
+ byte[] ciphertextBody = getCiphertext(messageKeys, paddedMessage);
+ CiphertextMessage ciphertextMessage = new WhisperMessageV2(messageKeys.getMacKey(),
+ senderEphemeral, chainKey.getIndex(),
+ previousCounter, ciphertextBody);
+
+ if (sessionRecord.hasPendingPreKey()) {
+ Pair pendingPreKey = sessionRecord.getPendingPreKey();
+ ciphertextMessage = new PreKeyWhisperMessage(pendingPreKey.first, pendingPreKey.second,
+ sessionRecord.getLocalIdentityKey(),
+ (WhisperMessageV2) ciphertextMessage);
+ }
+
+ sessionRecord.setSenderChainKey(chainKey.getNextChainKey());
+ sessionRecord.save();
+
+ return ciphertextMessage;
+ }
+ }
+
+ @Override
+ public byte[] decrypt(byte[] decodedMessage) throws InvalidMessageException {
+ synchronized (SESSION_LOCK) {
+ SessionRecordV2 sessionRecord = getSessionRecord();
+ WhisperMessageV2 ciphertextMessage = new WhisperMessageV2(decodedMessage);
+ ECPublicKey theirEphemeral = ciphertextMessage.getSenderEphemeral();
+ int counter = ciphertextMessage.getCounter();
+ ChainKey chainKey = getOrCreateChainKey(sessionRecord, theirEphemeral);
+ MessageKeys messageKeys = getOrCreateMessageKeys(sessionRecord, theirEphemeral,
+ chainKey, counter);
+
+ ciphertextMessage.verifyMac(messageKeys.getMacKey());
+
+ byte[] plaintext = getPlaintext(messageKeys, ciphertextMessage.getBody());
+
+ sessionRecord.clearPendingPreKey();
+ sessionRecord.save();
+
+ return plaintext;
+ }
+ }
+
+ private ChainKey getOrCreateChainKey(SessionRecordV2 sessionRecord, ECPublicKey theirEphemeral)
+ throws InvalidMessageException
+ {
+ try {
+ if (sessionRecord.hasReceiverChain(theirEphemeral)) {
+ return sessionRecord.getReceiverChainKey(theirEphemeral);
+ } else {
+ RootKey rootKey = sessionRecord.getRootKey();
+ ECKeyPair ourEphemeral = sessionRecord.getSenderEphemeralPair();
+ Pair receiverChain = rootKey.createChain(theirEphemeral, ourEphemeral);
+ ECKeyPair ourNewEphemeral = Curve.generateKeyPairForType(Curve.DJB_TYPE);
+ Pair senderChain = receiverChain.first.createChain(theirEphemeral, ourNewEphemeral);
+
+ sessionRecord.setRootKey(senderChain.first);
+ sessionRecord.addReceiverChain(theirEphemeral, receiverChain.second);
+ sessionRecord.setPreviousCounter(sessionRecord.getSenderChainKey().getIndex()-1);
+ sessionRecord.setSenderChain(ourNewEphemeral, senderChain.second);
+
+ return receiverChain.second;
+ }
+ } catch (InvalidKeyException e) {
+ throw new InvalidMessageException(e);
+ }
+ }
+
+ private MessageKeys getOrCreateMessageKeys(SessionRecordV2 sessionRecord,
+ ECPublicKey theirEphemeral,
+ ChainKey chainKey, int counter)
+ throws InvalidMessageException
+ {
+ if (chainKey.getIndex() > counter) {
+ if (sessionRecord.hasMessageKeys(theirEphemeral, counter)) {
+ return sessionRecord.removeMessageKeys(theirEphemeral, counter);
+ } else {
+ throw new InvalidMessageException("Received message with old counter!");
+ }
+ }
+
+ if (chainKey.getIndex() - counter > 500) {
+ throw new InvalidMessageException("Over 500 messages into the future!");
+ }
+
+ while (chainKey.getIndex() < counter) {
+ MessageKeys messageKeys = chainKey.getMessageKeys();
+ sessionRecord.setMessageKeys(theirEphemeral, messageKeys);
+ chainKey = chainKey.getNextChainKey();
+ }
+
+ sessionRecord.setReceiverChainKey(theirEphemeral, chainKey.getNextChainKey());
+ return chainKey.getMessageKeys();
+ }
+
+ private byte[] getCiphertext(MessageKeys messageKeys, byte[] plaintext) {
+ try {
+ Cipher cipher = getCipher(Cipher.ENCRYPT_MODE,
+ messageKeys.getCipherKey(),
+ messageKeys.getCounter());
+
+ return cipher.doFinal(plaintext);
+ } catch (IllegalBlockSizeException e) {
+ throw new AssertionError(e);
+ } catch (BadPaddingException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ private byte[] getPlaintext(MessageKeys messageKeys, byte[] cipherText) {
+ try {
+ Cipher cipher = getCipher(Cipher.DECRYPT_MODE,
+ messageKeys.getCipherKey(),
+ messageKeys.getCounter());
+ return cipher.doFinal(cipherText);
+ } catch (IllegalBlockSizeException e) {
+ throw new AssertionError(e);
+ } catch (BadPaddingException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ private Cipher getCipher(int mode, SecretKeySpec key, int counter) {
+ try {
+ Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");
+
+ byte[] ivBytes = new byte[16];
+ Conversions.intToByteArray(ivBytes, 0, counter);
+
+ IvParameterSpec iv = new IvParameterSpec(ivBytes);
+ cipher.init(mode, key, iv);
+
+ return cipher;
+ } catch (NoSuchAlgorithmException e) {
+ throw new AssertionError(e);
+ } catch (NoSuchPaddingException e) {
+ throw new AssertionError(e);
+ } catch (java.security.InvalidKeyException e) {
+ throw new AssertionError(e);
+ } catch (InvalidAlgorithmParameterException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+
+ private SessionRecordV2 getSessionRecord() {
+ return new SessionRecordV2(context, masterSecret, recipient);
+ }
+
+}
diff --git a/library/src/org/whispersystems/textsecure/crypto/SharedSecretCalculator.java b/library/src/org/whispersystems/textsecure/crypto/SharedSecretCalculator.java
deleted file mode 100644
index 6fd3f9956a..0000000000
--- a/library/src/org/whispersystems/textsecure/crypto/SharedSecretCalculator.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/**
- * Copyright (C) 2013 Open Whisper Systems
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-package org.whispersystems.textsecure.crypto;
-
-import android.util.Log;
-
-import org.whispersystems.textsecure.crypto.ecc.Curve;
-import org.whispersystems.textsecure.crypto.ecc.ECPublicKey;
-import org.whispersystems.textsecure.crypto.kdf.DerivedSecrets;
-import org.whispersystems.textsecure.crypto.kdf.HKDF;
-import org.whispersystems.textsecure.crypto.kdf.KDF;
-import org.whispersystems.textsecure.crypto.kdf.NKDF;
-import org.whispersystems.textsecure.crypto.protocol.CiphertextMessage;
-import org.whispersystems.textsecure.util.Conversions;
-
-import java.util.LinkedList;
-import java.util.List;
-
-public class SharedSecretCalculator {
-
- public static DerivedSecrets calculateSharedSecret(boolean isLowEnd, KeyPair localKeyPair,
- int localKeyId,
- IdentityKeyPair localIdentityKeyPair,
- ECPublicKey remoteKey,
- int remoteKeyId,
- IdentityKey remoteIdentityKey)
- throws InvalidKeyException
- {
- Log.w("SharedSecretCalculator", "Calculating shared secret with 3DHE agreement...");
- KDF kdf = new HKDF();
- List results = new LinkedList();
-
- if (isSmaller(localKeyPair.getPublicKey().getKey(), remoteKey)) {
- results.add(Curve.calculateAgreement(remoteKey, localIdentityKeyPair.getPrivateKey()));
- results.add(Curve.calculateAgreement(remoteIdentityKey.getPublicKey(),
- localKeyPair.getPrivateKey()));
- } else {
- results.add(Curve.calculateAgreement(remoteIdentityKey.getPublicKey(),
- localKeyPair.getPrivateKey()));
- results.add(Curve.calculateAgreement(remoteKey, localIdentityKeyPair.getPrivateKey()));
- }
-
- results.add(Curve.calculateAgreement(remoteKey, localKeyPair.getPrivateKey()));
-
- return kdf.deriveSecrets(results, isLowEnd, getInfo(localKeyId, remoteKeyId));
- }
-
- public static DerivedSecrets calculateSharedSecret(int messageVersion, boolean isLowEnd,
- KeyPair localKeyPair, int localKeyId,
- ECPublicKey remoteKey, int remoteKeyId)
- throws InvalidKeyException
- {
- Log.w("SharedSecretCalculator", "Calculating shared secret with standard agreement...");
- KDF kdf;
-
- if (messageVersion >= CiphertextMessage.DHE3_INTRODUCED_VERSION) kdf = new HKDF();
- else kdf = new NKDF();
-
- Log.w("SharedSecretCalculator", "Using kdf: " + kdf);
-
- List results = new LinkedList();
- results.add(Curve.calculateAgreement(remoteKey, localKeyPair.getPrivateKey()));
-
- return kdf.deriveSecrets(results, isLowEnd, getInfo(localKeyId, remoteKeyId));
- }
-
- private static byte[] getInfo(int localKeyId, int remoteKeyId) {
- byte[] info = new byte[3 * 2];
-
- if (localKeyId < remoteKeyId) {
- Conversions.mediumToByteArray(info, 0, localKeyId);
- Conversions.mediumToByteArray(info, 3, remoteKeyId);
- } else {
- Conversions.mediumToByteArray(info, 0, remoteKeyId);
- Conversions.mediumToByteArray(info, 3, localKeyId);
- }
-
- return info;
- }
-
- private static boolean isSmaller(ECPublicKey localPublic,
- ECPublicKey remotePublic)
- {
- return localPublic.compareTo(remotePublic) < 0;
- }
-
-}
diff --git a/library/src/org/whispersystems/textsecure/crypto/ecc/Curve.java b/library/src/org/whispersystems/textsecure/crypto/ecc/Curve.java
index 9cd221335f..aa9381969a 100644
--- a/library/src/org/whispersystems/textsecure/crypto/ecc/Curve.java
+++ b/library/src/org/whispersystems/textsecure/crypto/ecc/Curve.java
@@ -36,10 +36,10 @@ public class Curve {
}
public static ECKeyPair generateKeyPairForSession(int messageVersion) {
- if (messageVersion >= CiphertextMessage.CURVE25519_INTRODUCED_VERSION) {
- return generateKeyPairForType(DJB_TYPE);
- } else {
+ if (messageVersion <= CiphertextMessage.LEGACY_VERSION) {
return generateKeyPairForType(NIST_TYPE);
+ } else {
+ return generateKeyPairForType(DJB_TYPE);
}
}
diff --git a/library/src/org/whispersystems/textsecure/crypto/ecc/ECKeyPair.java b/library/src/org/whispersystems/textsecure/crypto/ecc/ECKeyPair.java
index 2fc454c73c..a592080eaa 100644
--- a/library/src/org/whispersystems/textsecure/crypto/ecc/ECKeyPair.java
+++ b/library/src/org/whispersystems/textsecure/crypto/ecc/ECKeyPair.java
@@ -27,7 +27,6 @@ public class ECKeyPair {
this.privateKey = privateKey;
}
-
public ECPublicKey getPublicKey() {
return publicKey;
}
diff --git a/library/src/org/whispersystems/textsecure/crypto/kdf/HKDF.java b/library/src/org/whispersystems/textsecure/crypto/kdf/HKDF.java
index e07e4baa4c..d6cea242f1 100644
--- a/library/src/org/whispersystems/textsecure/crypto/kdf/HKDF.java
+++ b/library/src/org/whispersystems/textsecure/crypto/kdf/HKDF.java
@@ -26,50 +26,38 @@ import java.util.List;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
-public class HKDF extends KDF {
+public class HKDF {
private static final int HASH_OUTPUT_SIZE = 32;
- private static final int KEY_MATERIAL_SIZE = 72;
+ private static final int KEY_MATERIAL_SIZE = 64;
private static final int CIPHER_KEYS_OFFSET = 0;
private static final int MAC_KEYS_OFFSET = 32;
- @Override
- public DerivedSecrets deriveSecrets(List sharedSecret,
- boolean isLowEnd, byte[] info)
- {
- byte[] inputKeyMaterial = concatenateSharedSecrets(sharedSecret);
- byte[] salt = new byte[HASH_OUTPUT_SIZE];
+ public DerivedSecrets deriveSecrets(byte[] inputKeyMaterial, byte[] info) {
+ byte[] salt = new byte[HASH_OUTPUT_SIZE];
+ return deriveSecrets(inputKeyMaterial, salt, info);
+ }
+
+ public DerivedSecrets deriveSecrets(byte[] inputKeyMaterial, byte[] salt, byte[] info) {
byte[] prk = extract(salt, inputKeyMaterial);
byte[] okm = expand(prk, info, KEY_MATERIAL_SIZE);
- SecretKeySpec cipherKey = deriveCipherKey(okm, isLowEnd);
- SecretKeySpec macKey = deriveMacKey(okm, isLowEnd);
+ SecretKeySpec cipherKey = deriveCipherKey(okm);
+ SecretKeySpec macKey = deriveMacKey(okm);
return new DerivedSecrets(cipherKey, macKey);
}
- private SecretKeySpec deriveCipherKey(byte[] okm, boolean isLowEnd) {
- byte[] cipherKey = new byte[16];
-
- if (isLowEnd) {
- System.arraycopy(okm, CIPHER_KEYS_OFFSET + 0, cipherKey, 0, cipherKey.length);
- } else {
- System.arraycopy(okm, CIPHER_KEYS_OFFSET + 16, cipherKey, 0, cipherKey.length);
- }
-
+ private SecretKeySpec deriveCipherKey(byte[] okm) {
+ byte[] cipherKey = new byte[32];
+ System.arraycopy(okm, CIPHER_KEYS_OFFSET, cipherKey, 0, cipherKey.length);
return new SecretKeySpec(cipherKey, "AES");
}
- private SecretKeySpec deriveMacKey(byte[] okm, boolean isLowEnd) {
- byte[] macKey = new byte[20];
-
- if (isLowEnd) {
- System.arraycopy(okm, MAC_KEYS_OFFSET + 0, macKey, 0, macKey.length);
- } else {
- System.arraycopy(okm, MAC_KEYS_OFFSET + 20, macKey, 0, macKey.length);
- }
-
+ private SecretKeySpec deriveMacKey(byte[] okm) {
+ byte[] macKey = new byte[32];
+ System.arraycopy(okm, MAC_KEYS_OFFSET, macKey, 0, macKey.length);
return new SecretKeySpec(macKey, "HmacSHA1");
}
@@ -96,7 +84,9 @@ public class HKDF extends KDF {
mac.init(new SecretKeySpec(prk, "HmacSHA256"));
mac.update(mixin);
- mac.update(info);
+ if (info != null) {
+ mac.update(info);
+ }
mac.update((byte)i);
byte[] stepResult = mac.doFinal();
diff --git a/library/src/org/whispersystems/textsecure/crypto/kdf/KDF.java b/library/src/org/whispersystems/textsecure/crypto/kdf/KDF.java
deleted file mode 100644
index 66e9b86e59..0000000000
--- a/library/src/org/whispersystems/textsecure/crypto/kdf/KDF.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/**
- * Copyright (C) 2013 Open Whisper Systems
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-package org.whispersystems.textsecure.crypto.kdf;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.math.BigInteger;
-import java.util.LinkedList;
-import java.util.List;
-
-public abstract class KDF {
-
- public abstract DerivedSecrets deriveSecrets(List sharedSecret,
- boolean isLowEnd, byte[] info);
-
- protected byte[] concatenateSharedSecrets(List sharedSecrets) {
- try {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
-
- for (byte[] sharedSecret : sharedSecrets) {
- baos.write(sharedSecret);
- }
-
- return baos.toByteArray();
- } catch (IOException e) {
- throw new AssertionError(e);
- }
- }
-
-}
diff --git a/library/src/org/whispersystems/textsecure/crypto/kdf/NKDF.java b/library/src/org/whispersystems/textsecure/crypto/kdf/NKDF.java
index afde62a1a4..1ae5913744 100644
--- a/library/src/org/whispersystems/textsecure/crypto/kdf/NKDF.java
+++ b/library/src/org/whispersystems/textsecure/crypto/kdf/NKDF.java
@@ -23,15 +23,15 @@ import org.whispersystems.textsecure.util.Conversions;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
-import java.util.List;
import javax.crypto.spec.SecretKeySpec;
-public class NKDF extends KDF {
+public class NKDF {
- @Override
- public DerivedSecrets deriveSecrets(List sharedSecret,
- boolean isLowEnd, byte[] info)
+ public static final int LEGACY_CIPHER_KEY_LENGTH = 16;
+ public static final int LEGACY_MAC_KEY_LENGTH = 20;
+
+ public DerivedSecrets deriveSecrets(byte[] sharedSecret, boolean isLowEnd)
{
SecretKeySpec cipherKey = deriveCipherSecret(isLowEnd, sharedSecret);
SecretKeySpec macKey = deriveMacSecret(cipherKey);
@@ -39,15 +39,14 @@ public class NKDF extends KDF {
return new DerivedSecrets(cipherKey, macKey);
}
- private SecretKeySpec deriveCipherSecret(boolean isLowEnd, List sharedSecret) {
- byte[] sharedSecretBytes = concatenateSharedSecrets(sharedSecret);
- byte[] derivedBytes = deriveBytes(sharedSecretBytes, 16 * 2);
- byte[] cipherSecret = new byte[16];
+ private SecretKeySpec deriveCipherSecret(boolean isLowEnd, byte[] sharedSecret) {
+ byte[] derivedBytes = deriveBytes(sharedSecret, LEGACY_CIPHER_KEY_LENGTH * 2);
+ byte[] cipherSecret = new byte[LEGACY_CIPHER_KEY_LENGTH];
if (isLowEnd) {
- System.arraycopy(derivedBytes, 16, cipherSecret, 0, 16);
+ System.arraycopy(derivedBytes, LEGACY_CIPHER_KEY_LENGTH, cipherSecret, 0, LEGACY_CIPHER_KEY_LENGTH);
} else {
- System.arraycopy(derivedBytes, 0, cipherSecret, 0, 16);
+ System.arraycopy(derivedBytes, 0, cipherSecret, 0, LEGACY_CIPHER_KEY_LENGTH);
}
return new SecretKeySpec(cipherSecret, "AES");
@@ -84,6 +83,4 @@ public class NKDF extends KDF {
return md.digest();
}
-
-
}
diff --git a/library/src/org/whispersystems/textsecure/crypto/protocol/CiphertextMessage.java b/library/src/org/whispersystems/textsecure/crypto/protocol/CiphertextMessage.java
index e2322e694e..b431b39ee1 100644
--- a/library/src/org/whispersystems/textsecure/crypto/protocol/CiphertextMessage.java
+++ b/library/src/org/whispersystems/textsecure/crypto/protocol/CiphertextMessage.java
@@ -1,145 +1,18 @@
package org.whispersystems.textsecure.crypto.protocol;
-import org.whispersystems.textsecure.crypto.InvalidMacException;
-import org.whispersystems.textsecure.crypto.InvalidMessageException;
-import org.whispersystems.textsecure.crypto.MessageMac;
-import org.whispersystems.textsecure.crypto.PublicKey;
-import org.whispersystems.textsecure.crypto.SessionCipher;
-import org.whispersystems.textsecure.util.Conversions;
+public interface CiphertextMessage {
-public class CiphertextMessage {
+ public static final int LEGACY_VERSION = 1;
+ public static final int CURRENT_VERSION = 2;
- public static final int SUPPORTED_VERSION = 2;
- public static final int DHE3_INTRODUCED_VERSION = 2;
- public static final int CURVE25519_INTRODUCED_VERSION = 2;
+ public static final int LEGACY_WHISPER_TYPE = 1;
+ public static final int CURRENT_WHISPER_TYPE = 2;
+ public static final int PREKEY_WHISPER_TYPE = 3;
- static final int VERSION_LENGTH = 1;
- private static final int SENDER_KEY_ID_LENGTH = 3;
- private static final int RECEIVER_KEY_ID_LENGTH = 3;
- private static final int NEXT_KEY_LENGTH = PublicKey.KEY_SIZE;
- private static final int COUNTER_LENGTH = 3;
- private static final int HEADER_LENGTH = VERSION_LENGTH + SENDER_KEY_ID_LENGTH +
- RECEIVER_KEY_ID_LENGTH + COUNTER_LENGTH +
- NEXT_KEY_LENGTH;
+ // This should be the worst case (worse than V2). So not always accurate, but good enough for padding.
+ public static final int ENCRYPTED_MESSAGE_OVERHEAD = WhisperMessageV1.ENCRYPTED_MESSAGE_OVERHEAD;
- static final int VERSION_OFFSET = 0;
- private static final int SENDER_KEY_ID_OFFSET = VERSION_OFFSET + VERSION_LENGTH;
- private static final int RECEIVER_KEY_ID_OFFSET = SENDER_KEY_ID_OFFSET + SENDER_KEY_ID_LENGTH;
- private static final int NEXT_KEY_OFFSET = RECEIVER_KEY_ID_OFFSET + RECEIVER_KEY_ID_LENGTH;
- private static final int COUNTER_OFFSET = NEXT_KEY_OFFSET + NEXT_KEY_LENGTH;
- private static final int BODY_OFFSET = COUNTER_OFFSET + COUNTER_LENGTH;
+ public byte[] serialize();
+ public int getType();
- public static final int ENCRYPTED_MESSAGE_OVERHEAD = HEADER_LENGTH + MessageMac.MAC_LENGTH;
-
- private final byte[] ciphertext;
-
- public CiphertextMessage(SessionCipher.SessionCipherContext sessionContext, byte[] ciphertextBody) {
- this.ciphertext = new byte[HEADER_LENGTH + ciphertextBody.length + MessageMac.MAC_LENGTH];
- setVersion(sessionContext.getMessageVersion(), SUPPORTED_VERSION);
- setSenderKeyId(sessionContext.getSenderKeyId());
- setReceiverKeyId(sessionContext.getRecipientKeyId());
- setNextKeyBytes(sessionContext.getNextKey().serialize());
- setCounter(sessionContext.getCounter());
- setBody(ciphertextBody);
- setMac(MessageMac.calculateMac(ciphertext, 0, ciphertext.length - MessageMac.MAC_LENGTH,
- sessionContext.getSessionKey().getMacKey()));
- }
-
- public CiphertextMessage(byte[] ciphertext) throws InvalidMessageException {
- this.ciphertext = ciphertext;
-
- if (ciphertext.length < HEADER_LENGTH) {
- throw new InvalidMessageException("Not long enough for ciphertext header!");
- }
-
- if (getCurrentVersion() > SUPPORTED_VERSION) {
- throw new InvalidMessageException("Unspported version: " + getCurrentVersion());
- }
- }
-
- public void setVersion(int current, int supported) {
- ciphertext[VERSION_OFFSET] = Conversions.intsToByteHighAndLow(current, supported);
- }
-
- public int getCurrentVersion() {
- return Conversions.highBitsToInt(ciphertext[VERSION_OFFSET]);
- }
-
- public int getSupportedVersion() {
- return Conversions.lowBitsToInt(ciphertext[VERSION_OFFSET]);
- }
-
- public void setSenderKeyId(int senderKeyId) {
- Conversions.mediumToByteArray(ciphertext, SENDER_KEY_ID_OFFSET, senderKeyId);
- }
-
- public int getSenderKeyId() {
- return Conversions.byteArrayToMedium(ciphertext, SENDER_KEY_ID_OFFSET);
- }
-
- public void setReceiverKeyId(int receiverKeyId) {
- Conversions.mediumToByteArray(ciphertext, RECEIVER_KEY_ID_OFFSET, receiverKeyId);
- }
-
- public int getReceiverKeyId() {
- return Conversions.byteArrayToMedium(ciphertext, RECEIVER_KEY_ID_OFFSET);
- }
-
- public void setNextKeyBytes(byte[] nextKey) {
- assert(nextKey.length == NEXT_KEY_LENGTH);
- System.arraycopy(nextKey, 0, ciphertext, NEXT_KEY_OFFSET, nextKey.length);
- }
-
- public byte[] getNextKeyBytes() {
- byte[] nextKeyBytes = new byte[NEXT_KEY_LENGTH];
- System.arraycopy(ciphertext, NEXT_KEY_OFFSET, nextKeyBytes, 0, nextKeyBytes.length);
-
- return nextKeyBytes;
- }
-
- public void setCounter(int counter) {
- Conversions.mediumToByteArray(ciphertext, COUNTER_OFFSET, counter);
- }
-
- public int getCounter() {
- return Conversions.byteArrayToMedium(ciphertext, COUNTER_OFFSET);
- }
-
- public void setBody(byte[] body) {
- System.arraycopy(body, 0, ciphertext, BODY_OFFSET, body.length);
- }
-
- public byte[] getBody() {
- byte[] body = new byte[ciphertext.length - HEADER_LENGTH - MessageMac.MAC_LENGTH];
- System.arraycopy(ciphertext, BODY_OFFSET, body, 0, body.length);
-
- return body;
- }
-
- public void setMac(byte[] mac) {
- System.arraycopy(mac, 0, ciphertext, ciphertext.length-mac.length, mac.length);
- }
-
- public byte[] getMac() {
- byte[] mac = new byte[MessageMac.MAC_LENGTH];
- System.arraycopy(ciphertext, ciphertext.length-mac.length, mac, 0, mac.length);
-
- return mac;
- }
-
- public byte[] serialize() {
- return ciphertext;
- }
-
- public void verifyMac(SessionCipher.SessionCipherContext sessionContext)
- throws InvalidMessageException
- {
- try {
- MessageMac.verifyMac(this.ciphertext, 0, this.ciphertext.length - MessageMac.MAC_LENGTH,
- getMac(), sessionContext.getSessionKey().getMacKey());
- } catch (InvalidMacException e) {
- throw new InvalidMessageException(e);
- }
- }
-
-}
+}
\ No newline at end of file
diff --git a/library/src/org/whispersystems/textsecure/crypto/protocol/PreKeyBundleMessage.java b/library/src/org/whispersystems/textsecure/crypto/protocol/PreKeyBundleMessage.java
deleted file mode 100644
index 741f0979a0..0000000000
--- a/library/src/org/whispersystems/textsecure/crypto/protocol/PreKeyBundleMessage.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/**
- * Copyright (C) 2013 Open Whisper Systems
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.whispersystems.textsecure.crypto.protocol;
-
-import org.whispersystems.textsecure.crypto.IdentityKey;
-import org.whispersystems.textsecure.crypto.InvalidKeyException;
-import org.whispersystems.textsecure.crypto.InvalidMessageException;
-import org.whispersystems.textsecure.crypto.InvalidVersionException;
-import org.whispersystems.textsecure.crypto.PublicKey;
-import org.whispersystems.textsecure.util.Conversions;
-
-/**
- * Class responsible for parsing and constructing PreKeyBundle messages.
- *
- * The class takes an existing encrypted message and bundles in the necessary
- * additional information for a prekeybundle, namely the addition of the local
- * identity key.
- */
-public class PreKeyBundleMessage {
-
- public static final int SUPPORTED_VERSION = CiphertextMessage.SUPPORTED_VERSION;
-
- private static final int VERSION_LENGTH = CiphertextMessage.VERSION_LENGTH;
- private static final int IDENTITY_KEY_LENGTH = IdentityKey.SIZE;
-
- private static final int VERSION_OFFSET = CiphertextMessage.VERSION_OFFSET;
- private static final int IDENTITY_KEY_OFFSET = VERSION_OFFSET + VERSION_LENGTH;
-
- private final byte[] messageBytes;
- private final CiphertextMessage bundledMessage;
- private final IdentityKey identityKey;
-
- public PreKeyBundleMessage(byte[] messageBytes)
- throws InvalidVersionException, InvalidKeyException
- {
- try {
- this.messageBytes = messageBytes;
- int messageVersion = Conversions.highBitsToInt(this.messageBytes[VERSION_OFFSET]);
-
- if (messageVersion > CiphertextMessage.SUPPORTED_VERSION)
- throw new InvalidVersionException("Key exchange with version: " + messageVersion);
-
- this.identityKey = new IdentityKey(messageBytes, IDENTITY_KEY_OFFSET);
- byte[] bundledMessageBytes = new byte[messageBytes.length - IDENTITY_KEY_LENGTH];
-
- bundledMessageBytes[VERSION_OFFSET] = this.messageBytes[VERSION_OFFSET];
- System.arraycopy(messageBytes, IDENTITY_KEY_OFFSET+IDENTITY_KEY_LENGTH, bundledMessageBytes,
- VERSION_OFFSET+VERSION_LENGTH, bundledMessageBytes.length-VERSION_LENGTH);
-
- this.bundledMessage = new CiphertextMessage(bundledMessageBytes);
- } catch (InvalidMessageException e) {
- throw new InvalidKeyException(e);
- }
- }
-
- public PreKeyBundleMessage(CiphertextMessage bundledMessage, IdentityKey identityKey) {
- this.bundledMessage = bundledMessage;
- this.identityKey = identityKey;
- this.messageBytes = new byte[IDENTITY_KEY_LENGTH + bundledMessage.serialize().length];
-
- byte[] bundledMessageBytes = bundledMessage.serialize();
- byte[] identityKeyBytes = identityKey.serialize();
-
- messageBytes[VERSION_OFFSET] = bundledMessageBytes[VERSION_OFFSET];
- System.arraycopy(identityKeyBytes, 0, messageBytes, IDENTITY_KEY_OFFSET, identityKeyBytes.length);
- System.arraycopy(bundledMessageBytes, VERSION_OFFSET+VERSION_LENGTH,
- messageBytes, IDENTITY_KEY_OFFSET+IDENTITY_KEY_LENGTH,
- bundledMessageBytes.length-VERSION_LENGTH);
- }
-
- public byte[] serialize() {
- return this.messageBytes;
- }
-
- public int getSupportedVersion() {
- return bundledMessage.getSupportedVersion();
- }
-
- public IdentityKey getIdentityKey() {
- return identityKey;
- }
-
- public PublicKey getPublicKey() throws InvalidKeyException {
- return new PublicKey(bundledMessage.getNextKeyBytes());
- }
-
- public CiphertextMessage getBundledMessage() {
- return bundledMessage;
- }
-
- public int getPreKeyId() {
- return bundledMessage.getReceiverKeyId();
- }
-}
diff --git a/library/src/org/whispersystems/textsecure/crypto/protocol/PreKeyWhisperMessage.java b/library/src/org/whispersystems/textsecure/crypto/protocol/PreKeyWhisperMessage.java
new file mode 100644
index 0000000000..bd0226ce8c
--- /dev/null
+++ b/library/src/org/whispersystems/textsecure/crypto/protocol/PreKeyWhisperMessage.java
@@ -0,0 +1,104 @@
+package org.whispersystems.textsecure.crypto.protocol;
+
+import com.google.protobuf.ByteString;
+import com.google.protobuf.InvalidProtocolBufferException;
+
+import org.whispersystems.textsecure.crypto.IdentityKey;
+import org.whispersystems.textsecure.crypto.InvalidKeyException;
+import org.whispersystems.textsecure.crypto.InvalidMessageException;
+import org.whispersystems.textsecure.crypto.InvalidVersionException;
+import org.whispersystems.textsecure.crypto.ecc.Curve;
+import org.whispersystems.textsecure.crypto.ecc.ECPublicKey;
+import org.whispersystems.textsecure.util.Conversions;
+import org.whispersystems.textsecure.util.Util;
+
+public class PreKeyWhisperMessage implements CiphertextMessage {
+
+ private final int version;
+ private final int preKeyId;
+ private final ECPublicKey baseKey;
+ private final IdentityKey identityKey;
+ private final WhisperMessageV2 message;
+ private final byte[] serialized;
+
+ public PreKeyWhisperMessage(byte[] serialized)
+ throws InvalidMessageException, InvalidVersionException
+ {
+ try {
+ this.version = Conversions.lowBitsToInt(serialized[0]);
+
+ if (this.version > CiphertextMessage.CURRENT_VERSION) {
+ throw new InvalidVersionException("Unknown version: " + this.version);
+ }
+
+ WhisperProtos.PreKeyWhisperMessage preKeyWhisperMessage
+ = WhisperProtos.PreKeyWhisperMessage.parseFrom(ByteString.copyFrom(serialized, 1,
+ serialized.length-1));
+
+ if (!preKeyWhisperMessage.hasPreKeyId() ||
+ !preKeyWhisperMessage.hasBaseKey() ||
+ !preKeyWhisperMessage.hasIdentityKey() ||
+ !preKeyWhisperMessage.hasMessage())
+ {
+ throw new InvalidMessageException("Incomplete message.");
+ }
+
+ this.serialized = serialized;
+ this.preKeyId = preKeyWhisperMessage.getPreKeyId();
+ this.baseKey = Curve.decodePoint(preKeyWhisperMessage.getBaseKey().toByteArray(), 0);
+ this.identityKey = new IdentityKey(Curve.decodePoint(preKeyWhisperMessage.getIdentityKey().toByteArray(), 0));
+ this.message = new WhisperMessageV2(preKeyWhisperMessage.getMessage().toByteArray());
+ } catch (InvalidProtocolBufferException e) {
+ throw new InvalidMessageException(e);
+ } catch (InvalidKeyException e) {
+ throw new InvalidMessageException(e);
+ }
+ }
+
+ public PreKeyWhisperMessage(int preKeyId, ECPublicKey baseKey, IdentityKey identityKey,
+ WhisperMessageV2 message)
+ {
+ this.version = CiphertextMessage.CURRENT_VERSION;
+ this.preKeyId = preKeyId;
+ this.baseKey = baseKey;
+ this.identityKey = identityKey;
+ this.message = message;
+
+ byte[] versionBytes = {Conversions.intsToByteHighAndLow(CURRENT_VERSION, this.version)};
+ byte[] messageBytes = WhisperProtos.PreKeyWhisperMessage.newBuilder()
+ .setPreKeyId(preKeyId)
+ .setBaseKey(ByteString.copyFrom(baseKey.serialize()))
+ .setIdentityKey(ByteString.copyFrom(identityKey.serialize()))
+ .setMessage(ByteString.copyFrom(message.serialize()))
+ .build().toByteArray();
+
+ this.serialized = Util.combine(versionBytes, messageBytes);
+ }
+
+ public IdentityKey getIdentityKey() {
+ return identityKey;
+ }
+
+ public int getPreKeyId() {
+ return preKeyId;
+ }
+
+ public ECPublicKey getBaseKey() {
+ return baseKey;
+ }
+
+ public WhisperMessageV2 getWhisperMessage() {
+ return message;
+ }
+
+ @Override
+ public byte[] serialize() {
+ return serialized;
+ }
+
+ @Override
+ public int getType() {
+ return CiphertextMessage.PREKEY_WHISPER_TYPE;
+ }
+
+}
diff --git a/library/src/org/whispersystems/textsecure/crypto/protocol/WhisperMessageV1.java b/library/src/org/whispersystems/textsecure/crypto/protocol/WhisperMessageV1.java
new file mode 100644
index 0000000000..7efe8e3b6a
--- /dev/null
+++ b/library/src/org/whispersystems/textsecure/crypto/protocol/WhisperMessageV1.java
@@ -0,0 +1,187 @@
+package org.whispersystems.textsecure.crypto.protocol;
+
+import android.util.Log;
+
+import org.whispersystems.textsecure.crypto.InvalidMessageException;
+import org.whispersystems.textsecure.crypto.PublicKey;
+import org.whispersystems.textsecure.crypto.SessionCipherV1;
+import org.whispersystems.textsecure.util.Conversions;
+import org.whispersystems.textsecure.util.Hex;
+import org.whispersystems.textsecure.util.Util;
+
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+
+
+public class WhisperMessageV1 implements CiphertextMessage{
+
+ private static final int VERSION_LENGTH = 1;
+ private static final int SENDER_KEY_ID_LENGTH = 3;
+ private static final int RECEIVER_KEY_ID_LENGTH = 3;
+ private static final int NEXT_KEY_LENGTH = PublicKey.KEY_SIZE;
+ private static final int COUNTER_LENGTH = 3;
+ private static final int HEADER_LENGTH = VERSION_LENGTH + SENDER_KEY_ID_LENGTH +
+ RECEIVER_KEY_ID_LENGTH + COUNTER_LENGTH +
+ NEXT_KEY_LENGTH;
+ private static final int MAC_LENGTH = 10;
+
+
+ private static final int VERSION_OFFSET = 0;
+ private static final int SENDER_KEY_ID_OFFSET = VERSION_OFFSET + VERSION_LENGTH;
+ private static final int RECEIVER_KEY_ID_OFFSET = SENDER_KEY_ID_OFFSET + SENDER_KEY_ID_LENGTH;
+ private static final int NEXT_KEY_OFFSET = RECEIVER_KEY_ID_OFFSET + RECEIVER_KEY_ID_LENGTH;
+ private static final int COUNTER_OFFSET = NEXT_KEY_OFFSET + NEXT_KEY_LENGTH;
+ private static final int BODY_OFFSET = COUNTER_OFFSET + COUNTER_LENGTH;
+
+ static final int ENCRYPTED_MESSAGE_OVERHEAD = HEADER_LENGTH + MAC_LENGTH;
+
+ private final byte[] ciphertext;
+
+ public WhisperMessageV1(SessionCipherV1.SessionCipherContext sessionContext,
+ byte[] ciphertextBody)
+ {
+ this.ciphertext = new byte[HEADER_LENGTH + ciphertextBody.length + MAC_LENGTH];
+ setVersion(sessionContext.getMessageVersion(), CURRENT_VERSION);
+ setSenderKeyId(sessionContext.getSenderKeyId());
+ setReceiverKeyId(sessionContext.getRecipientKeyId());
+ setNextKeyBytes(sessionContext.getNextKey().serialize());
+ setCounter(sessionContext.getCounter());
+ setBody(ciphertextBody);
+ setMac(calculateMac(sessionContext.getSessionKey().getMacKey(),
+ ciphertext, 0, ciphertext.length - MAC_LENGTH));
+ }
+
+ public WhisperMessageV1(byte[] ciphertext) throws InvalidMessageException {
+ this.ciphertext = ciphertext;
+
+ if (ciphertext.length < HEADER_LENGTH) {
+ throw new InvalidMessageException("Not long enough for ciphertext header!");
+ }
+
+ if (getCurrentVersion() > LEGACY_VERSION) {
+ throw new InvalidMessageException("Received non-legacy version: " + getCurrentVersion());
+ }
+ }
+
+ public void setVersion(int current, int supported) {
+ ciphertext[VERSION_OFFSET] = Conversions.intsToByteHighAndLow(current, supported);
+ }
+
+ public int getCurrentVersion() {
+ return Conversions.highBitsToInt(ciphertext[VERSION_OFFSET]);
+ }
+
+ public int getSupportedVersion() {
+ return Conversions.lowBitsToInt(ciphertext[VERSION_OFFSET]);
+ }
+
+ public void setSenderKeyId(int senderKeyId) {
+ Conversions.mediumToByteArray(ciphertext, SENDER_KEY_ID_OFFSET, senderKeyId);
+ }
+
+ public int getSenderKeyId() {
+ return Conversions.byteArrayToMedium(ciphertext, SENDER_KEY_ID_OFFSET);
+ }
+
+ public void setReceiverKeyId(int receiverKeyId) {
+ Conversions.mediumToByteArray(ciphertext, RECEIVER_KEY_ID_OFFSET, receiverKeyId);
+ }
+
+ public int getReceiverKeyId() {
+ return Conversions.byteArrayToMedium(ciphertext, RECEIVER_KEY_ID_OFFSET);
+ }
+
+ public void setNextKeyBytes(byte[] nextKey) {
+ assert(nextKey.length == NEXT_KEY_LENGTH);
+ System.arraycopy(nextKey, 0, ciphertext, NEXT_KEY_OFFSET, nextKey.length);
+ }
+
+ public byte[] getNextKeyBytes() {
+ byte[] nextKeyBytes = new byte[NEXT_KEY_LENGTH];
+ System.arraycopy(ciphertext, NEXT_KEY_OFFSET, nextKeyBytes, 0, nextKeyBytes.length);
+
+ return nextKeyBytes;
+ }
+
+ public void setCounter(int counter) {
+ Conversions.mediumToByteArray(ciphertext, COUNTER_OFFSET, counter);
+ }
+
+ public int getCounter() {
+ return Conversions.byteArrayToMedium(ciphertext, COUNTER_OFFSET);
+ }
+
+ public void setBody(byte[] body) {
+ System.arraycopy(body, 0, ciphertext, BODY_OFFSET, body.length);
+ }
+
+ public byte[] getBody() {
+ byte[] body = new byte[ciphertext.length - HEADER_LENGTH - MAC_LENGTH];
+ System.arraycopy(ciphertext, BODY_OFFSET, body, 0, body.length);
+
+ return body;
+ }
+
+ public void setMac(byte[] mac) {
+ System.arraycopy(mac, 0, ciphertext, ciphertext.length-mac.length, mac.length);
+ }
+
+ public byte[] getMac() {
+ byte[] mac = new byte[MAC_LENGTH];
+ System.arraycopy(ciphertext, ciphertext.length-mac.length, mac, 0, mac.length);
+
+ return mac;
+ }
+
+ @Override
+ public byte[] serialize() {
+ return ciphertext;
+ }
+
+ @Override
+ public int getType() {
+ return CiphertextMessage.LEGACY_WHISPER_TYPE;
+ }
+
+ public void verifyMac(SessionCipherV1.SessionCipherContext sessionContext)
+ throws InvalidMessageException
+ {
+ verifyMac(sessionContext.getSessionKey().getMacKey(),
+ this.ciphertext, 0, this.ciphertext.length - MAC_LENGTH, getMac());
+ }
+
+ private byte[] calculateMac(SecretKeySpec macKey, byte[] message, int offset, int length) {
+ try {
+ Mac mac = Mac.getInstance("HmacSHA1");
+ mac.init(macKey);
+
+ mac.update(message, offset, length);
+ byte[] macBytes = mac.doFinal();
+
+ return Util.trim(macBytes, MAC_LENGTH);
+ } catch (NoSuchAlgorithmException e) {
+ throw new IllegalArgumentException(e);
+ } catch (InvalidKeyException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ private void verifyMac(SecretKeySpec macKey, byte[] message, int offset, int length,
+ byte[] receivedMac)
+ throws InvalidMessageException
+ {
+ byte[] localMac = calculateMac(macKey, message, offset, length);
+
+ Log.w("WhisperMessageV1", "Local Mac: " + Hex.toString(localMac));
+ Log.w("WhisperMessageV1", "Remot Mac: " + Hex.toString(receivedMac));
+
+ if (!Arrays.equals(localMac, receivedMac)) {
+ throw new InvalidMessageException("MAC on message does not match calculated MAC.");
+ }
+ }
+
+}
diff --git a/library/src/org/whispersystems/textsecure/crypto/protocol/WhisperMessageV2.java b/library/src/org/whispersystems/textsecure/crypto/protocol/WhisperMessageV2.java
new file mode 100644
index 0000000000..af6d972c13
--- /dev/null
+++ b/library/src/org/whispersystems/textsecure/crypto/protocol/WhisperMessageV2.java
@@ -0,0 +1,132 @@
+package org.whispersystems.textsecure.crypto.protocol;
+
+import android.util.Log;
+
+import com.google.protobuf.ByteString;
+import com.google.protobuf.InvalidProtocolBufferException;
+
+import org.whispersystems.textsecure.crypto.InvalidKeyException;
+import org.whispersystems.textsecure.crypto.InvalidMessageException;
+import org.whispersystems.textsecure.crypto.ecc.Curve;
+import org.whispersystems.textsecure.crypto.ecc.ECPublicKey;
+import org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage;
+import org.whispersystems.textsecure.util.Conversions;
+import org.whispersystems.textsecure.util.Hex;
+import org.whispersystems.textsecure.util.Util;
+
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+
+public class WhisperMessageV2 implements CiphertextMessage {
+
+ private static final int MAC_LENGTH = 8;
+
+ private final ECPublicKey senderEphemeral;
+ private final int counter;
+ private final int previousCounter;
+ private final byte[] ciphertext;
+ private final byte[] serialized;
+
+ public WhisperMessageV2(byte[] serialized) throws InvalidMessageException {
+ try {
+ byte[][] messageParts = Util.split(serialized, 1, serialized.length - 1 - MAC_LENGTH, MAC_LENGTH);
+ byte version = messageParts[0][0];
+ byte[] message = messageParts[1];
+ byte[] mac = messageParts[2];
+
+ if (Conversions.highBitsToInt(version) != CURRENT_VERSION) {
+ throw new InvalidMessageException("Unknown version: " + Conversions.lowBitsToInt(version));
+ }
+
+ WhisperMessage whisperMessage = WhisperMessage.parseFrom(message);
+
+ if (!whisperMessage.hasCiphertext() ||
+ !whisperMessage.hasCounter() ||
+ !whisperMessage.hasEphemeralKey())
+ {
+ throw new InvalidMessageException("Incomplete message.");
+ }
+
+ this.serialized = serialized;
+ this.senderEphemeral = Curve.decodePoint(whisperMessage.getEphemeralKey().toByteArray(), 0);
+ this.counter = whisperMessage.getCounter();
+ this.previousCounter = whisperMessage.getPreviousCounter();
+ this.ciphertext = whisperMessage.getCiphertext().toByteArray();
+ } catch (InvalidProtocolBufferException e) {
+ throw new InvalidMessageException(e);
+ } catch (InvalidKeyException e) {
+ throw new InvalidMessageException(e);
+ }
+ }
+
+ public WhisperMessageV2(SecretKeySpec macKey, ECPublicKey senderEphemeral,
+ int counter, int previousCounter, byte[] ciphertext)
+ {
+ byte[] version = {Conversions.intsToByteHighAndLow(CURRENT_VERSION, CURRENT_VERSION)};
+ byte[] message = WhisperMessage.newBuilder()
+ .setEphemeralKey(ByteString.copyFrom(senderEphemeral.serialize()))
+ .setCounter(counter)
+ .setPreviousCounter(previousCounter)
+ .setCiphertext(ByteString.copyFrom(ciphertext))
+ .build().toByteArray();
+ byte[] mac = getMac(macKey, Util.combine(version, message));
+
+ this.serialized = Util.combine(version, message, mac);
+ this.senderEphemeral = senderEphemeral;
+ this.counter = counter;
+ this.previousCounter = previousCounter;
+ this.ciphertext = ciphertext;
+ }
+
+ public ECPublicKey getSenderEphemeral() {
+ return senderEphemeral;
+ }
+
+ public int getCounter() {
+ return counter;
+ }
+
+ public byte[] getBody() {
+ return ciphertext;
+ }
+
+ public void verifyMac(SecretKeySpec macKey)
+ throws InvalidMessageException
+ {
+ byte[][] parts = Util.split(serialized, serialized.length - MAC_LENGTH, MAC_LENGTH);
+ byte[] ourMac = getMac(macKey, parts[0]);
+ byte[] theirMac = parts[1];
+
+ if (!Arrays.equals(ourMac, theirMac)) {
+ throw new InvalidMessageException("Bad Mac!");
+ }
+ }
+
+ private byte[] getMac(SecretKeySpec macKey, byte[] serialized) {
+ try {
+ Mac mac = Mac.getInstance("HmacSHA256");
+ mac.init(macKey);
+
+ byte[] fullMac = mac.doFinal(serialized);
+ return Util.trim(fullMac, MAC_LENGTH);
+ } catch (NoSuchAlgorithmException e) {
+ throw new AssertionError(e);
+ } catch (java.security.InvalidKeyException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ @Override
+ public byte[] serialize() {
+ return serialized;
+ }
+
+ @Override
+ public int getType() {
+ return CiphertextMessage.CURRENT_WHISPER_TYPE;
+ }
+
+}
diff --git a/library/src/org/whispersystems/textsecure/crypto/protocol/WhisperProtos.java b/library/src/org/whispersystems/textsecure/crypto/protocol/WhisperProtos.java
new file mode 100644
index 0000000000..ba1dfddbb2
--- /dev/null
+++ b/library/src/org/whispersystems/textsecure/crypto/protocol/WhisperProtos.java
@@ -0,0 +1,1636 @@
+// Generated by the protocol buffer compiler. DO NOT EDIT!
+// source: WhisperTextProtocol.proto
+
+package org.whispersystems.textsecure.crypto.protocol;
+
+public final class WhisperProtos {
+ private WhisperProtos() {}
+ public static void registerAllExtensions(
+ com.google.protobuf.ExtensionRegistry registry) {
+ }
+ public interface WhisperMessageOrBuilder
+ extends com.google.protobuf.MessageOrBuilder {
+
+ // optional bytes ephemeralKey = 1;
+ boolean hasEphemeralKey();
+ com.google.protobuf.ByteString getEphemeralKey();
+
+ // optional uint32 counter = 2;
+ boolean hasCounter();
+ int getCounter();
+
+ // optional uint32 previousCounter = 3;
+ boolean hasPreviousCounter();
+ int getPreviousCounter();
+
+ // optional bytes ciphertext = 4;
+ boolean hasCiphertext();
+ com.google.protobuf.ByteString getCiphertext();
+ }
+ public static final class WhisperMessage extends
+ com.google.protobuf.GeneratedMessage
+ implements WhisperMessageOrBuilder {
+ // Use WhisperMessage.newBuilder() to construct.
+ private WhisperMessage(Builder builder) {
+ super(builder);
+ }
+ private WhisperMessage(boolean noInit) {}
+
+ private static final WhisperMessage defaultInstance;
+ public static WhisperMessage getDefaultInstance() {
+ return defaultInstance;
+ }
+
+ public WhisperMessage getDefaultInstanceForType() {
+ return defaultInstance;
+ }
+
+ public static final com.google.protobuf.Descriptors.Descriptor
+ getDescriptor() {
+ return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.internal_static_textsecure_WhisperMessage_descriptor;
+ }
+
+ protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+ internalGetFieldAccessorTable() {
+ return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.internal_static_textsecure_WhisperMessage_fieldAccessorTable;
+ }
+
+ private int bitField0_;
+ // optional bytes ephemeralKey = 1;
+ public static final int EPHEMERALKEY_FIELD_NUMBER = 1;
+ private com.google.protobuf.ByteString ephemeralKey_;
+ public boolean hasEphemeralKey() {
+ return ((bitField0_ & 0x00000001) == 0x00000001);
+ }
+ public com.google.protobuf.ByteString getEphemeralKey() {
+ return ephemeralKey_;
+ }
+
+ // optional uint32 counter = 2;
+ public static final int COUNTER_FIELD_NUMBER = 2;
+ private int counter_;
+ public boolean hasCounter() {
+ return ((bitField0_ & 0x00000002) == 0x00000002);
+ }
+ public int getCounter() {
+ return counter_;
+ }
+
+ // optional uint32 previousCounter = 3;
+ public static final int PREVIOUSCOUNTER_FIELD_NUMBER = 3;
+ private int previousCounter_;
+ public boolean hasPreviousCounter() {
+ return ((bitField0_ & 0x00000004) == 0x00000004);
+ }
+ public int getPreviousCounter() {
+ return previousCounter_;
+ }
+
+ // optional bytes ciphertext = 4;
+ public static final int CIPHERTEXT_FIELD_NUMBER = 4;
+ private com.google.protobuf.ByteString ciphertext_;
+ public boolean hasCiphertext() {
+ return ((bitField0_ & 0x00000008) == 0x00000008);
+ }
+ public com.google.protobuf.ByteString getCiphertext() {
+ return ciphertext_;
+ }
+
+ private void initFields() {
+ ephemeralKey_ = com.google.protobuf.ByteString.EMPTY;
+ counter_ = 0;
+ previousCounter_ = 0;
+ ciphertext_ = com.google.protobuf.ByteString.EMPTY;
+ }
+ private byte memoizedIsInitialized = -1;
+ public final boolean isInitialized() {
+ byte isInitialized = memoizedIsInitialized;
+ if (isInitialized != -1) return isInitialized == 1;
+
+ memoizedIsInitialized = 1;
+ return true;
+ }
+
+ public void writeTo(com.google.protobuf.CodedOutputStream output)
+ throws java.io.IOException {
+ getSerializedSize();
+ if (((bitField0_ & 0x00000001) == 0x00000001)) {
+ output.writeBytes(1, ephemeralKey_);
+ }
+ if (((bitField0_ & 0x00000002) == 0x00000002)) {
+ output.writeUInt32(2, counter_);
+ }
+ if (((bitField0_ & 0x00000004) == 0x00000004)) {
+ output.writeUInt32(3, previousCounter_);
+ }
+ if (((bitField0_ & 0x00000008) == 0x00000008)) {
+ output.writeBytes(4, ciphertext_);
+ }
+ getUnknownFields().writeTo(output);
+ }
+
+ private int memoizedSerializedSize = -1;
+ public int getSerializedSize() {
+ int size = memoizedSerializedSize;
+ if (size != -1) return size;
+
+ size = 0;
+ if (((bitField0_ & 0x00000001) == 0x00000001)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeBytesSize(1, ephemeralKey_);
+ }
+ if (((bitField0_ & 0x00000002) == 0x00000002)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeUInt32Size(2, counter_);
+ }
+ if (((bitField0_ & 0x00000004) == 0x00000004)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeUInt32Size(3, previousCounter_);
+ }
+ if (((bitField0_ & 0x00000008) == 0x00000008)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeBytesSize(4, ciphertext_);
+ }
+ size += getUnknownFields().getSerializedSize();
+ memoizedSerializedSize = size;
+ return size;
+ }
+
+ private static final long serialVersionUID = 0L;
+ @java.lang.Override
+ protected java.lang.Object writeReplace()
+ throws java.io.ObjectStreamException {
+ return super.writeReplace();
+ }
+
+ public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage parseFrom(
+ com.google.protobuf.ByteString data)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data).buildParsed();
+ }
+ public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage parseFrom(
+ com.google.protobuf.ByteString data,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data, extensionRegistry)
+ .buildParsed();
+ }
+ public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage parseFrom(byte[] data)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data).buildParsed();
+ }
+ public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage parseFrom(
+ byte[] data,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data, extensionRegistry)
+ .buildParsed();
+ }
+ public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage parseFrom(java.io.InputStream input)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input).buildParsed();
+ }
+ public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage parseFrom(
+ java.io.InputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input, extensionRegistry)
+ .buildParsed();
+ }
+ public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage parseDelimitedFrom(java.io.InputStream input)
+ throws java.io.IOException {
+ Builder builder = newBuilder();
+ if (builder.mergeDelimitedFrom(input)) {
+ return builder.buildParsed();
+ } else {
+ return null;
+ }
+ }
+ public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage parseDelimitedFrom(
+ java.io.InputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ Builder builder = newBuilder();
+ if (builder.mergeDelimitedFrom(input, extensionRegistry)) {
+ return builder.buildParsed();
+ } else {
+ return null;
+ }
+ }
+ public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage parseFrom(
+ com.google.protobuf.CodedInputStream input)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input).buildParsed();
+ }
+ public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage parseFrom(
+ com.google.protobuf.CodedInputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input, extensionRegistry)
+ .buildParsed();
+ }
+
+ public static Builder newBuilder() { return Builder.create(); }
+ public Builder newBuilderForType() { return newBuilder(); }
+ public static Builder newBuilder(org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage prototype) {
+ return newBuilder().mergeFrom(prototype);
+ }
+ public Builder toBuilder() { return newBuilder(this); }
+
+ @java.lang.Override
+ protected Builder newBuilderForType(
+ com.google.protobuf.GeneratedMessage.BuilderParent parent) {
+ Builder builder = new Builder(parent);
+ return builder;
+ }
+ public static final class Builder extends
+ com.google.protobuf.GeneratedMessage.Builder
+ implements org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessageOrBuilder {
+ public static final com.google.protobuf.Descriptors.Descriptor
+ getDescriptor() {
+ return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.internal_static_textsecure_WhisperMessage_descriptor;
+ }
+
+ protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+ internalGetFieldAccessorTable() {
+ return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.internal_static_textsecure_WhisperMessage_fieldAccessorTable;
+ }
+
+ // Construct using org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage.newBuilder()
+ private Builder() {
+ maybeForceBuilderInitialization();
+ }
+
+ private Builder(BuilderParent parent) {
+ super(parent);
+ maybeForceBuilderInitialization();
+ }
+ private void maybeForceBuilderInitialization() {
+ if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
+ }
+ }
+ private static Builder create() {
+ return new Builder();
+ }
+
+ public Builder clear() {
+ super.clear();
+ ephemeralKey_ = com.google.protobuf.ByteString.EMPTY;
+ bitField0_ = (bitField0_ & ~0x00000001);
+ counter_ = 0;
+ bitField0_ = (bitField0_ & ~0x00000002);
+ previousCounter_ = 0;
+ bitField0_ = (bitField0_ & ~0x00000004);
+ ciphertext_ = com.google.protobuf.ByteString.EMPTY;
+ bitField0_ = (bitField0_ & ~0x00000008);
+ return this;
+ }
+
+ public Builder clone() {
+ return create().mergeFrom(buildPartial());
+ }
+
+ public com.google.protobuf.Descriptors.Descriptor
+ getDescriptorForType() {
+ return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage.getDescriptor();
+ }
+
+ public org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage getDefaultInstanceForType() {
+ return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage.getDefaultInstance();
+ }
+
+ public org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage build() {
+ org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage result = buildPartial();
+ if (!result.isInitialized()) {
+ throw newUninitializedMessageException(result);
+ }
+ return result;
+ }
+
+ private org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage buildParsed()
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage result = buildPartial();
+ if (!result.isInitialized()) {
+ throw newUninitializedMessageException(
+ result).asInvalidProtocolBufferException();
+ }
+ return result;
+ }
+
+ public org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage buildPartial() {
+ org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage result = new org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage(this);
+ int from_bitField0_ = bitField0_;
+ int to_bitField0_ = 0;
+ if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
+ to_bitField0_ |= 0x00000001;
+ }
+ result.ephemeralKey_ = ephemeralKey_;
+ if (((from_bitField0_ & 0x00000002) == 0x00000002)) {
+ to_bitField0_ |= 0x00000002;
+ }
+ result.counter_ = counter_;
+ if (((from_bitField0_ & 0x00000004) == 0x00000004)) {
+ to_bitField0_ |= 0x00000004;
+ }
+ result.previousCounter_ = previousCounter_;
+ if (((from_bitField0_ & 0x00000008) == 0x00000008)) {
+ to_bitField0_ |= 0x00000008;
+ }
+ result.ciphertext_ = ciphertext_;
+ result.bitField0_ = to_bitField0_;
+ onBuilt();
+ return result;
+ }
+
+ public Builder mergeFrom(com.google.protobuf.Message other) {
+ if (other instanceof org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage) {
+ return mergeFrom((org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage)other);
+ } else {
+ super.mergeFrom(other);
+ return this;
+ }
+ }
+
+ public Builder mergeFrom(org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage other) {
+ if (other == org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage.getDefaultInstance()) return this;
+ if (other.hasEphemeralKey()) {
+ setEphemeralKey(other.getEphemeralKey());
+ }
+ if (other.hasCounter()) {
+ setCounter(other.getCounter());
+ }
+ if (other.hasPreviousCounter()) {
+ setPreviousCounter(other.getPreviousCounter());
+ }
+ if (other.hasCiphertext()) {
+ setCiphertext(other.getCiphertext());
+ }
+ this.mergeUnknownFields(other.getUnknownFields());
+ return this;
+ }
+
+ public final boolean isInitialized() {
+ return true;
+ }
+
+ public Builder mergeFrom(
+ com.google.protobuf.CodedInputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ com.google.protobuf.UnknownFieldSet.Builder unknownFields =
+ com.google.protobuf.UnknownFieldSet.newBuilder(
+ this.getUnknownFields());
+ while (true) {
+ int tag = input.readTag();
+ switch (tag) {
+ case 0:
+ this.setUnknownFields(unknownFields.build());
+ onChanged();
+ return this;
+ default: {
+ if (!parseUnknownField(input, unknownFields,
+ extensionRegistry, tag)) {
+ this.setUnknownFields(unknownFields.build());
+ onChanged();
+ return this;
+ }
+ break;
+ }
+ case 10: {
+ bitField0_ |= 0x00000001;
+ ephemeralKey_ = input.readBytes();
+ break;
+ }
+ case 16: {
+ bitField0_ |= 0x00000002;
+ counter_ = input.readUInt32();
+ break;
+ }
+ case 24: {
+ bitField0_ |= 0x00000004;
+ previousCounter_ = input.readUInt32();
+ break;
+ }
+ case 34: {
+ bitField0_ |= 0x00000008;
+ ciphertext_ = input.readBytes();
+ break;
+ }
+ }
+ }
+ }
+
+ private int bitField0_;
+
+ // optional bytes ephemeralKey = 1;
+ private com.google.protobuf.ByteString ephemeralKey_ = com.google.protobuf.ByteString.EMPTY;
+ public boolean hasEphemeralKey() {
+ return ((bitField0_ & 0x00000001) == 0x00000001);
+ }
+ public com.google.protobuf.ByteString getEphemeralKey() {
+ return ephemeralKey_;
+ }
+ public Builder setEphemeralKey(com.google.protobuf.ByteString value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ bitField0_ |= 0x00000001;
+ ephemeralKey_ = value;
+ onChanged();
+ return this;
+ }
+ public Builder clearEphemeralKey() {
+ bitField0_ = (bitField0_ & ~0x00000001);
+ ephemeralKey_ = getDefaultInstance().getEphemeralKey();
+ onChanged();
+ return this;
+ }
+
+ // optional uint32 counter = 2;
+ private int counter_ ;
+ public boolean hasCounter() {
+ return ((bitField0_ & 0x00000002) == 0x00000002);
+ }
+ public int getCounter() {
+ return counter_;
+ }
+ public Builder setCounter(int value) {
+ bitField0_ |= 0x00000002;
+ counter_ = value;
+ onChanged();
+ return this;
+ }
+ public Builder clearCounter() {
+ bitField0_ = (bitField0_ & ~0x00000002);
+ counter_ = 0;
+ onChanged();
+ return this;
+ }
+
+ // optional uint32 previousCounter = 3;
+ private int previousCounter_ ;
+ public boolean hasPreviousCounter() {
+ return ((bitField0_ & 0x00000004) == 0x00000004);
+ }
+ public int getPreviousCounter() {
+ return previousCounter_;
+ }
+ public Builder setPreviousCounter(int value) {
+ bitField0_ |= 0x00000004;
+ previousCounter_ = value;
+ onChanged();
+ return this;
+ }
+ public Builder clearPreviousCounter() {
+ bitField0_ = (bitField0_ & ~0x00000004);
+ previousCounter_ = 0;
+ onChanged();
+ return this;
+ }
+
+ // optional bytes ciphertext = 4;
+ private com.google.protobuf.ByteString ciphertext_ = com.google.protobuf.ByteString.EMPTY;
+ public boolean hasCiphertext() {
+ return ((bitField0_ & 0x00000008) == 0x00000008);
+ }
+ public com.google.protobuf.ByteString getCiphertext() {
+ return ciphertext_;
+ }
+ public Builder setCiphertext(com.google.protobuf.ByteString value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ bitField0_ |= 0x00000008;
+ ciphertext_ = value;
+ onChanged();
+ return this;
+ }
+ public Builder clearCiphertext() {
+ bitField0_ = (bitField0_ & ~0x00000008);
+ ciphertext_ = getDefaultInstance().getCiphertext();
+ onChanged();
+ return this;
+ }
+
+ // @@protoc_insertion_point(builder_scope:textsecure.WhisperMessage)
+ }
+
+ static {
+ defaultInstance = new WhisperMessage(true);
+ defaultInstance.initFields();
+ }
+
+ // @@protoc_insertion_point(class_scope:textsecure.WhisperMessage)
+ }
+
+ public interface PreKeyWhisperMessageOrBuilder
+ extends com.google.protobuf.MessageOrBuilder {
+
+ // optional uint32 preKeyId = 1;
+ boolean hasPreKeyId();
+ int getPreKeyId();
+
+ // optional bytes baseKey = 2;
+ boolean hasBaseKey();
+ com.google.protobuf.ByteString getBaseKey();
+
+ // optional bytes identityKey = 3;
+ boolean hasIdentityKey();
+ com.google.protobuf.ByteString getIdentityKey();
+
+ // optional bytes message = 4;
+ boolean hasMessage();
+ com.google.protobuf.ByteString getMessage();
+ }
+ public static final class PreKeyWhisperMessage extends
+ com.google.protobuf.GeneratedMessage
+ implements PreKeyWhisperMessageOrBuilder {
+ // Use PreKeyWhisperMessage.newBuilder() to construct.
+ private PreKeyWhisperMessage(Builder builder) {
+ super(builder);
+ }
+ private PreKeyWhisperMessage(boolean noInit) {}
+
+ private static final PreKeyWhisperMessage defaultInstance;
+ public static PreKeyWhisperMessage getDefaultInstance() {
+ return defaultInstance;
+ }
+
+ public PreKeyWhisperMessage getDefaultInstanceForType() {
+ return defaultInstance;
+ }
+
+ public static final com.google.protobuf.Descriptors.Descriptor
+ getDescriptor() {
+ return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.internal_static_textsecure_PreKeyWhisperMessage_descriptor;
+ }
+
+ protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+ internalGetFieldAccessorTable() {
+ return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.internal_static_textsecure_PreKeyWhisperMessage_fieldAccessorTable;
+ }
+
+ private int bitField0_;
+ // optional uint32 preKeyId = 1;
+ public static final int PREKEYID_FIELD_NUMBER = 1;
+ private int preKeyId_;
+ public boolean hasPreKeyId() {
+ return ((bitField0_ & 0x00000001) == 0x00000001);
+ }
+ public int getPreKeyId() {
+ return preKeyId_;
+ }
+
+ // optional bytes baseKey = 2;
+ public static final int BASEKEY_FIELD_NUMBER = 2;
+ private com.google.protobuf.ByteString baseKey_;
+ public boolean hasBaseKey() {
+ return ((bitField0_ & 0x00000002) == 0x00000002);
+ }
+ public com.google.protobuf.ByteString getBaseKey() {
+ return baseKey_;
+ }
+
+ // optional bytes identityKey = 3;
+ public static final int IDENTITYKEY_FIELD_NUMBER = 3;
+ private com.google.protobuf.ByteString identityKey_;
+ public boolean hasIdentityKey() {
+ return ((bitField0_ & 0x00000004) == 0x00000004);
+ }
+ public com.google.protobuf.ByteString getIdentityKey() {
+ return identityKey_;
+ }
+
+ // optional bytes message = 4;
+ public static final int MESSAGE_FIELD_NUMBER = 4;
+ private com.google.protobuf.ByteString message_;
+ public boolean hasMessage() {
+ return ((bitField0_ & 0x00000008) == 0x00000008);
+ }
+ public com.google.protobuf.ByteString getMessage() {
+ return message_;
+ }
+
+ private void initFields() {
+ preKeyId_ = 0;
+ baseKey_ = com.google.protobuf.ByteString.EMPTY;
+ identityKey_ = com.google.protobuf.ByteString.EMPTY;
+ message_ = com.google.protobuf.ByteString.EMPTY;
+ }
+ private byte memoizedIsInitialized = -1;
+ public final boolean isInitialized() {
+ byte isInitialized = memoizedIsInitialized;
+ if (isInitialized != -1) return isInitialized == 1;
+
+ memoizedIsInitialized = 1;
+ return true;
+ }
+
+ public void writeTo(com.google.protobuf.CodedOutputStream output)
+ throws java.io.IOException {
+ getSerializedSize();
+ if (((bitField0_ & 0x00000001) == 0x00000001)) {
+ output.writeUInt32(1, preKeyId_);
+ }
+ if (((bitField0_ & 0x00000002) == 0x00000002)) {
+ output.writeBytes(2, baseKey_);
+ }
+ if (((bitField0_ & 0x00000004) == 0x00000004)) {
+ output.writeBytes(3, identityKey_);
+ }
+ if (((bitField0_ & 0x00000008) == 0x00000008)) {
+ output.writeBytes(4, message_);
+ }
+ getUnknownFields().writeTo(output);
+ }
+
+ private int memoizedSerializedSize = -1;
+ public int getSerializedSize() {
+ int size = memoizedSerializedSize;
+ if (size != -1) return size;
+
+ size = 0;
+ if (((bitField0_ & 0x00000001) == 0x00000001)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeUInt32Size(1, preKeyId_);
+ }
+ if (((bitField0_ & 0x00000002) == 0x00000002)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeBytesSize(2, baseKey_);
+ }
+ if (((bitField0_ & 0x00000004) == 0x00000004)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeBytesSize(3, identityKey_);
+ }
+ if (((bitField0_ & 0x00000008) == 0x00000008)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeBytesSize(4, message_);
+ }
+ size += getUnknownFields().getSerializedSize();
+ memoizedSerializedSize = size;
+ return size;
+ }
+
+ private static final long serialVersionUID = 0L;
+ @java.lang.Override
+ protected java.lang.Object writeReplace()
+ throws java.io.ObjectStreamException {
+ return super.writeReplace();
+ }
+
+ public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom(
+ com.google.protobuf.ByteString data)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data).buildParsed();
+ }
+ public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom(
+ com.google.protobuf.ByteString data,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data, extensionRegistry)
+ .buildParsed();
+ }
+ public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom(byte[] data)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data).buildParsed();
+ }
+ public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom(
+ byte[] data,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data, extensionRegistry)
+ .buildParsed();
+ }
+ public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom(java.io.InputStream input)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input).buildParsed();
+ }
+ public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom(
+ java.io.InputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input, extensionRegistry)
+ .buildParsed();
+ }
+ public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage parseDelimitedFrom(java.io.InputStream input)
+ throws java.io.IOException {
+ Builder builder = newBuilder();
+ if (builder.mergeDelimitedFrom(input)) {
+ return builder.buildParsed();
+ } else {
+ return null;
+ }
+ }
+ public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage parseDelimitedFrom(
+ java.io.InputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ Builder builder = newBuilder();
+ if (builder.mergeDelimitedFrom(input, extensionRegistry)) {
+ return builder.buildParsed();
+ } else {
+ return null;
+ }
+ }
+ public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom(
+ com.google.protobuf.CodedInputStream input)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input).buildParsed();
+ }
+ public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom(
+ com.google.protobuf.CodedInputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input, extensionRegistry)
+ .buildParsed();
+ }
+
+ public static Builder newBuilder() { return Builder.create(); }
+ public Builder newBuilderForType() { return newBuilder(); }
+ public static Builder newBuilder(org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage prototype) {
+ return newBuilder().mergeFrom(prototype);
+ }
+ public Builder toBuilder() { return newBuilder(this); }
+
+ @java.lang.Override
+ protected Builder newBuilderForType(
+ com.google.protobuf.GeneratedMessage.BuilderParent parent) {
+ Builder builder = new Builder(parent);
+ return builder;
+ }
+ public static final class Builder extends
+ com.google.protobuf.GeneratedMessage.Builder
+ implements org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessageOrBuilder {
+ public static final com.google.protobuf.Descriptors.Descriptor
+ getDescriptor() {
+ return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.internal_static_textsecure_PreKeyWhisperMessage_descriptor;
+ }
+
+ protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+ internalGetFieldAccessorTable() {
+ return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.internal_static_textsecure_PreKeyWhisperMessage_fieldAccessorTable;
+ }
+
+ // Construct using org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage.newBuilder()
+ private Builder() {
+ maybeForceBuilderInitialization();
+ }
+
+ private Builder(BuilderParent parent) {
+ super(parent);
+ maybeForceBuilderInitialization();
+ }
+ private void maybeForceBuilderInitialization() {
+ if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
+ }
+ }
+ private static Builder create() {
+ return new Builder();
+ }
+
+ public Builder clear() {
+ super.clear();
+ preKeyId_ = 0;
+ bitField0_ = (bitField0_ & ~0x00000001);
+ baseKey_ = com.google.protobuf.ByteString.EMPTY;
+ bitField0_ = (bitField0_ & ~0x00000002);
+ identityKey_ = com.google.protobuf.ByteString.EMPTY;
+ bitField0_ = (bitField0_ & ~0x00000004);
+ message_ = com.google.protobuf.ByteString.EMPTY;
+ bitField0_ = (bitField0_ & ~0x00000008);
+ return this;
+ }
+
+ public Builder clone() {
+ return create().mergeFrom(buildPartial());
+ }
+
+ public com.google.protobuf.Descriptors.Descriptor
+ getDescriptorForType() {
+ return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage.getDescriptor();
+ }
+
+ public org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage getDefaultInstanceForType() {
+ return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage.getDefaultInstance();
+ }
+
+ public org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage build() {
+ org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage result = buildPartial();
+ if (!result.isInitialized()) {
+ throw newUninitializedMessageException(result);
+ }
+ return result;
+ }
+
+ private org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage buildParsed()
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage result = buildPartial();
+ if (!result.isInitialized()) {
+ throw newUninitializedMessageException(
+ result).asInvalidProtocolBufferException();
+ }
+ return result;
+ }
+
+ public org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage buildPartial() {
+ org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage result = new org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage(this);
+ int from_bitField0_ = bitField0_;
+ int to_bitField0_ = 0;
+ if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
+ to_bitField0_ |= 0x00000001;
+ }
+ result.preKeyId_ = preKeyId_;
+ if (((from_bitField0_ & 0x00000002) == 0x00000002)) {
+ to_bitField0_ |= 0x00000002;
+ }
+ result.baseKey_ = baseKey_;
+ if (((from_bitField0_ & 0x00000004) == 0x00000004)) {
+ to_bitField0_ |= 0x00000004;
+ }
+ result.identityKey_ = identityKey_;
+ if (((from_bitField0_ & 0x00000008) == 0x00000008)) {
+ to_bitField0_ |= 0x00000008;
+ }
+ result.message_ = message_;
+ result.bitField0_ = to_bitField0_;
+ onBuilt();
+ return result;
+ }
+
+ public Builder mergeFrom(com.google.protobuf.Message other) {
+ if (other instanceof org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage) {
+ return mergeFrom((org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage)other);
+ } else {
+ super.mergeFrom(other);
+ return this;
+ }
+ }
+
+ public Builder mergeFrom(org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage other) {
+ if (other == org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage.getDefaultInstance()) return this;
+ if (other.hasPreKeyId()) {
+ setPreKeyId(other.getPreKeyId());
+ }
+ if (other.hasBaseKey()) {
+ setBaseKey(other.getBaseKey());
+ }
+ if (other.hasIdentityKey()) {
+ setIdentityKey(other.getIdentityKey());
+ }
+ if (other.hasMessage()) {
+ setMessage(other.getMessage());
+ }
+ this.mergeUnknownFields(other.getUnknownFields());
+ return this;
+ }
+
+ public final boolean isInitialized() {
+ return true;
+ }
+
+ public Builder mergeFrom(
+ com.google.protobuf.CodedInputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ com.google.protobuf.UnknownFieldSet.Builder unknownFields =
+ com.google.protobuf.UnknownFieldSet.newBuilder(
+ this.getUnknownFields());
+ while (true) {
+ int tag = input.readTag();
+ switch (tag) {
+ case 0:
+ this.setUnknownFields(unknownFields.build());
+ onChanged();
+ return this;
+ default: {
+ if (!parseUnknownField(input, unknownFields,
+ extensionRegistry, tag)) {
+ this.setUnknownFields(unknownFields.build());
+ onChanged();
+ return this;
+ }
+ break;
+ }
+ case 8: {
+ bitField0_ |= 0x00000001;
+ preKeyId_ = input.readUInt32();
+ break;
+ }
+ case 18: {
+ bitField0_ |= 0x00000002;
+ baseKey_ = input.readBytes();
+ break;
+ }
+ case 26: {
+ bitField0_ |= 0x00000004;
+ identityKey_ = input.readBytes();
+ break;
+ }
+ case 34: {
+ bitField0_ |= 0x00000008;
+ message_ = input.readBytes();
+ break;
+ }
+ }
+ }
+ }
+
+ private int bitField0_;
+
+ // optional uint32 preKeyId = 1;
+ private int preKeyId_ ;
+ public boolean hasPreKeyId() {
+ return ((bitField0_ & 0x00000001) == 0x00000001);
+ }
+ public int getPreKeyId() {
+ return preKeyId_;
+ }
+ public Builder setPreKeyId(int value) {
+ bitField0_ |= 0x00000001;
+ preKeyId_ = value;
+ onChanged();
+ return this;
+ }
+ public Builder clearPreKeyId() {
+ bitField0_ = (bitField0_ & ~0x00000001);
+ preKeyId_ = 0;
+ onChanged();
+ return this;
+ }
+
+ // optional bytes baseKey = 2;
+ private com.google.protobuf.ByteString baseKey_ = com.google.protobuf.ByteString.EMPTY;
+ public boolean hasBaseKey() {
+ return ((bitField0_ & 0x00000002) == 0x00000002);
+ }
+ public com.google.protobuf.ByteString getBaseKey() {
+ return baseKey_;
+ }
+ public Builder setBaseKey(com.google.protobuf.ByteString value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ bitField0_ |= 0x00000002;
+ baseKey_ = value;
+ onChanged();
+ return this;
+ }
+ public Builder clearBaseKey() {
+ bitField0_ = (bitField0_ & ~0x00000002);
+ baseKey_ = getDefaultInstance().getBaseKey();
+ onChanged();
+ return this;
+ }
+
+ // optional bytes identityKey = 3;
+ private com.google.protobuf.ByteString identityKey_ = com.google.protobuf.ByteString.EMPTY;
+ public boolean hasIdentityKey() {
+ return ((bitField0_ & 0x00000004) == 0x00000004);
+ }
+ public com.google.protobuf.ByteString getIdentityKey() {
+ return identityKey_;
+ }
+ public Builder setIdentityKey(com.google.protobuf.ByteString value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ bitField0_ |= 0x00000004;
+ identityKey_ = value;
+ onChanged();
+ return this;
+ }
+ public Builder clearIdentityKey() {
+ bitField0_ = (bitField0_ & ~0x00000004);
+ identityKey_ = getDefaultInstance().getIdentityKey();
+ onChanged();
+ return this;
+ }
+
+ // optional bytes message = 4;
+ private com.google.protobuf.ByteString message_ = com.google.protobuf.ByteString.EMPTY;
+ public boolean hasMessage() {
+ return ((bitField0_ & 0x00000008) == 0x00000008);
+ }
+ public com.google.protobuf.ByteString getMessage() {
+ return message_;
+ }
+ public Builder setMessage(com.google.protobuf.ByteString value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ bitField0_ |= 0x00000008;
+ message_ = value;
+ onChanged();
+ return this;
+ }
+ public Builder clearMessage() {
+ bitField0_ = (bitField0_ & ~0x00000008);
+ message_ = getDefaultInstance().getMessage();
+ onChanged();
+ return this;
+ }
+
+ // @@protoc_insertion_point(builder_scope:textsecure.PreKeyWhisperMessage)
+ }
+
+ static {
+ defaultInstance = new PreKeyWhisperMessage(true);
+ defaultInstance.initFields();
+ }
+
+ // @@protoc_insertion_point(class_scope:textsecure.PreKeyWhisperMessage)
+ }
+
+ public interface KeyExchangeMessageOrBuilder
+ extends com.google.protobuf.MessageOrBuilder {
+
+ // optional uint32 id = 1;
+ boolean hasId();
+ int getId();
+
+ // optional bytes baseKey = 2;
+ boolean hasBaseKey();
+ com.google.protobuf.ByteString getBaseKey();
+
+ // optional bytes ephemeralKey = 3;
+ boolean hasEphemeralKey();
+ com.google.protobuf.ByteString getEphemeralKey();
+
+ // optional bytes identityKey = 4;
+ boolean hasIdentityKey();
+ com.google.protobuf.ByteString getIdentityKey();
+ }
+ public static final class KeyExchangeMessage extends
+ com.google.protobuf.GeneratedMessage
+ implements KeyExchangeMessageOrBuilder {
+ // Use KeyExchangeMessage.newBuilder() to construct.
+ private KeyExchangeMessage(Builder builder) {
+ super(builder);
+ }
+ private KeyExchangeMessage(boolean noInit) {}
+
+ private static final KeyExchangeMessage defaultInstance;
+ public static KeyExchangeMessage getDefaultInstance() {
+ return defaultInstance;
+ }
+
+ public KeyExchangeMessage getDefaultInstanceForType() {
+ return defaultInstance;
+ }
+
+ public static final com.google.protobuf.Descriptors.Descriptor
+ getDescriptor() {
+ return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.internal_static_textsecure_KeyExchangeMessage_descriptor;
+ }
+
+ protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+ internalGetFieldAccessorTable() {
+ return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.internal_static_textsecure_KeyExchangeMessage_fieldAccessorTable;
+ }
+
+ private int bitField0_;
+ // optional uint32 id = 1;
+ public static final int ID_FIELD_NUMBER = 1;
+ private int id_;
+ public boolean hasId() {
+ return ((bitField0_ & 0x00000001) == 0x00000001);
+ }
+ public int getId() {
+ return id_;
+ }
+
+ // optional bytes baseKey = 2;
+ public static final int BASEKEY_FIELD_NUMBER = 2;
+ private com.google.protobuf.ByteString baseKey_;
+ public boolean hasBaseKey() {
+ return ((bitField0_ & 0x00000002) == 0x00000002);
+ }
+ public com.google.protobuf.ByteString getBaseKey() {
+ return baseKey_;
+ }
+
+ // optional bytes ephemeralKey = 3;
+ public static final int EPHEMERALKEY_FIELD_NUMBER = 3;
+ private com.google.protobuf.ByteString ephemeralKey_;
+ public boolean hasEphemeralKey() {
+ return ((bitField0_ & 0x00000004) == 0x00000004);
+ }
+ public com.google.protobuf.ByteString getEphemeralKey() {
+ return ephemeralKey_;
+ }
+
+ // optional bytes identityKey = 4;
+ public static final int IDENTITYKEY_FIELD_NUMBER = 4;
+ private com.google.protobuf.ByteString identityKey_;
+ public boolean hasIdentityKey() {
+ return ((bitField0_ & 0x00000008) == 0x00000008);
+ }
+ public com.google.protobuf.ByteString getIdentityKey() {
+ return identityKey_;
+ }
+
+ private void initFields() {
+ id_ = 0;
+ baseKey_ = com.google.protobuf.ByteString.EMPTY;
+ ephemeralKey_ = com.google.protobuf.ByteString.EMPTY;
+ identityKey_ = com.google.protobuf.ByteString.EMPTY;
+ }
+ private byte memoizedIsInitialized = -1;
+ public final boolean isInitialized() {
+ byte isInitialized = memoizedIsInitialized;
+ if (isInitialized != -1) return isInitialized == 1;
+
+ memoizedIsInitialized = 1;
+ return true;
+ }
+
+ public void writeTo(com.google.protobuf.CodedOutputStream output)
+ throws java.io.IOException {
+ getSerializedSize();
+ if (((bitField0_ & 0x00000001) == 0x00000001)) {
+ output.writeUInt32(1, id_);
+ }
+ if (((bitField0_ & 0x00000002) == 0x00000002)) {
+ output.writeBytes(2, baseKey_);
+ }
+ if (((bitField0_ & 0x00000004) == 0x00000004)) {
+ output.writeBytes(3, ephemeralKey_);
+ }
+ if (((bitField0_ & 0x00000008) == 0x00000008)) {
+ output.writeBytes(4, identityKey_);
+ }
+ getUnknownFields().writeTo(output);
+ }
+
+ private int memoizedSerializedSize = -1;
+ public int getSerializedSize() {
+ int size = memoizedSerializedSize;
+ if (size != -1) return size;
+
+ size = 0;
+ if (((bitField0_ & 0x00000001) == 0x00000001)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeUInt32Size(1, id_);
+ }
+ if (((bitField0_ & 0x00000002) == 0x00000002)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeBytesSize(2, baseKey_);
+ }
+ if (((bitField0_ & 0x00000004) == 0x00000004)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeBytesSize(3, ephemeralKey_);
+ }
+ if (((bitField0_ & 0x00000008) == 0x00000008)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeBytesSize(4, identityKey_);
+ }
+ size += getUnknownFields().getSerializedSize();
+ memoizedSerializedSize = size;
+ return size;
+ }
+
+ private static final long serialVersionUID = 0L;
+ @java.lang.Override
+ protected java.lang.Object writeReplace()
+ throws java.io.ObjectStreamException {
+ return super.writeReplace();
+ }
+
+ public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage parseFrom(
+ com.google.protobuf.ByteString data)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data).buildParsed();
+ }
+ public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage parseFrom(
+ com.google.protobuf.ByteString data,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data, extensionRegistry)
+ .buildParsed();
+ }
+ public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage parseFrom(byte[] data)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data).buildParsed();
+ }
+ public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage parseFrom(
+ byte[] data,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data, extensionRegistry)
+ .buildParsed();
+ }
+ public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage parseFrom(java.io.InputStream input)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input).buildParsed();
+ }
+ public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage parseFrom(
+ java.io.InputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input, extensionRegistry)
+ .buildParsed();
+ }
+ public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage parseDelimitedFrom(java.io.InputStream input)
+ throws java.io.IOException {
+ Builder builder = newBuilder();
+ if (builder.mergeDelimitedFrom(input)) {
+ return builder.buildParsed();
+ } else {
+ return null;
+ }
+ }
+ public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage parseDelimitedFrom(
+ java.io.InputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ Builder builder = newBuilder();
+ if (builder.mergeDelimitedFrom(input, extensionRegistry)) {
+ return builder.buildParsed();
+ } else {
+ return null;
+ }
+ }
+ public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage parseFrom(
+ com.google.protobuf.CodedInputStream input)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input).buildParsed();
+ }
+ public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage parseFrom(
+ com.google.protobuf.CodedInputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input, extensionRegistry)
+ .buildParsed();
+ }
+
+ public static Builder newBuilder() { return Builder.create(); }
+ public Builder newBuilderForType() { return newBuilder(); }
+ public static Builder newBuilder(org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage prototype) {
+ return newBuilder().mergeFrom(prototype);
+ }
+ public Builder toBuilder() { return newBuilder(this); }
+
+ @java.lang.Override
+ protected Builder newBuilderForType(
+ com.google.protobuf.GeneratedMessage.BuilderParent parent) {
+ Builder builder = new Builder(parent);
+ return builder;
+ }
+ public static final class Builder extends
+ com.google.protobuf.GeneratedMessage.Builder
+ implements org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessageOrBuilder {
+ public static final com.google.protobuf.Descriptors.Descriptor
+ getDescriptor() {
+ return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.internal_static_textsecure_KeyExchangeMessage_descriptor;
+ }
+
+ protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+ internalGetFieldAccessorTable() {
+ return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.internal_static_textsecure_KeyExchangeMessage_fieldAccessorTable;
+ }
+
+ // Construct using org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage.newBuilder()
+ private Builder() {
+ maybeForceBuilderInitialization();
+ }
+
+ private Builder(BuilderParent parent) {
+ super(parent);
+ maybeForceBuilderInitialization();
+ }
+ private void maybeForceBuilderInitialization() {
+ if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
+ }
+ }
+ private static Builder create() {
+ return new Builder();
+ }
+
+ public Builder clear() {
+ super.clear();
+ id_ = 0;
+ bitField0_ = (bitField0_ & ~0x00000001);
+ baseKey_ = com.google.protobuf.ByteString.EMPTY;
+ bitField0_ = (bitField0_ & ~0x00000002);
+ ephemeralKey_ = com.google.protobuf.ByteString.EMPTY;
+ bitField0_ = (bitField0_ & ~0x00000004);
+ identityKey_ = com.google.protobuf.ByteString.EMPTY;
+ bitField0_ = (bitField0_ & ~0x00000008);
+ return this;
+ }
+
+ public Builder clone() {
+ return create().mergeFrom(buildPartial());
+ }
+
+ public com.google.protobuf.Descriptors.Descriptor
+ getDescriptorForType() {
+ return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage.getDescriptor();
+ }
+
+ public org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage getDefaultInstanceForType() {
+ return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage.getDefaultInstance();
+ }
+
+ public org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage build() {
+ org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage result = buildPartial();
+ if (!result.isInitialized()) {
+ throw newUninitializedMessageException(result);
+ }
+ return result;
+ }
+
+ private org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage buildParsed()
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage result = buildPartial();
+ if (!result.isInitialized()) {
+ throw newUninitializedMessageException(
+ result).asInvalidProtocolBufferException();
+ }
+ return result;
+ }
+
+ public org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage buildPartial() {
+ org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage result = new org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage(this);
+ int from_bitField0_ = bitField0_;
+ int to_bitField0_ = 0;
+ if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
+ to_bitField0_ |= 0x00000001;
+ }
+ result.id_ = id_;
+ if (((from_bitField0_ & 0x00000002) == 0x00000002)) {
+ to_bitField0_ |= 0x00000002;
+ }
+ result.baseKey_ = baseKey_;
+ if (((from_bitField0_ & 0x00000004) == 0x00000004)) {
+ to_bitField0_ |= 0x00000004;
+ }
+ result.ephemeralKey_ = ephemeralKey_;
+ if (((from_bitField0_ & 0x00000008) == 0x00000008)) {
+ to_bitField0_ |= 0x00000008;
+ }
+ result.identityKey_ = identityKey_;
+ result.bitField0_ = to_bitField0_;
+ onBuilt();
+ return result;
+ }
+
+ public Builder mergeFrom(com.google.protobuf.Message other) {
+ if (other instanceof org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage) {
+ return mergeFrom((org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage)other);
+ } else {
+ super.mergeFrom(other);
+ return this;
+ }
+ }
+
+ public Builder mergeFrom(org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage other) {
+ if (other == org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage.getDefaultInstance()) return this;
+ if (other.hasId()) {
+ setId(other.getId());
+ }
+ if (other.hasBaseKey()) {
+ setBaseKey(other.getBaseKey());
+ }
+ if (other.hasEphemeralKey()) {
+ setEphemeralKey(other.getEphemeralKey());
+ }
+ if (other.hasIdentityKey()) {
+ setIdentityKey(other.getIdentityKey());
+ }
+ this.mergeUnknownFields(other.getUnknownFields());
+ return this;
+ }
+
+ public final boolean isInitialized() {
+ return true;
+ }
+
+ public Builder mergeFrom(
+ com.google.protobuf.CodedInputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ com.google.protobuf.UnknownFieldSet.Builder unknownFields =
+ com.google.protobuf.UnknownFieldSet.newBuilder(
+ this.getUnknownFields());
+ while (true) {
+ int tag = input.readTag();
+ switch (tag) {
+ case 0:
+ this.setUnknownFields(unknownFields.build());
+ onChanged();
+ return this;
+ default: {
+ if (!parseUnknownField(input, unknownFields,
+ extensionRegistry, tag)) {
+ this.setUnknownFields(unknownFields.build());
+ onChanged();
+ return this;
+ }
+ break;
+ }
+ case 8: {
+ bitField0_ |= 0x00000001;
+ id_ = input.readUInt32();
+ break;
+ }
+ case 18: {
+ bitField0_ |= 0x00000002;
+ baseKey_ = input.readBytes();
+ break;
+ }
+ case 26: {
+ bitField0_ |= 0x00000004;
+ ephemeralKey_ = input.readBytes();
+ break;
+ }
+ case 34: {
+ bitField0_ |= 0x00000008;
+ identityKey_ = input.readBytes();
+ break;
+ }
+ }
+ }
+ }
+
+ private int bitField0_;
+
+ // optional uint32 id = 1;
+ private int id_ ;
+ public boolean hasId() {
+ return ((bitField0_ & 0x00000001) == 0x00000001);
+ }
+ public int getId() {
+ return id_;
+ }
+ public Builder setId(int value) {
+ bitField0_ |= 0x00000001;
+ id_ = value;
+ onChanged();
+ return this;
+ }
+ public Builder clearId() {
+ bitField0_ = (bitField0_ & ~0x00000001);
+ id_ = 0;
+ onChanged();
+ return this;
+ }
+
+ // optional bytes baseKey = 2;
+ private com.google.protobuf.ByteString baseKey_ = com.google.protobuf.ByteString.EMPTY;
+ public boolean hasBaseKey() {
+ return ((bitField0_ & 0x00000002) == 0x00000002);
+ }
+ public com.google.protobuf.ByteString getBaseKey() {
+ return baseKey_;
+ }
+ public Builder setBaseKey(com.google.protobuf.ByteString value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ bitField0_ |= 0x00000002;
+ baseKey_ = value;
+ onChanged();
+ return this;
+ }
+ public Builder clearBaseKey() {
+ bitField0_ = (bitField0_ & ~0x00000002);
+ baseKey_ = getDefaultInstance().getBaseKey();
+ onChanged();
+ return this;
+ }
+
+ // optional bytes ephemeralKey = 3;
+ private com.google.protobuf.ByteString ephemeralKey_ = com.google.protobuf.ByteString.EMPTY;
+ public boolean hasEphemeralKey() {
+ return ((bitField0_ & 0x00000004) == 0x00000004);
+ }
+ public com.google.protobuf.ByteString getEphemeralKey() {
+ return ephemeralKey_;
+ }
+ public Builder setEphemeralKey(com.google.protobuf.ByteString value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ bitField0_ |= 0x00000004;
+ ephemeralKey_ = value;
+ onChanged();
+ return this;
+ }
+ public Builder clearEphemeralKey() {
+ bitField0_ = (bitField0_ & ~0x00000004);
+ ephemeralKey_ = getDefaultInstance().getEphemeralKey();
+ onChanged();
+ return this;
+ }
+
+ // optional bytes identityKey = 4;
+ private com.google.protobuf.ByteString identityKey_ = com.google.protobuf.ByteString.EMPTY;
+ public boolean hasIdentityKey() {
+ return ((bitField0_ & 0x00000008) == 0x00000008);
+ }
+ public com.google.protobuf.ByteString getIdentityKey() {
+ return identityKey_;
+ }
+ public Builder setIdentityKey(com.google.protobuf.ByteString value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ bitField0_ |= 0x00000008;
+ identityKey_ = value;
+ onChanged();
+ return this;
+ }
+ public Builder clearIdentityKey() {
+ bitField0_ = (bitField0_ & ~0x00000008);
+ identityKey_ = getDefaultInstance().getIdentityKey();
+ onChanged();
+ return this;
+ }
+
+ // @@protoc_insertion_point(builder_scope:textsecure.KeyExchangeMessage)
+ }
+
+ static {
+ defaultInstance = new KeyExchangeMessage(true);
+ defaultInstance.initFields();
+ }
+
+ // @@protoc_insertion_point(class_scope:textsecure.KeyExchangeMessage)
+ }
+
+ private static com.google.protobuf.Descriptors.Descriptor
+ internal_static_textsecure_WhisperMessage_descriptor;
+ private static
+ com.google.protobuf.GeneratedMessage.FieldAccessorTable
+ internal_static_textsecure_WhisperMessage_fieldAccessorTable;
+ private static com.google.protobuf.Descriptors.Descriptor
+ internal_static_textsecure_PreKeyWhisperMessage_descriptor;
+ private static
+ com.google.protobuf.GeneratedMessage.FieldAccessorTable
+ internal_static_textsecure_PreKeyWhisperMessage_fieldAccessorTable;
+ private static com.google.protobuf.Descriptors.Descriptor
+ internal_static_textsecure_KeyExchangeMessage_descriptor;
+ private static
+ com.google.protobuf.GeneratedMessage.FieldAccessorTable
+ internal_static_textsecure_KeyExchangeMessage_fieldAccessorTable;
+
+ public static com.google.protobuf.Descriptors.FileDescriptor
+ getDescriptor() {
+ return descriptor;
+ }
+ private static com.google.protobuf.Descriptors.FileDescriptor
+ descriptor;
+ 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\"_\n\024PreKeyWhisperMe" +
+ "ssage\022\020\n\010preKeyId\030\001 \001(\r\022\017\n\007baseKey\030\002 \001(\014" +
+ "\022\023\n\013identityKey\030\003 \001(\014\022\017\n\007message\030\004 \001(\014\"\\" +
+ "\n\022KeyExchangeMessage\022\n\n\002id\030\001 \001(\r\022\017\n\007base" +
+ "Key\030\002 \001(\014\022\024\n\014ephemeralKey\030\003 \001(\014\022\023\n\013ident" +
+ "ityKey\030\004 \001(\014B>\n-org.whispersystems.texts" +
+ "ecure.crypto.protocolB\rWhisperProtos"
+ };
+ com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
+ new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
+ public com.google.protobuf.ExtensionRegistry assignDescriptors(
+ com.google.protobuf.Descriptors.FileDescriptor root) {
+ descriptor = root;
+ internal_static_textsecure_WhisperMessage_descriptor =
+ getDescriptor().getMessageTypes().get(0);
+ internal_static_textsecure_WhisperMessage_fieldAccessorTable = new
+ com.google.protobuf.GeneratedMessage.FieldAccessorTable(
+ internal_static_textsecure_WhisperMessage_descriptor,
+ new java.lang.String[] { "EphemeralKey", "Counter", "PreviousCounter", "Ciphertext", },
+ org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage.class,
+ org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage.Builder.class);
+ internal_static_textsecure_PreKeyWhisperMessage_descriptor =
+ getDescriptor().getMessageTypes().get(1);
+ internal_static_textsecure_PreKeyWhisperMessage_fieldAccessorTable = new
+ com.google.protobuf.GeneratedMessage.FieldAccessorTable(
+ internal_static_textsecure_PreKeyWhisperMessage_descriptor,
+ new java.lang.String[] { "PreKeyId", "BaseKey", "IdentityKey", "Message", },
+ org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage.class,
+ org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage.Builder.class);
+ internal_static_textsecure_KeyExchangeMessage_descriptor =
+ getDescriptor().getMessageTypes().get(2);
+ internal_static_textsecure_KeyExchangeMessage_fieldAccessorTable = new
+ com.google.protobuf.GeneratedMessage.FieldAccessorTable(
+ internal_static_textsecure_KeyExchangeMessage_descriptor,
+ new java.lang.String[] { "Id", "BaseKey", "EphemeralKey", "IdentityKey", },
+ org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage.class,
+ org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage.Builder.class);
+ return null;
+ }
+ };
+ com.google.protobuf.Descriptors.FileDescriptor
+ .internalBuildGeneratedFileFrom(descriptorData,
+ new com.google.protobuf.Descriptors.FileDescriptor[] {
+ }, assigner);
+ }
+
+ // @@protoc_insertion_point(outer_class_scope)
+}
diff --git a/library/src/org/whispersystems/textsecure/crypto/ratchet/ChainKey.java b/library/src/org/whispersystems/textsecure/crypto/ratchet/ChainKey.java
new file mode 100644
index 0000000000..0b17a30e74
--- /dev/null
+++ b/library/src/org/whispersystems/textsecure/crypto/ratchet/ChainKey.java
@@ -0,0 +1,58 @@
+package org.whispersystems.textsecure.crypto.ratchet;
+
+import org.whispersystems.textsecure.crypto.kdf.DerivedSecrets;
+import org.whispersystems.textsecure.crypto.kdf.HKDF;
+
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+
+public class ChainKey {
+
+ private static final byte[] MESSAGE_KEY_SEED = {0x01};
+ private static final byte[] CHAIN_KEY_SEED = {0x02};
+
+ private final byte[] key;
+ private final int index;
+
+ public ChainKey(byte[] key, int index) {
+ this.key = key;
+ this.index = index;
+ }
+
+ public byte[] getKey() {
+ return key;
+ }
+
+ public int getIndex() {
+ return index;
+ }
+
+ public ChainKey getNextChainKey() {
+ byte[] nextKey = getBaseMaterial(CHAIN_KEY_SEED);
+ return new ChainKey(nextKey, index + 1);
+ }
+
+ public MessageKeys getMessageKeys() {
+ HKDF kdf = new HKDF();
+ byte[] inputKeyMaterial = getBaseMaterial(MESSAGE_KEY_SEED);
+ DerivedSecrets keyMaterial = kdf.deriveSecrets(inputKeyMaterial, null);
+
+ return new MessageKeys(keyMaterial.getCipherKey(), keyMaterial.getMacKey(), index);
+ }
+
+ private byte[] getBaseMaterial(byte[] seed) {
+ try {
+ Mac mac = Mac.getInstance("HmacSHA256");
+ mac.init(new SecretKeySpec(key, "HmacSHA256"));
+
+ return mac.doFinal(seed);
+ } catch (NoSuchAlgorithmException e) {
+ throw new AssertionError(e);
+ } catch (InvalidKeyException e) {
+ throw new AssertionError(e);
+ }
+ }
+}
diff --git a/library/src/org/whispersystems/textsecure/crypto/ratchet/MessageKeys.java b/library/src/org/whispersystems/textsecure/crypto/ratchet/MessageKeys.java
new file mode 100644
index 0000000000..1ab6208de1
--- /dev/null
+++ b/library/src/org/whispersystems/textsecure/crypto/ratchet/MessageKeys.java
@@ -0,0 +1,28 @@
+package org.whispersystems.textsecure.crypto.ratchet;
+
+import javax.crypto.spec.SecretKeySpec;
+
+public class MessageKeys {
+
+ private final SecretKeySpec cipherKey;
+ private final SecretKeySpec macKey;
+ private final int counter;
+
+ public MessageKeys(SecretKeySpec cipherKey, SecretKeySpec macKey, int counter) {
+ this.cipherKey = cipherKey;
+ this.macKey = macKey;
+ this.counter = counter;
+ }
+
+ public SecretKeySpec getCipherKey() {
+ return cipherKey;
+ }
+
+ public SecretKeySpec getMacKey() {
+ return macKey;
+ }
+
+ public int getCounter() {
+ return counter;
+ }
+}
diff --git a/library/src/org/whispersystems/textsecure/crypto/ratchet/RatchetingSession.java b/library/src/org/whispersystems/textsecure/crypto/ratchet/RatchetingSession.java
new file mode 100644
index 0000000000..456416bc58
--- /dev/null
+++ b/library/src/org/whispersystems/textsecure/crypto/ratchet/RatchetingSession.java
@@ -0,0 +1,120 @@
+package org.whispersystems.textsecure.crypto.ratchet;
+
+import android.util.Pair;
+
+import org.whispersystems.textsecure.crypto.IdentityKey;
+import org.whispersystems.textsecure.crypto.IdentityKeyPair;
+import org.whispersystems.textsecure.crypto.InvalidKeyException;
+import org.whispersystems.textsecure.crypto.ecc.Curve;
+import org.whispersystems.textsecure.crypto.ecc.ECKeyPair;
+import org.whispersystems.textsecure.crypto.ecc.ECPublicKey;
+import org.whispersystems.textsecure.crypto.kdf.DerivedSecrets;
+import org.whispersystems.textsecure.crypto.kdf.HKDF;
+import org.whispersystems.textsecure.storage.SessionRecordV2;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+public class RatchetingSession {
+
+ public static void initializeSession(SessionRecordV2 sessionRecord,
+ ECKeyPair ourBaseKey,
+ ECPublicKey theirBaseKey,
+ ECKeyPair ourEphemeralKey,
+ ECPublicKey theirEphemeralKey,
+ IdentityKeyPair ourIdentityKey,
+ IdentityKey theirIdentityKey)
+ throws InvalidKeyException
+ {
+ if (isAlice(ourBaseKey.getPublicKey(), theirBaseKey, ourEphemeralKey.getPublicKey(), theirEphemeralKey)) {
+ initializeSessionAsAlice(sessionRecord, ourBaseKey, theirBaseKey, theirEphemeralKey,
+ ourIdentityKey, theirIdentityKey);
+ } else {
+ initializeSessionAsBob(sessionRecord, ourBaseKey, theirBaseKey,
+ ourEphemeralKey, ourIdentityKey, theirIdentityKey);
+ }
+ }
+
+ private static void initializeSessionAsAlice(SessionRecordV2 sessionRecord,
+ ECKeyPair ourBaseKey, ECPublicKey theirBaseKey,
+ ECPublicKey theirEphemeralKey,
+ IdentityKeyPair ourIdentityKey,
+ IdentityKey theirIdentityKey)
+ throws InvalidKeyException
+ {
+ sessionRecord.setRemoteIdentityKey(theirIdentityKey);
+ sessionRecord.setLocalIdentityKey(ourIdentityKey.getPublicKey());
+
+ ECKeyPair sendingKey = Curve.generateKeyPairForType(ourIdentityKey.getPublicKey().getPublicKey().getType());
+ Pair receivingChain = calculate3DHE(ourBaseKey, theirBaseKey, ourIdentityKey, theirIdentityKey);
+ Pair sendingChain = receivingChain.first.createChain(theirEphemeralKey, sendingKey);
+
+ sessionRecord.addReceiverChain(theirEphemeralKey, receivingChain.second);
+ sessionRecord.setSenderChain(sendingKey, sendingChain.second);
+ sessionRecord.setRootKey(sendingChain.first);
+ }
+
+ private static void initializeSessionAsBob(SessionRecordV2 sessionRecord,
+ ECKeyPair ourBaseKey, ECPublicKey theirBaseKey,
+ ECKeyPair ourEphemeralKey,
+ IdentityKeyPair ourIdentityKey,
+ IdentityKey theirIdentityKey)
+ throws InvalidKeyException
+ {
+ sessionRecord.setRemoteIdentityKey(theirIdentityKey);
+ sessionRecord.setLocalIdentityKey(ourIdentityKey.getPublicKey());
+
+ Pair sendingChain = calculate3DHE(ourBaseKey, theirBaseKey,
+ ourIdentityKey, theirIdentityKey);
+
+ sessionRecord.setSenderChain(ourEphemeralKey, sendingChain.second);
+ sessionRecord.setRootKey(sendingChain.first);
+ }
+
+ public static Pair calculate3DHE(ECKeyPair ourEphemeral, ECPublicKey theirEphemeral,
+ IdentityKeyPair ourIdentity, IdentityKey theirIdentity)
+ throws InvalidKeyException
+ {
+ try {
+ ByteArrayOutputStream secrets = new ByteArrayOutputStream();
+
+ if (isLowEnd(ourEphemeral.getPublicKey(), theirEphemeral)) {
+ secrets.write(Curve.calculateAgreement(theirEphemeral, ourIdentity.getPrivateKey()));
+ secrets.write(Curve.calculateAgreement(theirIdentity.getPublicKey(), ourEphemeral.getPrivateKey()));
+ } else {
+ secrets.write(Curve.calculateAgreement(theirIdentity.getPublicKey(), ourEphemeral.getPrivateKey()));
+ secrets.write(Curve.calculateAgreement(theirEphemeral, ourIdentity.getPrivateKey()));
+ }
+
+ secrets.write(Curve.calculateAgreement(theirEphemeral, ourEphemeral.getPrivateKey()));
+
+ DerivedSecrets derivedSecrets = new HKDF().deriveSecrets(secrets.toByteArray(),
+ "WhisperText".getBytes());
+
+ return new Pair(new RootKey(derivedSecrets.getCipherKey().getEncoded()),
+ new ChainKey(derivedSecrets.getMacKey().getEncoded(), 0));
+ } catch (IOException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ private static boolean isAlice(ECPublicKey ourBaseKey, ECPublicKey theirBaseKey,
+ ECPublicKey ourEphemeralKey, ECPublicKey theirEphemeralKey)
+ {
+ if (ourEphemeralKey.equals(ourBaseKey)) {
+ return false;
+ }
+
+ if (theirEphemeralKey.equals(theirBaseKey)) {
+ return true;
+ }
+
+ return isLowEnd(ourBaseKey, theirBaseKey);
+ }
+
+ private static boolean isLowEnd(ECPublicKey ourKey, ECPublicKey theirKey) {
+ return ourKey.compareTo(theirKey) < 0;
+ }
+
+
+}
diff --git a/library/src/org/whispersystems/textsecure/crypto/ratchet/RootKey.java b/library/src/org/whispersystems/textsecure/crypto/ratchet/RootKey.java
new file mode 100644
index 0000000000..2d8a4d521d
--- /dev/null
+++ b/library/src/org/whispersystems/textsecure/crypto/ratchet/RootKey.java
@@ -0,0 +1,38 @@
+package org.whispersystems.textsecure.crypto.ratchet;
+
+import android.util.Pair;
+
+import org.whispersystems.textsecure.crypto.InvalidKeyException;
+import org.whispersystems.textsecure.crypto.ecc.Curve;
+import org.whispersystems.textsecure.crypto.ecc.ECKeyPair;
+import org.whispersystems.textsecure.crypto.ecc.ECPublicKey;
+import org.whispersystems.textsecure.crypto.kdf.DerivedSecrets;
+import org.whispersystems.textsecure.crypto.kdf.HKDF;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+public class RootKey {
+
+ private final byte[] key;
+
+ public RootKey(byte[] key) {
+ this.key = key;
+ }
+
+ public byte[] getKeyBytes() {
+ return key;
+ }
+
+ public Pair createChain(ECPublicKey theirEphemeral, ECKeyPair ourEphemeral)
+ throws InvalidKeyException
+ {
+ HKDF kdf = new HKDF();
+ byte[] sharedSecret = Curve.calculateAgreement(theirEphemeral, ourEphemeral.getPrivateKey());
+ DerivedSecrets keys = kdf.deriveSecrets(sharedSecret, key, "WhisperRatchet".getBytes());
+ RootKey newRootKey = new RootKey(keys.getMacKey().getEncoded());
+ ChainKey newChainKey = new ChainKey(keys.getCipherKey().getEncoded(), 0);
+
+ return new Pair(newRootKey, newChainKey);
+ }
+}
diff --git a/library/src/org/whispersystems/textsecure/storage/Record.java b/library/src/org/whispersystems/textsecure/storage/Record.java
index 00634a8d75..4b69da80c8 100644
--- a/library/src/org/whispersystems/textsecure/storage/Record.java
+++ b/library/src/org/whispersystems/textsecure/storage/Record.java
@@ -30,8 +30,9 @@ import java.nio.channels.FileChannel;
public abstract class Record {
- protected static final String SESSIONS_DIRECTORY = "sessions";
- public static final String PREKEY_DIRECTORY = "prekeys";
+ protected static final String SESSIONS_DIRECTORY = "sessions";
+ protected static final String SESSIONS_DIRECTORY_V2 = "sessions-v2";
+ public static final String PREKEY_DIRECTORY = "prekeys";
protected final String address;
protected final String directory;
diff --git a/library/src/org/whispersystems/textsecure/storage/Session.java b/library/src/org/whispersystems/textsecure/storage/Session.java
new file mode 100644
index 0000000000..b57a68f6db
--- /dev/null
+++ b/library/src/org/whispersystems/textsecure/storage/Session.java
@@ -0,0 +1,93 @@
+package org.whispersystems.textsecure.storage;
+
+import android.content.Context;
+import android.util.Log;
+
+import org.whispersystems.textsecure.crypto.IdentityKey;
+import org.whispersystems.textsecure.crypto.MasterSecret;
+
+/**
+ * Helper class for generating key pairs and calculating ECDH agreements.
+ *
+ * @author Moxie Marlinspike
+ */
+
+public class Session {
+
+ public static void clearV1SessionFor(Context context, CanonicalRecipientAddress recipient) {
+ //XXX Obviously we should probably do something more thorough here eventually.
+ LocalKeyRecord.delete(context, recipient);
+ RemoteKeyRecord.delete(context, recipient);
+ SessionRecordV1.delete(context, recipient);
+ }
+
+ public static void abortSessionFor(Context context, CanonicalRecipientAddress recipient) {
+ Log.w("Session", "Aborting session, deleting keys...");
+ clearV1SessionFor(context, recipient);
+ SessionRecordV2.delete(context, recipient);
+ }
+
+ public static boolean hasSession(Context context, MasterSecret masterSecret,
+ CanonicalRecipientAddress recipient)
+ {
+ Log.w("Session", "Checking session...");
+ return hasV1Session(context, recipient) || hasV2Session(context, masterSecret, recipient);
+ }
+
+ public static boolean hasRemoteIdentityKey(Context context,
+ MasterSecret masterSecret,
+ CanonicalRecipientAddress recipient)
+ {
+ return (hasV2Session(context, masterSecret, recipient) ||
+ (hasV1Session(context, recipient) &&
+ new SessionRecordV1(context, masterSecret, recipient).getIdentityKey() != null));
+ }
+
+ private static boolean hasV2Session(Context context, MasterSecret masterSecret,
+ CanonicalRecipientAddress recipient)
+ {
+ return SessionRecordV2.hasSession(context, masterSecret, recipient);
+ }
+
+ private static boolean hasV1Session(Context context, CanonicalRecipientAddress recipient) {
+ return SessionRecordV1.hasSession(context, recipient) &&
+ RemoteKeyRecord.hasRecord(context, recipient) &&
+ LocalKeyRecord.hasRecord(context, recipient);
+ }
+
+ public static IdentityKey getRemoteIdentityKey(Context context, MasterSecret masterSecret,
+ CanonicalRecipientAddress recipient)
+ {
+ if (SessionRecordV2.hasSession(context, masterSecret, recipient)) {
+ return new SessionRecordV2(context, masterSecret, recipient).getRemoteIdentityKey();
+ } else if (SessionRecordV1.hasSession(context, recipient)) {
+ return new SessionRecordV1(context, masterSecret, recipient).getIdentityKey();
+ } else {
+ return null;
+ }
+ }
+
+ public static IdentityKey getRemoteIdentityKey(Context context, MasterSecret masterSecret,
+ long recipientId)
+ {
+ if (SessionRecordV2.hasSession(context, masterSecret, recipientId)) {
+ return new SessionRecordV2(context, masterSecret, recipientId).getRemoteIdentityKey();
+ } else if (SessionRecordV1.hasSession(context, recipientId)) {
+ return new SessionRecordV1(context, masterSecret, recipientId).getIdentityKey();
+ } else {
+ return null;
+ }
+ }
+
+ public static int getSessionVersion(Context context, MasterSecret masterSecret,
+ CanonicalRecipientAddress recipient)
+ {
+ if (SessionRecordV2.hasSession(context, masterSecret, recipient)) {
+ return new SessionRecordV2(context, masterSecret, recipient).getSessionVersion();
+ } else if (SessionRecordV1.hasSession(context, recipient)) {
+ return new SessionRecordV1(context, masterSecret, recipient).getSessionVersion();
+ }
+
+ return 0;
+ }
+}
diff --git a/library/src/org/whispersystems/textsecure/storage/SessionKey.java b/library/src/org/whispersystems/textsecure/storage/SessionKey.java
index c45fb3a080..05b24e7db1 100644
--- a/library/src/org/whispersystems/textsecure/storage/SessionKey.java
+++ b/library/src/org/whispersystems/textsecure/storage/SessionKey.java
@@ -19,7 +19,7 @@ package org.whispersystems.textsecure.storage;
import org.whispersystems.textsecure.crypto.InvalidMessageException;
import org.whispersystems.textsecure.crypto.MasterCipher;
import org.whispersystems.textsecure.crypto.MasterSecret;
-import org.whispersystems.textsecure.crypto.SessionCipher;
+import org.whispersystems.textsecure.crypto.kdf.NKDF;
import org.whispersystems.textsecure.util.Conversions;
import org.whispersystems.textsecure.util.Util;
@@ -77,13 +77,13 @@ public class SessionKey {
this.localKeyId = Conversions.byteArrayToMedium(decrypted, 0);
this.remoteKeyId = Conversions.byteArrayToMedium(decrypted, 3);
- byte[] keyBytes = new byte[SessionCipher.CIPHER_KEY_LENGTH];
+ byte[] keyBytes = new byte[NKDF.LEGACY_CIPHER_KEY_LENGTH];
System.arraycopy(decrypted, 6, keyBytes, 0, keyBytes.length);
- byte[] macBytes = new byte[SessionCipher.MAC_KEY_LENGTH];
+ byte[] macBytes = new byte[NKDF.LEGACY_MAC_KEY_LENGTH];
System.arraycopy(decrypted, 6 + keyBytes.length, macBytes, 0, macBytes.length);
- if (decrypted.length < 6 + SessionCipher.CIPHER_KEY_LENGTH + SessionCipher.MAC_KEY_LENGTH + 1) {
+ if (decrypted.length < 6 + NKDF.LEGACY_CIPHER_KEY_LENGTH + NKDF.LEGACY_MAC_KEY_LENGTH + 1) {
throw new InvalidMessageException("No mode included");
}
diff --git a/library/src/org/whispersystems/textsecure/storage/SessionRecord.java b/library/src/org/whispersystems/textsecure/storage/SessionRecordV1.java
similarity index 73%
rename from library/src/org/whispersystems/textsecure/storage/SessionRecord.java
rename to library/src/org/whispersystems/textsecure/storage/SessionRecordV1.java
index af3002189a..49b1dce871 100644
--- a/library/src/org/whispersystems/textsecure/storage/SessionRecord.java
+++ b/library/src/org/whispersystems/textsecure/storage/SessionRecordV1.java
@@ -1,19 +1,3 @@
-/**
- * Copyright (C) 2011 Whisper Systems
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
package org.whispersystems.textsecure.storage;
import android.content.Context;
@@ -36,30 +20,28 @@ import java.nio.channels.FileChannel;
* @author Moxie Marlinspike
*/
-public class SessionRecord extends Record {
+public class SessionRecordV1 extends Record {
- private static final int CURRENT_VERSION_MARKER = 0X55555557;
- private static final int[] VALID_VERSION_MARKERS = {CURRENT_VERSION_MARKER, 0X55555556, 0X55555555};
+ private static final int CURRENT_VERSION_MARKER = 0X55555556;
+ private static final int[] VALID_VERSION_MARKERS = {CURRENT_VERSION_MARKER, 0X55555555};
private static final Object FILE_LOCK = new Object();
private int counter;
private byte[] localFingerprint;
private byte[] remoteFingerprint;
- private int negotiatedSessionVersion;
private int currentSessionVersion;
private IdentityKey identityKey;
private SessionKey sessionKeyRecord;
private boolean verifiedSessionKey;
- private boolean prekeyBundleRequired;
private final MasterSecret masterSecret;
- public SessionRecord(Context context, MasterSecret masterSecret, CanonicalRecipientAddress recipient) {
+ public SessionRecordV1(Context context, MasterSecret masterSecret, CanonicalRecipientAddress recipient) {
this(context, masterSecret, getRecipientId(context, recipient));
}
- public SessionRecord(Context context, MasterSecret masterSecret, long recipientId) {
+ public SessionRecordV1(Context context, MasterSecret masterSecret, long recipientId) {
super(context, SESSIONS_DIRECTORY, recipientId+"");
this.masterSecret = masterSecret;
this.currentSessionVersion = 31337;
@@ -71,8 +53,12 @@ public class SessionRecord extends Record {
}
public static boolean hasSession(Context context, CanonicalRecipientAddress recipient) {
- Log.w("LocalKeyRecord", "Checking: " + getRecipientId(context, recipient));
- return hasRecord(context, SESSIONS_DIRECTORY, getRecipientId(context, recipient)+"");
+ return hasSession(context, getRecipientId(context, recipient));
+ }
+
+ public static boolean hasSession(Context context, long recipientId) {
+ Log.w("SessionRecordV1", "Checking: " + recipientId);
+ return hasRecord(context, SESSIONS_DIRECTORY, recipientId+"");
}
private static long getRecipientId(Context context, CanonicalRecipientAddress recipient) {
@@ -96,14 +82,6 @@ public class SessionRecord extends Record {
return (currentSessionVersion == 31337 ? 0 : currentSessionVersion);
}
- public int getNegotiatedSessionVersion() {
- return negotiatedSessionVersion;
- }
-
- public void setNegotiatedSessionVersion(int sessionVersion) {
- this.negotiatedSessionVersion = sessionVersion;
- }
-
public void setSessionVersion(int sessionVersion) {
this.currentSessionVersion = sessionVersion;
}
@@ -128,18 +106,6 @@ public class SessionRecord extends Record {
return this.identityKey;
}
- public boolean isPrekeyBundleRequired() {
- return prekeyBundleRequired;
- }
-
- public void setPrekeyBundleRequired(boolean prekeyBundleRequired) {
- this.prekeyBundleRequired = prekeyBundleRequired;
- }
-
-// public void setVerifiedSessionKey(boolean verifiedSessionKey) {
-// this.verifiedSessionKey = verifiedSessionKey;
-// }
-
public boolean isVerifiedSession() {
return this.verifiedSessionKey;
}
@@ -182,8 +148,6 @@ public class SessionRecord extends Record {
writeInteger(currentSessionVersion, out);
writeIdentityKey(out);
writeInteger(verifiedSessionKey ? 1 : 0, out);
- writeInteger(prekeyBundleRequired ? 1 : 0, out);
- writeInteger(negotiatedSessionVersion, out);
if (sessionKeyRecord != null)
writeBlob(sessionKeyRecord.serialize(), out);
@@ -230,13 +194,6 @@ public class SessionRecord extends Record {
this.verifiedSessionKey = (readInteger(in) == 1);
}
- if (versionMarker >= 0X55555557) {
- this.prekeyBundleRequired = (readInteger(in) == 1);
- this.negotiatedSessionVersion = readInteger(in);
- } else {
- this.negotiatedSessionVersion = currentSessionVersion;
- }
-
if (in.available() != 0) {
try {
this.sessionKeyRecord = new SessionKey(readBlob(in), masterSecret);
@@ -265,7 +222,7 @@ public class SessionRecord extends Record {
(this.sessionKeyRecord.getRemoteKeyId() == remoteKeyId) &&
(this.sessionKeyRecord.getMode() == mode))
{
- return this.sessionKeyRecord;
+ return this.sessionKeyRecord;
}
return null;
diff --git a/library/src/org/whispersystems/textsecure/storage/SessionRecordV2.java b/library/src/org/whispersystems/textsecure/storage/SessionRecordV2.java
new file mode 100644
index 0000000000..6d9bc96595
--- /dev/null
+++ b/library/src/org/whispersystems/textsecure/storage/SessionRecordV2.java
@@ -0,0 +1,505 @@
+/**
+ * Copyright (C) 2013 Open Whisper Systems
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.whispersystems.textsecure.storage;
+
+import android.content.Context;
+import android.util.Log;
+import android.util.Pair;
+
+import com.google.protobuf.ByteString;
+
+import org.whispersystems.textsecure.crypto.IdentityKey;
+import org.whispersystems.textsecure.crypto.IdentityKeyPair;
+import org.whispersystems.textsecure.crypto.InvalidKeyException;
+import org.whispersystems.textsecure.crypto.InvalidMessageException;
+import org.whispersystems.textsecure.crypto.MasterCipher;
+import org.whispersystems.textsecure.crypto.MasterSecret;
+import org.whispersystems.textsecure.crypto.ecc.Curve;
+import org.whispersystems.textsecure.crypto.ecc.ECKeyPair;
+import org.whispersystems.textsecure.crypto.ecc.ECPrivateKey;
+import org.whispersystems.textsecure.crypto.ecc.ECPublicKey;
+import org.whispersystems.textsecure.crypto.ratchet.ChainKey;
+import org.whispersystems.textsecure.crypto.ratchet.MessageKeys;
+import org.whispersystems.textsecure.crypto.ratchet.RootKey;
+import org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain;
+import org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange;
+import org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.channels.FileChannel;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.crypto.spec.SecretKeySpec;
+
+/**
+ * A disk record representing a current session.
+ *
+ * @author Moxie Marlinspike
+ */
+
+public class SessionRecordV2 extends Record {
+
+ private static final Object FILE_LOCK = new Object();
+ private static final int CURRENT_VERSION = 1;
+
+ private final MasterSecret masterSecret;
+ private StorageProtos.SessionStructure sessionStructure =
+ StorageProtos.SessionStructure.newBuilder().build();
+
+ public SessionRecordV2(Context context, MasterSecret masterSecret, CanonicalRecipientAddress recipient) {
+ this(context, masterSecret, getRecipientId(context, recipient));
+ }
+
+ public SessionRecordV2(Context context, MasterSecret masterSecret, long recipientId) {
+ super(context, SESSIONS_DIRECTORY_V2, recipientId+"");
+ this.masterSecret = masterSecret;
+ loadData();
+ }
+
+ public static void delete(Context context, CanonicalRecipientAddress recipient) {
+ delete(context, SESSIONS_DIRECTORY_V2, getRecipientId(context, recipient) + "");
+ }
+
+ public static boolean hasSession(Context context, MasterSecret masterSecret,
+ CanonicalRecipientAddress recipient)
+ {
+ return hasSession(context, masterSecret, getRecipientId(context, recipient));
+ }
+
+ public static boolean hasSession(Context context, MasterSecret masterSecret, long recipientId) {
+ return hasRecord(context, SESSIONS_DIRECTORY_V2, recipientId+"") &&
+ new SessionRecordV2(context, masterSecret, recipientId).hasSenderChain();
+ }
+
+ private static long getRecipientId(Context context, CanonicalRecipientAddress recipient) {
+ return recipient.getCanonicalAddress(context);
+ }
+
+ public void clear() {
+ this.sessionStructure = StorageProtos.SessionStructure.newBuilder().build();
+ }
+
+ public void setSessionVersion(int version) {
+ this.sessionStructure = this.sessionStructure.toBuilder()
+ .setSessionVersion(version)
+ .build();
+ }
+
+ public int getSessionVersion() {
+ return this.sessionStructure.getSessionVersion();
+ }
+
+ public void setRemoteIdentityKey(IdentityKey identityKey) {
+ this.sessionStructure = this.sessionStructure.toBuilder()
+ .setRemoteIdentityPublic(ByteString.copyFrom(identityKey.serialize()))
+ .build();
+ }
+
+ public void setLocalIdentityKey(IdentityKey identityKey) {
+ this.sessionStructure = this.sessionStructure.toBuilder()
+ .setLocalIdentityPublic(ByteString.copyFrom(identityKey.serialize()))
+ .build();
+ }
+
+ public IdentityKey getRemoteIdentityKey() {
+ try {
+ if (!this.sessionStructure.hasRemoteIdentityPublic()) {
+ return null;
+ }
+
+ return new IdentityKey(this.sessionStructure.getRemoteIdentityPublic().toByteArray(), 0);
+ } catch (InvalidKeyException e) {
+ Log.w("SessionRecordV2", e);
+ return null;
+ }
+ }
+
+ public IdentityKey getLocalIdentityKey() {
+ try {
+ return new IdentityKey(this.sessionStructure.getLocalIdentityPublic().toByteArray(), 0);
+ } catch (InvalidKeyException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ public int getPreviousCounter() {
+ return sessionStructure.getPreviousCounter();
+ }
+
+ public void setPreviousCounter(int previousCounter) {
+ this.sessionStructure = this.sessionStructure.toBuilder()
+ .setPreviousCounter(previousCounter)
+ .build();
+ }
+
+ public RootKey getRootKey() {
+ return new RootKey(this.sessionStructure.getRootKey().toByteArray());
+ }
+
+ public void setRootKey(RootKey rootKey) {
+ this.sessionStructure = this.sessionStructure.toBuilder()
+ .setRootKey(ByteString.copyFrom(rootKey.getKeyBytes()))
+ .build();
+ }
+
+ public ECPublicKey getSenderEphemeral() {
+ try {
+ return Curve.decodePoint(sessionStructure.getSenderChain().getSenderEphemeral().toByteArray(), 0);
+ } catch (InvalidKeyException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ public ECKeyPair getSenderEphemeralPair() {
+ ECPublicKey publicKey = getSenderEphemeral();
+ ECPrivateKey privateKey = Curve.decodePrivatePoint(publicKey.getType(),
+ sessionStructure.getSenderChain()
+ .getSenderEphemeralPrivate()
+ .toByteArray());
+
+ return new ECKeyPair(publicKey, privateKey);
+ }
+
+ public boolean hasReceiverChain(ECPublicKey senderEphemeral) {
+ return getReceiverChain(senderEphemeral) != null;
+ }
+
+ public boolean hasSenderChain() {
+ return sessionStructure.hasSenderChain();
+ }
+
+ private Pair getReceiverChain(ECPublicKey senderEphemeral) {
+ List receiverChains = sessionStructure.getReceiverChainsList();
+ int index = 0;
+
+ for (Chain receiverChain : receiverChains) {
+ try {
+ ECPublicKey chainSenderEphemeral = Curve.decodePoint(receiverChain.getSenderEphemeral().toByteArray(), 0);
+
+ if (chainSenderEphemeral.equals(senderEphemeral)) {
+ return new Pair(receiverChain,index);
+ }
+ } catch (InvalidKeyException e) {
+ Log.w("SessionRecordV2", e);
+ }
+
+ index++;
+ }
+
+ return null;
+ }
+
+ public ChainKey getReceiverChainKey(ECPublicKey senderEphemeral) {
+ Pair receiverChainAndIndex = getReceiverChain(senderEphemeral);
+ Chain receiverChain = receiverChainAndIndex.first;
+
+ if (receiverChain == null) {
+ return null;
+ } else {
+ return new ChainKey(receiverChain.getChainKey().getKey().toByteArray(),
+ receiverChain.getChainKey().getIndex());
+ }
+ }
+
+ public void addReceiverChain(ECPublicKey senderEphemeral, ChainKey chainKey) {
+ Chain.ChainKey chainKeyStructure = Chain.ChainKey.newBuilder()
+ .setKey(ByteString.copyFrom(chainKey.getKey()))
+ .setIndex(chainKey.getIndex())
+ .build();
+
+ Chain chain = Chain.newBuilder()
+ .setChainKey(chainKeyStructure)
+ .setSenderEphemeral(ByteString.copyFrom(senderEphemeral.serialize()))
+ .build();
+
+ // XXX knock old chain out.
+ this.sessionStructure = this.sessionStructure.toBuilder().addReceiverChains(chain).build();
+ }
+
+ public void setSenderChain(ECKeyPair senderEphemeralPair, 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()))
+ .setChainKey(chainKeyStructure)
+ .build();
+
+ this.sessionStructure = this.sessionStructure.toBuilder().setSenderChain(senderChain).build();
+ }
+
+ public ChainKey getSenderChainKey() {
+ Chain.ChainKey chainKeyStructure = sessionStructure.getSenderChain().getChainKey();
+ return new ChainKey(chainKeyStructure.getKey().toByteArray(), chainKeyStructure.getIndex());
+ }
+
+
+ public void setSenderChainKey(ChainKey nextChainKey) {
+ Chain.ChainKey chainKey = Chain.ChainKey.newBuilder()
+ .setKey(ByteString.copyFrom(nextChainKey.getKey()))
+ .setIndex(nextChainKey.getIndex())
+ .build();
+
+ Chain chain = sessionStructure.getSenderChain().toBuilder()
+ .setChainKey(chainKey).build();
+
+ this.sessionStructure = this.sessionStructure.toBuilder().setSenderChain(chain).build();
+ }
+
+ public boolean hasMessageKeys(ECPublicKey senderEphemeral, int counter) {
+ Pair chainAndIndex = getReceiverChain(senderEphemeral);
+ Chain chain = chainAndIndex.first;
+
+ if (chain == null) {
+ return false;
+ }
+
+ List messageKeyList = chain.getMessageKeysList();
+
+ for (Chain.MessageKey messageKey : messageKeyList) {
+ if (messageKey.getIndex() == counter) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public MessageKeys removeMessageKeys(ECPublicKey senderEphemeral, int counter) {
+ Pair chainAndIndex = getReceiverChain(senderEphemeral);
+ Chain chain = chainAndIndex.first;
+
+ if (chain == null) {
+ return null;
+ }
+
+ List messageKeyList = chain.getMessageKeysList();
+ Iterator messageKeyIterator = messageKeyList.iterator();
+ MessageKeys result = null;
+
+ while (messageKeyIterator.hasNext()) {
+ Chain.MessageKey messageKey = messageKeyIterator.next();
+
+ if (messageKey.getIndex() == counter) {
+ result = new MessageKeys(new SecretKeySpec(messageKey.getCipherKey().toByteArray(), "AES"),
+ new SecretKeySpec(messageKey.getMacKey().toByteArray(), "HmacSHA256"),
+ messageKey.getIndex());
+
+ messageKeyIterator.remove();
+ break;
+ }
+ }
+
+ Chain updatedChain = chain.toBuilder().clearMessageKeys()
+ .addAllMessageKeys(messageKeyList)
+ .build();
+
+ this.sessionStructure = this.sessionStructure.toBuilder()
+ .setReceiverChains(chainAndIndex.second, updatedChain)
+ .build();
+
+ return result;
+ }
+
+ public void setMessageKeys(ECPublicKey senderEphemeral, MessageKeys messageKeys) {
+ Pair chainAndIndex = getReceiverChain(senderEphemeral);
+ Chain chain = chainAndIndex.first;
+ Chain.MessageKey messageKeyStructure = Chain.MessageKey.newBuilder()
+ .setCipherKey(ByteString.copyFrom(messageKeys.getCipherKey().getEncoded()))
+ .setMacKey(ByteString.copyFrom(messageKeys.getMacKey().getEncoded()))
+ .setIndex(messageKeys.getCounter())
+ .build();
+
+ Chain updatedChain = chain.toBuilder()
+ .addMessageKeys(messageKeyStructure)
+ .build();
+
+ this.sessionStructure = this.sessionStructure.toBuilder()
+ .setReceiverChains(chainAndIndex.second, updatedChain)
+ .build();
+ }
+
+ public void setReceiverChainKey(ECPublicKey senderEphemeral, ChainKey chainKey) {
+ Pair chainAndIndex = getReceiverChain(senderEphemeral);
+ Chain chain = chainAndIndex.first;
+
+ Chain.ChainKey chainKeyStructure = Chain.ChainKey.newBuilder()
+ .setKey(ByteString.copyFrom(chainKey.getKey()))
+ .setIndex(chainKey.getIndex())
+ .build();
+
+ Chain updatedChain = chain.toBuilder().setChainKey(chainKeyStructure).build();
+
+ this.sessionStructure = this.sessionStructure.toBuilder()
+ .setReceiverChains(chainAndIndex.second, updatedChain)
+ .build();
+ }
+
+ public void setPendingKeyExchange(int sequence,
+ ECKeyPair ourBaseKey,
+ ECKeyPair ourEphemeralKey,
+ IdentityKeyPair ourIdentityKey)
+ {
+ PendingKeyExchange structure =
+ PendingKeyExchange.newBuilder()
+ .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()))
+ .setLocalIdentityKey(ByteString.copyFrom(ourIdentityKey.getPublicKey().serialize()))
+ .setLocalIdentityKeyPrivate(ByteString.copyFrom(ourIdentityKey.getPrivateKey().serialize()))
+ .build();
+
+ this.sessionStructure = this.sessionStructure.toBuilder()
+ .setPendingKeyExchange(structure)
+ .build();
+ }
+
+ public int getPendingKeyExchangeSequence() {
+ return sessionStructure.getPendingKeyExchange().getSequence();
+ }
+
+ public ECKeyPair getPendingKeyExchangeBaseKey() throws InvalidKeyException {
+ ECPublicKey publicKey = Curve.decodePoint(sessionStructure.getPendingKeyExchange()
+ .getLocalBaseKey().toByteArray(), 0);
+
+ ECPrivateKey privateKey = Curve.decodePrivatePoint(publicKey.getType(),
+ sessionStructure.getPendingKeyExchange()
+ .getLocalBaseKeyPrivate()
+ .toByteArray());
+
+ return new ECKeyPair(publicKey, privateKey);
+ }
+
+ public ECKeyPair getPendingKeyExchangeEphemeralKey() throws InvalidKeyException {
+ ECPublicKey publicKey = Curve.decodePoint(sessionStructure.getPendingKeyExchange()
+ .getLocalEphemeralKey().toByteArray(), 0);
+
+ ECPrivateKey privateKey = Curve.decodePrivatePoint(publicKey.getType(),
+ sessionStructure.getPendingKeyExchange()
+ .getLocalEphemeralKeyPrivate()
+ .toByteArray());
+
+ return new ECKeyPair(publicKey, privateKey);
+ }
+
+ public IdentityKeyPair getPendingKeyExchangeIdentityKey() throws InvalidKeyException {
+ IdentityKey publicKey = new IdentityKey(sessionStructure.getPendingKeyExchange()
+ .getLocalIdentityKey().toByteArray(), 0);
+
+ ECPrivateKey privateKey = Curve.decodePrivatePoint(publicKey.getPublicKey().getType(),
+ sessionStructure.getPendingKeyExchange()
+ .getLocalIdentityKeyPrivate()
+ .toByteArray());
+
+ return new IdentityKeyPair(publicKey, privateKey);
+ }
+
+ public boolean hasPendingKeyExchange() {
+ return sessionStructure.hasPendingKeyExchange();
+ }
+
+ public void setPendingPreKey(int preKeyId, ECPublicKey baseKey) {
+ PendingPreKey pending = PendingPreKey.newBuilder()
+ .setPreKeyId(preKeyId)
+ .setBaseKey(ByteString.copyFrom(baseKey.serialize()))
+ .build();
+
+ this.sessionStructure = this.sessionStructure.toBuilder()
+ .setPendingPreKey(pending)
+ .build();
+ }
+
+ public boolean hasPendingPreKey() {
+ return this.sessionStructure.hasPendingPreKey();
+ }
+
+ public Pair getPendingPreKey() {
+ try {
+ return new Pair(sessionStructure.getPendingPreKey().getPreKeyId(),
+ Curve.decodePoint(sessionStructure.getPendingPreKey()
+ .getBaseKey()
+ .toByteArray(), 0));
+ } catch (InvalidKeyException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ public void clearPendingPreKey() {
+ this.sessionStructure = this.sessionStructure.toBuilder()
+ .clearPendingPreKey()
+ .build();
+ }
+
+ public void save() {
+ synchronized (FILE_LOCK) {
+ try {
+ RandomAccessFile file = openRandomAccessFile();
+ FileChannel out = file.getChannel();
+ out.position(0);
+
+ MasterCipher cipher = new MasterCipher(masterSecret);
+ writeInteger(CURRENT_VERSION, out);
+ writeBlob(cipher.encryptBytes(sessionStructure.toByteArray()), out);
+
+ out.truncate(out.position());
+ file.close();
+ } catch (IOException ioe) {
+ throw new IllegalArgumentException(ioe);
+ }
+ }
+ }
+
+ private void loadData() {
+ synchronized (FILE_LOCK) {
+ try {
+ FileInputStream in = this.openInputStream();
+ int versionMarker = readInteger(in);
+
+ if (versionMarker > CURRENT_VERSION) {
+ throw new AssertionError("Unknown version: " + versionMarker);
+ }
+
+ MasterCipher cipher = new MasterCipher(masterSecret);
+ byte[] encryptedBlob = readBlob(in);
+
+
+ this.sessionStructure = StorageProtos.SessionStructure
+ .parseFrom(cipher.decryptBytes(encryptedBlob));
+
+ in.close();
+ } catch (FileNotFoundException e) {
+ Log.w("SessionRecordV2", "No session information found.");
+ // XXX
+ } catch (IOException ioe) {
+ Log.w("SessionRecordV2", ioe);
+ // XXX
+ } catch (InvalidMessageException e) {
+ Log.w("SessionRecordV2", e);
+ }
+ }
+ }
+
+}
diff --git a/library/src/org/whispersystems/textsecure/storage/StorageProtos.java b/library/src/org/whispersystems/textsecure/storage/StorageProtos.java
new file mode 100644
index 0000000000..7f51de31f8
--- /dev/null
+++ b/library/src/org/whispersystems/textsecure/storage/StorageProtos.java
@@ -0,0 +1,4187 @@
+// Generated by the protocol buffer compiler. DO NOT EDIT!
+// source: LocalStorageProtocol.proto
+
+package org.whispersystems.textsecure.storage;
+
+public final class StorageProtos {
+ private StorageProtos() {}
+ public static void registerAllExtensions(
+ com.google.protobuf.ExtensionRegistry registry) {
+ }
+ public interface SessionStructureOrBuilder
+ extends com.google.protobuf.MessageOrBuilder {
+
+ // optional uint32 sessionVersion = 1;
+ boolean hasSessionVersion();
+ int getSessionVersion();
+
+ // optional bytes localIdentityPublic = 2;
+ boolean hasLocalIdentityPublic();
+ com.google.protobuf.ByteString getLocalIdentityPublic();
+
+ // optional bytes remoteIdentityPublic = 3;
+ boolean hasRemoteIdentityPublic();
+ com.google.protobuf.ByteString getRemoteIdentityPublic();
+
+ // optional bytes rootKey = 4;
+ boolean hasRootKey();
+ com.google.protobuf.ByteString getRootKey();
+
+ // optional uint32 previousCounter = 5;
+ boolean hasPreviousCounter();
+ int getPreviousCounter();
+
+ // optional .textsecure.SessionStructure.Chain senderChain = 6;
+ boolean hasSenderChain();
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain getSenderChain();
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.ChainOrBuilder getSenderChainOrBuilder();
+
+ // repeated .textsecure.SessionStructure.Chain receiverChains = 7;
+ java.util.List
+ getReceiverChainsList();
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain getReceiverChains(int index);
+ int getReceiverChainsCount();
+ java.util.List extends org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.ChainOrBuilder>
+ getReceiverChainsOrBuilderList();
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.ChainOrBuilder getReceiverChainsOrBuilder(
+ int index);
+
+ // optional .textsecure.SessionStructure.PendingKeyExchange pendingKeyExchange = 8;
+ boolean hasPendingKeyExchange();
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange getPendingKeyExchange();
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchangeOrBuilder getPendingKeyExchangeOrBuilder();
+
+ // optional .textsecure.SessionStructure.PendingPreKey pendingPreKey = 9;
+ boolean hasPendingPreKey();
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey getPendingPreKey();
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKeyOrBuilder getPendingPreKeyOrBuilder();
+ }
+ public static final class SessionStructure extends
+ com.google.protobuf.GeneratedMessage
+ implements SessionStructureOrBuilder {
+ // Use SessionStructure.newBuilder() to construct.
+ private SessionStructure(Builder builder) {
+ super(builder);
+ }
+ private SessionStructure(boolean noInit) {}
+
+ private static final SessionStructure defaultInstance;
+ public static SessionStructure getDefaultInstance() {
+ return defaultInstance;
+ }
+
+ public SessionStructure getDefaultInstanceForType() {
+ return defaultInstance;
+ }
+
+ public static final com.google.protobuf.Descriptors.Descriptor
+ getDescriptor() {
+ return org.whispersystems.textsecure.storage.StorageProtos.internal_static_textsecure_SessionStructure_descriptor;
+ }
+
+ protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+ internalGetFieldAccessorTable() {
+ return org.whispersystems.textsecure.storage.StorageProtos.internal_static_textsecure_SessionStructure_fieldAccessorTable;
+ }
+
+ public interface ChainOrBuilder
+ extends com.google.protobuf.MessageOrBuilder {
+
+ // optional bytes senderEphemeral = 1;
+ boolean hasSenderEphemeral();
+ com.google.protobuf.ByteString getSenderEphemeral();
+
+ // optional bytes senderEphemeralPrivate = 2;
+ boolean hasSenderEphemeralPrivate();
+ com.google.protobuf.ByteString getSenderEphemeralPrivate();
+
+ // optional .textsecure.SessionStructure.Chain.ChainKey chainKey = 3;
+ boolean hasChainKey();
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKey getChainKey();
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKeyOrBuilder getChainKeyOrBuilder();
+
+ // repeated .textsecure.SessionStructure.Chain.MessageKey messageKeys = 4;
+ java.util.List
+ getMessageKeysList();
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKey getMessageKeys(int index);
+ int getMessageKeysCount();
+ java.util.List extends org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKeyOrBuilder>
+ getMessageKeysOrBuilderList();
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKeyOrBuilder getMessageKeysOrBuilder(
+ int index);
+ }
+ public static final class Chain extends
+ com.google.protobuf.GeneratedMessage
+ implements ChainOrBuilder {
+ // Use Chain.newBuilder() to construct.
+ private Chain(Builder builder) {
+ super(builder);
+ }
+ private Chain(boolean noInit) {}
+
+ private static final Chain defaultInstance;
+ public static Chain getDefaultInstance() {
+ return defaultInstance;
+ }
+
+ public Chain getDefaultInstanceForType() {
+ return defaultInstance;
+ }
+
+ public static final com.google.protobuf.Descriptors.Descriptor
+ getDescriptor() {
+ return org.whispersystems.textsecure.storage.StorageProtos.internal_static_textsecure_SessionStructure_Chain_descriptor;
+ }
+
+ protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+ internalGetFieldAccessorTable() {
+ return org.whispersystems.textsecure.storage.StorageProtos.internal_static_textsecure_SessionStructure_Chain_fieldAccessorTable;
+ }
+
+ public interface ChainKeyOrBuilder
+ extends com.google.protobuf.MessageOrBuilder {
+
+ // optional uint32 index = 1;
+ boolean hasIndex();
+ int getIndex();
+
+ // optional bytes key = 2;
+ boolean hasKey();
+ com.google.protobuf.ByteString getKey();
+ }
+ public static final class ChainKey extends
+ com.google.protobuf.GeneratedMessage
+ implements ChainKeyOrBuilder {
+ // Use ChainKey.newBuilder() to construct.
+ private ChainKey(Builder builder) {
+ super(builder);
+ }
+ private ChainKey(boolean noInit) {}
+
+ private static final ChainKey defaultInstance;
+ public static ChainKey getDefaultInstance() {
+ return defaultInstance;
+ }
+
+ public ChainKey getDefaultInstanceForType() {
+ return defaultInstance;
+ }
+
+ public static final com.google.protobuf.Descriptors.Descriptor
+ getDescriptor() {
+ return org.whispersystems.textsecure.storage.StorageProtos.internal_static_textsecure_SessionStructure_Chain_ChainKey_descriptor;
+ }
+
+ protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+ internalGetFieldAccessorTable() {
+ return org.whispersystems.textsecure.storage.StorageProtos.internal_static_textsecure_SessionStructure_Chain_ChainKey_fieldAccessorTable;
+ }
+
+ private int bitField0_;
+ // optional uint32 index = 1;
+ public static final int INDEX_FIELD_NUMBER = 1;
+ private int index_;
+ public boolean hasIndex() {
+ return ((bitField0_ & 0x00000001) == 0x00000001);
+ }
+ public int getIndex() {
+ return index_;
+ }
+
+ // optional bytes key = 2;
+ public static final int KEY_FIELD_NUMBER = 2;
+ private com.google.protobuf.ByteString key_;
+ public boolean hasKey() {
+ return ((bitField0_ & 0x00000002) == 0x00000002);
+ }
+ public com.google.protobuf.ByteString getKey() {
+ return key_;
+ }
+
+ private void initFields() {
+ index_ = 0;
+ key_ = com.google.protobuf.ByteString.EMPTY;
+ }
+ private byte memoizedIsInitialized = -1;
+ public final boolean isInitialized() {
+ byte isInitialized = memoizedIsInitialized;
+ if (isInitialized != -1) return isInitialized == 1;
+
+ memoizedIsInitialized = 1;
+ return true;
+ }
+
+ public void writeTo(com.google.protobuf.CodedOutputStream output)
+ throws java.io.IOException {
+ getSerializedSize();
+ if (((bitField0_ & 0x00000001) == 0x00000001)) {
+ output.writeUInt32(1, index_);
+ }
+ if (((bitField0_ & 0x00000002) == 0x00000002)) {
+ output.writeBytes(2, key_);
+ }
+ getUnknownFields().writeTo(output);
+ }
+
+ private int memoizedSerializedSize = -1;
+ public int getSerializedSize() {
+ int size = memoizedSerializedSize;
+ if (size != -1) return size;
+
+ size = 0;
+ if (((bitField0_ & 0x00000001) == 0x00000001)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeUInt32Size(1, index_);
+ }
+ if (((bitField0_ & 0x00000002) == 0x00000002)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeBytesSize(2, key_);
+ }
+ size += getUnknownFields().getSerializedSize();
+ memoizedSerializedSize = size;
+ return size;
+ }
+
+ private static final long serialVersionUID = 0L;
+ @java.lang.Override
+ protected java.lang.Object writeReplace()
+ throws java.io.ObjectStreamException {
+ return super.writeReplace();
+ }
+
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKey parseFrom(
+ com.google.protobuf.ByteString data)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data).buildParsed();
+ }
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKey parseFrom(
+ com.google.protobuf.ByteString data,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data, extensionRegistry)
+ .buildParsed();
+ }
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKey parseFrom(byte[] data)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data).buildParsed();
+ }
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKey parseFrom(
+ byte[] data,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data, extensionRegistry)
+ .buildParsed();
+ }
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKey parseFrom(java.io.InputStream input)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input).buildParsed();
+ }
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKey parseFrom(
+ java.io.InputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input, extensionRegistry)
+ .buildParsed();
+ }
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKey parseDelimitedFrom(java.io.InputStream input)
+ throws java.io.IOException {
+ Builder builder = newBuilder();
+ if (builder.mergeDelimitedFrom(input)) {
+ return builder.buildParsed();
+ } else {
+ return null;
+ }
+ }
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKey parseDelimitedFrom(
+ java.io.InputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ Builder builder = newBuilder();
+ if (builder.mergeDelimitedFrom(input, extensionRegistry)) {
+ return builder.buildParsed();
+ } else {
+ return null;
+ }
+ }
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKey parseFrom(
+ com.google.protobuf.CodedInputStream input)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input).buildParsed();
+ }
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKey parseFrom(
+ com.google.protobuf.CodedInputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input, extensionRegistry)
+ .buildParsed();
+ }
+
+ public static Builder newBuilder() { return Builder.create(); }
+ public Builder newBuilderForType() { return newBuilder(); }
+ public static Builder newBuilder(org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKey prototype) {
+ return newBuilder().mergeFrom(prototype);
+ }
+ public Builder toBuilder() { return newBuilder(this); }
+
+ @java.lang.Override
+ protected Builder newBuilderForType(
+ com.google.protobuf.GeneratedMessage.BuilderParent parent) {
+ Builder builder = new Builder(parent);
+ return builder;
+ }
+ public static final class Builder extends
+ com.google.protobuf.GeneratedMessage.Builder
+ implements org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKeyOrBuilder {
+ public static final com.google.protobuf.Descriptors.Descriptor
+ getDescriptor() {
+ return org.whispersystems.textsecure.storage.StorageProtos.internal_static_textsecure_SessionStructure_Chain_ChainKey_descriptor;
+ }
+
+ protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+ internalGetFieldAccessorTable() {
+ return org.whispersystems.textsecure.storage.StorageProtos.internal_static_textsecure_SessionStructure_Chain_ChainKey_fieldAccessorTable;
+ }
+
+ // Construct using org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKey.newBuilder()
+ private Builder() {
+ maybeForceBuilderInitialization();
+ }
+
+ private Builder(BuilderParent parent) {
+ super(parent);
+ maybeForceBuilderInitialization();
+ }
+ private void maybeForceBuilderInitialization() {
+ if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
+ }
+ }
+ private static Builder create() {
+ return new Builder();
+ }
+
+ public Builder clear() {
+ super.clear();
+ index_ = 0;
+ bitField0_ = (bitField0_ & ~0x00000001);
+ key_ = com.google.protobuf.ByteString.EMPTY;
+ bitField0_ = (bitField0_ & ~0x00000002);
+ return this;
+ }
+
+ public Builder clone() {
+ return create().mergeFrom(buildPartial());
+ }
+
+ public com.google.protobuf.Descriptors.Descriptor
+ getDescriptorForType() {
+ return org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKey.getDescriptor();
+ }
+
+ public org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKey getDefaultInstanceForType() {
+ return org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKey.getDefaultInstance();
+ }
+
+ public org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKey build() {
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKey result = buildPartial();
+ if (!result.isInitialized()) {
+ throw newUninitializedMessageException(result);
+ }
+ return result;
+ }
+
+ private org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKey buildParsed()
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKey result = buildPartial();
+ if (!result.isInitialized()) {
+ throw newUninitializedMessageException(
+ result).asInvalidProtocolBufferException();
+ }
+ return result;
+ }
+
+ public org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKey buildPartial() {
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKey result = new org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKey(this);
+ int from_bitField0_ = bitField0_;
+ int to_bitField0_ = 0;
+ if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
+ to_bitField0_ |= 0x00000001;
+ }
+ result.index_ = index_;
+ if (((from_bitField0_ & 0x00000002) == 0x00000002)) {
+ to_bitField0_ |= 0x00000002;
+ }
+ result.key_ = key_;
+ result.bitField0_ = to_bitField0_;
+ onBuilt();
+ return result;
+ }
+
+ public Builder mergeFrom(com.google.protobuf.Message other) {
+ if (other instanceof org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKey) {
+ return mergeFrom((org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKey)other);
+ } else {
+ super.mergeFrom(other);
+ return this;
+ }
+ }
+
+ public Builder mergeFrom(org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKey other) {
+ if (other == org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKey.getDefaultInstance()) return this;
+ if (other.hasIndex()) {
+ setIndex(other.getIndex());
+ }
+ if (other.hasKey()) {
+ setKey(other.getKey());
+ }
+ this.mergeUnknownFields(other.getUnknownFields());
+ return this;
+ }
+
+ public final boolean isInitialized() {
+ return true;
+ }
+
+ public Builder mergeFrom(
+ com.google.protobuf.CodedInputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ com.google.protobuf.UnknownFieldSet.Builder unknownFields =
+ com.google.protobuf.UnknownFieldSet.newBuilder(
+ this.getUnknownFields());
+ while (true) {
+ int tag = input.readTag();
+ switch (tag) {
+ case 0:
+ this.setUnknownFields(unknownFields.build());
+ onChanged();
+ return this;
+ default: {
+ if (!parseUnknownField(input, unknownFields,
+ extensionRegistry, tag)) {
+ this.setUnknownFields(unknownFields.build());
+ onChanged();
+ return this;
+ }
+ break;
+ }
+ case 8: {
+ bitField0_ |= 0x00000001;
+ index_ = input.readUInt32();
+ break;
+ }
+ case 18: {
+ bitField0_ |= 0x00000002;
+ key_ = input.readBytes();
+ break;
+ }
+ }
+ }
+ }
+
+ private int bitField0_;
+
+ // optional uint32 index = 1;
+ private int index_ ;
+ public boolean hasIndex() {
+ return ((bitField0_ & 0x00000001) == 0x00000001);
+ }
+ public int getIndex() {
+ return index_;
+ }
+ public Builder setIndex(int value) {
+ bitField0_ |= 0x00000001;
+ index_ = value;
+ onChanged();
+ return this;
+ }
+ public Builder clearIndex() {
+ bitField0_ = (bitField0_ & ~0x00000001);
+ index_ = 0;
+ onChanged();
+ return this;
+ }
+
+ // optional bytes key = 2;
+ private com.google.protobuf.ByteString key_ = com.google.protobuf.ByteString.EMPTY;
+ public boolean hasKey() {
+ return ((bitField0_ & 0x00000002) == 0x00000002);
+ }
+ public com.google.protobuf.ByteString getKey() {
+ return key_;
+ }
+ public Builder setKey(com.google.protobuf.ByteString value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ bitField0_ |= 0x00000002;
+ key_ = value;
+ onChanged();
+ return this;
+ }
+ public Builder clearKey() {
+ bitField0_ = (bitField0_ & ~0x00000002);
+ key_ = getDefaultInstance().getKey();
+ onChanged();
+ return this;
+ }
+
+ // @@protoc_insertion_point(builder_scope:textsecure.SessionStructure.Chain.ChainKey)
+ }
+
+ static {
+ defaultInstance = new ChainKey(true);
+ defaultInstance.initFields();
+ }
+
+ // @@protoc_insertion_point(class_scope:textsecure.SessionStructure.Chain.ChainKey)
+ }
+
+ public interface MessageKeyOrBuilder
+ extends com.google.protobuf.MessageOrBuilder {
+
+ // optional uint32 index = 1;
+ boolean hasIndex();
+ int getIndex();
+
+ // optional bytes cipherKey = 2;
+ boolean hasCipherKey();
+ com.google.protobuf.ByteString getCipherKey();
+
+ // optional bytes macKey = 3;
+ boolean hasMacKey();
+ com.google.protobuf.ByteString getMacKey();
+ }
+ public static final class MessageKey extends
+ com.google.protobuf.GeneratedMessage
+ implements MessageKeyOrBuilder {
+ // Use MessageKey.newBuilder() to construct.
+ private MessageKey(Builder builder) {
+ super(builder);
+ }
+ private MessageKey(boolean noInit) {}
+
+ private static final MessageKey defaultInstance;
+ public static MessageKey getDefaultInstance() {
+ return defaultInstance;
+ }
+
+ public MessageKey getDefaultInstanceForType() {
+ return defaultInstance;
+ }
+
+ public static final com.google.protobuf.Descriptors.Descriptor
+ getDescriptor() {
+ return org.whispersystems.textsecure.storage.StorageProtos.internal_static_textsecure_SessionStructure_Chain_MessageKey_descriptor;
+ }
+
+ protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+ internalGetFieldAccessorTable() {
+ return org.whispersystems.textsecure.storage.StorageProtos.internal_static_textsecure_SessionStructure_Chain_MessageKey_fieldAccessorTable;
+ }
+
+ private int bitField0_;
+ // optional uint32 index = 1;
+ public static final int INDEX_FIELD_NUMBER = 1;
+ private int index_;
+ public boolean hasIndex() {
+ return ((bitField0_ & 0x00000001) == 0x00000001);
+ }
+ public int getIndex() {
+ return index_;
+ }
+
+ // optional bytes cipherKey = 2;
+ public static final int CIPHERKEY_FIELD_NUMBER = 2;
+ private com.google.protobuf.ByteString cipherKey_;
+ public boolean hasCipherKey() {
+ return ((bitField0_ & 0x00000002) == 0x00000002);
+ }
+ public com.google.protobuf.ByteString getCipherKey() {
+ return cipherKey_;
+ }
+
+ // optional bytes macKey = 3;
+ public static final int MACKEY_FIELD_NUMBER = 3;
+ private com.google.protobuf.ByteString macKey_;
+ public boolean hasMacKey() {
+ return ((bitField0_ & 0x00000004) == 0x00000004);
+ }
+ public com.google.protobuf.ByteString getMacKey() {
+ return macKey_;
+ }
+
+ private void initFields() {
+ index_ = 0;
+ cipherKey_ = com.google.protobuf.ByteString.EMPTY;
+ macKey_ = com.google.protobuf.ByteString.EMPTY;
+ }
+ private byte memoizedIsInitialized = -1;
+ public final boolean isInitialized() {
+ byte isInitialized = memoizedIsInitialized;
+ if (isInitialized != -1) return isInitialized == 1;
+
+ memoizedIsInitialized = 1;
+ return true;
+ }
+
+ public void writeTo(com.google.protobuf.CodedOutputStream output)
+ throws java.io.IOException {
+ getSerializedSize();
+ if (((bitField0_ & 0x00000001) == 0x00000001)) {
+ output.writeUInt32(1, index_);
+ }
+ if (((bitField0_ & 0x00000002) == 0x00000002)) {
+ output.writeBytes(2, cipherKey_);
+ }
+ if (((bitField0_ & 0x00000004) == 0x00000004)) {
+ output.writeBytes(3, macKey_);
+ }
+ getUnknownFields().writeTo(output);
+ }
+
+ private int memoizedSerializedSize = -1;
+ public int getSerializedSize() {
+ int size = memoizedSerializedSize;
+ if (size != -1) return size;
+
+ size = 0;
+ if (((bitField0_ & 0x00000001) == 0x00000001)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeUInt32Size(1, index_);
+ }
+ if (((bitField0_ & 0x00000002) == 0x00000002)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeBytesSize(2, cipherKey_);
+ }
+ if (((bitField0_ & 0x00000004) == 0x00000004)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeBytesSize(3, macKey_);
+ }
+ size += getUnknownFields().getSerializedSize();
+ memoizedSerializedSize = size;
+ return size;
+ }
+
+ private static final long serialVersionUID = 0L;
+ @java.lang.Override
+ protected java.lang.Object writeReplace()
+ throws java.io.ObjectStreamException {
+ return super.writeReplace();
+ }
+
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKey parseFrom(
+ com.google.protobuf.ByteString data)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data).buildParsed();
+ }
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKey parseFrom(
+ com.google.protobuf.ByteString data,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data, extensionRegistry)
+ .buildParsed();
+ }
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKey parseFrom(byte[] data)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data).buildParsed();
+ }
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKey parseFrom(
+ byte[] data,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data, extensionRegistry)
+ .buildParsed();
+ }
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKey parseFrom(java.io.InputStream input)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input).buildParsed();
+ }
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKey parseFrom(
+ java.io.InputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input, extensionRegistry)
+ .buildParsed();
+ }
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKey parseDelimitedFrom(java.io.InputStream input)
+ throws java.io.IOException {
+ Builder builder = newBuilder();
+ if (builder.mergeDelimitedFrom(input)) {
+ return builder.buildParsed();
+ } else {
+ return null;
+ }
+ }
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKey parseDelimitedFrom(
+ java.io.InputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ Builder builder = newBuilder();
+ if (builder.mergeDelimitedFrom(input, extensionRegistry)) {
+ return builder.buildParsed();
+ } else {
+ return null;
+ }
+ }
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKey parseFrom(
+ com.google.protobuf.CodedInputStream input)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input).buildParsed();
+ }
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKey parseFrom(
+ com.google.protobuf.CodedInputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input, extensionRegistry)
+ .buildParsed();
+ }
+
+ public static Builder newBuilder() { return Builder.create(); }
+ public Builder newBuilderForType() { return newBuilder(); }
+ public static Builder newBuilder(org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKey prototype) {
+ return newBuilder().mergeFrom(prototype);
+ }
+ public Builder toBuilder() { return newBuilder(this); }
+
+ @java.lang.Override
+ protected Builder newBuilderForType(
+ com.google.protobuf.GeneratedMessage.BuilderParent parent) {
+ Builder builder = new Builder(parent);
+ return builder;
+ }
+ public static final class Builder extends
+ com.google.protobuf.GeneratedMessage.Builder
+ implements org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKeyOrBuilder {
+ public static final com.google.protobuf.Descriptors.Descriptor
+ getDescriptor() {
+ return org.whispersystems.textsecure.storage.StorageProtos.internal_static_textsecure_SessionStructure_Chain_MessageKey_descriptor;
+ }
+
+ protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+ internalGetFieldAccessorTable() {
+ return org.whispersystems.textsecure.storage.StorageProtos.internal_static_textsecure_SessionStructure_Chain_MessageKey_fieldAccessorTable;
+ }
+
+ // Construct using org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKey.newBuilder()
+ private Builder() {
+ maybeForceBuilderInitialization();
+ }
+
+ private Builder(BuilderParent parent) {
+ super(parent);
+ maybeForceBuilderInitialization();
+ }
+ private void maybeForceBuilderInitialization() {
+ if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
+ }
+ }
+ private static Builder create() {
+ return new Builder();
+ }
+
+ public Builder clear() {
+ super.clear();
+ index_ = 0;
+ bitField0_ = (bitField0_ & ~0x00000001);
+ cipherKey_ = com.google.protobuf.ByteString.EMPTY;
+ bitField0_ = (bitField0_ & ~0x00000002);
+ macKey_ = com.google.protobuf.ByteString.EMPTY;
+ bitField0_ = (bitField0_ & ~0x00000004);
+ return this;
+ }
+
+ public Builder clone() {
+ return create().mergeFrom(buildPartial());
+ }
+
+ public com.google.protobuf.Descriptors.Descriptor
+ getDescriptorForType() {
+ return org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKey.getDescriptor();
+ }
+
+ public org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKey getDefaultInstanceForType() {
+ return org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKey.getDefaultInstance();
+ }
+
+ public org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKey build() {
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKey result = buildPartial();
+ if (!result.isInitialized()) {
+ throw newUninitializedMessageException(result);
+ }
+ return result;
+ }
+
+ private org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKey buildParsed()
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKey result = buildPartial();
+ if (!result.isInitialized()) {
+ throw newUninitializedMessageException(
+ result).asInvalidProtocolBufferException();
+ }
+ return result;
+ }
+
+ public org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKey buildPartial() {
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKey result = new org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKey(this);
+ int from_bitField0_ = bitField0_;
+ int to_bitField0_ = 0;
+ if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
+ to_bitField0_ |= 0x00000001;
+ }
+ result.index_ = index_;
+ if (((from_bitField0_ & 0x00000002) == 0x00000002)) {
+ to_bitField0_ |= 0x00000002;
+ }
+ result.cipherKey_ = cipherKey_;
+ if (((from_bitField0_ & 0x00000004) == 0x00000004)) {
+ to_bitField0_ |= 0x00000004;
+ }
+ result.macKey_ = macKey_;
+ result.bitField0_ = to_bitField0_;
+ onBuilt();
+ return result;
+ }
+
+ public Builder mergeFrom(com.google.protobuf.Message other) {
+ if (other instanceof org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKey) {
+ return mergeFrom((org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKey)other);
+ } else {
+ super.mergeFrom(other);
+ return this;
+ }
+ }
+
+ public Builder mergeFrom(org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKey other) {
+ if (other == org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKey.getDefaultInstance()) return this;
+ if (other.hasIndex()) {
+ setIndex(other.getIndex());
+ }
+ if (other.hasCipherKey()) {
+ setCipherKey(other.getCipherKey());
+ }
+ if (other.hasMacKey()) {
+ setMacKey(other.getMacKey());
+ }
+ this.mergeUnknownFields(other.getUnknownFields());
+ return this;
+ }
+
+ public final boolean isInitialized() {
+ return true;
+ }
+
+ public Builder mergeFrom(
+ com.google.protobuf.CodedInputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ com.google.protobuf.UnknownFieldSet.Builder unknownFields =
+ com.google.protobuf.UnknownFieldSet.newBuilder(
+ this.getUnknownFields());
+ while (true) {
+ int tag = input.readTag();
+ switch (tag) {
+ case 0:
+ this.setUnknownFields(unknownFields.build());
+ onChanged();
+ return this;
+ default: {
+ if (!parseUnknownField(input, unknownFields,
+ extensionRegistry, tag)) {
+ this.setUnknownFields(unknownFields.build());
+ onChanged();
+ return this;
+ }
+ break;
+ }
+ case 8: {
+ bitField0_ |= 0x00000001;
+ index_ = input.readUInt32();
+ break;
+ }
+ case 18: {
+ bitField0_ |= 0x00000002;
+ cipherKey_ = input.readBytes();
+ break;
+ }
+ case 26: {
+ bitField0_ |= 0x00000004;
+ macKey_ = input.readBytes();
+ break;
+ }
+ }
+ }
+ }
+
+ private int bitField0_;
+
+ // optional uint32 index = 1;
+ private int index_ ;
+ public boolean hasIndex() {
+ return ((bitField0_ & 0x00000001) == 0x00000001);
+ }
+ public int getIndex() {
+ return index_;
+ }
+ public Builder setIndex(int value) {
+ bitField0_ |= 0x00000001;
+ index_ = value;
+ onChanged();
+ return this;
+ }
+ public Builder clearIndex() {
+ bitField0_ = (bitField0_ & ~0x00000001);
+ index_ = 0;
+ onChanged();
+ return this;
+ }
+
+ // optional bytes cipherKey = 2;
+ private com.google.protobuf.ByteString cipherKey_ = com.google.protobuf.ByteString.EMPTY;
+ public boolean hasCipherKey() {
+ return ((bitField0_ & 0x00000002) == 0x00000002);
+ }
+ public com.google.protobuf.ByteString getCipherKey() {
+ return cipherKey_;
+ }
+ public Builder setCipherKey(com.google.protobuf.ByteString value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ bitField0_ |= 0x00000002;
+ cipherKey_ = value;
+ onChanged();
+ return this;
+ }
+ public Builder clearCipherKey() {
+ bitField0_ = (bitField0_ & ~0x00000002);
+ cipherKey_ = getDefaultInstance().getCipherKey();
+ onChanged();
+ return this;
+ }
+
+ // optional bytes macKey = 3;
+ private com.google.protobuf.ByteString macKey_ = com.google.protobuf.ByteString.EMPTY;
+ public boolean hasMacKey() {
+ return ((bitField0_ & 0x00000004) == 0x00000004);
+ }
+ public com.google.protobuf.ByteString getMacKey() {
+ return macKey_;
+ }
+ public Builder setMacKey(com.google.protobuf.ByteString value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ bitField0_ |= 0x00000004;
+ macKey_ = value;
+ onChanged();
+ return this;
+ }
+ public Builder clearMacKey() {
+ bitField0_ = (bitField0_ & ~0x00000004);
+ macKey_ = getDefaultInstance().getMacKey();
+ onChanged();
+ return this;
+ }
+
+ // @@protoc_insertion_point(builder_scope:textsecure.SessionStructure.Chain.MessageKey)
+ }
+
+ static {
+ defaultInstance = new MessageKey(true);
+ defaultInstance.initFields();
+ }
+
+ // @@protoc_insertion_point(class_scope:textsecure.SessionStructure.Chain.MessageKey)
+ }
+
+ private int bitField0_;
+ // optional bytes senderEphemeral = 1;
+ public static final int SENDEREPHEMERAL_FIELD_NUMBER = 1;
+ private com.google.protobuf.ByteString senderEphemeral_;
+ public boolean hasSenderEphemeral() {
+ return ((bitField0_ & 0x00000001) == 0x00000001);
+ }
+ public com.google.protobuf.ByteString getSenderEphemeral() {
+ return senderEphemeral_;
+ }
+
+ // optional bytes senderEphemeralPrivate = 2;
+ public static final int SENDEREPHEMERALPRIVATE_FIELD_NUMBER = 2;
+ private com.google.protobuf.ByteString senderEphemeralPrivate_;
+ public boolean hasSenderEphemeralPrivate() {
+ return ((bitField0_ & 0x00000002) == 0x00000002);
+ }
+ public com.google.protobuf.ByteString getSenderEphemeralPrivate() {
+ return senderEphemeralPrivate_;
+ }
+
+ // optional .textsecure.SessionStructure.Chain.ChainKey chainKey = 3;
+ public static final int CHAINKEY_FIELD_NUMBER = 3;
+ private org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKey chainKey_;
+ public boolean hasChainKey() {
+ return ((bitField0_ & 0x00000004) == 0x00000004);
+ }
+ public org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKey getChainKey() {
+ return chainKey_;
+ }
+ public org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKeyOrBuilder getChainKeyOrBuilder() {
+ return chainKey_;
+ }
+
+ // repeated .textsecure.SessionStructure.Chain.MessageKey messageKeys = 4;
+ public static final int MESSAGEKEYS_FIELD_NUMBER = 4;
+ private java.util.List messageKeys_;
+ public java.util.List getMessageKeysList() {
+ return messageKeys_;
+ }
+ public java.util.List extends org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKeyOrBuilder>
+ getMessageKeysOrBuilderList() {
+ return messageKeys_;
+ }
+ public int getMessageKeysCount() {
+ return messageKeys_.size();
+ }
+ public org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKey getMessageKeys(int index) {
+ return messageKeys_.get(index);
+ }
+ public org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKeyOrBuilder getMessageKeysOrBuilder(
+ int index) {
+ return messageKeys_.get(index);
+ }
+
+ private void initFields() {
+ senderEphemeral_ = com.google.protobuf.ByteString.EMPTY;
+ senderEphemeralPrivate_ = com.google.protobuf.ByteString.EMPTY;
+ chainKey_ = org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKey.getDefaultInstance();
+ messageKeys_ = java.util.Collections.emptyList();
+ }
+ private byte memoizedIsInitialized = -1;
+ public final boolean isInitialized() {
+ byte isInitialized = memoizedIsInitialized;
+ if (isInitialized != -1) return isInitialized == 1;
+
+ memoizedIsInitialized = 1;
+ return true;
+ }
+
+ public void writeTo(com.google.protobuf.CodedOutputStream output)
+ throws java.io.IOException {
+ getSerializedSize();
+ if (((bitField0_ & 0x00000001) == 0x00000001)) {
+ output.writeBytes(1, senderEphemeral_);
+ }
+ if (((bitField0_ & 0x00000002) == 0x00000002)) {
+ output.writeBytes(2, senderEphemeralPrivate_);
+ }
+ if (((bitField0_ & 0x00000004) == 0x00000004)) {
+ output.writeMessage(3, chainKey_);
+ }
+ for (int i = 0; i < messageKeys_.size(); i++) {
+ output.writeMessage(4, messageKeys_.get(i));
+ }
+ getUnknownFields().writeTo(output);
+ }
+
+ private int memoizedSerializedSize = -1;
+ public int getSerializedSize() {
+ int size = memoizedSerializedSize;
+ if (size != -1) return size;
+
+ size = 0;
+ if (((bitField0_ & 0x00000001) == 0x00000001)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeBytesSize(1, senderEphemeral_);
+ }
+ if (((bitField0_ & 0x00000002) == 0x00000002)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeBytesSize(2, senderEphemeralPrivate_);
+ }
+ if (((bitField0_ & 0x00000004) == 0x00000004)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeMessageSize(3, chainKey_);
+ }
+ for (int i = 0; i < messageKeys_.size(); i++) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeMessageSize(4, messageKeys_.get(i));
+ }
+ size += getUnknownFields().getSerializedSize();
+ memoizedSerializedSize = size;
+ return size;
+ }
+
+ private static final long serialVersionUID = 0L;
+ @java.lang.Override
+ protected java.lang.Object writeReplace()
+ throws java.io.ObjectStreamException {
+ return super.writeReplace();
+ }
+
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain parseFrom(
+ com.google.protobuf.ByteString data)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data).buildParsed();
+ }
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain parseFrom(
+ com.google.protobuf.ByteString data,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data, extensionRegistry)
+ .buildParsed();
+ }
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain parseFrom(byte[] data)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data).buildParsed();
+ }
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain parseFrom(
+ byte[] data,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data, extensionRegistry)
+ .buildParsed();
+ }
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain parseFrom(java.io.InputStream input)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input).buildParsed();
+ }
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain parseFrom(
+ java.io.InputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input, extensionRegistry)
+ .buildParsed();
+ }
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain parseDelimitedFrom(java.io.InputStream input)
+ throws java.io.IOException {
+ Builder builder = newBuilder();
+ if (builder.mergeDelimitedFrom(input)) {
+ return builder.buildParsed();
+ } else {
+ return null;
+ }
+ }
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain parseDelimitedFrom(
+ java.io.InputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ Builder builder = newBuilder();
+ if (builder.mergeDelimitedFrom(input, extensionRegistry)) {
+ return builder.buildParsed();
+ } else {
+ return null;
+ }
+ }
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain parseFrom(
+ com.google.protobuf.CodedInputStream input)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input).buildParsed();
+ }
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain parseFrom(
+ com.google.protobuf.CodedInputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input, extensionRegistry)
+ .buildParsed();
+ }
+
+ public static Builder newBuilder() { return Builder.create(); }
+ public Builder newBuilderForType() { return newBuilder(); }
+ public static Builder newBuilder(org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain prototype) {
+ return newBuilder().mergeFrom(prototype);
+ }
+ public Builder toBuilder() { return newBuilder(this); }
+
+ @java.lang.Override
+ protected Builder newBuilderForType(
+ com.google.protobuf.GeneratedMessage.BuilderParent parent) {
+ Builder builder = new Builder(parent);
+ return builder;
+ }
+ public static final class Builder extends
+ com.google.protobuf.GeneratedMessage.Builder
+ implements org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.ChainOrBuilder {
+ public static final com.google.protobuf.Descriptors.Descriptor
+ getDescriptor() {
+ return org.whispersystems.textsecure.storage.StorageProtos.internal_static_textsecure_SessionStructure_Chain_descriptor;
+ }
+
+ protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+ internalGetFieldAccessorTable() {
+ return org.whispersystems.textsecure.storage.StorageProtos.internal_static_textsecure_SessionStructure_Chain_fieldAccessorTable;
+ }
+
+ // Construct using org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.newBuilder()
+ private Builder() {
+ maybeForceBuilderInitialization();
+ }
+
+ private Builder(BuilderParent parent) {
+ super(parent);
+ maybeForceBuilderInitialization();
+ }
+ private void maybeForceBuilderInitialization() {
+ if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
+ getChainKeyFieldBuilder();
+ getMessageKeysFieldBuilder();
+ }
+ }
+ private static Builder create() {
+ return new Builder();
+ }
+
+ public Builder clear() {
+ super.clear();
+ senderEphemeral_ = com.google.protobuf.ByteString.EMPTY;
+ bitField0_ = (bitField0_ & ~0x00000001);
+ senderEphemeralPrivate_ = com.google.protobuf.ByteString.EMPTY;
+ bitField0_ = (bitField0_ & ~0x00000002);
+ if (chainKeyBuilder_ == null) {
+ chainKey_ = org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKey.getDefaultInstance();
+ } else {
+ chainKeyBuilder_.clear();
+ }
+ bitField0_ = (bitField0_ & ~0x00000004);
+ if (messageKeysBuilder_ == null) {
+ messageKeys_ = java.util.Collections.emptyList();
+ bitField0_ = (bitField0_ & ~0x00000008);
+ } else {
+ messageKeysBuilder_.clear();
+ }
+ return this;
+ }
+
+ public Builder clone() {
+ return create().mergeFrom(buildPartial());
+ }
+
+ public com.google.protobuf.Descriptors.Descriptor
+ getDescriptorForType() {
+ return org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.getDescriptor();
+ }
+
+ public org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain getDefaultInstanceForType() {
+ return org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.getDefaultInstance();
+ }
+
+ public org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain build() {
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain result = buildPartial();
+ if (!result.isInitialized()) {
+ throw newUninitializedMessageException(result);
+ }
+ return result;
+ }
+
+ private org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain buildParsed()
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain result = buildPartial();
+ if (!result.isInitialized()) {
+ throw newUninitializedMessageException(
+ result).asInvalidProtocolBufferException();
+ }
+ return result;
+ }
+
+ public org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain buildPartial() {
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain result = new org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain(this);
+ int from_bitField0_ = bitField0_;
+ int to_bitField0_ = 0;
+ if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
+ to_bitField0_ |= 0x00000001;
+ }
+ result.senderEphemeral_ = senderEphemeral_;
+ if (((from_bitField0_ & 0x00000002) == 0x00000002)) {
+ to_bitField0_ |= 0x00000002;
+ }
+ result.senderEphemeralPrivate_ = senderEphemeralPrivate_;
+ if (((from_bitField0_ & 0x00000004) == 0x00000004)) {
+ to_bitField0_ |= 0x00000004;
+ }
+ if (chainKeyBuilder_ == null) {
+ result.chainKey_ = chainKey_;
+ } else {
+ result.chainKey_ = chainKeyBuilder_.build();
+ }
+ if (messageKeysBuilder_ == null) {
+ if (((bitField0_ & 0x00000008) == 0x00000008)) {
+ messageKeys_ = java.util.Collections.unmodifiableList(messageKeys_);
+ bitField0_ = (bitField0_ & ~0x00000008);
+ }
+ result.messageKeys_ = messageKeys_;
+ } else {
+ result.messageKeys_ = messageKeysBuilder_.build();
+ }
+ result.bitField0_ = to_bitField0_;
+ onBuilt();
+ return result;
+ }
+
+ public Builder mergeFrom(com.google.protobuf.Message other) {
+ if (other instanceof org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain) {
+ return mergeFrom((org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain)other);
+ } else {
+ super.mergeFrom(other);
+ return this;
+ }
+ }
+
+ public Builder mergeFrom(org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain other) {
+ if (other == org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.getDefaultInstance()) return this;
+ if (other.hasSenderEphemeral()) {
+ setSenderEphemeral(other.getSenderEphemeral());
+ }
+ if (other.hasSenderEphemeralPrivate()) {
+ setSenderEphemeralPrivate(other.getSenderEphemeralPrivate());
+ }
+ if (other.hasChainKey()) {
+ mergeChainKey(other.getChainKey());
+ }
+ if (messageKeysBuilder_ == null) {
+ if (!other.messageKeys_.isEmpty()) {
+ if (messageKeys_.isEmpty()) {
+ messageKeys_ = other.messageKeys_;
+ bitField0_ = (bitField0_ & ~0x00000008);
+ } else {
+ ensureMessageKeysIsMutable();
+ messageKeys_.addAll(other.messageKeys_);
+ }
+ onChanged();
+ }
+ } else {
+ if (!other.messageKeys_.isEmpty()) {
+ if (messageKeysBuilder_.isEmpty()) {
+ messageKeysBuilder_.dispose();
+ messageKeysBuilder_ = null;
+ messageKeys_ = other.messageKeys_;
+ bitField0_ = (bitField0_ & ~0x00000008);
+ messageKeysBuilder_ =
+ com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ?
+ getMessageKeysFieldBuilder() : null;
+ } else {
+ messageKeysBuilder_.addAllMessages(other.messageKeys_);
+ }
+ }
+ }
+ this.mergeUnknownFields(other.getUnknownFields());
+ return this;
+ }
+
+ public final boolean isInitialized() {
+ return true;
+ }
+
+ public Builder mergeFrom(
+ com.google.protobuf.CodedInputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ com.google.protobuf.UnknownFieldSet.Builder unknownFields =
+ com.google.protobuf.UnknownFieldSet.newBuilder(
+ this.getUnknownFields());
+ while (true) {
+ int tag = input.readTag();
+ switch (tag) {
+ case 0:
+ this.setUnknownFields(unknownFields.build());
+ onChanged();
+ return this;
+ default: {
+ if (!parseUnknownField(input, unknownFields,
+ extensionRegistry, tag)) {
+ this.setUnknownFields(unknownFields.build());
+ onChanged();
+ return this;
+ }
+ break;
+ }
+ case 10: {
+ bitField0_ |= 0x00000001;
+ senderEphemeral_ = input.readBytes();
+ break;
+ }
+ case 18: {
+ bitField0_ |= 0x00000002;
+ senderEphemeralPrivate_ = input.readBytes();
+ break;
+ }
+ case 26: {
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKey.Builder subBuilder = org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKey.newBuilder();
+ if (hasChainKey()) {
+ subBuilder.mergeFrom(getChainKey());
+ }
+ input.readMessage(subBuilder, extensionRegistry);
+ setChainKey(subBuilder.buildPartial());
+ break;
+ }
+ case 34: {
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKey.Builder subBuilder = org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKey.newBuilder();
+ input.readMessage(subBuilder, extensionRegistry);
+ addMessageKeys(subBuilder.buildPartial());
+ break;
+ }
+ }
+ }
+ }
+
+ private int bitField0_;
+
+ // optional bytes senderEphemeral = 1;
+ private com.google.protobuf.ByteString senderEphemeral_ = com.google.protobuf.ByteString.EMPTY;
+ public boolean hasSenderEphemeral() {
+ return ((bitField0_ & 0x00000001) == 0x00000001);
+ }
+ public com.google.protobuf.ByteString getSenderEphemeral() {
+ return senderEphemeral_;
+ }
+ public Builder setSenderEphemeral(com.google.protobuf.ByteString value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ bitField0_ |= 0x00000001;
+ senderEphemeral_ = value;
+ onChanged();
+ return this;
+ }
+ public Builder clearSenderEphemeral() {
+ bitField0_ = (bitField0_ & ~0x00000001);
+ senderEphemeral_ = getDefaultInstance().getSenderEphemeral();
+ onChanged();
+ return this;
+ }
+
+ // optional bytes senderEphemeralPrivate = 2;
+ private com.google.protobuf.ByteString senderEphemeralPrivate_ = com.google.protobuf.ByteString.EMPTY;
+ public boolean hasSenderEphemeralPrivate() {
+ return ((bitField0_ & 0x00000002) == 0x00000002);
+ }
+ public com.google.protobuf.ByteString getSenderEphemeralPrivate() {
+ return senderEphemeralPrivate_;
+ }
+ public Builder setSenderEphemeralPrivate(com.google.protobuf.ByteString value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ bitField0_ |= 0x00000002;
+ senderEphemeralPrivate_ = value;
+ onChanged();
+ return this;
+ }
+ public Builder clearSenderEphemeralPrivate() {
+ bitField0_ = (bitField0_ & ~0x00000002);
+ senderEphemeralPrivate_ = getDefaultInstance().getSenderEphemeralPrivate();
+ onChanged();
+ return this;
+ }
+
+ // optional .textsecure.SessionStructure.Chain.ChainKey chainKey = 3;
+ private org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKey chainKey_ = org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKey.getDefaultInstance();
+ private com.google.protobuf.SingleFieldBuilder<
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKey, org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKey.Builder, org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKeyOrBuilder> chainKeyBuilder_;
+ public boolean hasChainKey() {
+ return ((bitField0_ & 0x00000004) == 0x00000004);
+ }
+ public org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKey getChainKey() {
+ if (chainKeyBuilder_ == null) {
+ return chainKey_;
+ } else {
+ return chainKeyBuilder_.getMessage();
+ }
+ }
+ public Builder setChainKey(org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKey value) {
+ if (chainKeyBuilder_ == null) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ chainKey_ = value;
+ onChanged();
+ } else {
+ chainKeyBuilder_.setMessage(value);
+ }
+ bitField0_ |= 0x00000004;
+ return this;
+ }
+ public Builder setChainKey(
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKey.Builder builderForValue) {
+ if (chainKeyBuilder_ == null) {
+ chainKey_ = builderForValue.build();
+ onChanged();
+ } else {
+ chainKeyBuilder_.setMessage(builderForValue.build());
+ }
+ bitField0_ |= 0x00000004;
+ return this;
+ }
+ public Builder mergeChainKey(org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKey value) {
+ if (chainKeyBuilder_ == null) {
+ if (((bitField0_ & 0x00000004) == 0x00000004) &&
+ chainKey_ != org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKey.getDefaultInstance()) {
+ chainKey_ =
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKey.newBuilder(chainKey_).mergeFrom(value).buildPartial();
+ } else {
+ chainKey_ = value;
+ }
+ onChanged();
+ } else {
+ chainKeyBuilder_.mergeFrom(value);
+ }
+ bitField0_ |= 0x00000004;
+ return this;
+ }
+ public Builder clearChainKey() {
+ if (chainKeyBuilder_ == null) {
+ chainKey_ = org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKey.getDefaultInstance();
+ onChanged();
+ } else {
+ chainKeyBuilder_.clear();
+ }
+ bitField0_ = (bitField0_ & ~0x00000004);
+ return this;
+ }
+ public org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKey.Builder getChainKeyBuilder() {
+ bitField0_ |= 0x00000004;
+ onChanged();
+ return getChainKeyFieldBuilder().getBuilder();
+ }
+ public org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKeyOrBuilder getChainKeyOrBuilder() {
+ if (chainKeyBuilder_ != null) {
+ return chainKeyBuilder_.getMessageOrBuilder();
+ } else {
+ return chainKey_;
+ }
+ }
+ private com.google.protobuf.SingleFieldBuilder<
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKey, org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKey.Builder, org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKeyOrBuilder>
+ getChainKeyFieldBuilder() {
+ if (chainKeyBuilder_ == null) {
+ chainKeyBuilder_ = new com.google.protobuf.SingleFieldBuilder<
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKey, org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKey.Builder, org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKeyOrBuilder>(
+ chainKey_,
+ getParentForChildren(),
+ isClean());
+ chainKey_ = null;
+ }
+ return chainKeyBuilder_;
+ }
+
+ // repeated .textsecure.SessionStructure.Chain.MessageKey messageKeys = 4;
+ private java.util.List messageKeys_ =
+ java.util.Collections.emptyList();
+ private void ensureMessageKeysIsMutable() {
+ if (!((bitField0_ & 0x00000008) == 0x00000008)) {
+ messageKeys_ = new java.util.ArrayList(messageKeys_);
+ bitField0_ |= 0x00000008;
+ }
+ }
+
+ private com.google.protobuf.RepeatedFieldBuilder<
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKey, org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKey.Builder, org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKeyOrBuilder> messageKeysBuilder_;
+
+ public java.util.List getMessageKeysList() {
+ if (messageKeysBuilder_ == null) {
+ return java.util.Collections.unmodifiableList(messageKeys_);
+ } else {
+ return messageKeysBuilder_.getMessageList();
+ }
+ }
+ public int getMessageKeysCount() {
+ if (messageKeysBuilder_ == null) {
+ return messageKeys_.size();
+ } else {
+ return messageKeysBuilder_.getCount();
+ }
+ }
+ public org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKey getMessageKeys(int index) {
+ if (messageKeysBuilder_ == null) {
+ return messageKeys_.get(index);
+ } else {
+ return messageKeysBuilder_.getMessage(index);
+ }
+ }
+ public Builder setMessageKeys(
+ int index, org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKey value) {
+ if (messageKeysBuilder_ == null) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ ensureMessageKeysIsMutable();
+ messageKeys_.set(index, value);
+ onChanged();
+ } else {
+ messageKeysBuilder_.setMessage(index, value);
+ }
+ return this;
+ }
+ public Builder setMessageKeys(
+ int index, org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKey.Builder builderForValue) {
+ if (messageKeysBuilder_ == null) {
+ ensureMessageKeysIsMutable();
+ messageKeys_.set(index, builderForValue.build());
+ onChanged();
+ } else {
+ messageKeysBuilder_.setMessage(index, builderForValue.build());
+ }
+ return this;
+ }
+ public Builder addMessageKeys(org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKey value) {
+ if (messageKeysBuilder_ == null) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ ensureMessageKeysIsMutable();
+ messageKeys_.add(value);
+ onChanged();
+ } else {
+ messageKeysBuilder_.addMessage(value);
+ }
+ return this;
+ }
+ public Builder addMessageKeys(
+ int index, org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKey value) {
+ if (messageKeysBuilder_ == null) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ ensureMessageKeysIsMutable();
+ messageKeys_.add(index, value);
+ onChanged();
+ } else {
+ messageKeysBuilder_.addMessage(index, value);
+ }
+ return this;
+ }
+ public Builder addMessageKeys(
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKey.Builder builderForValue) {
+ if (messageKeysBuilder_ == null) {
+ ensureMessageKeysIsMutable();
+ messageKeys_.add(builderForValue.build());
+ onChanged();
+ } else {
+ messageKeysBuilder_.addMessage(builderForValue.build());
+ }
+ return this;
+ }
+ public Builder addMessageKeys(
+ int index, org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKey.Builder builderForValue) {
+ if (messageKeysBuilder_ == null) {
+ ensureMessageKeysIsMutable();
+ messageKeys_.add(index, builderForValue.build());
+ onChanged();
+ } else {
+ messageKeysBuilder_.addMessage(index, builderForValue.build());
+ }
+ return this;
+ }
+ public Builder addAllMessageKeys(
+ java.lang.Iterable extends org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKey> values) {
+ if (messageKeysBuilder_ == null) {
+ ensureMessageKeysIsMutable();
+ super.addAll(values, messageKeys_);
+ onChanged();
+ } else {
+ messageKeysBuilder_.addAllMessages(values);
+ }
+ return this;
+ }
+ public Builder clearMessageKeys() {
+ if (messageKeysBuilder_ == null) {
+ messageKeys_ = java.util.Collections.emptyList();
+ bitField0_ = (bitField0_ & ~0x00000008);
+ onChanged();
+ } else {
+ messageKeysBuilder_.clear();
+ }
+ return this;
+ }
+ public Builder removeMessageKeys(int index) {
+ if (messageKeysBuilder_ == null) {
+ ensureMessageKeysIsMutable();
+ messageKeys_.remove(index);
+ onChanged();
+ } else {
+ messageKeysBuilder_.remove(index);
+ }
+ return this;
+ }
+ public org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKey.Builder getMessageKeysBuilder(
+ int index) {
+ return getMessageKeysFieldBuilder().getBuilder(index);
+ }
+ public org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKeyOrBuilder getMessageKeysOrBuilder(
+ int index) {
+ if (messageKeysBuilder_ == null) {
+ return messageKeys_.get(index); } else {
+ return messageKeysBuilder_.getMessageOrBuilder(index);
+ }
+ }
+ public java.util.List extends org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKeyOrBuilder>
+ getMessageKeysOrBuilderList() {
+ if (messageKeysBuilder_ != null) {
+ return messageKeysBuilder_.getMessageOrBuilderList();
+ } else {
+ return java.util.Collections.unmodifiableList(messageKeys_);
+ }
+ }
+ public org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKey.Builder addMessageKeysBuilder() {
+ return getMessageKeysFieldBuilder().addBuilder(
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKey.getDefaultInstance());
+ }
+ public org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKey.Builder addMessageKeysBuilder(
+ int index) {
+ return getMessageKeysFieldBuilder().addBuilder(
+ index, org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKey.getDefaultInstance());
+ }
+ public java.util.List
+ getMessageKeysBuilderList() {
+ return getMessageKeysFieldBuilder().getBuilderList();
+ }
+ private com.google.protobuf.RepeatedFieldBuilder<
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKey, org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKey.Builder, org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKeyOrBuilder>
+ getMessageKeysFieldBuilder() {
+ if (messageKeysBuilder_ == null) {
+ messageKeysBuilder_ = new com.google.protobuf.RepeatedFieldBuilder<
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKey, org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKey.Builder, org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKeyOrBuilder>(
+ messageKeys_,
+ ((bitField0_ & 0x00000008) == 0x00000008),
+ getParentForChildren(),
+ isClean());
+ messageKeys_ = null;
+ }
+ return messageKeysBuilder_;
+ }
+
+ // @@protoc_insertion_point(builder_scope:textsecure.SessionStructure.Chain)
+ }
+
+ static {
+ defaultInstance = new Chain(true);
+ defaultInstance.initFields();
+ }
+
+ // @@protoc_insertion_point(class_scope:textsecure.SessionStructure.Chain)
+ }
+
+ public interface PendingKeyExchangeOrBuilder
+ extends com.google.protobuf.MessageOrBuilder {
+
+ // optional uint32 sequence = 1;
+ boolean hasSequence();
+ int getSequence();
+
+ // optional bytes localBaseKey = 2;
+ boolean hasLocalBaseKey();
+ com.google.protobuf.ByteString getLocalBaseKey();
+
+ // optional bytes localBaseKeyPrivate = 3;
+ boolean hasLocalBaseKeyPrivate();
+ com.google.protobuf.ByteString getLocalBaseKeyPrivate();
+
+ // optional bytes localEphemeralKey = 4;
+ boolean hasLocalEphemeralKey();
+ com.google.protobuf.ByteString getLocalEphemeralKey();
+
+ // optional bytes localEphemeralKeyPrivate = 5;
+ boolean hasLocalEphemeralKeyPrivate();
+ com.google.protobuf.ByteString getLocalEphemeralKeyPrivate();
+
+ // optional bytes localIdentityKey = 7;
+ boolean hasLocalIdentityKey();
+ com.google.protobuf.ByteString getLocalIdentityKey();
+
+ // optional bytes localIdentityKeyPrivate = 8;
+ boolean hasLocalIdentityKeyPrivate();
+ com.google.protobuf.ByteString getLocalIdentityKeyPrivate();
+ }
+ public static final class PendingKeyExchange extends
+ com.google.protobuf.GeneratedMessage
+ implements PendingKeyExchangeOrBuilder {
+ // Use PendingKeyExchange.newBuilder() to construct.
+ private PendingKeyExchange(Builder builder) {
+ super(builder);
+ }
+ private PendingKeyExchange(boolean noInit) {}
+
+ private static final PendingKeyExchange defaultInstance;
+ public static PendingKeyExchange getDefaultInstance() {
+ return defaultInstance;
+ }
+
+ public PendingKeyExchange getDefaultInstanceForType() {
+ return defaultInstance;
+ }
+
+ public static final com.google.protobuf.Descriptors.Descriptor
+ getDescriptor() {
+ return org.whispersystems.textsecure.storage.StorageProtos.internal_static_textsecure_SessionStructure_PendingKeyExchange_descriptor;
+ }
+
+ protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+ internalGetFieldAccessorTable() {
+ return org.whispersystems.textsecure.storage.StorageProtos.internal_static_textsecure_SessionStructure_PendingKeyExchange_fieldAccessorTable;
+ }
+
+ private int bitField0_;
+ // optional uint32 sequence = 1;
+ public static final int SEQUENCE_FIELD_NUMBER = 1;
+ private int sequence_;
+ public boolean hasSequence() {
+ return ((bitField0_ & 0x00000001) == 0x00000001);
+ }
+ public int getSequence() {
+ return sequence_;
+ }
+
+ // optional bytes localBaseKey = 2;
+ public static final int LOCALBASEKEY_FIELD_NUMBER = 2;
+ private com.google.protobuf.ByteString localBaseKey_;
+ public boolean hasLocalBaseKey() {
+ return ((bitField0_ & 0x00000002) == 0x00000002);
+ }
+ public com.google.protobuf.ByteString getLocalBaseKey() {
+ return localBaseKey_;
+ }
+
+ // optional bytes localBaseKeyPrivate = 3;
+ public static final int LOCALBASEKEYPRIVATE_FIELD_NUMBER = 3;
+ private com.google.protobuf.ByteString localBaseKeyPrivate_;
+ public boolean hasLocalBaseKeyPrivate() {
+ return ((bitField0_ & 0x00000004) == 0x00000004);
+ }
+ public com.google.protobuf.ByteString getLocalBaseKeyPrivate() {
+ return localBaseKeyPrivate_;
+ }
+
+ // optional bytes localEphemeralKey = 4;
+ public static final int LOCALEPHEMERALKEY_FIELD_NUMBER = 4;
+ private com.google.protobuf.ByteString localEphemeralKey_;
+ public boolean hasLocalEphemeralKey() {
+ return ((bitField0_ & 0x00000008) == 0x00000008);
+ }
+ public com.google.protobuf.ByteString getLocalEphemeralKey() {
+ return localEphemeralKey_;
+ }
+
+ // optional bytes localEphemeralKeyPrivate = 5;
+ public static final int LOCALEPHEMERALKEYPRIVATE_FIELD_NUMBER = 5;
+ private com.google.protobuf.ByteString localEphemeralKeyPrivate_;
+ public boolean hasLocalEphemeralKeyPrivate() {
+ return ((bitField0_ & 0x00000010) == 0x00000010);
+ }
+ public com.google.protobuf.ByteString getLocalEphemeralKeyPrivate() {
+ return localEphemeralKeyPrivate_;
+ }
+
+ // optional bytes localIdentityKey = 7;
+ public static final int LOCALIDENTITYKEY_FIELD_NUMBER = 7;
+ private com.google.protobuf.ByteString localIdentityKey_;
+ public boolean hasLocalIdentityKey() {
+ return ((bitField0_ & 0x00000020) == 0x00000020);
+ }
+ public com.google.protobuf.ByteString getLocalIdentityKey() {
+ return localIdentityKey_;
+ }
+
+ // optional bytes localIdentityKeyPrivate = 8;
+ public static final int LOCALIDENTITYKEYPRIVATE_FIELD_NUMBER = 8;
+ private com.google.protobuf.ByteString localIdentityKeyPrivate_;
+ public boolean hasLocalIdentityKeyPrivate() {
+ return ((bitField0_ & 0x00000040) == 0x00000040);
+ }
+ public com.google.protobuf.ByteString getLocalIdentityKeyPrivate() {
+ return localIdentityKeyPrivate_;
+ }
+
+ private void initFields() {
+ 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;
+ localIdentityKey_ = com.google.protobuf.ByteString.EMPTY;
+ localIdentityKeyPrivate_ = com.google.protobuf.ByteString.EMPTY;
+ }
+ private byte memoizedIsInitialized = -1;
+ public final boolean isInitialized() {
+ byte isInitialized = memoizedIsInitialized;
+ if (isInitialized != -1) return isInitialized == 1;
+
+ memoizedIsInitialized = 1;
+ return true;
+ }
+
+ public void writeTo(com.google.protobuf.CodedOutputStream output)
+ throws java.io.IOException {
+ getSerializedSize();
+ if (((bitField0_ & 0x00000001) == 0x00000001)) {
+ output.writeUInt32(1, sequence_);
+ }
+ if (((bitField0_ & 0x00000002) == 0x00000002)) {
+ output.writeBytes(2, localBaseKey_);
+ }
+ if (((bitField0_ & 0x00000004) == 0x00000004)) {
+ output.writeBytes(3, localBaseKeyPrivate_);
+ }
+ if (((bitField0_ & 0x00000008) == 0x00000008)) {
+ output.writeBytes(4, localEphemeralKey_);
+ }
+ if (((bitField0_ & 0x00000010) == 0x00000010)) {
+ output.writeBytes(5, localEphemeralKeyPrivate_);
+ }
+ if (((bitField0_ & 0x00000020) == 0x00000020)) {
+ output.writeBytes(7, localIdentityKey_);
+ }
+ if (((bitField0_ & 0x00000040) == 0x00000040)) {
+ output.writeBytes(8, localIdentityKeyPrivate_);
+ }
+ getUnknownFields().writeTo(output);
+ }
+
+ private int memoizedSerializedSize = -1;
+ public int getSerializedSize() {
+ int size = memoizedSerializedSize;
+ if (size != -1) return size;
+
+ size = 0;
+ if (((bitField0_ & 0x00000001) == 0x00000001)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeUInt32Size(1, sequence_);
+ }
+ if (((bitField0_ & 0x00000002) == 0x00000002)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeBytesSize(2, localBaseKey_);
+ }
+ if (((bitField0_ & 0x00000004) == 0x00000004)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeBytesSize(3, localBaseKeyPrivate_);
+ }
+ if (((bitField0_ & 0x00000008) == 0x00000008)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeBytesSize(4, localEphemeralKey_);
+ }
+ if (((bitField0_ & 0x00000010) == 0x00000010)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeBytesSize(5, localEphemeralKeyPrivate_);
+ }
+ if (((bitField0_ & 0x00000020) == 0x00000020)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeBytesSize(7, localIdentityKey_);
+ }
+ if (((bitField0_ & 0x00000040) == 0x00000040)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeBytesSize(8, localIdentityKeyPrivate_);
+ }
+ size += getUnknownFields().getSerializedSize();
+ memoizedSerializedSize = size;
+ return size;
+ }
+
+ private static final long serialVersionUID = 0L;
+ @java.lang.Override
+ protected java.lang.Object writeReplace()
+ throws java.io.ObjectStreamException {
+ return super.writeReplace();
+ }
+
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange parseFrom(
+ com.google.protobuf.ByteString data)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data).buildParsed();
+ }
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange parseFrom(
+ com.google.protobuf.ByteString data,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data, extensionRegistry)
+ .buildParsed();
+ }
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange parseFrom(byte[] data)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data).buildParsed();
+ }
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange parseFrom(
+ byte[] data,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data, extensionRegistry)
+ .buildParsed();
+ }
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange parseFrom(java.io.InputStream input)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input).buildParsed();
+ }
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange parseFrom(
+ java.io.InputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input, extensionRegistry)
+ .buildParsed();
+ }
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange parseDelimitedFrom(java.io.InputStream input)
+ throws java.io.IOException {
+ Builder builder = newBuilder();
+ if (builder.mergeDelimitedFrom(input)) {
+ return builder.buildParsed();
+ } else {
+ return null;
+ }
+ }
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange parseDelimitedFrom(
+ java.io.InputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ Builder builder = newBuilder();
+ if (builder.mergeDelimitedFrom(input, extensionRegistry)) {
+ return builder.buildParsed();
+ } else {
+ return null;
+ }
+ }
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange parseFrom(
+ com.google.protobuf.CodedInputStream input)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input).buildParsed();
+ }
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange parseFrom(
+ com.google.protobuf.CodedInputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input, extensionRegistry)
+ .buildParsed();
+ }
+
+ public static Builder newBuilder() { return Builder.create(); }
+ public Builder newBuilderForType() { return newBuilder(); }
+ public static Builder newBuilder(org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange prototype) {
+ return newBuilder().mergeFrom(prototype);
+ }
+ public Builder toBuilder() { return newBuilder(this); }
+
+ @java.lang.Override
+ protected Builder newBuilderForType(
+ com.google.protobuf.GeneratedMessage.BuilderParent parent) {
+ Builder builder = new Builder(parent);
+ return builder;
+ }
+ public static final class Builder extends
+ com.google.protobuf.GeneratedMessage.Builder
+ implements org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchangeOrBuilder {
+ public static final com.google.protobuf.Descriptors.Descriptor
+ getDescriptor() {
+ return org.whispersystems.textsecure.storage.StorageProtos.internal_static_textsecure_SessionStructure_PendingKeyExchange_descriptor;
+ }
+
+ protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+ internalGetFieldAccessorTable() {
+ return org.whispersystems.textsecure.storage.StorageProtos.internal_static_textsecure_SessionStructure_PendingKeyExchange_fieldAccessorTable;
+ }
+
+ // Construct using org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange.newBuilder()
+ private Builder() {
+ maybeForceBuilderInitialization();
+ }
+
+ private Builder(BuilderParent parent) {
+ super(parent);
+ maybeForceBuilderInitialization();
+ }
+ private void maybeForceBuilderInitialization() {
+ if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
+ }
+ }
+ private static Builder create() {
+ return new Builder();
+ }
+
+ public Builder clear() {
+ super.clear();
+ sequence_ = 0;
+ bitField0_ = (bitField0_ & ~0x00000001);
+ localBaseKey_ = com.google.protobuf.ByteString.EMPTY;
+ bitField0_ = (bitField0_ & ~0x00000002);
+ localBaseKeyPrivate_ = com.google.protobuf.ByteString.EMPTY;
+ bitField0_ = (bitField0_ & ~0x00000004);
+ localEphemeralKey_ = com.google.protobuf.ByteString.EMPTY;
+ bitField0_ = (bitField0_ & ~0x00000008);
+ localEphemeralKeyPrivate_ = com.google.protobuf.ByteString.EMPTY;
+ bitField0_ = (bitField0_ & ~0x00000010);
+ localIdentityKey_ = com.google.protobuf.ByteString.EMPTY;
+ bitField0_ = (bitField0_ & ~0x00000020);
+ localIdentityKeyPrivate_ = com.google.protobuf.ByteString.EMPTY;
+ bitField0_ = (bitField0_ & ~0x00000040);
+ return this;
+ }
+
+ public Builder clone() {
+ return create().mergeFrom(buildPartial());
+ }
+
+ public com.google.protobuf.Descriptors.Descriptor
+ getDescriptorForType() {
+ return org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange.getDescriptor();
+ }
+
+ public org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange getDefaultInstanceForType() {
+ return org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange.getDefaultInstance();
+ }
+
+ public org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange build() {
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange result = buildPartial();
+ if (!result.isInitialized()) {
+ throw newUninitializedMessageException(result);
+ }
+ return result;
+ }
+
+ private org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange buildParsed()
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange result = buildPartial();
+ if (!result.isInitialized()) {
+ throw newUninitializedMessageException(
+ result).asInvalidProtocolBufferException();
+ }
+ return result;
+ }
+
+ public org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange buildPartial() {
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange result = new org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange(this);
+ int from_bitField0_ = bitField0_;
+ int to_bitField0_ = 0;
+ if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
+ to_bitField0_ |= 0x00000001;
+ }
+ result.sequence_ = sequence_;
+ if (((from_bitField0_ & 0x00000002) == 0x00000002)) {
+ to_bitField0_ |= 0x00000002;
+ }
+ result.localBaseKey_ = localBaseKey_;
+ if (((from_bitField0_ & 0x00000004) == 0x00000004)) {
+ to_bitField0_ |= 0x00000004;
+ }
+ result.localBaseKeyPrivate_ = localBaseKeyPrivate_;
+ if (((from_bitField0_ & 0x00000008) == 0x00000008)) {
+ to_bitField0_ |= 0x00000008;
+ }
+ result.localEphemeralKey_ = localEphemeralKey_;
+ if (((from_bitField0_ & 0x00000010) == 0x00000010)) {
+ to_bitField0_ |= 0x00000010;
+ }
+ result.localEphemeralKeyPrivate_ = localEphemeralKeyPrivate_;
+ if (((from_bitField0_ & 0x00000020) == 0x00000020)) {
+ to_bitField0_ |= 0x00000020;
+ }
+ result.localIdentityKey_ = localIdentityKey_;
+ if (((from_bitField0_ & 0x00000040) == 0x00000040)) {
+ to_bitField0_ |= 0x00000040;
+ }
+ result.localIdentityKeyPrivate_ = localIdentityKeyPrivate_;
+ result.bitField0_ = to_bitField0_;
+ onBuilt();
+ return result;
+ }
+
+ public Builder mergeFrom(com.google.protobuf.Message other) {
+ if (other instanceof org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange) {
+ return mergeFrom((org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange)other);
+ } else {
+ super.mergeFrom(other);
+ return this;
+ }
+ }
+
+ public Builder mergeFrom(org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange other) {
+ if (other == org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange.getDefaultInstance()) return this;
+ if (other.hasSequence()) {
+ setSequence(other.getSequence());
+ }
+ if (other.hasLocalBaseKey()) {
+ setLocalBaseKey(other.getLocalBaseKey());
+ }
+ if (other.hasLocalBaseKeyPrivate()) {
+ setLocalBaseKeyPrivate(other.getLocalBaseKeyPrivate());
+ }
+ if (other.hasLocalEphemeralKey()) {
+ setLocalEphemeralKey(other.getLocalEphemeralKey());
+ }
+ if (other.hasLocalEphemeralKeyPrivate()) {
+ setLocalEphemeralKeyPrivate(other.getLocalEphemeralKeyPrivate());
+ }
+ if (other.hasLocalIdentityKey()) {
+ setLocalIdentityKey(other.getLocalIdentityKey());
+ }
+ if (other.hasLocalIdentityKeyPrivate()) {
+ setLocalIdentityKeyPrivate(other.getLocalIdentityKeyPrivate());
+ }
+ this.mergeUnknownFields(other.getUnknownFields());
+ return this;
+ }
+
+ public final boolean isInitialized() {
+ return true;
+ }
+
+ public Builder mergeFrom(
+ com.google.protobuf.CodedInputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ com.google.protobuf.UnknownFieldSet.Builder unknownFields =
+ com.google.protobuf.UnknownFieldSet.newBuilder(
+ this.getUnknownFields());
+ while (true) {
+ int tag = input.readTag();
+ switch (tag) {
+ case 0:
+ this.setUnknownFields(unknownFields.build());
+ onChanged();
+ return this;
+ default: {
+ if (!parseUnknownField(input, unknownFields,
+ extensionRegistry, tag)) {
+ this.setUnknownFields(unknownFields.build());
+ onChanged();
+ return this;
+ }
+ break;
+ }
+ case 8: {
+ bitField0_ |= 0x00000001;
+ sequence_ = input.readUInt32();
+ break;
+ }
+ case 18: {
+ bitField0_ |= 0x00000002;
+ localBaseKey_ = input.readBytes();
+ break;
+ }
+ case 26: {
+ bitField0_ |= 0x00000004;
+ localBaseKeyPrivate_ = input.readBytes();
+ break;
+ }
+ case 34: {
+ bitField0_ |= 0x00000008;
+ localEphemeralKey_ = input.readBytes();
+ break;
+ }
+ case 42: {
+ bitField0_ |= 0x00000010;
+ localEphemeralKeyPrivate_ = input.readBytes();
+ break;
+ }
+ case 58: {
+ bitField0_ |= 0x00000020;
+ localIdentityKey_ = input.readBytes();
+ break;
+ }
+ case 66: {
+ bitField0_ |= 0x00000040;
+ localIdentityKeyPrivate_ = input.readBytes();
+ break;
+ }
+ }
+ }
+ }
+
+ private int bitField0_;
+
+ // optional uint32 sequence = 1;
+ private int sequence_ ;
+ public boolean hasSequence() {
+ return ((bitField0_ & 0x00000001) == 0x00000001);
+ }
+ public int getSequence() {
+ return sequence_;
+ }
+ public Builder setSequence(int value) {
+ bitField0_ |= 0x00000001;
+ sequence_ = value;
+ onChanged();
+ return this;
+ }
+ public Builder clearSequence() {
+ bitField0_ = (bitField0_ & ~0x00000001);
+ sequence_ = 0;
+ onChanged();
+ return this;
+ }
+
+ // optional bytes localBaseKey = 2;
+ private com.google.protobuf.ByteString localBaseKey_ = com.google.protobuf.ByteString.EMPTY;
+ public boolean hasLocalBaseKey() {
+ return ((bitField0_ & 0x00000002) == 0x00000002);
+ }
+ public com.google.protobuf.ByteString getLocalBaseKey() {
+ return localBaseKey_;
+ }
+ public Builder setLocalBaseKey(com.google.protobuf.ByteString value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ bitField0_ |= 0x00000002;
+ localBaseKey_ = value;
+ onChanged();
+ return this;
+ }
+ public Builder clearLocalBaseKey() {
+ bitField0_ = (bitField0_ & ~0x00000002);
+ localBaseKey_ = getDefaultInstance().getLocalBaseKey();
+ onChanged();
+ return this;
+ }
+
+ // optional bytes localBaseKeyPrivate = 3;
+ private com.google.protobuf.ByteString localBaseKeyPrivate_ = com.google.protobuf.ByteString.EMPTY;
+ public boolean hasLocalBaseKeyPrivate() {
+ return ((bitField0_ & 0x00000004) == 0x00000004);
+ }
+ public com.google.protobuf.ByteString getLocalBaseKeyPrivate() {
+ return localBaseKeyPrivate_;
+ }
+ public Builder setLocalBaseKeyPrivate(com.google.protobuf.ByteString value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ bitField0_ |= 0x00000004;
+ localBaseKeyPrivate_ = value;
+ onChanged();
+ return this;
+ }
+ public Builder clearLocalBaseKeyPrivate() {
+ bitField0_ = (bitField0_ & ~0x00000004);
+ localBaseKeyPrivate_ = getDefaultInstance().getLocalBaseKeyPrivate();
+ onChanged();
+ return this;
+ }
+
+ // optional bytes localEphemeralKey = 4;
+ private com.google.protobuf.ByteString localEphemeralKey_ = com.google.protobuf.ByteString.EMPTY;
+ public boolean hasLocalEphemeralKey() {
+ return ((bitField0_ & 0x00000008) == 0x00000008);
+ }
+ public com.google.protobuf.ByteString getLocalEphemeralKey() {
+ return localEphemeralKey_;
+ }
+ public Builder setLocalEphemeralKey(com.google.protobuf.ByteString value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ bitField0_ |= 0x00000008;
+ localEphemeralKey_ = value;
+ onChanged();
+ return this;
+ }
+ public Builder clearLocalEphemeralKey() {
+ bitField0_ = (bitField0_ & ~0x00000008);
+ localEphemeralKey_ = getDefaultInstance().getLocalEphemeralKey();
+ onChanged();
+ return this;
+ }
+
+ // optional bytes localEphemeralKeyPrivate = 5;
+ private com.google.protobuf.ByteString localEphemeralKeyPrivate_ = com.google.protobuf.ByteString.EMPTY;
+ public boolean hasLocalEphemeralKeyPrivate() {
+ return ((bitField0_ & 0x00000010) == 0x00000010);
+ }
+ public com.google.protobuf.ByteString getLocalEphemeralKeyPrivate() {
+ return localEphemeralKeyPrivate_;
+ }
+ public Builder setLocalEphemeralKeyPrivate(com.google.protobuf.ByteString value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ bitField0_ |= 0x00000010;
+ localEphemeralKeyPrivate_ = value;
+ onChanged();
+ return this;
+ }
+ public Builder clearLocalEphemeralKeyPrivate() {
+ bitField0_ = (bitField0_ & ~0x00000010);
+ localEphemeralKeyPrivate_ = getDefaultInstance().getLocalEphemeralKeyPrivate();
+ onChanged();
+ return this;
+ }
+
+ // optional bytes localIdentityKey = 7;
+ private com.google.protobuf.ByteString localIdentityKey_ = com.google.protobuf.ByteString.EMPTY;
+ public boolean hasLocalIdentityKey() {
+ return ((bitField0_ & 0x00000020) == 0x00000020);
+ }
+ public com.google.protobuf.ByteString getLocalIdentityKey() {
+ return localIdentityKey_;
+ }
+ public Builder setLocalIdentityKey(com.google.protobuf.ByteString value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ bitField0_ |= 0x00000020;
+ localIdentityKey_ = value;
+ onChanged();
+ return this;
+ }
+ public Builder clearLocalIdentityKey() {
+ bitField0_ = (bitField0_ & ~0x00000020);
+ localIdentityKey_ = getDefaultInstance().getLocalIdentityKey();
+ onChanged();
+ return this;
+ }
+
+ // optional bytes localIdentityKeyPrivate = 8;
+ private com.google.protobuf.ByteString localIdentityKeyPrivate_ = com.google.protobuf.ByteString.EMPTY;
+ public boolean hasLocalIdentityKeyPrivate() {
+ return ((bitField0_ & 0x00000040) == 0x00000040);
+ }
+ public com.google.protobuf.ByteString getLocalIdentityKeyPrivate() {
+ return localIdentityKeyPrivate_;
+ }
+ public Builder setLocalIdentityKeyPrivate(com.google.protobuf.ByteString value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ bitField0_ |= 0x00000040;
+ localIdentityKeyPrivate_ = value;
+ onChanged();
+ return this;
+ }
+ public Builder clearLocalIdentityKeyPrivate() {
+ bitField0_ = (bitField0_ & ~0x00000040);
+ localIdentityKeyPrivate_ = getDefaultInstance().getLocalIdentityKeyPrivate();
+ onChanged();
+ return this;
+ }
+
+ // @@protoc_insertion_point(builder_scope:textsecure.SessionStructure.PendingKeyExchange)
+ }
+
+ static {
+ defaultInstance = new PendingKeyExchange(true);
+ defaultInstance.initFields();
+ }
+
+ // @@protoc_insertion_point(class_scope:textsecure.SessionStructure.PendingKeyExchange)
+ }
+
+ public interface PendingPreKeyOrBuilder
+ extends com.google.protobuf.MessageOrBuilder {
+
+ // optional uint32 preKeyId = 1;
+ boolean hasPreKeyId();
+ int getPreKeyId();
+
+ // optional bytes baseKey = 2;
+ boolean hasBaseKey();
+ com.google.protobuf.ByteString getBaseKey();
+ }
+ public static final class PendingPreKey extends
+ com.google.protobuf.GeneratedMessage
+ implements PendingPreKeyOrBuilder {
+ // Use PendingPreKey.newBuilder() to construct.
+ private PendingPreKey(Builder builder) {
+ super(builder);
+ }
+ private PendingPreKey(boolean noInit) {}
+
+ private static final PendingPreKey defaultInstance;
+ public static PendingPreKey getDefaultInstance() {
+ return defaultInstance;
+ }
+
+ public PendingPreKey getDefaultInstanceForType() {
+ return defaultInstance;
+ }
+
+ public static final com.google.protobuf.Descriptors.Descriptor
+ getDescriptor() {
+ return org.whispersystems.textsecure.storage.StorageProtos.internal_static_textsecure_SessionStructure_PendingPreKey_descriptor;
+ }
+
+ protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+ internalGetFieldAccessorTable() {
+ return org.whispersystems.textsecure.storage.StorageProtos.internal_static_textsecure_SessionStructure_PendingPreKey_fieldAccessorTable;
+ }
+
+ private int bitField0_;
+ // optional uint32 preKeyId = 1;
+ public static final int PREKEYID_FIELD_NUMBER = 1;
+ private int preKeyId_;
+ public boolean hasPreKeyId() {
+ return ((bitField0_ & 0x00000001) == 0x00000001);
+ }
+ public int getPreKeyId() {
+ return preKeyId_;
+ }
+
+ // optional bytes baseKey = 2;
+ public static final int BASEKEY_FIELD_NUMBER = 2;
+ private com.google.protobuf.ByteString baseKey_;
+ public boolean hasBaseKey() {
+ return ((bitField0_ & 0x00000002) == 0x00000002);
+ }
+ public com.google.protobuf.ByteString getBaseKey() {
+ return baseKey_;
+ }
+
+ private void initFields() {
+ preKeyId_ = 0;
+ baseKey_ = com.google.protobuf.ByteString.EMPTY;
+ }
+ private byte memoizedIsInitialized = -1;
+ public final boolean isInitialized() {
+ byte isInitialized = memoizedIsInitialized;
+ if (isInitialized != -1) return isInitialized == 1;
+
+ memoizedIsInitialized = 1;
+ return true;
+ }
+
+ public void writeTo(com.google.protobuf.CodedOutputStream output)
+ throws java.io.IOException {
+ getSerializedSize();
+ if (((bitField0_ & 0x00000001) == 0x00000001)) {
+ output.writeUInt32(1, preKeyId_);
+ }
+ if (((bitField0_ & 0x00000002) == 0x00000002)) {
+ output.writeBytes(2, baseKey_);
+ }
+ getUnknownFields().writeTo(output);
+ }
+
+ private int memoizedSerializedSize = -1;
+ public int getSerializedSize() {
+ int size = memoizedSerializedSize;
+ if (size != -1) return size;
+
+ size = 0;
+ if (((bitField0_ & 0x00000001) == 0x00000001)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeUInt32Size(1, preKeyId_);
+ }
+ if (((bitField0_ & 0x00000002) == 0x00000002)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeBytesSize(2, baseKey_);
+ }
+ size += getUnknownFields().getSerializedSize();
+ memoizedSerializedSize = size;
+ return size;
+ }
+
+ private static final long serialVersionUID = 0L;
+ @java.lang.Override
+ protected java.lang.Object writeReplace()
+ throws java.io.ObjectStreamException {
+ return super.writeReplace();
+ }
+
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey parseFrom(
+ com.google.protobuf.ByteString data)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data).buildParsed();
+ }
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey parseFrom(
+ com.google.protobuf.ByteString data,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data, extensionRegistry)
+ .buildParsed();
+ }
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey parseFrom(byte[] data)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data).buildParsed();
+ }
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey parseFrom(
+ byte[] data,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data, extensionRegistry)
+ .buildParsed();
+ }
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey parseFrom(java.io.InputStream input)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input).buildParsed();
+ }
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey parseFrom(
+ java.io.InputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input, extensionRegistry)
+ .buildParsed();
+ }
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey parseDelimitedFrom(java.io.InputStream input)
+ throws java.io.IOException {
+ Builder builder = newBuilder();
+ if (builder.mergeDelimitedFrom(input)) {
+ return builder.buildParsed();
+ } else {
+ return null;
+ }
+ }
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey parseDelimitedFrom(
+ java.io.InputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ Builder builder = newBuilder();
+ if (builder.mergeDelimitedFrom(input, extensionRegistry)) {
+ return builder.buildParsed();
+ } else {
+ return null;
+ }
+ }
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey parseFrom(
+ com.google.protobuf.CodedInputStream input)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input).buildParsed();
+ }
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey parseFrom(
+ com.google.protobuf.CodedInputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input, extensionRegistry)
+ .buildParsed();
+ }
+
+ public static Builder newBuilder() { return Builder.create(); }
+ public Builder newBuilderForType() { return newBuilder(); }
+ public static Builder newBuilder(org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey prototype) {
+ return newBuilder().mergeFrom(prototype);
+ }
+ public Builder toBuilder() { return newBuilder(this); }
+
+ @java.lang.Override
+ protected Builder newBuilderForType(
+ com.google.protobuf.GeneratedMessage.BuilderParent parent) {
+ Builder builder = new Builder(parent);
+ return builder;
+ }
+ public static final class Builder extends
+ com.google.protobuf.GeneratedMessage.Builder
+ implements org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKeyOrBuilder {
+ public static final com.google.protobuf.Descriptors.Descriptor
+ getDescriptor() {
+ return org.whispersystems.textsecure.storage.StorageProtos.internal_static_textsecure_SessionStructure_PendingPreKey_descriptor;
+ }
+
+ protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+ internalGetFieldAccessorTable() {
+ return org.whispersystems.textsecure.storage.StorageProtos.internal_static_textsecure_SessionStructure_PendingPreKey_fieldAccessorTable;
+ }
+
+ // Construct using org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey.newBuilder()
+ private Builder() {
+ maybeForceBuilderInitialization();
+ }
+
+ private Builder(BuilderParent parent) {
+ super(parent);
+ maybeForceBuilderInitialization();
+ }
+ private void maybeForceBuilderInitialization() {
+ if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
+ }
+ }
+ private static Builder create() {
+ return new Builder();
+ }
+
+ public Builder clear() {
+ super.clear();
+ preKeyId_ = 0;
+ bitField0_ = (bitField0_ & ~0x00000001);
+ baseKey_ = com.google.protobuf.ByteString.EMPTY;
+ bitField0_ = (bitField0_ & ~0x00000002);
+ return this;
+ }
+
+ public Builder clone() {
+ return create().mergeFrom(buildPartial());
+ }
+
+ public com.google.protobuf.Descriptors.Descriptor
+ getDescriptorForType() {
+ return org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey.getDescriptor();
+ }
+
+ public org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey getDefaultInstanceForType() {
+ return org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey.getDefaultInstance();
+ }
+
+ public org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey build() {
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey result = buildPartial();
+ if (!result.isInitialized()) {
+ throw newUninitializedMessageException(result);
+ }
+ return result;
+ }
+
+ private org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey buildParsed()
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey result = buildPartial();
+ if (!result.isInitialized()) {
+ throw newUninitializedMessageException(
+ result).asInvalidProtocolBufferException();
+ }
+ return result;
+ }
+
+ public org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey buildPartial() {
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey result = new org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey(this);
+ int from_bitField0_ = bitField0_;
+ int to_bitField0_ = 0;
+ if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
+ to_bitField0_ |= 0x00000001;
+ }
+ result.preKeyId_ = preKeyId_;
+ if (((from_bitField0_ & 0x00000002) == 0x00000002)) {
+ to_bitField0_ |= 0x00000002;
+ }
+ result.baseKey_ = baseKey_;
+ result.bitField0_ = to_bitField0_;
+ onBuilt();
+ return result;
+ }
+
+ public Builder mergeFrom(com.google.protobuf.Message other) {
+ if (other instanceof org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey) {
+ return mergeFrom((org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey)other);
+ } else {
+ super.mergeFrom(other);
+ return this;
+ }
+ }
+
+ public Builder mergeFrom(org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey other) {
+ if (other == org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey.getDefaultInstance()) return this;
+ if (other.hasPreKeyId()) {
+ setPreKeyId(other.getPreKeyId());
+ }
+ if (other.hasBaseKey()) {
+ setBaseKey(other.getBaseKey());
+ }
+ this.mergeUnknownFields(other.getUnknownFields());
+ return this;
+ }
+
+ public final boolean isInitialized() {
+ return true;
+ }
+
+ public Builder mergeFrom(
+ com.google.protobuf.CodedInputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ com.google.protobuf.UnknownFieldSet.Builder unknownFields =
+ com.google.protobuf.UnknownFieldSet.newBuilder(
+ this.getUnknownFields());
+ while (true) {
+ int tag = input.readTag();
+ switch (tag) {
+ case 0:
+ this.setUnknownFields(unknownFields.build());
+ onChanged();
+ return this;
+ default: {
+ if (!parseUnknownField(input, unknownFields,
+ extensionRegistry, tag)) {
+ this.setUnknownFields(unknownFields.build());
+ onChanged();
+ return this;
+ }
+ break;
+ }
+ case 8: {
+ bitField0_ |= 0x00000001;
+ preKeyId_ = input.readUInt32();
+ break;
+ }
+ case 18: {
+ bitField0_ |= 0x00000002;
+ baseKey_ = input.readBytes();
+ break;
+ }
+ }
+ }
+ }
+
+ private int bitField0_;
+
+ // optional uint32 preKeyId = 1;
+ private int preKeyId_ ;
+ public boolean hasPreKeyId() {
+ return ((bitField0_ & 0x00000001) == 0x00000001);
+ }
+ public int getPreKeyId() {
+ return preKeyId_;
+ }
+ public Builder setPreKeyId(int value) {
+ bitField0_ |= 0x00000001;
+ preKeyId_ = value;
+ onChanged();
+ return this;
+ }
+ public Builder clearPreKeyId() {
+ bitField0_ = (bitField0_ & ~0x00000001);
+ preKeyId_ = 0;
+ onChanged();
+ return this;
+ }
+
+ // optional bytes baseKey = 2;
+ private com.google.protobuf.ByteString baseKey_ = com.google.protobuf.ByteString.EMPTY;
+ public boolean hasBaseKey() {
+ return ((bitField0_ & 0x00000002) == 0x00000002);
+ }
+ public com.google.protobuf.ByteString getBaseKey() {
+ return baseKey_;
+ }
+ public Builder setBaseKey(com.google.protobuf.ByteString value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ bitField0_ |= 0x00000002;
+ baseKey_ = value;
+ onChanged();
+ return this;
+ }
+ public Builder clearBaseKey() {
+ bitField0_ = (bitField0_ & ~0x00000002);
+ baseKey_ = getDefaultInstance().getBaseKey();
+ onChanged();
+ return this;
+ }
+
+ // @@protoc_insertion_point(builder_scope:textsecure.SessionStructure.PendingPreKey)
+ }
+
+ static {
+ defaultInstance = new PendingPreKey(true);
+ defaultInstance.initFields();
+ }
+
+ // @@protoc_insertion_point(class_scope:textsecure.SessionStructure.PendingPreKey)
+ }
+
+ private int bitField0_;
+ // optional uint32 sessionVersion = 1;
+ public static final int SESSIONVERSION_FIELD_NUMBER = 1;
+ private int sessionVersion_;
+ public boolean hasSessionVersion() {
+ return ((bitField0_ & 0x00000001) == 0x00000001);
+ }
+ public int getSessionVersion() {
+ return sessionVersion_;
+ }
+
+ // optional bytes localIdentityPublic = 2;
+ public static final int LOCALIDENTITYPUBLIC_FIELD_NUMBER = 2;
+ private com.google.protobuf.ByteString localIdentityPublic_;
+ public boolean hasLocalIdentityPublic() {
+ return ((bitField0_ & 0x00000002) == 0x00000002);
+ }
+ public com.google.protobuf.ByteString getLocalIdentityPublic() {
+ return localIdentityPublic_;
+ }
+
+ // optional bytes remoteIdentityPublic = 3;
+ public static final int REMOTEIDENTITYPUBLIC_FIELD_NUMBER = 3;
+ private com.google.protobuf.ByteString remoteIdentityPublic_;
+ public boolean hasRemoteIdentityPublic() {
+ return ((bitField0_ & 0x00000004) == 0x00000004);
+ }
+ public com.google.protobuf.ByteString getRemoteIdentityPublic() {
+ return remoteIdentityPublic_;
+ }
+
+ // optional bytes rootKey = 4;
+ public static final int ROOTKEY_FIELD_NUMBER = 4;
+ private com.google.protobuf.ByteString rootKey_;
+ public boolean hasRootKey() {
+ return ((bitField0_ & 0x00000008) == 0x00000008);
+ }
+ public com.google.protobuf.ByteString getRootKey() {
+ return rootKey_;
+ }
+
+ // optional uint32 previousCounter = 5;
+ public static final int PREVIOUSCOUNTER_FIELD_NUMBER = 5;
+ private int previousCounter_;
+ public boolean hasPreviousCounter() {
+ return ((bitField0_ & 0x00000010) == 0x00000010);
+ }
+ public int getPreviousCounter() {
+ return previousCounter_;
+ }
+
+ // optional .textsecure.SessionStructure.Chain senderChain = 6;
+ public static final int SENDERCHAIN_FIELD_NUMBER = 6;
+ private org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain senderChain_;
+ public boolean hasSenderChain() {
+ return ((bitField0_ & 0x00000020) == 0x00000020);
+ }
+ public org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain getSenderChain() {
+ return senderChain_;
+ }
+ public org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.ChainOrBuilder getSenderChainOrBuilder() {
+ return senderChain_;
+ }
+
+ // repeated .textsecure.SessionStructure.Chain receiverChains = 7;
+ public static final int RECEIVERCHAINS_FIELD_NUMBER = 7;
+ private java.util.List receiverChains_;
+ public java.util.List getReceiverChainsList() {
+ return receiverChains_;
+ }
+ public java.util.List extends org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.ChainOrBuilder>
+ getReceiverChainsOrBuilderList() {
+ return receiverChains_;
+ }
+ public int getReceiverChainsCount() {
+ return receiverChains_.size();
+ }
+ public org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain getReceiverChains(int index) {
+ return receiverChains_.get(index);
+ }
+ public org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.ChainOrBuilder getReceiverChainsOrBuilder(
+ int index) {
+ return receiverChains_.get(index);
+ }
+
+ // optional .textsecure.SessionStructure.PendingKeyExchange pendingKeyExchange = 8;
+ public static final int PENDINGKEYEXCHANGE_FIELD_NUMBER = 8;
+ private org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange pendingKeyExchange_;
+ public boolean hasPendingKeyExchange() {
+ return ((bitField0_ & 0x00000040) == 0x00000040);
+ }
+ public org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange getPendingKeyExchange() {
+ return pendingKeyExchange_;
+ }
+ public org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchangeOrBuilder getPendingKeyExchangeOrBuilder() {
+ return pendingKeyExchange_;
+ }
+
+ // optional .textsecure.SessionStructure.PendingPreKey pendingPreKey = 9;
+ public static final int PENDINGPREKEY_FIELD_NUMBER = 9;
+ private org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey pendingPreKey_;
+ public boolean hasPendingPreKey() {
+ return ((bitField0_ & 0x00000080) == 0x00000080);
+ }
+ public org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey getPendingPreKey() {
+ return pendingPreKey_;
+ }
+ public org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKeyOrBuilder getPendingPreKeyOrBuilder() {
+ return pendingPreKey_;
+ }
+
+ private void initFields() {
+ sessionVersion_ = 0;
+ localIdentityPublic_ = com.google.protobuf.ByteString.EMPTY;
+ remoteIdentityPublic_ = com.google.protobuf.ByteString.EMPTY;
+ rootKey_ = com.google.protobuf.ByteString.EMPTY;
+ previousCounter_ = 0;
+ senderChain_ = org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.getDefaultInstance();
+ receiverChains_ = java.util.Collections.emptyList();
+ pendingKeyExchange_ = org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange.getDefaultInstance();
+ pendingPreKey_ = org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey.getDefaultInstance();
+ }
+ private byte memoizedIsInitialized = -1;
+ public final boolean isInitialized() {
+ byte isInitialized = memoizedIsInitialized;
+ if (isInitialized != -1) return isInitialized == 1;
+
+ memoizedIsInitialized = 1;
+ return true;
+ }
+
+ public void writeTo(com.google.protobuf.CodedOutputStream output)
+ throws java.io.IOException {
+ getSerializedSize();
+ if (((bitField0_ & 0x00000001) == 0x00000001)) {
+ output.writeUInt32(1, sessionVersion_);
+ }
+ if (((bitField0_ & 0x00000002) == 0x00000002)) {
+ output.writeBytes(2, localIdentityPublic_);
+ }
+ if (((bitField0_ & 0x00000004) == 0x00000004)) {
+ output.writeBytes(3, remoteIdentityPublic_);
+ }
+ if (((bitField0_ & 0x00000008) == 0x00000008)) {
+ output.writeBytes(4, rootKey_);
+ }
+ if (((bitField0_ & 0x00000010) == 0x00000010)) {
+ output.writeUInt32(5, previousCounter_);
+ }
+ if (((bitField0_ & 0x00000020) == 0x00000020)) {
+ output.writeMessage(6, senderChain_);
+ }
+ for (int i = 0; i < receiverChains_.size(); i++) {
+ output.writeMessage(7, receiverChains_.get(i));
+ }
+ if (((bitField0_ & 0x00000040) == 0x00000040)) {
+ output.writeMessage(8, pendingKeyExchange_);
+ }
+ if (((bitField0_ & 0x00000080) == 0x00000080)) {
+ output.writeMessage(9, pendingPreKey_);
+ }
+ getUnknownFields().writeTo(output);
+ }
+
+ private int memoizedSerializedSize = -1;
+ public int getSerializedSize() {
+ int size = memoizedSerializedSize;
+ if (size != -1) return size;
+
+ size = 0;
+ if (((bitField0_ & 0x00000001) == 0x00000001)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeUInt32Size(1, sessionVersion_);
+ }
+ if (((bitField0_ & 0x00000002) == 0x00000002)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeBytesSize(2, localIdentityPublic_);
+ }
+ if (((bitField0_ & 0x00000004) == 0x00000004)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeBytesSize(3, remoteIdentityPublic_);
+ }
+ if (((bitField0_ & 0x00000008) == 0x00000008)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeBytesSize(4, rootKey_);
+ }
+ if (((bitField0_ & 0x00000010) == 0x00000010)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeUInt32Size(5, previousCounter_);
+ }
+ if (((bitField0_ & 0x00000020) == 0x00000020)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeMessageSize(6, senderChain_);
+ }
+ for (int i = 0; i < receiverChains_.size(); i++) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeMessageSize(7, receiverChains_.get(i));
+ }
+ if (((bitField0_ & 0x00000040) == 0x00000040)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeMessageSize(8, pendingKeyExchange_);
+ }
+ if (((bitField0_ & 0x00000080) == 0x00000080)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeMessageSize(9, pendingPreKey_);
+ }
+ size += getUnknownFields().getSerializedSize();
+ memoizedSerializedSize = size;
+ return size;
+ }
+
+ private static final long serialVersionUID = 0L;
+ @java.lang.Override
+ protected java.lang.Object writeReplace()
+ throws java.io.ObjectStreamException {
+ return super.writeReplace();
+ }
+
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure parseFrom(
+ com.google.protobuf.ByteString data)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data).buildParsed();
+ }
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure parseFrom(
+ com.google.protobuf.ByteString data,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data, extensionRegistry)
+ .buildParsed();
+ }
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure parseFrom(byte[] data)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data).buildParsed();
+ }
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure parseFrom(
+ byte[] data,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data, extensionRegistry)
+ .buildParsed();
+ }
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure parseFrom(java.io.InputStream input)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input).buildParsed();
+ }
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure parseFrom(
+ java.io.InputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input, extensionRegistry)
+ .buildParsed();
+ }
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure parseDelimitedFrom(java.io.InputStream input)
+ throws java.io.IOException {
+ Builder builder = newBuilder();
+ if (builder.mergeDelimitedFrom(input)) {
+ return builder.buildParsed();
+ } else {
+ return null;
+ }
+ }
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure parseDelimitedFrom(
+ java.io.InputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ Builder builder = newBuilder();
+ if (builder.mergeDelimitedFrom(input, extensionRegistry)) {
+ return builder.buildParsed();
+ } else {
+ return null;
+ }
+ }
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure parseFrom(
+ com.google.protobuf.CodedInputStream input)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input).buildParsed();
+ }
+ public static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure parseFrom(
+ com.google.protobuf.CodedInputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input, extensionRegistry)
+ .buildParsed();
+ }
+
+ public static Builder newBuilder() { return Builder.create(); }
+ public Builder newBuilderForType() { return newBuilder(); }
+ public static Builder newBuilder(org.whispersystems.textsecure.storage.StorageProtos.SessionStructure prototype) {
+ return newBuilder().mergeFrom(prototype);
+ }
+ public Builder toBuilder() { return newBuilder(this); }
+
+ @java.lang.Override
+ protected Builder newBuilderForType(
+ com.google.protobuf.GeneratedMessage.BuilderParent parent) {
+ Builder builder = new Builder(parent);
+ return builder;
+ }
+ public static final class Builder extends
+ com.google.protobuf.GeneratedMessage.Builder
+ implements org.whispersystems.textsecure.storage.StorageProtos.SessionStructureOrBuilder {
+ public static final com.google.protobuf.Descriptors.Descriptor
+ getDescriptor() {
+ return org.whispersystems.textsecure.storage.StorageProtos.internal_static_textsecure_SessionStructure_descriptor;
+ }
+
+ protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+ internalGetFieldAccessorTable() {
+ return org.whispersystems.textsecure.storage.StorageProtos.internal_static_textsecure_SessionStructure_fieldAccessorTable;
+ }
+
+ // Construct using org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.newBuilder()
+ private Builder() {
+ maybeForceBuilderInitialization();
+ }
+
+ private Builder(BuilderParent parent) {
+ super(parent);
+ maybeForceBuilderInitialization();
+ }
+ private void maybeForceBuilderInitialization() {
+ if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
+ getSenderChainFieldBuilder();
+ getReceiverChainsFieldBuilder();
+ getPendingKeyExchangeFieldBuilder();
+ getPendingPreKeyFieldBuilder();
+ }
+ }
+ private static Builder create() {
+ return new Builder();
+ }
+
+ public Builder clear() {
+ super.clear();
+ sessionVersion_ = 0;
+ bitField0_ = (bitField0_ & ~0x00000001);
+ localIdentityPublic_ = com.google.protobuf.ByteString.EMPTY;
+ bitField0_ = (bitField0_ & ~0x00000002);
+ remoteIdentityPublic_ = com.google.protobuf.ByteString.EMPTY;
+ bitField0_ = (bitField0_ & ~0x00000004);
+ rootKey_ = com.google.protobuf.ByteString.EMPTY;
+ bitField0_ = (bitField0_ & ~0x00000008);
+ previousCounter_ = 0;
+ bitField0_ = (bitField0_ & ~0x00000010);
+ if (senderChainBuilder_ == null) {
+ senderChain_ = org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.getDefaultInstance();
+ } else {
+ senderChainBuilder_.clear();
+ }
+ bitField0_ = (bitField0_ & ~0x00000020);
+ if (receiverChainsBuilder_ == null) {
+ receiverChains_ = java.util.Collections.emptyList();
+ bitField0_ = (bitField0_ & ~0x00000040);
+ } else {
+ receiverChainsBuilder_.clear();
+ }
+ if (pendingKeyExchangeBuilder_ == null) {
+ pendingKeyExchange_ = org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange.getDefaultInstance();
+ } else {
+ pendingKeyExchangeBuilder_.clear();
+ }
+ bitField0_ = (bitField0_ & ~0x00000080);
+ if (pendingPreKeyBuilder_ == null) {
+ pendingPreKey_ = org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey.getDefaultInstance();
+ } else {
+ pendingPreKeyBuilder_.clear();
+ }
+ bitField0_ = (bitField0_ & ~0x00000100);
+ return this;
+ }
+
+ public Builder clone() {
+ return create().mergeFrom(buildPartial());
+ }
+
+ public com.google.protobuf.Descriptors.Descriptor
+ getDescriptorForType() {
+ return org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.getDescriptor();
+ }
+
+ public org.whispersystems.textsecure.storage.StorageProtos.SessionStructure getDefaultInstanceForType() {
+ return org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.getDefaultInstance();
+ }
+
+ public org.whispersystems.textsecure.storage.StorageProtos.SessionStructure build() {
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure result = buildPartial();
+ if (!result.isInitialized()) {
+ throw newUninitializedMessageException(result);
+ }
+ return result;
+ }
+
+ private org.whispersystems.textsecure.storage.StorageProtos.SessionStructure buildParsed()
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure result = buildPartial();
+ if (!result.isInitialized()) {
+ throw newUninitializedMessageException(
+ result).asInvalidProtocolBufferException();
+ }
+ return result;
+ }
+
+ public org.whispersystems.textsecure.storage.StorageProtos.SessionStructure buildPartial() {
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure result = new org.whispersystems.textsecure.storage.StorageProtos.SessionStructure(this);
+ int from_bitField0_ = bitField0_;
+ int to_bitField0_ = 0;
+ if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
+ to_bitField0_ |= 0x00000001;
+ }
+ result.sessionVersion_ = sessionVersion_;
+ if (((from_bitField0_ & 0x00000002) == 0x00000002)) {
+ to_bitField0_ |= 0x00000002;
+ }
+ result.localIdentityPublic_ = localIdentityPublic_;
+ if (((from_bitField0_ & 0x00000004) == 0x00000004)) {
+ to_bitField0_ |= 0x00000004;
+ }
+ result.remoteIdentityPublic_ = remoteIdentityPublic_;
+ if (((from_bitField0_ & 0x00000008) == 0x00000008)) {
+ to_bitField0_ |= 0x00000008;
+ }
+ result.rootKey_ = rootKey_;
+ if (((from_bitField0_ & 0x00000010) == 0x00000010)) {
+ to_bitField0_ |= 0x00000010;
+ }
+ result.previousCounter_ = previousCounter_;
+ if (((from_bitField0_ & 0x00000020) == 0x00000020)) {
+ to_bitField0_ |= 0x00000020;
+ }
+ if (senderChainBuilder_ == null) {
+ result.senderChain_ = senderChain_;
+ } else {
+ result.senderChain_ = senderChainBuilder_.build();
+ }
+ if (receiverChainsBuilder_ == null) {
+ if (((bitField0_ & 0x00000040) == 0x00000040)) {
+ receiverChains_ = java.util.Collections.unmodifiableList(receiverChains_);
+ bitField0_ = (bitField0_ & ~0x00000040);
+ }
+ result.receiverChains_ = receiverChains_;
+ } else {
+ result.receiverChains_ = receiverChainsBuilder_.build();
+ }
+ if (((from_bitField0_ & 0x00000080) == 0x00000080)) {
+ to_bitField0_ |= 0x00000040;
+ }
+ if (pendingKeyExchangeBuilder_ == null) {
+ result.pendingKeyExchange_ = pendingKeyExchange_;
+ } else {
+ result.pendingKeyExchange_ = pendingKeyExchangeBuilder_.build();
+ }
+ if (((from_bitField0_ & 0x00000100) == 0x00000100)) {
+ to_bitField0_ |= 0x00000080;
+ }
+ if (pendingPreKeyBuilder_ == null) {
+ result.pendingPreKey_ = pendingPreKey_;
+ } else {
+ result.pendingPreKey_ = pendingPreKeyBuilder_.build();
+ }
+ result.bitField0_ = to_bitField0_;
+ onBuilt();
+ return result;
+ }
+
+ public Builder mergeFrom(com.google.protobuf.Message other) {
+ if (other instanceof org.whispersystems.textsecure.storage.StorageProtos.SessionStructure) {
+ return mergeFrom((org.whispersystems.textsecure.storage.StorageProtos.SessionStructure)other);
+ } else {
+ super.mergeFrom(other);
+ return this;
+ }
+ }
+
+ public Builder mergeFrom(org.whispersystems.textsecure.storage.StorageProtos.SessionStructure other) {
+ if (other == org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.getDefaultInstance()) return this;
+ if (other.hasSessionVersion()) {
+ setSessionVersion(other.getSessionVersion());
+ }
+ if (other.hasLocalIdentityPublic()) {
+ setLocalIdentityPublic(other.getLocalIdentityPublic());
+ }
+ if (other.hasRemoteIdentityPublic()) {
+ setRemoteIdentityPublic(other.getRemoteIdentityPublic());
+ }
+ if (other.hasRootKey()) {
+ setRootKey(other.getRootKey());
+ }
+ if (other.hasPreviousCounter()) {
+ setPreviousCounter(other.getPreviousCounter());
+ }
+ if (other.hasSenderChain()) {
+ mergeSenderChain(other.getSenderChain());
+ }
+ if (receiverChainsBuilder_ == null) {
+ if (!other.receiverChains_.isEmpty()) {
+ if (receiverChains_.isEmpty()) {
+ receiverChains_ = other.receiverChains_;
+ bitField0_ = (bitField0_ & ~0x00000040);
+ } else {
+ ensureReceiverChainsIsMutable();
+ receiverChains_.addAll(other.receiverChains_);
+ }
+ onChanged();
+ }
+ } else {
+ if (!other.receiverChains_.isEmpty()) {
+ if (receiverChainsBuilder_.isEmpty()) {
+ receiverChainsBuilder_.dispose();
+ receiverChainsBuilder_ = null;
+ receiverChains_ = other.receiverChains_;
+ bitField0_ = (bitField0_ & ~0x00000040);
+ receiverChainsBuilder_ =
+ com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ?
+ getReceiverChainsFieldBuilder() : null;
+ } else {
+ receiverChainsBuilder_.addAllMessages(other.receiverChains_);
+ }
+ }
+ }
+ if (other.hasPendingKeyExchange()) {
+ mergePendingKeyExchange(other.getPendingKeyExchange());
+ }
+ if (other.hasPendingPreKey()) {
+ mergePendingPreKey(other.getPendingPreKey());
+ }
+ this.mergeUnknownFields(other.getUnknownFields());
+ return this;
+ }
+
+ public final boolean isInitialized() {
+ return true;
+ }
+
+ public Builder mergeFrom(
+ com.google.protobuf.CodedInputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ com.google.protobuf.UnknownFieldSet.Builder unknownFields =
+ com.google.protobuf.UnknownFieldSet.newBuilder(
+ this.getUnknownFields());
+ while (true) {
+ int tag = input.readTag();
+ switch (tag) {
+ case 0:
+ this.setUnknownFields(unknownFields.build());
+ onChanged();
+ return this;
+ default: {
+ if (!parseUnknownField(input, unknownFields,
+ extensionRegistry, tag)) {
+ this.setUnknownFields(unknownFields.build());
+ onChanged();
+ return this;
+ }
+ break;
+ }
+ case 8: {
+ bitField0_ |= 0x00000001;
+ sessionVersion_ = input.readUInt32();
+ break;
+ }
+ case 18: {
+ bitField0_ |= 0x00000002;
+ localIdentityPublic_ = input.readBytes();
+ break;
+ }
+ case 26: {
+ bitField0_ |= 0x00000004;
+ remoteIdentityPublic_ = input.readBytes();
+ break;
+ }
+ case 34: {
+ bitField0_ |= 0x00000008;
+ rootKey_ = input.readBytes();
+ break;
+ }
+ case 40: {
+ bitField0_ |= 0x00000010;
+ previousCounter_ = input.readUInt32();
+ break;
+ }
+ case 50: {
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.Builder subBuilder = org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.newBuilder();
+ if (hasSenderChain()) {
+ subBuilder.mergeFrom(getSenderChain());
+ }
+ input.readMessage(subBuilder, extensionRegistry);
+ setSenderChain(subBuilder.buildPartial());
+ break;
+ }
+ case 58: {
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.Builder subBuilder = org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.newBuilder();
+ input.readMessage(subBuilder, extensionRegistry);
+ addReceiverChains(subBuilder.buildPartial());
+ break;
+ }
+ case 66: {
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange.Builder subBuilder = org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange.newBuilder();
+ if (hasPendingKeyExchange()) {
+ subBuilder.mergeFrom(getPendingKeyExchange());
+ }
+ input.readMessage(subBuilder, extensionRegistry);
+ setPendingKeyExchange(subBuilder.buildPartial());
+ break;
+ }
+ case 74: {
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey.Builder subBuilder = org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey.newBuilder();
+ if (hasPendingPreKey()) {
+ subBuilder.mergeFrom(getPendingPreKey());
+ }
+ input.readMessage(subBuilder, extensionRegistry);
+ setPendingPreKey(subBuilder.buildPartial());
+ break;
+ }
+ }
+ }
+ }
+
+ private int bitField0_;
+
+ // optional uint32 sessionVersion = 1;
+ private int sessionVersion_ ;
+ public boolean hasSessionVersion() {
+ return ((bitField0_ & 0x00000001) == 0x00000001);
+ }
+ public int getSessionVersion() {
+ return sessionVersion_;
+ }
+ public Builder setSessionVersion(int value) {
+ bitField0_ |= 0x00000001;
+ sessionVersion_ = value;
+ onChanged();
+ return this;
+ }
+ public Builder clearSessionVersion() {
+ bitField0_ = (bitField0_ & ~0x00000001);
+ sessionVersion_ = 0;
+ onChanged();
+ return this;
+ }
+
+ // optional bytes localIdentityPublic = 2;
+ private com.google.protobuf.ByteString localIdentityPublic_ = com.google.protobuf.ByteString.EMPTY;
+ public boolean hasLocalIdentityPublic() {
+ return ((bitField0_ & 0x00000002) == 0x00000002);
+ }
+ public com.google.protobuf.ByteString getLocalIdentityPublic() {
+ return localIdentityPublic_;
+ }
+ public Builder setLocalIdentityPublic(com.google.protobuf.ByteString value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ bitField0_ |= 0x00000002;
+ localIdentityPublic_ = value;
+ onChanged();
+ return this;
+ }
+ public Builder clearLocalIdentityPublic() {
+ bitField0_ = (bitField0_ & ~0x00000002);
+ localIdentityPublic_ = getDefaultInstance().getLocalIdentityPublic();
+ onChanged();
+ return this;
+ }
+
+ // optional bytes remoteIdentityPublic = 3;
+ private com.google.protobuf.ByteString remoteIdentityPublic_ = com.google.protobuf.ByteString.EMPTY;
+ public boolean hasRemoteIdentityPublic() {
+ return ((bitField0_ & 0x00000004) == 0x00000004);
+ }
+ public com.google.protobuf.ByteString getRemoteIdentityPublic() {
+ return remoteIdentityPublic_;
+ }
+ public Builder setRemoteIdentityPublic(com.google.protobuf.ByteString value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ bitField0_ |= 0x00000004;
+ remoteIdentityPublic_ = value;
+ onChanged();
+ return this;
+ }
+ public Builder clearRemoteIdentityPublic() {
+ bitField0_ = (bitField0_ & ~0x00000004);
+ remoteIdentityPublic_ = getDefaultInstance().getRemoteIdentityPublic();
+ onChanged();
+ return this;
+ }
+
+ // optional bytes rootKey = 4;
+ private com.google.protobuf.ByteString rootKey_ = com.google.protobuf.ByteString.EMPTY;
+ public boolean hasRootKey() {
+ return ((bitField0_ & 0x00000008) == 0x00000008);
+ }
+ public com.google.protobuf.ByteString getRootKey() {
+ return rootKey_;
+ }
+ public Builder setRootKey(com.google.protobuf.ByteString value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ bitField0_ |= 0x00000008;
+ rootKey_ = value;
+ onChanged();
+ return this;
+ }
+ public Builder clearRootKey() {
+ bitField0_ = (bitField0_ & ~0x00000008);
+ rootKey_ = getDefaultInstance().getRootKey();
+ onChanged();
+ return this;
+ }
+
+ // optional uint32 previousCounter = 5;
+ private int previousCounter_ ;
+ public boolean hasPreviousCounter() {
+ return ((bitField0_ & 0x00000010) == 0x00000010);
+ }
+ public int getPreviousCounter() {
+ return previousCounter_;
+ }
+ public Builder setPreviousCounter(int value) {
+ bitField0_ |= 0x00000010;
+ previousCounter_ = value;
+ onChanged();
+ return this;
+ }
+ public Builder clearPreviousCounter() {
+ bitField0_ = (bitField0_ & ~0x00000010);
+ previousCounter_ = 0;
+ onChanged();
+ return this;
+ }
+
+ // optional .textsecure.SessionStructure.Chain senderChain = 6;
+ private org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain senderChain_ = org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.getDefaultInstance();
+ private com.google.protobuf.SingleFieldBuilder<
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain, org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.Builder, org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.ChainOrBuilder> senderChainBuilder_;
+ public boolean hasSenderChain() {
+ return ((bitField0_ & 0x00000020) == 0x00000020);
+ }
+ public org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain getSenderChain() {
+ if (senderChainBuilder_ == null) {
+ return senderChain_;
+ } else {
+ return senderChainBuilder_.getMessage();
+ }
+ }
+ public Builder setSenderChain(org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain value) {
+ if (senderChainBuilder_ == null) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ senderChain_ = value;
+ onChanged();
+ } else {
+ senderChainBuilder_.setMessage(value);
+ }
+ bitField0_ |= 0x00000020;
+ return this;
+ }
+ public Builder setSenderChain(
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.Builder builderForValue) {
+ if (senderChainBuilder_ == null) {
+ senderChain_ = builderForValue.build();
+ onChanged();
+ } else {
+ senderChainBuilder_.setMessage(builderForValue.build());
+ }
+ bitField0_ |= 0x00000020;
+ return this;
+ }
+ public Builder mergeSenderChain(org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain value) {
+ if (senderChainBuilder_ == null) {
+ if (((bitField0_ & 0x00000020) == 0x00000020) &&
+ senderChain_ != org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.getDefaultInstance()) {
+ senderChain_ =
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.newBuilder(senderChain_).mergeFrom(value).buildPartial();
+ } else {
+ senderChain_ = value;
+ }
+ onChanged();
+ } else {
+ senderChainBuilder_.mergeFrom(value);
+ }
+ bitField0_ |= 0x00000020;
+ return this;
+ }
+ public Builder clearSenderChain() {
+ if (senderChainBuilder_ == null) {
+ senderChain_ = org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.getDefaultInstance();
+ onChanged();
+ } else {
+ senderChainBuilder_.clear();
+ }
+ bitField0_ = (bitField0_ & ~0x00000020);
+ return this;
+ }
+ public org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.Builder getSenderChainBuilder() {
+ bitField0_ |= 0x00000020;
+ onChanged();
+ return getSenderChainFieldBuilder().getBuilder();
+ }
+ public org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.ChainOrBuilder getSenderChainOrBuilder() {
+ if (senderChainBuilder_ != null) {
+ return senderChainBuilder_.getMessageOrBuilder();
+ } else {
+ return senderChain_;
+ }
+ }
+ private com.google.protobuf.SingleFieldBuilder<
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain, org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.Builder, org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.ChainOrBuilder>
+ getSenderChainFieldBuilder() {
+ if (senderChainBuilder_ == null) {
+ senderChainBuilder_ = new com.google.protobuf.SingleFieldBuilder<
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain, org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.Builder, org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.ChainOrBuilder>(
+ senderChain_,
+ getParentForChildren(),
+ isClean());
+ senderChain_ = null;
+ }
+ return senderChainBuilder_;
+ }
+
+ // repeated .textsecure.SessionStructure.Chain receiverChains = 7;
+ private java.util.List receiverChains_ =
+ java.util.Collections.emptyList();
+ private void ensureReceiverChainsIsMutable() {
+ if (!((bitField0_ & 0x00000040) == 0x00000040)) {
+ receiverChains_ = new java.util.ArrayList(receiverChains_);
+ bitField0_ |= 0x00000040;
+ }
+ }
+
+ private com.google.protobuf.RepeatedFieldBuilder<
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain, org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.Builder, org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.ChainOrBuilder> receiverChainsBuilder_;
+
+ public java.util.List getReceiverChainsList() {
+ if (receiverChainsBuilder_ == null) {
+ return java.util.Collections.unmodifiableList(receiverChains_);
+ } else {
+ return receiverChainsBuilder_.getMessageList();
+ }
+ }
+ public int getReceiverChainsCount() {
+ if (receiverChainsBuilder_ == null) {
+ return receiverChains_.size();
+ } else {
+ return receiverChainsBuilder_.getCount();
+ }
+ }
+ public org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain getReceiverChains(int index) {
+ if (receiverChainsBuilder_ == null) {
+ return receiverChains_.get(index);
+ } else {
+ return receiverChainsBuilder_.getMessage(index);
+ }
+ }
+ public Builder setReceiverChains(
+ int index, org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain value) {
+ if (receiverChainsBuilder_ == null) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ ensureReceiverChainsIsMutable();
+ receiverChains_.set(index, value);
+ onChanged();
+ } else {
+ receiverChainsBuilder_.setMessage(index, value);
+ }
+ return this;
+ }
+ public Builder setReceiverChains(
+ int index, org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.Builder builderForValue) {
+ if (receiverChainsBuilder_ == null) {
+ ensureReceiverChainsIsMutable();
+ receiverChains_.set(index, builderForValue.build());
+ onChanged();
+ } else {
+ receiverChainsBuilder_.setMessage(index, builderForValue.build());
+ }
+ return this;
+ }
+ public Builder addReceiverChains(org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain value) {
+ if (receiverChainsBuilder_ == null) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ ensureReceiverChainsIsMutable();
+ receiverChains_.add(value);
+ onChanged();
+ } else {
+ receiverChainsBuilder_.addMessage(value);
+ }
+ return this;
+ }
+ public Builder addReceiverChains(
+ int index, org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain value) {
+ if (receiverChainsBuilder_ == null) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ ensureReceiverChainsIsMutable();
+ receiverChains_.add(index, value);
+ onChanged();
+ } else {
+ receiverChainsBuilder_.addMessage(index, value);
+ }
+ return this;
+ }
+ public Builder addReceiverChains(
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.Builder builderForValue) {
+ if (receiverChainsBuilder_ == null) {
+ ensureReceiverChainsIsMutable();
+ receiverChains_.add(builderForValue.build());
+ onChanged();
+ } else {
+ receiverChainsBuilder_.addMessage(builderForValue.build());
+ }
+ return this;
+ }
+ public Builder addReceiverChains(
+ int index, org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.Builder builderForValue) {
+ if (receiverChainsBuilder_ == null) {
+ ensureReceiverChainsIsMutable();
+ receiverChains_.add(index, builderForValue.build());
+ onChanged();
+ } else {
+ receiverChainsBuilder_.addMessage(index, builderForValue.build());
+ }
+ return this;
+ }
+ public Builder addAllReceiverChains(
+ java.lang.Iterable extends org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain> values) {
+ if (receiverChainsBuilder_ == null) {
+ ensureReceiverChainsIsMutable();
+ super.addAll(values, receiverChains_);
+ onChanged();
+ } else {
+ receiverChainsBuilder_.addAllMessages(values);
+ }
+ return this;
+ }
+ public Builder clearReceiverChains() {
+ if (receiverChainsBuilder_ == null) {
+ receiverChains_ = java.util.Collections.emptyList();
+ bitField0_ = (bitField0_ & ~0x00000040);
+ onChanged();
+ } else {
+ receiverChainsBuilder_.clear();
+ }
+ return this;
+ }
+ public Builder removeReceiverChains(int index) {
+ if (receiverChainsBuilder_ == null) {
+ ensureReceiverChainsIsMutable();
+ receiverChains_.remove(index);
+ onChanged();
+ } else {
+ receiverChainsBuilder_.remove(index);
+ }
+ return this;
+ }
+ public org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.Builder getReceiverChainsBuilder(
+ int index) {
+ return getReceiverChainsFieldBuilder().getBuilder(index);
+ }
+ public org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.ChainOrBuilder getReceiverChainsOrBuilder(
+ int index) {
+ if (receiverChainsBuilder_ == null) {
+ return receiverChains_.get(index); } else {
+ return receiverChainsBuilder_.getMessageOrBuilder(index);
+ }
+ }
+ public java.util.List extends org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.ChainOrBuilder>
+ getReceiverChainsOrBuilderList() {
+ if (receiverChainsBuilder_ != null) {
+ return receiverChainsBuilder_.getMessageOrBuilderList();
+ } else {
+ return java.util.Collections.unmodifiableList(receiverChains_);
+ }
+ }
+ public org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.Builder addReceiverChainsBuilder() {
+ return getReceiverChainsFieldBuilder().addBuilder(
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.getDefaultInstance());
+ }
+ public org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.Builder addReceiverChainsBuilder(
+ int index) {
+ return getReceiverChainsFieldBuilder().addBuilder(
+ index, org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.getDefaultInstance());
+ }
+ public java.util.List
+ getReceiverChainsBuilderList() {
+ return getReceiverChainsFieldBuilder().getBuilderList();
+ }
+ private com.google.protobuf.RepeatedFieldBuilder<
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain, org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.Builder, org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.ChainOrBuilder>
+ getReceiverChainsFieldBuilder() {
+ if (receiverChainsBuilder_ == null) {
+ receiverChainsBuilder_ = new com.google.protobuf.RepeatedFieldBuilder<
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain, org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.Builder, org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.ChainOrBuilder>(
+ receiverChains_,
+ ((bitField0_ & 0x00000040) == 0x00000040),
+ getParentForChildren(),
+ isClean());
+ receiverChains_ = null;
+ }
+ return receiverChainsBuilder_;
+ }
+
+ // optional .textsecure.SessionStructure.PendingKeyExchange pendingKeyExchange = 8;
+ private org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange pendingKeyExchange_ = org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange.getDefaultInstance();
+ private com.google.protobuf.SingleFieldBuilder<
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange, org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange.Builder, org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchangeOrBuilder> pendingKeyExchangeBuilder_;
+ public boolean hasPendingKeyExchange() {
+ return ((bitField0_ & 0x00000080) == 0x00000080);
+ }
+ public org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange getPendingKeyExchange() {
+ if (pendingKeyExchangeBuilder_ == null) {
+ return pendingKeyExchange_;
+ } else {
+ return pendingKeyExchangeBuilder_.getMessage();
+ }
+ }
+ public Builder setPendingKeyExchange(org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange value) {
+ if (pendingKeyExchangeBuilder_ == null) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ pendingKeyExchange_ = value;
+ onChanged();
+ } else {
+ pendingKeyExchangeBuilder_.setMessage(value);
+ }
+ bitField0_ |= 0x00000080;
+ return this;
+ }
+ public Builder setPendingKeyExchange(
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange.Builder builderForValue) {
+ if (pendingKeyExchangeBuilder_ == null) {
+ pendingKeyExchange_ = builderForValue.build();
+ onChanged();
+ } else {
+ pendingKeyExchangeBuilder_.setMessage(builderForValue.build());
+ }
+ bitField0_ |= 0x00000080;
+ return this;
+ }
+ public Builder mergePendingKeyExchange(org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange value) {
+ if (pendingKeyExchangeBuilder_ == null) {
+ if (((bitField0_ & 0x00000080) == 0x00000080) &&
+ pendingKeyExchange_ != org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange.getDefaultInstance()) {
+ pendingKeyExchange_ =
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange.newBuilder(pendingKeyExchange_).mergeFrom(value).buildPartial();
+ } else {
+ pendingKeyExchange_ = value;
+ }
+ onChanged();
+ } else {
+ pendingKeyExchangeBuilder_.mergeFrom(value);
+ }
+ bitField0_ |= 0x00000080;
+ return this;
+ }
+ public Builder clearPendingKeyExchange() {
+ if (pendingKeyExchangeBuilder_ == null) {
+ pendingKeyExchange_ = org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange.getDefaultInstance();
+ onChanged();
+ } else {
+ pendingKeyExchangeBuilder_.clear();
+ }
+ bitField0_ = (bitField0_ & ~0x00000080);
+ return this;
+ }
+ public org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange.Builder getPendingKeyExchangeBuilder() {
+ bitField0_ |= 0x00000080;
+ onChanged();
+ return getPendingKeyExchangeFieldBuilder().getBuilder();
+ }
+ public org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchangeOrBuilder getPendingKeyExchangeOrBuilder() {
+ if (pendingKeyExchangeBuilder_ != null) {
+ return pendingKeyExchangeBuilder_.getMessageOrBuilder();
+ } else {
+ return pendingKeyExchange_;
+ }
+ }
+ private com.google.protobuf.SingleFieldBuilder<
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange, org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange.Builder, org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchangeOrBuilder>
+ getPendingKeyExchangeFieldBuilder() {
+ if (pendingKeyExchangeBuilder_ == null) {
+ pendingKeyExchangeBuilder_ = new com.google.protobuf.SingleFieldBuilder<
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange, org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange.Builder, org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchangeOrBuilder>(
+ pendingKeyExchange_,
+ getParentForChildren(),
+ isClean());
+ pendingKeyExchange_ = null;
+ }
+ return pendingKeyExchangeBuilder_;
+ }
+
+ // optional .textsecure.SessionStructure.PendingPreKey pendingPreKey = 9;
+ private org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey pendingPreKey_ = org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey.getDefaultInstance();
+ private com.google.protobuf.SingleFieldBuilder<
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey, org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey.Builder, org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKeyOrBuilder> pendingPreKeyBuilder_;
+ public boolean hasPendingPreKey() {
+ return ((bitField0_ & 0x00000100) == 0x00000100);
+ }
+ public org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey getPendingPreKey() {
+ if (pendingPreKeyBuilder_ == null) {
+ return pendingPreKey_;
+ } else {
+ return pendingPreKeyBuilder_.getMessage();
+ }
+ }
+ public Builder setPendingPreKey(org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey value) {
+ if (pendingPreKeyBuilder_ == null) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ pendingPreKey_ = value;
+ onChanged();
+ } else {
+ pendingPreKeyBuilder_.setMessage(value);
+ }
+ bitField0_ |= 0x00000100;
+ return this;
+ }
+ public Builder setPendingPreKey(
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey.Builder builderForValue) {
+ if (pendingPreKeyBuilder_ == null) {
+ pendingPreKey_ = builderForValue.build();
+ onChanged();
+ } else {
+ pendingPreKeyBuilder_.setMessage(builderForValue.build());
+ }
+ bitField0_ |= 0x00000100;
+ return this;
+ }
+ public Builder mergePendingPreKey(org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey value) {
+ if (pendingPreKeyBuilder_ == null) {
+ if (((bitField0_ & 0x00000100) == 0x00000100) &&
+ pendingPreKey_ != org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey.getDefaultInstance()) {
+ pendingPreKey_ =
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey.newBuilder(pendingPreKey_).mergeFrom(value).buildPartial();
+ } else {
+ pendingPreKey_ = value;
+ }
+ onChanged();
+ } else {
+ pendingPreKeyBuilder_.mergeFrom(value);
+ }
+ bitField0_ |= 0x00000100;
+ return this;
+ }
+ public Builder clearPendingPreKey() {
+ if (pendingPreKeyBuilder_ == null) {
+ pendingPreKey_ = org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey.getDefaultInstance();
+ onChanged();
+ } else {
+ pendingPreKeyBuilder_.clear();
+ }
+ bitField0_ = (bitField0_ & ~0x00000100);
+ return this;
+ }
+ public org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey.Builder getPendingPreKeyBuilder() {
+ bitField0_ |= 0x00000100;
+ onChanged();
+ return getPendingPreKeyFieldBuilder().getBuilder();
+ }
+ public org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKeyOrBuilder getPendingPreKeyOrBuilder() {
+ if (pendingPreKeyBuilder_ != null) {
+ return pendingPreKeyBuilder_.getMessageOrBuilder();
+ } else {
+ return pendingPreKey_;
+ }
+ }
+ private com.google.protobuf.SingleFieldBuilder<
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey, org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey.Builder, org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKeyOrBuilder>
+ getPendingPreKeyFieldBuilder() {
+ if (pendingPreKeyBuilder_ == null) {
+ pendingPreKeyBuilder_ = new com.google.protobuf.SingleFieldBuilder<
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey, org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey.Builder, org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKeyOrBuilder>(
+ pendingPreKey_,
+ getParentForChildren(),
+ isClean());
+ pendingPreKey_ = null;
+ }
+ return pendingPreKeyBuilder_;
+ }
+
+ // @@protoc_insertion_point(builder_scope:textsecure.SessionStructure)
+ }
+
+ static {
+ defaultInstance = new SessionStructure(true);
+ defaultInstance.initFields();
+ }
+
+ // @@protoc_insertion_point(class_scope:textsecure.SessionStructure)
+ }
+
+ private static com.google.protobuf.Descriptors.Descriptor
+ internal_static_textsecure_SessionStructure_descriptor;
+ private static
+ com.google.protobuf.GeneratedMessage.FieldAccessorTable
+ internal_static_textsecure_SessionStructure_fieldAccessorTable;
+ private static com.google.protobuf.Descriptors.Descriptor
+ internal_static_textsecure_SessionStructure_Chain_descriptor;
+ private static
+ com.google.protobuf.GeneratedMessage.FieldAccessorTable
+ internal_static_textsecure_SessionStructure_Chain_fieldAccessorTable;
+ private static com.google.protobuf.Descriptors.Descriptor
+ internal_static_textsecure_SessionStructure_Chain_ChainKey_descriptor;
+ private static
+ com.google.protobuf.GeneratedMessage.FieldAccessorTable
+ internal_static_textsecure_SessionStructure_Chain_ChainKey_fieldAccessorTable;
+ private static com.google.protobuf.Descriptors.Descriptor
+ internal_static_textsecure_SessionStructure_Chain_MessageKey_descriptor;
+ private static
+ com.google.protobuf.GeneratedMessage.FieldAccessorTable
+ internal_static_textsecure_SessionStructure_Chain_MessageKey_fieldAccessorTable;
+ private static com.google.protobuf.Descriptors.Descriptor
+ internal_static_textsecure_SessionStructure_PendingKeyExchange_descriptor;
+ private static
+ com.google.protobuf.GeneratedMessage.FieldAccessorTable
+ internal_static_textsecure_SessionStructure_PendingKeyExchange_fieldAccessorTable;
+ private static com.google.protobuf.Descriptors.Descriptor
+ internal_static_textsecure_SessionStructure_PendingPreKey_descriptor;
+ private static
+ com.google.protobuf.GeneratedMessage.FieldAccessorTable
+ internal_static_textsecure_SessionStructure_PendingPreKey_fieldAccessorTable;
+
+ public static com.google.protobuf.Descriptors.FileDescriptor
+ getDescriptor() {
+ return descriptor;
+ }
+ private static com.google.protobuf.Descriptors.FileDescriptor
+ descriptor;
+ static {
+ java.lang.String[] descriptorData = {
+ "\n\032LocalStorageProtocol.proto\022\ntextsecure" +
+ "\"\312\007\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" +
+ "n\030\006 \001(\0132\".textsecure.SessionStructure.Ch" +
+ "ain\022:\n\016receiverChains\030\007 \003(\0132\".textsecure" +
+ ".SessionStructure.Chain\022K\n\022pendingKeyExc" +
+ "hange\030\010 \001(\0132/.textsecure.SessionStructur" +
+ "e.PendingKeyExchange\022A\n\rpendingPreKey\030\t ",
+ "\001(\0132*.textsecure.SessionStructure.Pendin" +
+ "gPreKey\032\253\002\n\005Chain\022\027\n\017senderEphemeral\030\001 \001" +
+ "(\014\022\036\n\026senderEphemeralPrivate\030\002 \001(\014\022=\n\010ch" +
+ "ainKey\030\003 \001(\0132+.textsecure.SessionStructu" +
+ "re.Chain.ChainKey\022B\n\013messageKeys\030\004 \003(\0132-" +
+ ".textsecure.SessionStructure.Chain.Messa" +
+ "geKey\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\tci" +
+ "pherKey\030\002 \001(\014\022\016\n\006macKey\030\003 \001(\014\032\321\001\n\022Pendin" +
+ "gKeyExchange\022\020\n\010sequence\030\001 \001(\r\022\024\n\014localB",
+ "aseKey\030\002 \001(\014\022\033\n\023localBaseKeyPrivate\030\003 \001(" +
+ "\014\022\031\n\021localEphemeralKey\030\004 \001(\014\022 \n\030localEph" +
+ "emeralKeyPrivate\030\005 \001(\014\022\030\n\020localIdentityK" +
+ "ey\030\007 \001(\014\022\037\n\027localIdentityKeyPrivate\030\010 \001(" +
+ "\014\0322\n\rPendingPreKey\022\020\n\010preKeyId\030\001 \001(\r\022\017\n\007" +
+ "baseKey\030\002 \001(\014B6\n%org.whispersystems.text" +
+ "secure.storageB\rStorageProtos"
+ };
+ com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
+ new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
+ public com.google.protobuf.ExtensionRegistry assignDescriptors(
+ com.google.protobuf.Descriptors.FileDescriptor root) {
+ descriptor = root;
+ internal_static_textsecure_SessionStructure_descriptor =
+ getDescriptor().getMessageTypes().get(0);
+ internal_static_textsecure_SessionStructure_fieldAccessorTable = new
+ com.google.protobuf.GeneratedMessage.FieldAccessorTable(
+ internal_static_textsecure_SessionStructure_descriptor,
+ new java.lang.String[] { "SessionVersion", "LocalIdentityPublic", "RemoteIdentityPublic", "RootKey", "PreviousCounter", "SenderChain", "ReceiverChains", "PendingKeyExchange", "PendingPreKey", },
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.class,
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Builder.class);
+ internal_static_textsecure_SessionStructure_Chain_descriptor =
+ internal_static_textsecure_SessionStructure_descriptor.getNestedTypes().get(0);
+ 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", },
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.class,
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.Builder.class);
+ internal_static_textsecure_SessionStructure_Chain_ChainKey_descriptor =
+ internal_static_textsecure_SessionStructure_Chain_descriptor.getNestedTypes().get(0);
+ internal_static_textsecure_SessionStructure_Chain_ChainKey_fieldAccessorTable = new
+ com.google.protobuf.GeneratedMessage.FieldAccessorTable(
+ internal_static_textsecure_SessionStructure_Chain_ChainKey_descriptor,
+ new java.lang.String[] { "Index", "Key", },
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKey.class,
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.ChainKey.Builder.class);
+ internal_static_textsecure_SessionStructure_Chain_MessageKey_descriptor =
+ internal_static_textsecure_SessionStructure_Chain_descriptor.getNestedTypes().get(1);
+ internal_static_textsecure_SessionStructure_Chain_MessageKey_fieldAccessorTable = new
+ com.google.protobuf.GeneratedMessage.FieldAccessorTable(
+ internal_static_textsecure_SessionStructure_Chain_MessageKey_descriptor,
+ new java.lang.String[] { "Index", "CipherKey", "MacKey", },
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKey.class,
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain.MessageKey.Builder.class);
+ internal_static_textsecure_SessionStructure_PendingKeyExchange_descriptor =
+ internal_static_textsecure_SessionStructure_descriptor.getNestedTypes().get(1);
+ 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", },
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange.class,
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange.Builder.class);
+ internal_static_textsecure_SessionStructure_PendingPreKey_descriptor =
+ internal_static_textsecure_SessionStructure_descriptor.getNestedTypes().get(2);
+ internal_static_textsecure_SessionStructure_PendingPreKey_fieldAccessorTable = new
+ com.google.protobuf.GeneratedMessage.FieldAccessorTable(
+ internal_static_textsecure_SessionStructure_PendingPreKey_descriptor,
+ new java.lang.String[] { "PreKeyId", "BaseKey", },
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey.class,
+ org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey.Builder.class);
+ return null;
+ }
+ };
+ com.google.protobuf.Descriptors.FileDescriptor
+ .internalBuildGeneratedFileFrom(descriptorData,
+ new com.google.protobuf.Descriptors.FileDescriptor[] {
+ }, assigner);
+ }
+
+ // @@protoc_insertion_point(outer_class_scope)
+}
diff --git a/res/menu/conversation_secure_no_identity.xml b/res/menu/conversation_secure_no_identity.xml
index fb84902e79..ab7cf31658 100644
--- a/res/menu/conversation_secure_no_identity.xml
+++ b/res/menu/conversation_secure_no_identity.xml
@@ -5,8 +5,9 @@
android:icon="@drawable/ic_menu_lock_holo_dark"
android:showAsAction="ifRoom">