encrypted-datastore

Additional

Language
Kotlin
Version
v1.0.0-beta01 (Feb 26, 2023)
Created
Oct 12, 2021
Updated
Sep 17, 2023
Owner
Osip Fatkullin (osipxd)
Contributor
Osip Fatkullin (osipxd)
1
Activity
Badge
Generate
Download
Source code

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

License

MIT