From e1df942c3ca3a2f52a76e9cb327d11fb6bb4cfb0 Mon Sep 17 00:00:00 2001 From: Greyson Parrelli Date: Tue, 18 Aug 2026 08:29:09 -0400 Subject: [PATCH] Store the authCredentialSalt when registering. --- .../org/thoughtcrime/securesms/keyvalue/AccountValues.kt | 4 ++++ .../registration/v2/AppRegistrationStorageController.kt | 4 ++++ .../registration/v2/AppRegistrationStorageControllerTest.kt | 5 ++++- .../java/org/signal/registration/RegistrationRepository.kt | 1 + feature/registration/src/main/protowire/Registration.proto | 3 +++ 5 files changed, 16 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/AccountValues.kt b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/AccountValues.kt index 7e9a95c7f2..6d58178b8d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/AccountValues.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/AccountValues.kt @@ -49,6 +49,7 @@ class AccountValues internal constructor(store: KeyValueStore, context: Context) private const val KEY_DEVICE_NAME = "account.device_name" private const val KEY_DEVICE_ID = "account.device_id" private const val KEY_PNI_REGISTRATION_ID = "account.pni_registration_id" + private const val KEY_AUTH_CREDENTIAL_SALT = "account.auth_credential_salt" 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" @@ -276,6 +277,9 @@ class AccountValues internal constructor(store: KeyValueStore, context: Context) putString(KEY_SERVICE_PASSWORD, servicePassword) } + /** Salt used by the service to generate PNI auth credentials. Only present for an account registered without a phone number. */ + var authCredentialSalt: ByteArray? by nullableBlobValue(KEY_AUTH_CREDENTIAL_SALT, null) + /** A randomly-generated value that represents this registration instance. Helps the server know if you reinstalled. */ var registrationId: Int by integerValue(KEY_REGISTRATION_ID, 0) diff --git a/app/src/main/java/org/thoughtcrime/securesms/registration/v2/AppRegistrationStorageController.kt b/app/src/main/java/org/thoughtcrime/securesms/registration/v2/AppRegistrationStorageController.kt index df2225fc4e..467d4c1cc2 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/registration/v2/AppRegistrationStorageController.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/registration/v2/AppRegistrationStorageController.kt @@ -820,6 +820,10 @@ class AppRegistrationStorageController(private val context: Context) : StorageCo SignalStore.misc.needsUsernameRestore = true } + accountData.authCredentialSalt?.let { + SignalStore.account.authCredentialSalt = it.toByteArray() + } + SignalStore.account.setServicePassword(accountData.servicePassword) SignalStore.account.setRegistered(registered = true, isAciChanged = isAciChanged) TextSecurePreferences.setPromptedPushRegistration(context, true) diff --git a/app/src/test/java/org/thoughtcrime/securesms/registration/v2/AppRegistrationStorageControllerTest.kt b/app/src/test/java/org/thoughtcrime/securesms/registration/v2/AppRegistrationStorageControllerTest.kt index 380a9f1116..20fb3ed69e 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/registration/v2/AppRegistrationStorageControllerTest.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/registration/v2/AppRegistrationStorageControllerTest.kt @@ -94,6 +94,7 @@ class AppRegistrationStorageControllerTest { private val pniSignedPreKey = PreKeyUtil.generateSignedPreKey(12, pniIdentity.privateKey) private val aciLastResortKyberPreKey = PreKeyUtil.generateLastResortKyberPreKey(21, aciIdentity.privateKey) private val pniLastResortKyberPreKey = PreKeyUtil.generateLastResortKyberPreKey(22, pniIdentity.privateKey) + private val authCredentialSalt = byteArrayOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16) private val blobData = mutableMapOf() private var blobCounter = 0 @@ -147,6 +148,7 @@ class AppRegistrationStorageControllerTest { assertThat(SignalStore.account.pniIdentityKey.serialize()).isEqualTo(pniIdentity.serialize()) assertThat(SignalStore.account.accountEntropyPool.value).isEqualTo(aep.value) assertThat(SignalStore.account.restoredAccountEntropyPool).isTrue() + assertThat(SignalStore.account.authCredentialSalt).isNotNull().isEqualTo(authCredentialSalt) assertThat(SignalStore.account.aciPreKeys.isSignedPreKeyRegistered).isTrue() assertThat(SignalStore.account.aciPreKeys.activeSignedPreKeyId).isEqualTo(11) @@ -539,7 +541,8 @@ class AppRegistrationStorageControllerTest { e164 = E164, servicePassword = servicePassword, linkedDeviceData = linkedDeviceData, - reRegistration = reRegistration + reRegistration = reRegistration, + authCredentialSalt = authCredentialSalt.toByteString() ) } } diff --git a/feature/registration/src/main/java/org/signal/registration/RegistrationRepository.kt b/feature/registration/src/main/java/org/signal/registration/RegistrationRepository.kt index 9d1c7e90a8..c79789698d 100644 --- a/feature/registration/src/main/java/org/signal/registration/RegistrationRepository.kt +++ b/feature/registration/src/main/java/org/signal/registration/RegistrationRepository.kt @@ -715,6 +715,7 @@ class RegistrationRepository( this.pni = result.result.pni this.servicePassword = keyMaterial.servicePassword this.reRegistration = result.result.reregistration + this.authCredentialSalt = result.result.authCredentialSalt?.let { Base64.decode(it).toByteString() } } storageController.commitRegistrationData() } diff --git a/feature/registration/src/main/protowire/Registration.proto b/feature/registration/src/main/protowire/Registration.proto index 317ca376f8..7e9c0fc1e8 100644 --- a/feature/registration/src/main/protowire/Registration.proto +++ b/feature/registration/src/main/protowire/Registration.proto @@ -50,6 +50,9 @@ message AccountData { // Whether the service reported this registration as a re-registration of an existing account. bool reRegistration = 16; + + // Salt used by the service to generate PNI auth credentials. Only present for an account registered without a phone number. + optional bytes authCredentialSalt = 17; } message SvrCredential {