Data Storage Security Quiz
SECURITY › Security
An attacker fully compromises your app's process at runtime on a device with a hardware-backed Keystore. What can they do with a key generated in the Keystore?
- Read the raw key bytes and exfiltrate them to a remote server
- Use the key for crypto while the process runs, but not extract it
- Nothing, because a compromised process cannot reach the Keystore at all
- Permanently copy the key into their own app's Keystore instance
Answer: Use the key for crypto while the process runs, but not extract it
Keystore keys are non-exportable: operations are delegated to a system process or secure hardware, so a compromised app can invoke the key but never read or copy the key material.
How does EncryptedSharedPreferences encrypt the preference KEYS (not the values)?
- AES256-GCM, so each key gets a fresh random IV every time
- It does not encrypt keys; only the preference values are encrypted
- AES256-SIV, a deterministic scheme for lookupable encrypted keys
- RSA-2048 with the Keystore public key for encrypting each key
Answer: AES256-SIV, a deterministic scheme for lookupable encrypted keys
Keys use AES256-SIV, which is deterministic so the same plaintext key always maps to the same ciphertext, enabling lookups; values use the randomized authenticated AES256-GCM.
Which of these is the WORST practice?
- Saving an OAuth refresh token as plain text in SharedPreferences
- Generating an AES key in the Android Keystore with PURPOSE_ENCRYPT
- Using the Storage Access Framework to let the user choose a file
- Writing a cached image into the app's internal files directory
Answer: Saving an OAuth refresh token as plain text in SharedPreferences
A refresh token in plain SharedPreferences sits in unencrypted XML readable on rooted devices and via backups; long-lived secrets must be encrypted with a Keystore-backed key.
You want a Keystore key that can only be used immediately after the user passes a biometric check, with no time window. Which configuration is correct?
- setUserAuthenticationRequired(false) paired with a 300-second key validity window instead
- setUserAuthenticationValidityDurationSeconds(60) alone, with no CryptoObject
- Rely on the device lock screen alone and declare no explicit key parameters at all
- setUserAuthenticationRequired(true), 0-second timeout, one CryptoObject per operation
Answer: setUserAuthenticationRequired(true), 0-second timeout, one CryptoObject per operation
A timeout of 0 forces per-operation authentication; you wrap the Cipher in a CryptoObject and pass it to BiometricPrompt so the key is authorized for exactly that one operation.
What is the key practical difference between a StrongBox-backed key and a TEE-backed key?
- StrongBox uses a discrete secure element, so it is tougher but slower to operate
- StrongBox keeps keys in the app's private data directory rather than in hardware
- TEE keys can be exported off-device, while StrongBox keys stay locked in hardware
- There is no real difference; the two names refer to the exact same component
Answer: StrongBox uses a discrete secure element, so it is tougher but slower to operate
StrongBox is a discrete secure element with its own CPU/storage/RNG, offering stronger physical tamper resistance than the on-SoC TEE, at the cost of speed, fewer algorithms, and limited concurrent operations.
Under scoped storage (Android 11+), how should an app let the user import an arbitrary PDF from anywhere on the device?
- Request WRITE_EXTERNAL_STORAGE and read the file from the raw /sdcard path
- Use the Storage Access Framework (ACTION_OPEN_DOCUMENT) for a granted URI
- Hardcode the absolute /storage path to the shared Download directory and read it
- Request the MANAGE_EXTERNAL_STORAGE all-files permission for an ordinary app
Answer: Use the Storage Access Framework (ACTION_OPEN_DOCUMENT) for a granted URI
Scoped storage removes broad filesystem access; the Storage Access Framework lets the user pick a file and grants the app a scoped content URI, which is the correct and policy-compliant path.
What is the current (2026) status of the EncryptedSharedPreferences / Jetpack Security Crypto library?
- It remains the single officially recommended API for all encrypted storage today
- It was fully removed from the Android SDK and no longer compiles at all
- Deprecated in 2024 and unmaintained; use the Keystore or encrypt data yourself
- It functions only on older devices that lack a hardware-backed Keystore
Answer: Deprecated in 2024 and unmaintained; use the Keystore or encrypt data yourself
androidx.security:security-crypto was deprecated in 2024; it still runs but receives no fixes, so new code should use the Keystore (or Tink) directly or encrypt before writing to prefs/DataStore/files.
Your backend needs cryptographic proof that a specific key was actually generated inside the device's secure hardware and is non-exportable. What does the Keystore provide for this?
- No direct proof exists; the server has to trust the client app alone
- Read KeyInfo.isInsideSecureHardware() and send that boolean upstream
- Hash the raw key bytes locally and compare the digest on the server
- Key attestation: a signed X.509 chain rooted in Google attestation
Answer: Key attestation: a signed X.509 chain rooted in Google attestation
Key attestation produces a certificate chain signed by a Google-rooted attestation key that lets a remote server verify the key's security level, origin, and that it is hardware-backed and non-exportable; a client-sent boolean is trivially spoofed by a compromised app.
By default, what happens to a biometric-bound Keystore key when the user enrolls a NEW fingerprint or face on the device?
- The key is permanently invalidated and can no longer be used
- Nothing; biometric keys are unaffected by enrollment changes
- The key is automatically re-encrypted under the new biometric
- The key is temporarily locked only until the next reboot
Answer: The key is permanently invalidated and can no longer be used
invalidatedByBiometricEnrollment defaults to true, so enrolling a new biometric permanently invalidates the key, defending against an attacker who adds their own biometric; you can opt out with setInvalidatedByBiometricEnrollment(false).
You want a Keystore key whose cryptographic operations only succeed while the screen is unlocked, so background code cannot decrypt data on a locked device. Which builder option enforces this?
- setRandomizedEncryptionRequired(true)
- setUserAuthenticationValidityDurationSeconds(0)
- setUnlockedDeviceRequired(true)
- setIsStrongBoxBacked(true)
Answer: setUnlockedDeviceRequired(true)
setUnlockedDeviceRequired(true) restricts the key to use only while the device is unlocked; the other options govern IV randomization, the post-auth validity window, and secure-element backing respectively.
With Jetpack Security Crypto deprecated, which Google-maintained library is a recommended higher-level option for developers who do not want to call the raw Keystore APIs directly?
- Bouncy Castle's lightweight API bundled directly into the app
- Tink with a keyset wrapped by an Android Keystore master key
- javax.crypto with a hardcoded AES key embedded in source
- OpenSSL shipped in the NDK and called through native code
Answer: Tink with a keyset wrapped by an Android Keystore master key
Google recommends Tink, whose Android integration stores a keyset encrypted by a Keystore-wrapped master key, giving misuse-resistant AEAD without hand-rolling crypto; the other options either lack hardware backing or rely on a hardcoded key.
A teammate migrates from SharedPreferences to Jetpack DataStore (Preferences) and claims the data is now encrypted at rest. Are they correct?
- Yes, DataStore encrypts every value by default with a Keystore key.
- Yes, but only Proto DataStore is encrypted; Preferences is not.
- No, but its binary file format alone keeps data unreadable to attackers.
- No, DataStore is plaintext on disk by default; encrypt secrets first.
Answer: No, DataStore is plaintext on disk by default; encrypt secrets first.
DataStore fixes the threading and consistency problems of SharedPreferences but adds no encryption; the file is plaintext on disk (a binary format is not a security boundary), so secrets must be encrypted with a Keystore-backed key first.
When you encrypt multiple records yourself with an AES-GCM key, why must you never reuse the same IV/nonce with the same key?
- Nonce reuse in GCM can reveal plaintext XOR and the auth subkey
- It only makes decryption fail later with an AEADBadTagException
- It just wastes a little storage, but the encryption stays secure
- Android rejects reused IVs automatically, so this cannot happen
Answer: Nonce reuse in GCM can reveal plaintext XOR and the auth subkey
GCM is broken by nonce reuse under the same key, potentially exposing the GHASH authentication subkey and the XOR of messages; for Keystore keys, randomizedEncryptionRequired defaults to true so the system supplies a fresh random IV per operation.
An app stores Keystore-encrypted secrets in SharedPreferences with auto-backup enabled, and the encrypted XML is backed up to the cloud and restored onto a NEW device. Can a thief who obtains that backup decrypt the secrets?
- Yes, because the backup bundles the Keystore key right alongside the encrypted data
- No; Keystore keys never leave the device, so restored ciphertext is undecryptable
- Yes, the Security-Crypto library exports its master key into the backup
- No, but only when the secrets stay smaller than the auto-backup quota
Answer: No; Keystore keys never leave the device, so restored ciphertext is undecryptable
Keystore keys are non-exportable and are never included in backups, so ciphertext restored to a different device is undecryptable; you should still exclude sensitive files from auto-backup as defense in depth.