Encrypted DataStore
Extensions to store DataStore in EncryptedFile
.
⚠️ This tiny library will be maintained until an official solution for DataStore encryption will be released by Google.
Vote for this feature on issue tracker: b/167697691
Installation
Add the dependency:
repositories {
mavenCentral()
google()
}
dependencies {
implementation("io.github.osipxd:security-crypto-datastore:1.0.0-beta01")
// Or, if you want to use Preferences DataStore:
implementation("io.github.osipxd:security-crypto-datastore-preferences:1.0.0-beta01")
}
Dependencies:
Usage
To create encrypted DataStore, just use method DataStoreFactory.createEncryptred
instead of create
and provide EncryptedFile
instead of File
:
val dataStore = DataStoreFactory.createEncrypted(serializer) {
EncryptedFile.Builder(
context.dataStoreFile("filename"),
context,
MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC),
EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
).build()
}
Or even simpler, if you use security-crypto-ktx:1.1.0
⚠️ security-crypto-ktx 1.1.0
is in alpha at the moment this library released, so use it at your own risk
val dataStore = DataStoreFactory.createEncrypted(serializer) {
EncryptedFile(
context = context,
file = context.dataStoreFile("filename"),
masterKey = MasterKey(context)
)
}
Similarly, you can create Preferences DataStore:
val dataStore = PreferenceDataStoreFactory.createEncrypted {
EncryptedFile.Builder(
// The file should have extension .preferences_pb
context.dataStoreFile("filename.preferences_pb"),
context,
MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC),
EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
).build()
}
Or even simpler, if you use security-crypto-ktx:1.1.0
⚠️ security-crypto-ktx 1.1.0
is in alpha at the moment this library released, so use it at your own risk
val dataStore = PreferenceDataStoreFactory.createEncrypted {
EncryptedFile(
context = context,
// The file should have extension .preferences_pb
file = context.dataStoreFile("filename.preferences_pb"),
masterKey = MasterKey(context)
)
}
Then you can use the created encrypted DataStore just like simple DataDtore. Look at the DataStore docs for usage guide and examples.
Migration
Migrate from encrypted-datastore
to security-crypto-datastore
Change the dependency in build script:
dependencies {
- implementation("io.github.osipxd:encrypted-datastore:...")
+ implementation("io.github.osipxd:security-crypto-datastore:...")
}
New library uses StreamingAead
instead of Aead
under the hood, so to not lose the previously encrypted data you should specify fallbackAead
:
// This AEAD was used to encrypt DataStore previously, we will use it as fallback
val aead = AndroidKeysetManager.Builder()
.withSharedPref(context, "master_keyset", "master_key_preference")
.withKeyTemplate(KeyTemplates.get("AES256_GCM"))
.withMasterKeyUri("android-keystore://master_key")
.build()
.keysetHandle
.getPrimitive(Aead::class.java)
The old code to create DataStore was looking like this:
val dataStore = DataStoreFactory.create(serializer.encrypted(aead)) {
context.dataStoreFile("filename")
}
The new code will look like this:
val dataStore = DataStoreFactory.createEncrypted(
serializer,
encryptionOptions = {
// Specify fallback Aead to make it possible to decrypt data encrypted with it
fallbackAead = aead
}
) {
EncryptedFile.Builder(
context.dataStoreFile("filename"), // Keep the same file
context,
MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC),
EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
).build()
}
Or even simpler, if you use security-crypto-ktx:1.1.0
⚠️ security-crypto-ktx 1.1.0
is in alpha at the moment this library released, so use it at your own risk
val dataStore = DataStoreFactory.createEncrypted(
serializer,
encryptionOptions = { fallbackAead = aead }
) {
EncryptedFile(
context = context,
file = context.dataStoreFile("filename"), // Keep the same file
masterKey = MasterKey(context)
)
}
Thanks
- Artem Kulakov (Fi5t), for his example of DataStore encryption.
- Gods of Kotlin, for posibility to hack
internal
visibility modifier