diff --git a/protobuf/DeviceName.proto b/protobuf/DeviceName.proto new file mode 100644 index 0000000000..c0b4b1135e --- /dev/null +++ b/protobuf/DeviceName.proto @@ -0,0 +1,15 @@ +/** + * Copyright (C) 2014-2016 Open Whisper Systems + * + * Licensed according to the LICENSE file in this repository. + */ +package signalservice; + +option java_package = "org.thoughtcrime.securesms.devicelist"; +option java_outer_classname = "DeviceNameProtos"; + +message DeviceName { + optional bytes ephemeralPublic = 1; + optional bytes syntheticIv = 2; + optional bytes ciphertext = 3; +} diff --git a/protobuf/Makefile b/protobuf/Makefile index d94e3c40cf..6387468dc8 100644 --- a/protobuf/Makefile +++ b/protobuf/Makefile @@ -1,3 +1,3 @@ all: - protoc --java_out=../src/ WebRtcData.proto Backups.proto + protoc --java_out=../src/ WebRtcData.proto Backups.proto DeviceName.proto diff --git a/src/org/thoughtcrime/securesms/DeviceListFragment.java b/src/org/thoughtcrime/securesms/DeviceListFragment.java index b94a13959f..461d2eb99a 100644 --- a/src/org/thoughtcrime/securesms/DeviceListFragment.java +++ b/src/org/thoughtcrime/securesms/DeviceListFragment.java @@ -10,6 +10,7 @@ import android.support.v4.app.LoaderManager; import android.support.v4.content.Loader; import android.support.v7.app.AlertDialog; +import org.thoughtcrime.securesms.devicelist.Device; import org.thoughtcrime.securesms.jobs.RefreshUnidentifiedDeliveryAbilityJob; import org.thoughtcrime.securesms.logging.Log; import android.view.LayoutInflater; @@ -29,7 +30,6 @@ import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask; import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.ViewUtil; import org.whispersystems.signalservice.api.SignalServiceAccountManager; -import org.whispersystems.signalservice.api.messages.multidevice.DeviceInfo; import java.io.IOException; import java.util.List; @@ -38,7 +38,7 @@ import java.util.Locale; import javax.inject.Inject; public class DeviceListFragment extends ListFragment - implements LoaderManager.LoaderCallbacks>, + implements LoaderManager.LoaderCallbacks>, ListView.OnItemClickListener, InjectableType, Button.OnClickListener { @@ -89,7 +89,7 @@ public class DeviceListFragment extends ListFragment } @Override - public Loader> onCreateLoader(int id, Bundle args) { + public Loader> onCreateLoader(int id, Bundle args) { empty.setVisibility(View.GONE); progressContainer.setVisibility(View.VISIBLE); @@ -97,7 +97,7 @@ public class DeviceListFragment extends ListFragment } @Override - public void onLoadFinished(Loader> loader, List data) { + public void onLoadFinished(Loader> loader, List data) { progressContainer.setVisibility(View.GONE); if (data == null) { @@ -116,7 +116,7 @@ public class DeviceListFragment extends ListFragment } @Override - public void onLoaderReset(Loader> loader) { + public void onLoaderReset(Loader> loader) { setListAdapter(null); } @@ -198,12 +198,12 @@ public class DeviceListFragment extends ListFragment if (addDeviceButtonListener != null) addDeviceButtonListener.onClick(v); } - private static class DeviceListAdapter extends ArrayAdapter { + private static class DeviceListAdapter extends ArrayAdapter { private final int resource; private final Locale locale; - public DeviceListAdapter(Context context, int resource, List objects, Locale locale) { + public DeviceListAdapter(Context context, int resource, List objects, Locale locale) { super(context, resource, objects); this.resource = resource; this.locale = locale; diff --git a/src/org/thoughtcrime/securesms/DeviceListItem.java b/src/org/thoughtcrime/securesms/DeviceListItem.java index 70bc593179..5284945734 100644 --- a/src/org/thoughtcrime/securesms/DeviceListItem.java +++ b/src/org/thoughtcrime/securesms/DeviceListItem.java @@ -6,8 +6,8 @@ import android.util.AttributeSet; import android.widget.LinearLayout; import android.widget.TextView; +import org.thoughtcrime.securesms.devicelist.Device; import org.thoughtcrime.securesms.util.DateUtils; -import org.whispersystems.signalservice.api.messages.multidevice.DeviceInfo; import java.util.Locale; @@ -34,7 +34,7 @@ public class DeviceListItem extends LinearLayout { this.lastActive = (TextView) findViewById(R.id.active); } - public void set(DeviceInfo deviceInfo, Locale locale) { + public void set(Device deviceInfo, Locale locale) { if (TextUtils.isEmpty(deviceInfo.getName())) this.name.setText(R.string.DeviceListItem_unnamed_device); else this.name.setText(deviceInfo.getName()); diff --git a/src/org/thoughtcrime/securesms/database/loaders/DeviceListLoader.java b/src/org/thoughtcrime/securesms/database/loaders/DeviceListLoader.java index e4e595a0c3..a9b0ad146c 100644 --- a/src/org/thoughtcrime/securesms/database/loaders/DeviceListLoader.java +++ b/src/org/thoughtcrime/securesms/database/loaders/DeviceListLoader.java @@ -1,20 +1,40 @@ package org.thoughtcrime.securesms.database.loaders; import android.content.Context; +import android.support.annotation.NonNull; +import com.annimon.stream.Stream; + +import org.thoughtcrime.securesms.crypto.IdentityKeyUtil; +import org.thoughtcrime.securesms.devicelist.Device; import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.util.AsyncLoader; +import org.thoughtcrime.securesms.util.Base64; +import org.whispersystems.libsignal.InvalidKeyException; +import org.whispersystems.libsignal.ecc.Curve; +import org.whispersystems.libsignal.ecc.ECPrivateKey; +import org.whispersystems.libsignal.ecc.ECPublicKey; +import org.whispersystems.libsignal.util.ByteUtil; import org.whispersystems.signalservice.api.SignalServiceAccountManager; import org.whispersystems.signalservice.api.messages.multidevice.DeviceInfo; import org.whispersystems.signalservice.api.push.SignalServiceAddress; import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.MessageDigest; +import java.util.Arrays; import java.util.Collections; import java.util.Comparator; -import java.util.Iterator; import java.util.List; -public class DeviceListLoader extends AsyncLoader> { +import javax.crypto.Cipher; +import javax.crypto.Mac; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +import static org.thoughtcrime.securesms.devicelist.DeviceNameProtos.*; + +public class DeviceListLoader extends AsyncLoader> { private static final String TAG = DeviceListLoader.class.getSimpleName(); @@ -26,18 +46,14 @@ public class DeviceListLoader extends AsyncLoader> { } @Override - public List loadInBackground() { + public List loadInBackground() { try { - List devices = accountManager.getDevices(); - Iterator iterator = devices.iterator(); + List devices = Stream.of(accountManager.getDevices()) + .filter(d -> d.getId() != SignalServiceAddress.DEFAULT_DEVICE_ID) + .map(this::mapToDevice) + .toList(); - while (iterator.hasNext()) { - if ((iterator.next().getId() == SignalServiceAddress.DEFAULT_DEVICE_ID)) { - iterator.remove(); - } - } - - Collections.sort(devices, new DeviceInfoComparator()); + Collections.sort(devices, new DeviceComparator()); return devices; } catch (IOException e) { @@ -46,10 +62,57 @@ public class DeviceListLoader extends AsyncLoader> { } } - private static class DeviceInfoComparator implements Comparator { + private Device mapToDevice(@NonNull DeviceInfo deviceInfo) { + try { + DeviceName deviceName = DeviceName.parseFrom(Base64.decode(deviceInfo.getName())); + + if (!deviceName.hasCiphertext() || !deviceName.hasEphemeralPublic() || !deviceName.hasSyntheticIv()) { + throw new IOException("Got a DeviceName that wasn't properly populated."); + } + + byte[] syntheticIv = deviceName.getSyntheticIv().toByteArray(); + byte[] cipherText = deviceName.getCiphertext().toByteArray(); + ECPrivateKey identityKey = IdentityKeyUtil.getIdentityKeyPair(getContext()).getPrivateKey(); + ECPublicKey ephemeralPublic = Curve.decodePoint(deviceName.getEphemeralPublic().toByteArray(), 0); + byte[] masterSecret = Curve.calculateAgreement(ephemeralPublic, identityKey); + + Mac mac = Mac.getInstance("HmacSHA256"); + mac.init(new SecretKeySpec(masterSecret, "HmacSHA256")); + byte[] cipherKeyPart1 = mac.doFinal("cipher".getBytes()); + + mac.init(new SecretKeySpec(cipherKeyPart1, "HmacSHA256")); + byte[] cipherKey = mac.doFinal(syntheticIv); + + Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding"); + cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(cipherKey, "AES"), new IvParameterSpec(new byte[16])); + final byte[] plaintext = cipher.doFinal(cipherText); + + mac.init(new SecretKeySpec(masterSecret, "HmacSHA256")); + byte[] verificationPart1 = mac.doFinal("auth".getBytes()); + + mac.init(new SecretKeySpec(verificationPart1, "HmacSHA256")); + byte[] verificationPart2 = mac.doFinal(plaintext); + byte[] ourSyntheticIv = ByteUtil.trim(verificationPart2, 16); + + if (!MessageDigest.isEqual(ourSyntheticIv, syntheticIv)) { + throw new GeneralSecurityException("The computed syntheticIv didn't match the actual syntheticIv."); + } + + return new Device(deviceInfo.getId(), new String(plaintext), deviceInfo.getCreated(), deviceInfo.getLastSeen()); + + } catch (IOException e) { + Log.w(TAG, "Failed while reading the protobuf.", e); + } catch (GeneralSecurityException | InvalidKeyException e) { + Log.w(TAG, "Failed during decryption.", e); + } + + return new Device(deviceInfo.getId(), deviceInfo.getName(), deviceInfo.getCreated(), deviceInfo.getLastSeen()); + } + + private static class DeviceComparator implements Comparator { @Override - public int compare(DeviceInfo lhs, DeviceInfo rhs) { + public int compare(Device lhs, Device rhs) { if (lhs.getCreated() < rhs.getCreated()) return -1; else if (lhs.getCreated() != rhs.getCreated()) return 1; else return 0; diff --git a/src/org/thoughtcrime/securesms/devicelist/Device.java b/src/org/thoughtcrime/securesms/devicelist/Device.java new file mode 100644 index 0000000000..1cf302596d --- /dev/null +++ b/src/org/thoughtcrime/securesms/devicelist/Device.java @@ -0,0 +1,32 @@ +package org.thoughtcrime.securesms.devicelist; + +public class Device { + + private final long id; + private final String name; + private final long created; + private final long lastSeen; + + public Device(long id, String name, long created, long lastSeen) { + this.id = id; + this.name = name; + this.created = created; + this.lastSeen = lastSeen; + } + + public long getId() { + return id; + } + + public String getName() { + return name; + } + + public long getCreated() { + return created; + } + + public long getLastSeen() { + return lastSeen; + } +} diff --git a/src/org/thoughtcrime/securesms/devicelist/DeviceNameProtos.java b/src/org/thoughtcrime/securesms/devicelist/DeviceNameProtos.java new file mode 100644 index 0000000000..8700abbcf7 --- /dev/null +++ b/src/org/thoughtcrime/securesms/devicelist/DeviceNameProtos.java @@ -0,0 +1,619 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: DeviceName.proto + +package org.thoughtcrime.securesms.devicelist; + +public final class DeviceNameProtos { + private DeviceNameProtos() {} + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistry registry) { + } + public interface DeviceNameOrBuilder + extends com.google.protobuf.MessageOrBuilder { + + // optional bytes ephemeralPublic = 1; + /** + * optional bytes ephemeralPublic = 1; + */ + boolean hasEphemeralPublic(); + /** + * optional bytes ephemeralPublic = 1; + */ + com.google.protobuf.ByteString getEphemeralPublic(); + + // optional bytes syntheticIv = 2; + /** + * optional bytes syntheticIv = 2; + */ + boolean hasSyntheticIv(); + /** + * optional bytes syntheticIv = 2; + */ + com.google.protobuf.ByteString getSyntheticIv(); + + // optional bytes ciphertext = 3; + /** + * optional bytes ciphertext = 3; + */ + boolean hasCiphertext(); + /** + * optional bytes ciphertext = 3; + */ + com.google.protobuf.ByteString getCiphertext(); + } + /** + * Protobuf type {@code signalservice.DeviceName} + */ + public static final class DeviceName extends + com.google.protobuf.GeneratedMessage + implements DeviceNameOrBuilder { + // Use DeviceName.newBuilder() to construct. + private DeviceName(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private DeviceName(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); } + + private static final DeviceName defaultInstance; + public static DeviceName getDefaultInstance() { + return defaultInstance; + } + + public DeviceName getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.UnknownFieldSet unknownFields; + @java.lang.Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return this.unknownFields; + } + private DeviceName( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder(); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFields, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 10: { + bitField0_ |= 0x00000001; + ephemeralPublic_ = input.readBytes(); + break; + } + case 18: { + bitField0_ |= 0x00000002; + syntheticIv_ = input.readBytes(); + break; + } + case 26: { + bitField0_ |= 0x00000004; + ciphertext_ = input.readBytes(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + this.unknownFields = unknownFields.build(); + makeExtensionsImmutable(); + } + } + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.thoughtcrime.securesms.devicelist.DeviceNameProtos.internal_static_signalservice_DeviceName_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.thoughtcrime.securesms.devicelist.DeviceNameProtos.internal_static_signalservice_DeviceName_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.thoughtcrime.securesms.devicelist.DeviceNameProtos.DeviceName.class, org.thoughtcrime.securesms.devicelist.DeviceNameProtos.DeviceName.Builder.class); + } + + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public DeviceName parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new DeviceName(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + // optional bytes ephemeralPublic = 1; + public static final int EPHEMERALPUBLIC_FIELD_NUMBER = 1; + private com.google.protobuf.ByteString ephemeralPublic_; + /** + * optional bytes ephemeralPublic = 1; + */ + public boolean hasEphemeralPublic() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * optional bytes ephemeralPublic = 1; + */ + public com.google.protobuf.ByteString getEphemeralPublic() { + return ephemeralPublic_; + } + + // optional bytes syntheticIv = 2; + public static final int SYNTHETICIV_FIELD_NUMBER = 2; + private com.google.protobuf.ByteString syntheticIv_; + /** + * optional bytes syntheticIv = 2; + */ + public boolean hasSyntheticIv() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * optional bytes syntheticIv = 2; + */ + public com.google.protobuf.ByteString getSyntheticIv() { + return syntheticIv_; + } + + // optional bytes ciphertext = 3; + public static final int CIPHERTEXT_FIELD_NUMBER = 3; + private com.google.protobuf.ByteString ciphertext_; + /** + * optional bytes ciphertext = 3; + */ + public boolean hasCiphertext() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * optional bytes ciphertext = 3; + */ + public com.google.protobuf.ByteString getCiphertext() { + return ciphertext_; + } + + private void initFields() { + ephemeralPublic_ = com.google.protobuf.ByteString.EMPTY; + syntheticIv_ = com.google.protobuf.ByteString.EMPTY; + 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, ephemeralPublic_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeBytes(2, syntheticIv_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeBytes(3, 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, ephemeralPublic_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(2, syntheticIv_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(3, 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.thoughtcrime.securesms.devicelist.DeviceNameProtos.DeviceName parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.thoughtcrime.securesms.devicelist.DeviceNameProtos.DeviceName parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.thoughtcrime.securesms.devicelist.DeviceNameProtos.DeviceName parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.thoughtcrime.securesms.devicelist.DeviceNameProtos.DeviceName parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.thoughtcrime.securesms.devicelist.DeviceNameProtos.DeviceName parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static org.thoughtcrime.securesms.devicelist.DeviceNameProtos.DeviceName parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static org.thoughtcrime.securesms.devicelist.DeviceNameProtos.DeviceName parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static org.thoughtcrime.securesms.devicelist.DeviceNameProtos.DeviceName parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static org.thoughtcrime.securesms.devicelist.DeviceNameProtos.DeviceName parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static org.thoughtcrime.securesms.devicelist.DeviceNameProtos.DeviceName parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(org.thoughtcrime.securesms.devicelist.DeviceNameProtos.DeviceName 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; + } + /** + * Protobuf type {@code signalservice.DeviceName} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder + implements org.thoughtcrime.securesms.devicelist.DeviceNameProtos.DeviceNameOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.thoughtcrime.securesms.devicelist.DeviceNameProtos.internal_static_signalservice_DeviceName_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.thoughtcrime.securesms.devicelist.DeviceNameProtos.internal_static_signalservice_DeviceName_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.thoughtcrime.securesms.devicelist.DeviceNameProtos.DeviceName.class, org.thoughtcrime.securesms.devicelist.DeviceNameProtos.DeviceName.Builder.class); + } + + // Construct using org.thoughtcrime.securesms.devicelist.DeviceNameProtos.DeviceName.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessage.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(); + ephemeralPublic_ = com.google.protobuf.ByteString.EMPTY; + bitField0_ = (bitField0_ & ~0x00000001); + syntheticIv_ = com.google.protobuf.ByteString.EMPTY; + bitField0_ = (bitField0_ & ~0x00000002); + ciphertext_ = 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.thoughtcrime.securesms.devicelist.DeviceNameProtos.internal_static_signalservice_DeviceName_descriptor; + } + + public org.thoughtcrime.securesms.devicelist.DeviceNameProtos.DeviceName getDefaultInstanceForType() { + return org.thoughtcrime.securesms.devicelist.DeviceNameProtos.DeviceName.getDefaultInstance(); + } + + public org.thoughtcrime.securesms.devicelist.DeviceNameProtos.DeviceName build() { + org.thoughtcrime.securesms.devicelist.DeviceNameProtos.DeviceName result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public org.thoughtcrime.securesms.devicelist.DeviceNameProtos.DeviceName buildPartial() { + org.thoughtcrime.securesms.devicelist.DeviceNameProtos.DeviceName result = new org.thoughtcrime.securesms.devicelist.DeviceNameProtos.DeviceName(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.ephemeralPublic_ = ephemeralPublic_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.syntheticIv_ = syntheticIv_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.ciphertext_ = ciphertext_; + result.bitField0_ = to_bitField0_; + onBuilt(); + return result; + } + + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.thoughtcrime.securesms.devicelist.DeviceNameProtos.DeviceName) { + return mergeFrom((org.thoughtcrime.securesms.devicelist.DeviceNameProtos.DeviceName)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.thoughtcrime.securesms.devicelist.DeviceNameProtos.DeviceName other) { + if (other == org.thoughtcrime.securesms.devicelist.DeviceNameProtos.DeviceName.getDefaultInstance()) return this; + if (other.hasEphemeralPublic()) { + setEphemeralPublic(other.getEphemeralPublic()); + } + if (other.hasSyntheticIv()) { + setSyntheticIv(other.getSyntheticIv()); + } + 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 { + org.thoughtcrime.securesms.devicelist.DeviceNameProtos.DeviceName parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (org.thoughtcrime.securesms.devicelist.DeviceNameProtos.DeviceName) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + // optional bytes ephemeralPublic = 1; + private com.google.protobuf.ByteString ephemeralPublic_ = com.google.protobuf.ByteString.EMPTY; + /** + * optional bytes ephemeralPublic = 1; + */ + public boolean hasEphemeralPublic() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * optional bytes ephemeralPublic = 1; + */ + public com.google.protobuf.ByteString getEphemeralPublic() { + return ephemeralPublic_; + } + /** + * optional bytes ephemeralPublic = 1; + */ + public Builder setEphemeralPublic(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000001; + ephemeralPublic_ = value; + onChanged(); + return this; + } + /** + * optional bytes ephemeralPublic = 1; + */ + public Builder clearEphemeralPublic() { + bitField0_ = (bitField0_ & ~0x00000001); + ephemeralPublic_ = getDefaultInstance().getEphemeralPublic(); + onChanged(); + return this; + } + + // optional bytes syntheticIv = 2; + private com.google.protobuf.ByteString syntheticIv_ = com.google.protobuf.ByteString.EMPTY; + /** + * optional bytes syntheticIv = 2; + */ + public boolean hasSyntheticIv() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * optional bytes syntheticIv = 2; + */ + public com.google.protobuf.ByteString getSyntheticIv() { + return syntheticIv_; + } + /** + * optional bytes syntheticIv = 2; + */ + public Builder setSyntheticIv(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + syntheticIv_ = value; + onChanged(); + return this; + } + /** + * optional bytes syntheticIv = 2; + */ + public Builder clearSyntheticIv() { + bitField0_ = (bitField0_ & ~0x00000002); + syntheticIv_ = getDefaultInstance().getSyntheticIv(); + onChanged(); + return this; + } + + // optional bytes ciphertext = 3; + private com.google.protobuf.ByteString ciphertext_ = com.google.protobuf.ByteString.EMPTY; + /** + * optional bytes ciphertext = 3; + */ + public boolean hasCiphertext() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * optional bytes ciphertext = 3; + */ + public com.google.protobuf.ByteString getCiphertext() { + return ciphertext_; + } + /** + * optional bytes ciphertext = 3; + */ + public Builder setCiphertext(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + ciphertext_ = value; + onChanged(); + return this; + } + /** + * optional bytes ciphertext = 3; + */ + public Builder clearCiphertext() { + bitField0_ = (bitField0_ & ~0x00000004); + ciphertext_ = getDefaultInstance().getCiphertext(); + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:signalservice.DeviceName) + } + + static { + defaultInstance = new DeviceName(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:signalservice.DeviceName) + } + + private static com.google.protobuf.Descriptors.Descriptor + internal_static_signalservice_DeviceName_descriptor; + private static + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_signalservice_DeviceName_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\020DeviceName.proto\022\rsignalservice\"N\n\nDev" + + "iceName\022\027\n\017ephemeralPublic\030\001 \001(\014\022\023\n\013synt" + + "heticIv\030\002 \001(\014\022\022\n\nciphertext\030\003 \001(\014B9\n%org" + + ".thoughtcrime.securesms.devicelistB\020Devi" + + "ceNameProtos" + }; + 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_signalservice_DeviceName_descriptor = + getDescriptor().getMessageTypes().get(0); + internal_static_signalservice_DeviceName_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_signalservice_DeviceName_descriptor, + new java.lang.String[] { "EphemeralPublic", "SyntheticIv", "Ciphertext", }); + return null; + } + }; + com.google.protobuf.Descriptors.FileDescriptor + .internalBuildGeneratedFileFrom(descriptorData, + new com.google.protobuf.Descriptors.FileDescriptor[] { + }, assigner); + } + + // @@protoc_insertion_point(outer_class_scope) +}