Secure Storage is a set of methods and technologies for protecting confidential data on a device: tokens, encryption keys, payment information, and users’ personal data. According to OWASP Mobile Top 10 (2024), insecure data storage is among the top three most critical risks. Proper implementation of secure storage prevents data leakage even with physical access to the device.
Key Takeaways
Secure Storage is the practice of storing mobile application confidential data in such a way that it is inaccessible to other applications, malware, and attackers with physical access to the device. Unlike regular storage, Secure Storage uses encryption, isolation, and hardware protection.
Not all data requires Secure Storage: profile images or news cache can be stored in the regular file system. However, encryption keys, authentication tokens, payment data, private keys, and biometric templates must be protected. According to Google Security Blog (2025), 67% of vulnerabilities in mobile applications are related to storing secrets in plain text.
Each mobile platform provides its own Secure Storage mechanisms: Android — Keystore and EncryptedSharedPreferences, iOS — Keychain and Data Protection API. These mechanisms are integrated with hardware security modules (TEE, Secure Enclave) and guarantee that data cannot be read even after jailbreaking or rooting the device.
The right choice of Secure Storage method depends on the data type, usage scenario, and performance requirements. Understanding the architecture of each mechanism allows the developer to make the correct architectural decision.
The Android platform provides several levels of data protection, from hardware key storage to encrypted SharedPreferences. The choice depends on data sensitivity and performance requirements.
Android Keystore is a cryptographic provider that generates and stores keys in an isolated execution environment (TEE — Trusted Execution Environment) on devices with hardware protection support. Keys never leave the TEE: cryptographic operations are performed inside a protected area inaccessible even to the operating system.
Starting from Android 9 (API 28), Keystore supports StrongBox Keymaster — a dedicated security chip with its own CPU, True Random Number Generator (TRNG), and protected memory. StrongBox is certified for Common Criteria EAL 4+ compliance and is the highest level of key storage security on Android. To use StrongBox, you must explicitly specify the inStrongBox() flag when generating a key.
Keystore supports algorithms: AES/GCM/NoPadding (256 bit), EC (secp256r1, secp384r1), RSA (2048–4096 bit), and HMAC-SHA256. All keys can be bound to biometric authentication via setUserAuthenticationRequired(true).
EncryptedSharedPreferences is a library from the AndroidX Security package that automatically encrypts all data saved through the SharedPreferences API. Values are encrypted with an AES-256 GCM key, and keys are encrypted with AES-256 SIV (synthetic IV), preventing dictionary attacks on key names.
The main encryption key is stored in Android Keystore, providing two-level protection: Keystore protects the master key, EncryptedSharedPreferences protects the data. Encryption performance is less than 5 ms per read/write operation for typical data (token, settings), making the library suitable for user scenarios.
EncryptedSharedPreferences is not designed for large volumes of data (more than 5 MB) — for those, use an encrypted database through SQLCipher or Room with encryption.
SQLCipher is an extension of SQLite that encrypts the entire database page by page using AES-256-CBC. Each database page is encrypted with a separate key derived from the master password via PBKDF2. SQLCipher adds about 5–15% performance overhead depending on the data size.
Integration with Android is done through the net.zetetic:android-database-sqlcipher library, which provides an API compatible with the standard SQLiteOpenHelper. The password for SQLCipher is recommended to be stored in Keystore, not in code or SharedPreferences.
The iOS platform provides Keychain Services as the main secure storage, as well as the Data Protection API for file encryption at the OS level.
Keychain is an encrypted SQLite database where iOS stores passwords, encryption keys, certificates, and notes. Each Keychain item (SecItem) is stored in encrypted form using a hardware key unique to the device. Access to an item is controlled through an ACL (Access Control List), which can require biometric authentication (Face ID, Touch ID) or a passcode.
Keychain supports protection classes that determine when data is accessible: kSecAttrAccessibleWhenUnlockedThisDeviceOnly — data is accessible only when the device is unlocked and is not transferred during backup. This class is recommended for most authentication token storage scenarios.
On iOS 15+, the Security framework is available with hardware key support through Secure Enclave — a dedicated Apple processor that handles cryptographic operations and stores private keys in isolated memory. Secure Enclave supports ECDSA (secp256r1) and ECDH algorithms for generating keys that cannot be extracted from the chip.
Data Protection is an iOS mechanism that encrypts each file at the file system level (APFS) using a key tied to the device passcode. The developer specifies the protection level through the NSFileProtectionType attribute when creating a file: NSFileProtectionComplete — the file is accessible only when the device is unlocked.
Data Protection works automatically on all devices with iOS 5+ if a passcode is set. Encryption is performed at the hardware level through Apple’s Dedicated AES Engine, ensuring high performance — encryption latency is virtually unnoticeable to the user. To enable protection in an application, simply set the protection attribute when creating a file through FileManager.
Data Protection does not replace Keychain for storing keys — it is used for encrypting files, Core Data databases, and other large volumes of data. The combination of Keychain (for keys) and Data Protection (for files) provides a complete secure storage cycle on iOS.
Let’s look at practical examples of Secure Storage using built-in Android and iOS APIs.
The example shows initialization of EncryptedSharedPreferences with a master key from Android Keystore. All subsequent read and write operations are automatically encrypted and decrypted.
import androidx.security.crypto.EncryptedSharedPreferences
import androidx.security.crypto.MasterKey
val masterKey = MasterKey.Builder(context)
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
.build()
val prefs = EncryptedSharedPreferences.create(
context,
"secure_prefs",
masterKey,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)
prefs.edit()
.putString("auth_token", "eyJhbGciOiJIUzI1NiJ9...")
.apply()
The example demonstrates saving and reading data from iOS Keychain using the Security framework. The code uses kSecAttrAccessibleWhenUnlockedThisDeviceOnly for maximum protection.
import Security
func saveToKeychain(key: String, data: Data) {
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: key,
kSecValueData as String: data,
kSecAttrAccessible as String:
kSecAttrAccessibleWhenUnlockedThisDeviceOnly
]
SecItemDelete(query as CFDictionary)
SecItemAdd(query as CFDictionary, nil)
}
func readFromKeychain(key: String) -> Data? {
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: key,
kSecReturnData as String: true,
kSecMatchLimit as String: kSecMatchLimitOne
]
var result: AnyObject?
let status = SecItemCopyMatching(
query as CFDictionary, &result
)
return status == errSecSuccess ? result as? Data : nil
}
An example of connecting to an encrypted SQLite database via SQLCipher with a password stored in Android Keystore.
import net.sqlcipher.database.SQLiteDatabase
import net.sqlcipher.database.SQLiteOpenHelper
class SecureDBHelper(context: Context) :
SQLiteOpenHelper(context, "secure.db", null, 1) {
private val password = getKeyFromKeystore()
override fun onCreate(db: SQLiteDatabase) {
db.execSQL("CREATE TABLE tokens (id INTEGER PRIMARY KEY, value TEXT)")
}
override fun onUpgrade(
db: SQLiteDatabase, oldVersion: Int, newVersion: Int
) {
onCreate(db)
}
}
// Usage: pass the password when opening
val helper = SecureDBHelper(context)
val db = helper.getWritableDatabase(password)
Proper use of Secure Storage requires following several fundamental principles that prevent common developer mistakes.
Define data classification: which data requires hardware protection (Keystore / Secure Enclave), which requires OS-level encryption (EncryptedSharedPreferences / Data Protection), and which can be stored in the regular file system. Authentication tokens, private keys, and payment data — hardware level only. User settings (theme, language) — EncryptedSharedPreferences is sufficient. Session data (temporary caches) can be stored in memory or a temporary directory.
Never store secrets in code: strings with API keys, passwords, or seed phrases in source code is a critical security mistake. Any reverse engineering will instantly expose this data. Use Keystore for keys, and for configuration — server-side loading at application startup (remote config).
Use biometric binding for critical operations: Android Keystore and iOS Keychain support binding keys to biometric authentication. Each time a key is accessed, the system requests Face ID, Touch ID, or Android biometrics (BiometricPrompt). This guarantees that even with full control over the device, an attacker cannot use the stored data without the owner.
Test security: use security analysis tools — MobSF (Mobile Security Framework) for static analysis, objection for runtime testing, and Frida for bypassing protection. Verify that data is inaccessible after rooting or jailbreaking. Android allows checking for root access through SafetyNet Attestation or Play Integrity API, iOS — through Secure Enclave integrity verification.
Regularly update cryptographic libraries: vulnerabilities in encryption libraries are discovered regularly. Monitor CVEs for AndroidX Security, SQLCipher, and Keychain wrappers. Implement an automatic notification system for new versions through Dependabot or Renovate.
According to Apple Security Research (2025), proper implementation of Secure Storage prevents 96% of attacks aimed at data theft from the device. The remaining 4% are attacks with physical access and zero-day exploits, against which biometric binding is effective.
Frequently Asked Questions
iOS Keychain is an encrypted database for storing passwords, keys, and certificates with ACL access control. Android Keystore is a cryptographic provider that generates and stores keys in an isolated environment (TEE/StrongBox) and does not allow extracting the private key.
EncryptedSharedPreferences uses AES-256 GCM for encrypting values and AES-256 SIV for encrypting keys. The master key is stored in Android Keystore, providing two-level protection. Additionally, HMAC-SHA256 is used for integrity verification.
Yes, HTTPS protects data only in the transmission channel. On the device, data is stored in plain text after decryption. If an attacker gains physical access to the device or installs malware, HTTPS will not protect stored data. Always encrypt data at the storage level.
Use Android Keystore with the setUnlockedDeviceRequired(true) flag, which blocks access to keys on rooted devices. Additionally, verify integrity through Play Integrity API and if it deviates from reference values, clear all secrets from storage.
No, UserDefaults stores data in plain text in a plist file inside the sandbox. Any application with reverse engineering tools (through backup or jailbreak) can read the tokens. Only Keychain is the only secure place to store secrets on iOS.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also