A secure, blazing-fast alternative to EncryptedSharedPreferences, designed for Android projects which demand both speed and security.
As of Jetpack Security 1.1.0-alpha07 (April 9, 2025), EncryptedSharedPreferences is deprecated in favor of platform APIs and direct Android Keystore use. Google has confirmed there will be no subsequent releases of the security-crypto library.
SafeBox keeps the SharedPreferences API without requiring apps to replace it with a different storage model.
| SafeBox | EncryptedSharedPreferences | |
|---|---|---|
| Encryption | Modern ChaCha20-Poly1305 with secure key vault | Older AES setup tied to deprecated MasterKey |
| Storage format | Memory-mapped binary file with minimal headers | XML text file with tag/attribute overhead |
| I/O model | New data is tail-appended | New data rewrites the whole XML |
| Concurrency | Stays smooth on concurrent writes | Gets slower on concurrent writes |
| Scalability | Stable performance on large size | Keeps getting heavier as data grows |
| Durability | Low-storage failures fallback to a recovery file | Low-storage failures = data loss |
| Customization | Cipher providers are replaceable | Ciphers are not customizable |
SafeBox uses deterministic encryption for reference keys (for fast lookup) and non-deterministic encryption for values (for strong security). Both powered by a single ChaCha20 key protected via AES-GCM and stored securely.
π SafeBox Key Derivation & Encryption Flow
[Android Keystore-backed AES-GCM Key]
β
[ChaCha20-Poly1305 Key]
β β
Reference Keys Entry Values
(deterministic IV) (randomized IV)
Compared to EncryptedSharedPreferences:
[Android Keystore MasterKey (deprecated)]
β β
[AES-SIV Key] [AES-GCM Key]
β β
Reference Keys Entry Values
dependencies {
implementation("io.github.harrytmthy:safebox:1.4.0")
// Optional: standalone crypto helper
implementation("io.github.harrytmthy:safebox-crypto:1.4.0")
}Create the instance:
val prefs: SharedPreferences = SafeBox.create(context, PREF_FILE_NAME)Then use it like any SharedPreferences:
prefs.edit()
.putInt("userId", 123)
.putString("name", "Luna Moonlight")
.apply()
val userId = prefs.getInt("userId", -1)
val email = prefs.getString("email", null)Once created, you can retrieve the same instance without a Context:
SafeBox.get(PREF_FILE_NAME) // or SafeBox.create(context, PREF_FILE_NAME)
.edit()
.clear()
.commit()Prefer
SafeBox.getOrNull(fileName)if you need a safe retrieval without throwing.
SafeBox returns the same instance per filename:
val a1 = SafeBox.create(context, "fileA")
val a2 = SafeBox.create(context, "fileA")
val a3 = SafeBox.get("fileA")
assertTrue(a1 === a2) // same reference
assertTrue(a1 === a3) // same reference
val b = SafeBox.create(context, "fileB")
assertTrue(a1 !== b) // different filenames = different instancesRepeating
SafeBox.create(context, fileName)returns the existing instance for thatfileName. When an instance already exists, all parameters are ignored, includingfailureListener.
To observe failures through
FailureListener, see the Observability Guide.
SafeBox is a drop-in replacement for EncryptedSharedPreferences.
β‘οΈ Read the Migration Guide
SafeBox includes a simple text encryption helper (SafeBoxCrypto) you can use for things like
encrypting values before writing to Room or sending over the network:
// 1. Create a secret and store it in your own vault
val secret: String = SafeBoxCrypto.createSecret()
// 2. Use it to encrypt
val userEntity = UserEntity(
id = SafeBoxCrypto.encrypt(userId, secret),
// ...
)
// 3. Retrieve it later
val userId: String = SafeBoxCrypto.decrypt(userEntity.id, secret)If you only need the helper, use the standalone :safebox-crypto module.
SafeBox performance is measured using Jetpack Microbenchmark on a physical Android device with a non-debuggable release build. Reported figures are median durations over 50 measured samples.
Compared with SafeBox 1.3.0, SafeBox 1.4.0 improves performance across every measured workload:
| Workload | Speedup vs 1.3.0 |
|---|---|
| Initialization | 1.67Γ |
| Reads | 1.80β2.59Γ |
| Commit 1 entry | 1.30Γ |
| Bulk commits | 3.73β18.73Γ |
| Separate commits | 1.06β1.31Γ |
The benchmark suite and raw Jetpack measurement JSON are included in the repository. See the methodology and full benchmark results, including the comparison with EncryptedSharedPreferences 1.1.0.
See CONTRIBUTING.md for setup, formatting, testing, and PR guidelines.
If SafeBox helped secure your app or saved your time, consider sponsoring to support future improvements and maintenance!
Apache License 2.0
Copyright (c) 2025 Harry Timothy Tumalewa