Migrate identity keys to SignalStore.

This commit is contained in:
Greyson Parrelli
2022-01-28 15:16:33 -05:00
parent 9a1b8c9bb2
commit db534cd376
31 changed files with 346 additions and 232 deletions

View File

@@ -52,6 +52,7 @@ public final class AppInitialization {
Log.i(TAG, "onPostBackupRestore()");
ApplicationDependencies.getMegaphoneRepository().onFirstEverAppLaunch();
SignalStore.onPostBackupRestore();
SignalStore.onFirstEverAppLaunch();
SignalStore.onboarding().clearAll();
TextSecurePreferences.onPostBackupRestore(context);

View File

@@ -24,6 +24,7 @@ import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
import org.thoughtcrime.securesms.crypto.ProfileKeyUtil;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.permissions.Permissions;
import org.thoughtcrime.securesms.qr.ScanListener;
import org.thoughtcrime.securesms.util.Base64;
@@ -187,7 +188,7 @@ public class DeviceActivity extends PassphraseRequiredActivity
}
ECPublicKey publicKey = Curve.decodePoint(Base64.decode(publicKeyEncoded), 0);
IdentityKeyPair identityKeyPair = IdentityKeyUtil.getIdentityKeyPair(context);
IdentityKeyPair identityKeyPair = SignalStore.account().getAciIdentityKey();
Optional<byte[]> profileKey = Optional.of(ProfileKeyUtil.getProfileKey(getContext()));
TextSecurePreferences.setMultiDevice(DeviceActivity.this, true);

View File

