diff --git a/app/src/main/java/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryImpl.kt b/app/src/main/java/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryImpl.kt
index 3dc4161c2..18c6eea4c 100644
--- a/app/src/main/java/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryImpl.kt
+++ b/app/src/main/java/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryImpl.kt
@@ -1626,7 +1626,8 @@ class AuthRepositoryImpl(
// The value for the organization keys here will typically be null. We can separately
// unlock the vault for organization data after receiving the sync response if this
// data is currently absent. These keys may be present during certain multi-phase login
- // processes.
+ // processes or if we needed to delete the user's token due to an encrypted data
+ // corruption issue and they are forced to log back in.
organizationKeys = authDiskSource.getOrganizationKeys(userId = userId),
)
}
diff --git a/app/src/main/java/com/x8bit/bitwarden/data/platform/datasource/di/PreferenceModule.kt b/app/src/main/java/com/x8bit/bitwarden/data/platform/datasource/di/PreferenceModule.kt
index cd69445f5..5b82b60ac 100644
--- a/app/src/main/java/com/x8bit/bitwarden/data/platform/datasource/di/PreferenceModule.kt
+++ b/app/src/main/java/com/x8bit/bitwarden/data/platform/datasource/di/PreferenceModule.kt
@@ -9,6 +9,8 @@ import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
+import java.security.GeneralSecurityException
+import java.security.KeyStore
import javax.inject.Singleton
/**
@@ -35,14 +37,57 @@ object PreferenceModule {
fun provideEncryptedSharedPreferences(
application: Application,
): SharedPreferences =
- EncryptedSharedPreferences
- .create(
- application,
- "${application.packageName}_encrypted_preferences",
- MasterKey.Builder(application)
- .setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
- .build(),
- EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
- EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM,
- )
+ @Suppress("TooGenericExceptionCaught")
+ try {
+ getEncryptedSharedPreferences(application = application)
+ } catch (e: GeneralSecurityException) {
+ // Handle when a bad master key or key-set has been attempted
+ destroyEncryptedSharedPreferencesAndRebuild(application = application)
+ } catch (e: RuntimeException) {
+ // Handle KeystoreExceptions that get wrapped up in a RuntimeException
+ destroyEncryptedSharedPreferencesAndRebuild(application = application)
+ }
+
+ /**
+ * Completely destroys the keystore master key and encrypted shared preferences file. This will
+ * cause all users to be logged out since the access and refresh tokens will be removed.
+ *
+ * This is not desirable and should only be called if we have completely failed to access our
+ * encrypted shared preferences instance.
+ */
+ private fun destroyEncryptedSharedPreferencesAndRebuild(
+ application: Application,
+ ): SharedPreferences {
+ // Delete the master key
+ KeyStore.getInstance(KeyStore.getDefaultType()).run {
+ load(null)
+ deleteEntry(MasterKey.DEFAULT_MASTER_KEY_ALIAS)
+ }
+ // Deletes the encrypted shared preferences file
+ application.deleteSharedPreferences(application.encryptedSharedPreferencesName)
+ // Attempts to create the encrypted shared preferences instance
+ return getEncryptedSharedPreferences(application = application)
+ }
+
+ /**
+ * Helper method to get the app's encrypted shared preferences instance.
+ */
+ private fun getEncryptedSharedPreferences(
+ application: Application,
+ ): SharedPreferences =
+ EncryptedSharedPreferences.create(
+ application,
+ application.encryptedSharedPreferencesName,
+ MasterKey.Builder(application)
+ .setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
+ .build(),
+ EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
+ EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM,
+ )
+
+ /**
+ * Helper method to get the app's encrypted shared preferences name.
+ */
+ private val Application.encryptedSharedPreferencesName: String
+ get() = "${packageName}_encrypted_preferences"
}
diff --git a/app/src/main/res/xml/backup_rules.xml b/app/src/main/res/xml/backup_rules.xml
index cf7893b5b..8730b8a3e 100644
--- a/app/src/main/res/xml/backup_rules.xml
+++ b/app/src/main/res/xml/backup_rules.xml
@@ -3,16 +3,28 @@
+
+
+
+
diff --git a/app/src/main/res/xml/data_extraction_rules.xml b/app/src/main/res/xml/data_extraction_rules.xml
index b8ddf7c0d..89b68c26f 100644
--- a/app/src/main/res/xml/data_extraction_rules.xml
+++ b/app/src/main/res/xml/data_extraction_rules.xml
@@ -4,34 +4,58 @@
+
+
+
+
+
+
+
+