Encrypting Data

Encrypting Files and Preferences

Jetpack 234 Security's EncryptedSharedPreferences and EncryptedFile (security-crypto) were the old answer, but its 1.1.0 release (30 July 2025) deprecated every API "in favour of existing platform APIs and direct use of Android Keystore", which many tutorials still miss.

DataStore 234 makes that easy, because the Serializer of Proto DataStore sees every byte on its way to and from the disk. Wrapping it in encrypt() and decrypt() gives an encrypted typed store for an @Serializable AuthToken(accessToken, expiresAt):

security/AuthTokenStore.kt: a DataStore serializer that encryptsKotlin
object EncryptedTokenSerializer : Serializer<AuthToken> {
  override val defaultValue = AuthToken()
  override suspend fun readFrom(input: InputStream): AuthToken {
    val blob = input.readBytes()
    if (blob.isEmpty()) return defaultValue
    return try {
      Json.decodeFromString(AuthToken.serializer(), KeystoreCipher.decrypt(blob).decodeToString())
    } catch (e: GeneralSecurityException) {          // wrong key, or tampered bytes
      throw CorruptionException("auth.bin cannot be decrypted", e)
    }
  }
  ...                           // writeTo() writes KeystoreCipher.encrypt(json bytes)
}

A CorruptionException lets a ReplaceFileCorruptionHandler reset the store (after a restore, when the key is gone) instead of crashing. For key rotation or streaming encryption of large files, Google's Tink 1 (github.com/tink-crypto/tink-java (https://github.com/tink-crypto/tink-java 306 ), tink-android, Apache-2.0) keeps its keyset encrypted by a Keystore master key.