@@ -22,6 +22,7 @@ import android.os.Bundle;
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.crypto.MasterSecretUtil;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.util.VersionTracker;
/**
@@ -61,7 +62,7 @@ public class PassphraseCreateActivity extends PassphraseActivity {
passphrase);
MasterSecretUtil.generateAsymmetricMasterSecret(PassphraseCreateActivity.this, masterSecret);
IdentityKeyUtil.generateIdentityKeys(PassphraseCreateActivity.this);
SignalStore.account().generateAciIdentityKey();
VersionTracker.updateLastSeenVersion(PassphraseCreateActivity.this);
return null;

View File

@@ -182,12 +182,6 @@ public class FullBackupExporter extends FullBackupBase {
stopwatch.split("table::" + table);
}
for (BackupProtos.SharedPreference preference : IdentityKeyUtil.getBackupRecord(context)) {
throwIfCanceled(cancellationSignal);
EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.PROGRESS, ++count, estimatedCount));
outputStream.write(preference);
}
for (BackupProtos.SharedPreference preference : TextSecurePreferences.getPreferencesToSaveToBackup(context)) {
throwIfCanceled(cancellationSignal);
EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.PROGRESS, ++count, estimatedCount));

View File

@@ -32,6 +32,7 @@ import org.thoughtcrime.securesms.database.SearchDatabase;
import org.thoughtcrime.securesms.database.StickerDatabase;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.keyvalue.KeyValueDataSet;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.profiles.AvatarHelper;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.BackupUtil;
@@ -250,6 +251,17 @@ public class FullBackupImporter extends FullBackupBase {
private static void processPreference(@NonNull Context context, SharedPreference preference) {
SharedPreferences preferences = context.getSharedPreferences(preference.getFile(), 0);
// Identity keys were moved from shared prefs into SignalStore. Need to handle importing backups made before the migration.
if ("SecureSMS-Preferences".equals(preference.getFile())) {
if ("pref_identity_public_v3".equals(preference.getKey()) && preference.hasValue()) {
SignalStore.account().restoreLegacyIdentityPublicKeyFromBackup(preference.getValue());
} else if ("pref_identity_private_v3".equals(preference.getKey()) && preference.hasValue()) {
SignalStore.account().restoreLegacyIdentityPrivateKeyFromBackup(preference.getValue());
}
return;
}
if (preference.hasValue()) {
preferences.edit().putString(preference.getKey(), preference.getValue()).commit();
} else if (preference.hasBooleanValue()) {

View File

@@ -9,7 +9,7 @@ import androidx.appcompat.app.AlertDialog;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.crypto.ReentrantSessionLock;
import org.thoughtcrime.securesms.crypto.storage.TextSecureIdentityKeyStore;
import org.thoughtcrime.securesms.crypto.storage.SignalIdentityKeyStore;
import org.thoughtcrime.securesms.database.model.IdentityRecord;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
@@ -40,7 +40,7 @@ public class UntrustedSendDialog extends AlertDialog.Builder implements DialogIn
@Override
public void onClick(DialogInterface dialog, int which) {
final TextSecureIdentityKeyStore identityStore = ApplicationDependencies.getProtocolStore().aci().identities();
final SignalIdentityKeyStore identityStore = ApplicationDependencies.getProtocolStore().aci().identities();
SimpleTask.run(() -> {
try(SignalSessionLock.Lock unused = ReentrantSessionLock.INSTANCE.acquire()) {

View File

@@ -14,7 +14,7 @@ import org.signal.core.util.concurrent.SignalExecutors;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.crypto.SessionUtil;
import org.thoughtcrime.securesms.crypto.ReentrantSessionLock;
import org.thoughtcrime.securesms.crypto.storage.TextSecureIdentityKeyStore;
import org.thoughtcrime.securesms.crypto.storage.SignalIdentityKeyStore;
import org.thoughtcrime.securesms.database.IdentityDatabase;
import org.thoughtcrime.securesms.database.SignalDatabase;
import org.thoughtcrime.securesms.database.model.IdentityRecord;
@@ -96,7 +96,7 @@ final class SafetyNumberChangeRepository {
@WorkerThread
private TrustAndVerifyResult trustOrVerifyChangedRecipientsInternal(@NonNull List<ChangedRecipient> changedRecipients) {
TextSecureIdentityKeyStore identityStore = ApplicationDependencies.getProtocolStore().aci().identities();
SignalIdentityKeyStore identityStore = ApplicationDependencies.getProtocolStore().aci().identities();
try(SignalSessionLock.Lock unused = ReentrantSessionLock.INSTANCE.acquire()) {
for (ChangedRecipient changedRecipient : changedRecipients) {
@@ -129,10 +129,10 @@ final class SafetyNumberChangeRepository {
SignalProtocolAddress mismatchAddress = new SignalProtocolAddress(changedRecipient.getRecipient().requireServiceId(), SignalServiceAddress.DEFAULT_DEVICE_ID);
Log.d(TAG, "Saving identity for: " + changedRecipient.getRecipient().getId() + " " + changedRecipient.getIdentityRecord().getIdentityKey().hashCode());
TextSecureIdentityKeyStore.SaveResult result = ApplicationDependencies.getProtocolStore().aci().identities().saveIdentity(mismatchAddress, changedRecipient.getIdentityRecord().getIdentityKey(), true);
SignalIdentityKeyStore.SaveResult result = ApplicationDependencies.getProtocolStore().aci().identities().saveIdentity(mismatchAddress, changedRecipient.getIdentityRecord().getIdentityKey(), true);
Log.d(TAG, "Saving identity result: " + result);
if (result == TextSecureIdentityKeyStore.SaveResult.NO_CHANGE) {
if (result == SignalIdentityKeyStore.SaveResult.NO_CHANGE) {
Log.i(TAG, "Archiving sessions explicitly as they appear to be out of sync.");
SessionUtil.archiveSession(changedRecipient.getRecipient().getId(), SignalServiceAddress.DEFAULT_DEVICE_ID);
SessionUtil.archiveSiblingSessions(mismatchAddress);

View File

@@ -17,27 +17,11 @@
*/
package org.thoughtcrime.securesms.crypto;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import androidx.annotation.NonNull;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.backup.BackupProtos;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.util.Base64;
import org.whispersystems.libsignal.IdentityKey;
import org.whispersystems.libsignal.IdentityKeyPair;
import org.whispersystems.libsignal.InvalidKeyException;
import org.whispersystems.libsignal.ecc.Curve;
import org.whispersystems.libsignal.ecc.ECKeyPair;
import org.whispersystems.libsignal.ecc.ECPrivateKey;
import org.whispersystems.libsignal.util.guava.Preconditions;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
/**
* Utility class for working with identity keys.
@@ -47,63 +31,6 @@ import java.util.List;
public class IdentityKeyUtil {
@SuppressWarnings("unused")
private static final String TAG = Log.tag(IdentityKeyUtil.class);
private static final String IDENTITY_PUBLIC_KEY_CIPHERTEXT_LEGACY_PREF = "pref_identity_public_curve25519";
private static final String IDENTITY_PRIVATE_KEY_CIPHERTEXT_LEGACY_PREF = "pref_identity_private_curve25519";
private static final String IDENTITY_PUBLIC_KEY_PREF = "pref_identity_public_v3";
private static final String IDENTITY_PRIVATE_KEY_PREF = "pref_identity_private_v3";
public static boolean hasIdentityKey(Context context) {
SharedPreferences preferences = context.getSharedPreferences(MasterSecretUtil.PREFERENCES_NAME, 0);
return
preferences.contains(IDENTITY_PUBLIC_KEY_PREF) &&
preferences.contains(IDENTITY_PRIVATE_KEY_PREF);
}
public static @NonNull IdentityKey getIdentityKey(@NonNull Context context) {
if (!hasIdentityKey(context)) throw new AssertionError("There isn't one!");
try {
byte[] publicKeyBytes = Base64.decode(retrieve(context, IDENTITY_PUBLIC_KEY_PREF));
return new IdentityKey(publicKeyBytes, 0);
} catch (IOException | InvalidKeyException e) {
throw new AssertionError(e);
}
}
public static @NonNull IdentityKeyPair getIdentityKeyPair(@NonNull Context context) {
if (!hasIdentityKey(context)) throw new AssertionError("There isn't one!");
try {
IdentityKey publicKey = getIdentityKey(context);
ECPrivateKey privateKey = Curve.decodePrivatePoint(Base64.decode(retrieve(context, IDENTITY_PRIVATE_KEY_PREF)));
return new IdentityKeyPair(publicKey, privateKey);
} catch (IOException e) {
throw new AssertionError(e);
}
}
public static void generateIdentityKeys(Context context) {
IdentityKeyPair identityKeyPair = generateIdentityKeyPair();
save(context, IDENTITY_PUBLIC_KEY_PREF, Base64.encodeBytes(identityKeyPair.getPublicKey().serialize()));
save(context, IDENTITY_PRIVATE_KEY_PREF, Base64.encodeBytes(identityKeyPair.getPrivateKey().serialize()));
}
/**
* Only call when configuring as a secondary linked device.
*/
public static void setIdentityKeys(Context context, IdentityKeyPair identityKeyPair) {
Preconditions.checkState(SignalStore.account().isLinkedDevice(), "Identity keys can only be set directly by a linked device");
save(context, IDENTITY_PUBLIC_KEY_PREF, Base64.encodeBytes(identityKeyPair.getPublicKey().serialize()));
save(context, IDENTITY_PRIVATE_KEY_PREF, Base64.encodeBytes(identityKeyPair.getPrivateKey().serialize()));
}
public static IdentityKeyPair generateIdentityKeyPair() {
ECKeyPair djbKeyPair = Curve.generateKeyPair();
IdentityKey djbIdentityKey = new IdentityKey(djbKeyPair.getPublicKey());
@@ -111,78 +38,4 @@ public class IdentityKeyUtil {
return new IdentityKeyPair(djbIdentityKey, djbPrivateKey);
}
public static void migrateIdentityKeys(@NonNull Context context,
@NonNull MasterSecret masterSecret)
{
if (!hasIdentityKey(context)) {
if (hasLegacyIdentityKeys(context)) {
IdentityKeyPair legacyPair = getLegacyIdentityKeyPair(context, masterSecret);
save(context, IDENTITY_PUBLIC_KEY_PREF, Base64.encodeBytes(legacyPair.getPublicKey().serialize()));
save(context, IDENTITY_PRIVATE_KEY_PREF, Base64.encodeBytes(legacyPair.getPrivateKey().serialize()));
delete(context, IDENTITY_PUBLIC_KEY_CIPHERTEXT_LEGACY_PREF);
delete(context, IDENTITY_PRIVATE_KEY_CIPHERTEXT_LEGACY_PREF);
} else {
generateIdentityKeys(context);
}
}
}
public static List<BackupProtos.SharedPreference> getBackupRecord(@NonNull Context context) {
SharedPreferences preferences = context.getSharedPreferences(MasterSecretUtil.PREFERENCES_NAME, 0);
return new LinkedList<BackupProtos.SharedPreference>() {{
add(BackupProtos.SharedPreference.newBuilder()
.setFile(MasterSecretUtil.PREFERENCES_NAME)
.setKey(IDENTITY_PUBLIC_KEY_PREF)
.setValue(preferences.getString(IDENTITY_PUBLIC_KEY_PREF, null))
.build());
add(BackupProtos.SharedPreference.newBuilder()
.setFile(MasterSecretUtil.PREFERENCES_NAME)
.setKey(IDENTITY_PRIVATE_KEY_PREF)
.setValue(preferences.getString(IDENTITY_PRIVATE_KEY_PREF, null))
.build());
}};
}
private static boolean hasLegacyIdentityKeys(Context context) {
return
retrieve(context, IDENTITY_PUBLIC_KEY_CIPHERTEXT_LEGACY_PREF) != null &&
retrieve(context, IDENTITY_PRIVATE_KEY_CIPHERTEXT_LEGACY_PREF) != null;
}
private static IdentityKeyPair getLegacyIdentityKeyPair(@NonNull Context context,
@NonNull MasterSecret masterSecret)
{
try {
MasterCipher masterCipher = new MasterCipher(masterSecret);
byte[] publicKeyBytes = Base64.decode(retrieve(context, IDENTITY_PUBLIC_KEY_CIPHERTEXT_LEGACY_PREF));
IdentityKey identityKey = new IdentityKey(publicKeyBytes, 0);
ECPrivateKey privateKey = masterCipher.decryptKey(Base64.decode(retrieve(context, IDENTITY_PRIVATE_KEY_CIPHERTEXT_LEGACY_PREF)));
return new IdentityKeyPair(identityKey, privateKey);
} catch (IOException | InvalidKeyException e) {
throw new AssertionError(e);
}
}
private static String retrieve(Context context, String key) {
SharedPreferences preferences = context.getSharedPreferences(MasterSecretUtil.PREFERENCES_NAME, 0);
return preferences.getString(key, null);
}
private static void save(Context context, String key, String value) {
SharedPreferences preferences = context.getSharedPreferences(MasterSecretUtil.PREFERENCES_NAME, 0);
Editor preferencesEditor = preferences.edit();
preferencesEditor.putString(key, value);
if (!preferencesEditor.commit()) throw new AssertionError("failed to save identity key/value to shared preferences");
}
private static void delete(Context context, String key) {
context.getSharedPreferences(MasterSecretUtil.PREFERENCES_NAME, 0).edit().remove(key).commit();
}
}

