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):
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.