mirror of
https://github.com/bitwarden/android.git
synced 2024-11-25 02:46:00 +03:00
BIT-2437: Add mitigation logic for bad encryption key (#3426)
This commit is contained in:
parent
d8471b41ca
commit
782b474e54
4 changed files with 93 additions and 11 deletions
|
@ -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),
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
@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.packageName}_encrypted_preferences",
|
||||
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"
|
||||
}
|
||||
|
|
|
@ -3,16 +3,28 @@
|
|||
<exclude
|
||||
domain="sharedpref"
|
||||
path="." />
|
||||
<exclude
|
||||
domain="device_sharedpref"
|
||||
path="." />
|
||||
<exclude
|
||||
domain="file"
|
||||
path="." />
|
||||
<exclude
|
||||
domain="device_file"
|
||||
path="." />
|
||||
<exclude
|
||||
domain="database"
|
||||
path="." />
|
||||
<exclude
|
||||
domain="device_database"
|
||||
path="." />
|
||||
<exclude
|
||||
domain="external"
|
||||
path="." />
|
||||
<exclude
|
||||
domain="root"
|
||||
path="." />
|
||||
<exclude
|
||||
domain="device_root"
|
||||
path="." />
|
||||
</full-backup-content>
|
||||
|
|
|
@ -4,34 +4,58 @@
|
|||
<exclude
|
||||
domain="sharedpref"
|
||||
path="." />
|
||||
<exclude
|
||||
domain="device_sharedpref"
|
||||
path="." />
|
||||
<exclude
|
||||
domain="file"
|
||||
path="." />
|
||||
<exclude
|
||||
domain="device_file"
|
||||
path="." />
|
||||
<exclude
|
||||
domain="database"
|
||||
path="." />
|
||||
<exclude
|
||||
domain="device_database"
|
||||
path="." />
|
||||
<exclude
|
||||
domain="external"
|
||||
path="." />
|
||||
<exclude
|
||||
domain="root"
|
||||
path="." />
|
||||
<exclude
|
||||
domain="device_root"
|
||||
path="." />
|
||||
</cloud-backup>
|
||||
<device-transfer>
|
||||
<exclude
|
||||
domain="sharedpref"
|
||||
path="." />
|
||||
<exclude
|
||||
domain="device_sharedpref"
|
||||
path="." />
|
||||
<exclude
|
||||
domain="file"
|
||||
path="." />
|
||||
<exclude
|
||||
domain="device_file"
|
||||
path="." />
|
||||
<exclude
|
||||
domain="database"
|
||||
path="." />
|
||||
<exclude
|
||||
domain="device_database"
|
||||
path="." />
|
||||
<exclude
|
||||
domain="external"
|
||||
path="." />
|
||||
<exclude
|
||||
domain="root"
|
||||
path="." />
|
||||
<exclude
|
||||
domain="device_root"
|
||||
path="." />
|
||||
</device-transfer>
|
||||
</data-extraction-rules>
|
||||
|
|
Loading…
Reference in a new issue