View File

@@ -8,6 +8,7 @@ import androidx.annotation.Nullable;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
import org.thoughtcrime.securesms.crypto.SessionUtil;
import org.thoughtcrime.securesms.crypto.storage.SignalIdentityKeyStore.SaveResult;
import org.thoughtcrime.securesms.database.IdentityDatabase;
import org.thoughtcrime.securesms.database.IdentityDatabase.VerifiedStatus;
import org.thoughtcrime.securesms.database.SignalDatabase;
@@ -19,12 +20,12 @@ import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.IdentityUtil;
import org.thoughtcrime.securesms.util.LRUCache;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.libsignal.IdentityKey;
import org.whispersystems.libsignal.IdentityKeyPair;
import org.whispersystems.libsignal.SignalProtocolAddress;
import org.whispersystems.libsignal.state.IdentityKeyStore;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.push.AccountIdentifier;
import java.util.ArrayList;
import java.util.List;
@@ -32,9 +33,14 @@ import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
public class TextSecureIdentityKeyStore implements IdentityKeyStore {
/**
* We technically need a separate ACI and PNI identity store, but we want them both to share the same underlying data, including the same cache.
* So this class represents the core store, and we can create multiple {@link SignalIdentityKeyStore} that use this same instance, changing only what each of
* those reports as their own identity key.
*/
public class SignalBaseIdentityKeyStore {
private static final String TAG = Log.tag(TextSecureIdentityKeyStore.class);
private static final String TAG = Log.tag(SignalBaseIdentityKeyStore.class);
private static final Object LOCK = new Object();
private static final int TIMESTAMP_THRESHOLD_SECONDS = 5;
@@ -42,26 +48,19 @@ public class TextSecureIdentityKeyStore implements IdentityKeyStore {
private final Context context;
private final Cache cache;
public TextSecureIdentityKeyStore(Context context) {
public SignalBaseIdentityKeyStore(@NonNull Context context) {
this(context, SignalDatabase.identities());
}
TextSecureIdentityKeyStore(@NonNull Context context, @NonNull IdentityDatabase identityDatabase) {
SignalBaseIdentityKeyStore(@NonNull Context context, @NonNull IdentityDatabase identityDatabase) {
this.context = context;
this.cache = new Cache(identityDatabase);
}
@Override
public IdentityKeyPair getIdentityKeyPair() {
return IdentityKeyUtil.getIdentityKeyPair(context);
}
@Override
public int getLocalRegistrationId() {
return SignalStore.account().getRegistrationId();
}
@Override
public boolean saveIdentity(SignalProtocolAddress address, IdentityKey identityKey) {
return saveIdentity(address, identityKey, false) == SaveResult.UPDATE;
}
@@ -121,15 +120,14 @@ public class TextSecureIdentityKeyStore implements IdentityKeyStore {
}
}
@Override
public boolean isTrustedIdentity(SignalProtocolAddress address, IdentityKey identityKey, Direction direction) {
public boolean isTrustedIdentity(SignalProtocolAddress address, IdentityKey identityKey, IdentityKeyStore.Direction direction) {
Recipient self = Recipient.self();
boolean isSelf = address.getName().equals(self.requireAci().toString()) ||
address.getName().equals(self.requireE164());
if (isSelf) {
return identityKey.equals(IdentityKeyUtil.getIdentityKey(context));
return identityKey.equals(SignalStore.account().getAciIdentityKey().getPublicKey());
}
IdentityStoreRecord record = cache.get(address.getName());
@@ -144,7 +142,6 @@ public class TextSecureIdentityKeyStore implements IdentityKeyStore {
}
}
@Override
public IdentityKey getIdentity(SignalProtocolAddress address) {
IdentityStoreRecord record = cache.get(address.getName());
return record != null ? record.getIdentityKey() : null;
@@ -317,11 +314,4 @@ public class TextSecureIdentityKeyStore implements IdentityKeyStore {
cache.remove(addressName);
}
}
public enum SaveResult {
NEW,
UPDATE,
NON_BLOCKING_APPROVAL_REQUIRED,
NO_CHANGE
}
}

View File

@@ -0,0 +1,102 @@
package org.thoughtcrime.securesms.crypto.storage;
import androidx.annotation.NonNull;
import org.thoughtcrime.securesms.database.IdentityDatabase.VerifiedStatus;
import org.thoughtcrime.securesms.database.identity.IdentityRecordList;
import org.thoughtcrime.securesms.database.model.IdentityRecord;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.whispersystems.libsignal.IdentityKey;
import org.whispersystems.libsignal.IdentityKeyPair;
import org.whispersystems.libsignal.SignalProtocolAddress;
import org.whispersystems.libsignal.state.IdentityKeyStore;
import org.whispersystems.libsignal.util.guava.Optional;
import java.util.List;
import java.util.function.Supplier;
/**
* A wrapper around an instance of {@link SignalBaseIdentityKeyStore} that lets us report different values for {@link #getIdentityKeyPair()}.
* This lets us have multiple instances (one for ACI, one for PNI) that share the same underlying data while also reporting the correct identity key.
*/
public class SignalIdentityKeyStore implements IdentityKeyStore {
private final SignalBaseIdentityKeyStore baseStore;
private final Supplier<IdentityKeyPair> identitySupplier;
public SignalIdentityKeyStore(@NonNull SignalBaseIdentityKeyStore baseStore, @NonNull Supplier<IdentityKeyPair> identitySupplier) {
this.baseStore = baseStore;
this.identitySupplier = identitySupplier;
}
@Override
public IdentityKeyPair getIdentityKeyPair() {
return identitySupplier.get();
}
@Override
public int getLocalRegistrationId() {
return baseStore.getLocalRegistrationId();
}
@Override
public boolean saveIdentity(SignalProtocolAddress address, IdentityKey identityKey) {
return baseStore.saveIdentity(address, identityKey);
}
public @NonNull SaveResult saveIdentity(SignalProtocolAddress address, IdentityKey identityKey, boolean nonBlockingApproval) {
return baseStore.saveIdentity(address, identityKey, nonBlockingApproval);
}
public void saveIdentityWithoutSideEffects(@NonNull RecipientId recipientId,
IdentityKey identityKey,
VerifiedStatus verifiedStatus,
boolean firstUse,
long timestamp,
boolean nonBlockingApproval)
{
baseStore.saveIdentityWithoutSideEffects(recipientId, identityKey, verifiedStatus, firstUse, timestamp, nonBlockingApproval);
}
@Override
public boolean isTrustedIdentity(SignalProtocolAddress address, IdentityKey identityKey, Direction direction) {
return baseStore.isTrustedIdentity(address, identityKey, direction);
}
@Override
public IdentityKey getIdentity(SignalProtocolAddress address) {
return baseStore.getIdentity(address);
}
public @NonNull Optional<IdentityRecord> getIdentityRecord(@NonNull RecipientId recipientId) {
return baseStore.getIdentityRecord(recipientId);
}
public @NonNull IdentityRecordList getIdentityRecords(@NonNull List<Recipient> recipients) {
return baseStore.getIdentityRecords(recipients);
}
public void setApproval(@NonNull RecipientId recipientId, boolean nonBlockingApproval) {
baseStore.setApproval(recipientId, nonBlockingApproval);
}
public void setVerified(@NonNull RecipientId recipientId, IdentityKey identityKey, VerifiedStatus verifiedStatus) {
baseStore.setVerified(recipientId, identityKey, verifiedStatus);
}
public void delete(@NonNull String addressName) {
baseStore.delete(addressName);
}
public void invalidate(@NonNull String addressName) {
baseStore.invalidate(addressName);
}
public enum SaveResult {
NEW,
UPDATE,
NON_BLOCKING_APPROVAL_REQUIRED,
NO_CHANGE
}
}

View File

@@ -4,7 +4,6 @@ import android.content.Context;
import androidx.annotation.NonNull;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.libsignal.IdentityKey;
import org.whispersystems.libsignal.IdentityKeyPair;
@@ -26,16 +25,16 @@ import java.util.UUID;
public class SignalServiceAccountDataStoreImpl implements SignalServiceAccountDataStore {
private final Context context;
private final TextSecurePreKeyStore preKeyStore;
private final TextSecurePreKeyStore signedPreKeyStore;
private final TextSecureIdentityKeyStore identityKeyStore;
private final TextSecureSessionStore sessionStore;
private final SignalSenderKeyStore senderKeyStore;
private final Context context;
private final TextSecurePreKeyStore preKeyStore;
private final TextSecurePreKeyStore signedPreKeyStore;
private final SignalIdentityKeyStore identityKeyStore;
private final TextSecureSessionStore sessionStore;
private final SignalSenderKeyStore senderKeyStore;
public SignalServiceAccountDataStoreImpl(@NonNull Context context,
@NonNull TextSecurePreKeyStore preKeyStore,
@NonNull TextSecureIdentityKeyStore identityKeyStore,
@NonNull SignalIdentityKeyStore identityKeyStore,
@NonNull TextSecureSessionStore sessionStore,
@NonNull SignalSenderKeyStore senderKeyStore)
{
@@ -193,7 +192,7 @@ public class SignalServiceAccountDataStoreImpl implements SignalServiceAccountDa
senderKeyStore.clearSenderKeySharedWith(addresses);
}
public @NonNull TextSecureIdentityKeyStore identities() {
public @NonNull SignalIdentityKeyStore identities() {
return identityKeyStore;
}

View File

@@ -29,7 +29,7 @@ public final class SignalServiceDataStoreImpl implements SignalServiceDataStore
if (accountIdentifier.equals(SignalStore.account().getAci())) {
return aciStore;
} else if (accountIdentifier.equals(SignalStore.account().getPni())) {
return pniStore;
throw new AssertionError("Not to be used yet!");
} else {
throw new IllegalArgumentException("No matching store found for " + accountIdentifier);
}

View File

@@ -11,6 +11,7 @@ import com.annimon.stream.Stream;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
import org.thoughtcrime.securesms.devicelist.Device;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.util.AsyncLoader;
import org.thoughtcrime.securesms.util.Base64;
import org.whispersystems.libsignal.IdentityKeyPair;
@@ -77,7 +78,7 @@ public class DeviceListLoader extends AsyncLoader<List<Device>> {
throw new IOException("Got a DeviceName that wasn't properly populated.");
}
return new Device(deviceInfo.getId(), new String(decryptName(deviceName, IdentityKeyUtil.getIdentityKeyPair(getContext()))), deviceInfo.getCreated(), deviceInfo.getLastSeen());
return new Device(deviceInfo.getId(), new String(decryptName(deviceName, SignalStore.account().getAciIdentityKey())), deviceInfo.getCreated(), deviceInfo.getLastSeen());
} catch (IOException e) {
Log.w(TAG, "Failed while reading the protobuf.", e);

View File

@@ -13,10 +13,11 @@ import org.thoughtcrime.securesms.BuildConfig;
import org.thoughtcrime.securesms.components.TypingStatusRepository;
import org.thoughtcrime.securesms.components.TypingStatusSender;
import org.thoughtcrime.securesms.crypto.ReentrantSessionLock;
import org.thoughtcrime.securesms.crypto.storage.SignalBaseIdentityKeyStore;
import org.thoughtcrime.securesms.crypto.storage.SignalServiceDataStoreImpl;
import org.thoughtcrime.securesms.crypto.storage.SignalServiceAccountDataStoreImpl;
import org.thoughtcrime.securesms.crypto.storage.SignalSenderKeyStore;
import org.thoughtcrime.securesms.crypto.storage.TextSecureIdentityKeyStore;
import org.thoughtcrime.securesms.crypto.storage.SignalIdentityKeyStore;
import org.thoughtcrime.securesms.crypto.storage.TextSecurePreKeyStore;
import org.thoughtcrime.securesms.crypto.storage.TextSecureSessionStore;
import org.thoughtcrime.securesms.database.DatabaseObserver;
@@ -75,6 +76,7 @@ import org.whispersystems.signalservice.api.SignalWebSocket;
import org.whispersystems.signalservice.api.groupsv2.ClientZkOperations;
import org.whispersystems.signalservice.api.groupsv2.GroupsV2Operations;
import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.push.PNI;
import org.whispersystems.signalservice.api.services.DonationsService;
import org.whispersystems.signalservice.api.util.CredentialsProvider;
import org.whispersystems.signalservice.api.util.SleepTimer;
@@ -276,12 +278,20 @@ public class ApplicationDependencyProvider implements ApplicationDependencies.Pr
@Override
public @NonNull SignalServiceDataStoreImpl provideProtocolStore() {
SignalServiceAccountDataStoreImpl aci = new SignalServiceAccountDataStoreImpl(context,
new TextSecurePreKeyStore(context),
new TextSecureIdentityKeyStore(context),
new TextSecureSessionStore(context),
new SignalSenderKeyStore(context));
return new SignalServiceDataStoreImpl(context, aci, aci);
SignalBaseIdentityKeyStore baseIdentityStore = new SignalBaseIdentityKeyStore(context);
SignalServiceAccountDataStoreImpl aciStore = new SignalServiceAccountDataStoreImpl(context,
new TextSecurePreKeyStore(context),
new SignalIdentityKeyStore(baseIdentityStore, () -> SignalStore.account().getAciIdentityKey()),
new TextSecureSessionStore(context),
new SignalSenderKeyStore(context));
SignalServiceAccountDataStoreImpl pniStore = new SignalServiceAccountDataStoreImpl(context,
new TextSecurePreKeyStore(context),
new SignalIdentityKeyStore(baseIdentityStore, () -> SignalStore.account().getPniIdentityKey()),
new TextSecureSessionStore(context),
new SignalSenderKeyStore(context));
return new SignalServiceDataStoreImpl(context, aciStore, pniStore);
}
@Override

View File

@@ -61,7 +61,7 @@ public class CreateSignedPreKeyJob extends BaseJob {
}
SignalServiceAccountManager accountManager = ApplicationDependencies.getSignalServiceAccountManager();
IdentityKeyPair identityKeyPair = IdentityKeyUtil.getIdentityKeyPair(context);
IdentityKeyPair identityKeyPair = SignalStore.account().getAciIdentityKey();
SignedPreKeyRecord signedPreKeyRecord = PreKeyUtil.generateSignedPreKey(context, identityKeyPair, true);
accountManager.setSignedPreKey(signedPreKeyRecord);

View File

@@ -129,7 +129,7 @@ public final class PushDecryptMessageJob extends BaseJob {
}
private boolean needsMigration() {
return !IdentityKeyUtil.hasIdentityKey(context) || TextSecurePreferences.getNeedsSqlCipherMigration(context);
return TextSecurePreferences.getNeedsSqlCipherMigration(context);
}
private void postMigrationNotification() {

View File

@@ -98,7 +98,7 @@ public class RefreshAttributesJob extends BaseJob {
boolean phoneNumberDiscoverable = SignalStore.phoneNumberPrivacy().getPhoneNumberListingMode().isDiscoverable();
String deviceName = SignalStore.account().getDeviceName();
byte[] encryptedDeviceName = (deviceName == null) ? null : DeviceNameCipher.encryptDeviceName(deviceName.getBytes(StandardCharsets.UTF_8), IdentityKeyUtil.getIdentityKeyPair(context));
byte[] encryptedDeviceName = (deviceName == null) ? null : DeviceNameCipher.encryptDeviceName(deviceName.getBytes(StandardCharsets.UTF_8), SignalStore.account().getAciIdentityKey());
AccountAttributes.Capabilities capabilities = AppCapabilities.getCapabilities(kbsValues.hasPin() && !kbsValues.hasOptedOut());
Log.i(TAG, "Calling setAccountAttributes() reglockV1? " + !TextUtils.isEmpty(registrationLockV1) + ", reglockV2? " + !TextUtils.isEmpty(registrationLockV2) + ", pin? " + kbsValues.hasPin() +

View File

@@ -85,7 +85,7 @@ public class RefreshPreKeysJob extends BaseJob {
}
List<PreKeyRecord> preKeyRecords = PreKeyUtil.generatePreKeys(context);
IdentityKeyPair identityKey = IdentityKeyUtil.getIdentityKeyPair(context);
IdentityKeyPair identityKey = SignalStore.account().getAciIdentityKey();
SignedPreKeyRecord signedPreKeyRecord = PreKeyUtil.generateSignedPreKey(context, identityKey, false);
Log.i(TAG, "Registering new prekeys...");

View File

@@ -10,6 +10,7 @@ import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.jobmanager.Data;
import org.thoughtcrime.securesms.jobmanager.Job;
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.libsignal.IdentityKeyPair;
import org.whispersystems.libsignal.state.SignedPreKeyRecord;
@@ -53,7 +54,7 @@ public class RotateSignedPreKeyJob extends BaseJob {
Log.i(TAG, "Rotating signed prekey...");
SignalServiceAccountManager accountManager = ApplicationDependencies.getSignalServiceAccountManager();
IdentityKeyPair identityKey = IdentityKeyUtil.getIdentityKeyPair(context);
IdentityKeyPair identityKey = SignalStore.account().getAciIdentityKey();
SignedPreKeyRecord signedPreKeyRecord = PreKeyUtil.generateSignedPreKey(context, identityKey, false);
accountManager.setSignedPreKey(signedPreKeyRecord);

View File

@@ -1,14 +1,23 @@
package org.thoughtcrime.securesms.keyvalue
import android.content.Context
import android.content.SharedPreferences
import android.preference.PreferenceManager
import androidx.annotation.VisibleForTesting
import org.signal.core.util.logging.Log
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil
import org.thoughtcrime.securesms.crypto.MasterCipher
import org.thoughtcrime.securesms.crypto.ProfileKeyUtil
import org.thoughtcrime.securesms.database.SignalDatabase
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.service.KeyCachingService
import org.thoughtcrime.securesms.util.Base64
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.thoughtcrime.securesms.util.Util
import org.whispersystems.libsignal.IdentityKey
import org.whispersystems.libsignal.IdentityKeyPair
import org.whispersystems.libsignal.ecc.Curve
import org.whispersystems.signalservice.api.push.ACI
import org.whispersystems.signalservice.api.push.PNI
import org.whispersystems.signalservice.api.push.SignalServiceAddress
@@ -26,6 +35,10 @@ internal class AccountValues internal constructor(store: KeyValueStore) : Signal
private const val KEY_FCM_TOKEN_LAST_SET_TIME = "account.fcm_token_last_set_time"
private const val KEY_DEVICE_NAME = "account.device_name"
private const val KEY_DEVICE_ID = "account.device_id"
private const val KEY_ACI_IDENTITY_PUBLIC_KEY = "account.aci_identity_public_key"
private const val KEY_ACI_IDENTITY_PRIVATE_KEY = "account.aci_identity_private_key"
private const val KEY_PNI_IDENTITY_PUBLIC_KEY = "account.pni_identity_public_key"
private const val KEY_PNI_IDENTITY_PRIVATE_KEY = "account.pni_identity_private_key"
@VisibleForTesting
const val KEY_E164 = "account.e164"
@@ -37,14 +50,23 @@ internal class AccountValues internal constructor(store: KeyValueStore) : Signal
init {
if (!store.containsKey(KEY_ACI)) {
migrateFromSharedPrefs(ApplicationDependencies.getApplication())
migrateFromSharedPrefsV1(ApplicationDependencies.getApplication())
}
if (!store.containsKey(KEY_ACI_IDENTITY_PUBLIC_KEY)) {
migrateFromSharedPrefsV2(ApplicationDependencies.getApplication())
}
}
public override fun onFirstEverAppLaunch() = Unit
public override fun getKeysToIncludeInBackup(): List<String> {
return emptyList()
return listOf(
KEY_ACI_IDENTITY_PUBLIC_KEY,
KEY_ACI_IDENTITY_PRIVATE_KEY,
KEY_PNI_IDENTITY_PUBLIC_KEY,
KEY_PNI_IDENTITY_PRIVATE_KEY,
)
}
/** The local user's [ACI]. */
@@ -84,6 +106,74 @@ internal class AccountValues internal constructor(store: KeyValueStore) : Signal
get() = getInteger(KEY_REGISTRATION_ID, 0)
set(value) = putInteger(KEY_REGISTRATION_ID, value)
/** The identity key pair for the ACI identity. */
val aciIdentityKey: IdentityKeyPair
get() {
require(store.containsKey(KEY_ACI_IDENTITY_PUBLIC_KEY)) { "Not yet set!" }
return IdentityKeyPair(
IdentityKey(getBlob(KEY_ACI_IDENTITY_PUBLIC_KEY, null)),
Curve.decodePrivatePoint(getBlob(KEY_ACI_IDENTITY_PRIVATE_KEY, null))
)
}
/** The identity key pair for the PNI identity. */
val pniIdentityKey: IdentityKeyPair
get() {
require(store.containsKey(KEY_PNI_IDENTITY_PUBLIC_KEY)) { "Not yet set!" }
return IdentityKeyPair(
IdentityKey(getBlob(KEY_PNI_IDENTITY_PUBLIC_KEY, null)),
Curve.decodePrivatePoint(getBlob(KEY_PNI_IDENTITY_PRIVATE_KEY, null))
)
}
/** Generates and saves an identity key pair for the ACI identity. Should only be done once. */
fun generateAciIdentityKey() {
Log.i(TAG, "Generating a new ACI identity key pair.")
require(!store.containsKey(KEY_ACI_IDENTITY_PUBLIC_KEY)) { "Already generated!" }
val key: IdentityKeyPair = IdentityKeyUtil.generateIdentityKeyPair()
store
.beginWrite()
.putBlob(KEY_ACI_IDENTITY_PUBLIC_KEY, key.publicKey.serialize())
.putBlob(KEY_ACI_IDENTITY_PRIVATE_KEY, key.privateKey.serialize())
.commit()
}
/** Generates and saves an identity key pair for the PNI identity. Should only be done once. */
fun generatePniIdentityKey() {
Log.i(TAG, "Generating a new PNI identity key pair.")
require(!store.containsKey(KEY_PNI_IDENTITY_PUBLIC_KEY)) { "Already generated!" }
val key: IdentityKeyPair = IdentityKeyUtil.generateIdentityKeyPair()
store
.beginWrite()
.putBlob(KEY_ACI_IDENTITY_PUBLIC_KEY, key.publicKey.serialize())
.putBlob(KEY_ACI_IDENTITY_PRIVATE_KEY, key.privateKey.serialize())
.commit()
}
/** When acting as a linked device, this method lets you store the identity keys sent from the primary device */
fun setIdentityKeysFromPrimaryDevice(aciKeys: IdentityKeyPair) {
require(isLinkedDevice) { "Must be a linked device!" }
store
.beginWrite()
.putBlob(KEY_ACI_IDENTITY_PUBLIC_KEY, aciKeys.publicKey.serialize())
.putBlob(KEY_ACI_IDENTITY_PRIVATE_KEY, aciKeys.privateKey.serialize())
.commit()
}
/** Only to be used when restoring an identity public key from an old backup */
fun restoreLegacyIdentityPublicKeyFromBackup(base64: String) {
Log.w(TAG, "Restoring legacy identity public key from backup.")
putBlob(KEY_ACI_IDENTITY_PUBLIC_KEY, Base64.decode(base64))
}
/** Only to be used when restoring an identity private key from an old backup */
fun restoreLegacyIdentityPrivateKeyFromBackup(base64: String) {
Log.w(TAG, "Restoring legacy identity private key from backup.")
putBlob(KEY_ACI_IDENTITY_PRIVATE_KEY, Base64.decode(base64))
}
/** Indicates whether the user has the ability to receive FCM messages. Largely coupled to whether they have Play Service. */
var fcmEnabled: Boolean
@JvmName("isFcmEnabled")
@@ -159,8 +249,8 @@ internal class AccountValues internal constructor(store: KeyValueStore) : Signal
ApplicationDependencies.getGroupsV2Authorization().clear()
}
private fun migrateFromSharedPrefs(context: Context) {
Log.i(TAG, "Migrating account values from shared prefs.")
private fun migrateFromSharedPrefsV1(context: Context) {
Log.i(TAG, "[V1] Migrating account values from shared prefs.")
putString(KEY_ACI, TextSecurePreferences.getStringPreference(context, "pref_local_uuid", null))
putString(KEY_E164, TextSecurePreferences.getStringPreference(context, "pref_local_number", null))
@@ -172,4 +262,63 @@ internal class AccountValues internal constructor(store: KeyValueStore) : Signal
putInteger(KEY_FCM_TOKEN_VERSION, TextSecurePreferences.getIntegerPreference(context, "pref_gcm_registration_id_version", 0))
putLong(KEY_FCM_TOKEN_LAST_SET_TIME, TextSecurePreferences.getLongPreference(context, "pref_gcm_registration_id_last_set_time", 0))
}
private fun migrateFromSharedPrefsV2(context: Context) {
Log.i(TAG, "[V2] Migrating account values from shared prefs.")
val masterSecretPrefs: SharedPreferences = context.getSharedPreferences("SecureSMS-Preferences", 0)
val defaultPrefs: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
if (masterSecretPrefs.hasStringData("pref_identity_public_v3")) {
Log.i(TAG, "Migrating modern identity key.")
val identityPublic = Base64.decode(masterSecretPrefs.getString("pref_identity_public_v3", null)!!)
val identityPrivate = Base64.decode(masterSecretPrefs.getString("pref_identity_private_v3", null)!!)
store
.beginWrite()
.putBlob(KEY_ACI_IDENTITY_PUBLIC_KEY, identityPublic)
.putBlob(KEY_ACI_IDENTITY_PRIVATE_KEY, identityPrivate)
.commit()
} else if (masterSecretPrefs.hasStringData("pref_identity_public_curve25519")) {
Log.i(TAG, "Migrating legacy identity key.")
val masterCipher = MasterCipher(KeyCachingService.getMasterSecret(context))
val identityPublic = Base64.decode(masterSecretPrefs.getString("pref_identity_public_curve25519", null)!!)
val identityPrivate = masterCipher.decryptKey(Base64.decode(masterSecretPrefs.getString("pref_identity_private_curve25519", null)!!)).serialize()
store
.beginWrite()
.putBlob(KEY_ACI_IDENTITY_PUBLIC_KEY, identityPublic)
.putBlob(KEY_ACI_IDENTITY_PRIVATE_KEY, identityPrivate)
.commit()
} else {
Log.w(TAG, "No pre-existing identity key! No migration.")
}
masterSecretPrefs
.edit()
.remove("pref_identity_public_v3")
.remove("pref_identity_private_v3")
.remove("pref_identity_public_curve25519")
.remove("pref_identity_private_curve25519")
.commit()
defaultPrefs
.edit()
.remove("pref_local_uuid")
.remove("pref_identity_public_v3")
.remove("pref_gcm_password")
.remove("pref_gcm_registered")
.remove("pref_local_registration_id")
.remove("pref_gcm_disabled")
.remove("pref_gcm_registration_id")
.remove("pref_gcm_registration_id_version")
.remove("pref_gcm_registration_id_last_set_time")
.commit()
}
private fun SharedPreferences.hasStringData(key: String): Boolean {
return this.getString(key, null) != null
}
}

View File

@@ -131,9 +131,7 @@ public final class KeyValueStore implements KeyValueReader {
/**
* Forces the store to re-fetch all of it's data from the database.
* Should only be used for testing!
*/
@VisibleForTesting
synchronized void resetCache() {
dataSet = null;
initializeIfNecessary();

View File

@@ -150,6 +150,13 @@ public final class SignalStore {
getInstance().store.resetCache();
}
/**
* Restoring a backup changes the underlying disk values, so the cache needs to be reset.
*/
public static void onPostBackupRestore() {
getInstance().store.resetCache();
}
public static @NonNull AccountValues account() {
return getInstance().accountValues;
}

View File

@@ -168,7 +168,6 @@ public class IncomingMessageProcessor {
private boolean needsToEnqueueDecryption() {
return !jobManager.areQueuesEmpty(SetUtil.newHashSet(Job.Parameters.MIGRATION_QUEUE_KEY, PushDecryptMessageJob.QUEUE)) ||
!IdentityKeyUtil.hasIdentityKey(context) ||
TextSecurePreferences.getNeedsSqlCipherMigration(context);
}

View File

@@ -113,10 +113,6 @@ public class LegacyMigrationJob extends MigrationJob {
throw new RetryLaterException();
}
if (lastSeenVersion < CURVE25519_VERSION) {
IdentityKeyUtil.migrateIdentityKeys(context, masterSecret);
}
if (lastSeenVersion < NO_V1_VERSION) {
File v1sessions = new File(context.getFilesDir(), "sessions");
@@ -149,7 +145,6 @@ public class LegacyMigrationJob extends MigrationJob {
// new TextSecureSessionStore(context, masterSecret).migrateSessions();
// new TextSecurePreKeyStore(context, masterSecret).migrateRecords();
IdentityKeyUtil.migrateIdentityKeys(context, masterSecret);
scheduleMessagesInPushDatabase(context);;
}

View File

@@ -134,7 +134,7 @@ public final class RegistrationRepository {
PNI pni = PNI.parseOrThrow(response.getPni());
boolean hasPin = response.isStorageCapable();
IdentityKeyPair identityKey = IdentityKeyUtil.getIdentityKeyPair(context);
IdentityKeyPair identityKey = SignalStore.account().getAciIdentityKey();
List<PreKeyRecord> records = PreKeyUtil.generatePreKeys(context);
SignedPreKeyRecord signedPreKey = PreKeyUtil.generateSignedPreKey(context, identityKey, true);

View File

@@ -14,6 +14,7 @@ import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
import org.thoughtcrime.securesms.database.SignalDatabase;
import org.thoughtcrime.securesms.events.CallParticipant;
import org.thoughtcrime.securesms.events.WebRtcViewModel;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientUtil;
import org.thoughtcrime.securesms.ringrtc.RemotePeer;
@@ -149,7 +150,7 @@ public class OutgoingCallActionProcessor extends DeviceAwareActionProcessor {
try {
byte[] remoteIdentityKey = WebRtcUtil.getPublicKeyBytes(receivedAnswerMetadata.getRemoteIdentityKey());
byte[] localIdentityKey = WebRtcUtil.getPublicKeyBytes(IdentityKeyUtil.getIdentityKey(context).serialize());
byte[] localIdentityKey = WebRtcUtil.getPublicKeyBytes(SignalStore.account().getAciIdentityKey().getPublicKey().serialize());
webRtcInteractor.getCallManager().receivedAnswer(callMetadata.getCallId(), callMetadata.getRemoteDevice(), answerMetadata.getOpaque(), remoteIdentityKey, localIdentityKey);
} catch (CallException | InvalidKeyException e) {

View File

@@ -215,7 +215,7 @@ public abstract class WebRtcActionProcessor {
try {
byte[] remoteIdentityKey = WebRtcUtil.getPublicKeyBytes(receivedOfferMetadata.getRemoteIdentityKey());
byte[] localIdentityKey = WebRtcUtil.getPublicKeyBytes(IdentityKeyUtil.getIdentityKey(context).serialize());
byte[] localIdentityKey = WebRtcUtil.getPublicKeyBytes(SignalStore.account().getAciIdentityKey().getPublicKey().serialize());
webRtcInteractor.getCallManager().receivedOffer(callMetadata.getCallId(),
callMetadata.getRemotePeer(),

View File

@@ -10,7 +10,7 @@ import org.signal.core.util.concurrent.SignalExecutors;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.crypto.ReentrantSessionLock;
import org.thoughtcrime.securesms.crypto.storage.TextSecureIdentityKeyStore;
import org.thoughtcrime.securesms.crypto.storage.SignalIdentityKeyStore;
import org.thoughtcrime.securesms.database.GroupDatabase;
import org.thoughtcrime.securesms.database.IdentityDatabase;
import org.thoughtcrime.securesms.database.MessageDatabase;
@@ -160,9 +160,9 @@ public final class IdentityUtil {
public static void processVerifiedMessage(Context context, VerifiedMessage verifiedMessage) {
try(SignalSessionLock.Lock unused = ReentrantSessionLock.INSTANCE.acquire()) {
TextSecureIdentityKeyStore identityStore = ApplicationDependencies.getProtocolStore().aci().identities();
Recipient recipient = Recipient.externalPush(context, verifiedMessage.getDestination());
Optional<IdentityRecord> identityRecord = identityStore.getIdentityRecord(recipient.getId());
SignalIdentityKeyStore identityStore = ApplicationDependencies.getProtocolStore().aci().identities();
Recipient recipient = Recipient.externalPush(context, verifiedMessage.getDestination());
Optional<IdentityRecord> identityRecord = identityStore.getIdentityRecord(recipient.getId());
if (!identityRecord.isPresent() && verifiedMessage.getVerified() == VerifiedMessage.VerifiedState.DEFAULT) {
Log.w(TAG, "No existing record for default status");

View File

@@ -300,7 +300,7 @@ public final class ProfileUtil {
if (!SignalStore.paymentsValues().mobileCoinPaymentsEnabled()) {
return null;
} else {
IdentityKeyPair identityKeyPair = IdentityKeyUtil.getIdentityKeyPair(ApplicationDependencies.getApplication());
IdentityKeyPair identityKeyPair = SignalStore.account().getAciIdentityKey();
MobileCoinPublicAddress publicAddress = ApplicationDependencies.getPayments()
.getWallet()
.getMobileCoinPublicAddress();

View File

@@ -8,7 +8,7 @@ import androidx.fragment.app.Fragment
import org.signal.core.util.ThreadUtil
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.crypto.IdentityKeyParcelable
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.permissions.Permissions
import org.thoughtcrime.securesms.qr.ScanListener
import org.thoughtcrime.securesms.recipients.Recipient
@@ -45,7 +45,7 @@ class VerifyIdentityFragment : Fragment(R.layout.fragment_container), ScanListen
VerifyDisplayFragment.create(
recipientId,
remoteIdentity,
IdentityKeyParcelable(IdentityKeyUtil.getIdentityKey(requireContext())),
IdentityKeyParcelable(SignalStore.account().aciIdentityKey.publicKey),
Recipient.self().requireE164(),
isVerified
)