Android SharedPreferences Tutorial and Example

Secure storage with Android KeyStore

Android apps often hold access tokens, licence state, account identifiers, or personal records that should not remain readable on a lost phone. Android KeyStore lets applications use generated cryptographic keys without embedding secret material in source code.

KeyStore is not a container for every sensitive value. It is a key-management service: an encryption key stays non-exportable while ciphertext is kept in SharedPreferences, a Room database, or an app-private file. Plaintext may still exist briefly in memory during use, so runtime compromise, unsafe logging, and screenshots require separate controls.

A practical design starts with a clear threat model and a limited protected data set. The common pattern is a hardware-backed key where supported, AES-GCM for local data, user authentication for sensitive actions, and a tested recovery and rotation path.

Understand the security boundary

Keys requested through the AndroidKeyStore provider may be protected by a secure element, hardware-backed keystore, or the device’s software implementation. KeyInfo can reveal the security level on newer Android versions, while StrongBox offers stronger isolation on supported hardware. Do not assume every handset provides the same protection.

The boundary protects key bytes and cryptographic operations; it does not make a compromised app trustworthy. A rooted device, injected code, accidental Log.d output, or a malicious accessibility service can still expose data. Australian banking, superannuation, and telehealth apps should combine local protection with TLS, server-side controls, least privilege, and short token lifetimes.

Select the right key and algorithm

Use asymmetric keys for signing and key agreement, and symmetric keys for encrypting local records. An EC P-256 signing key can authenticate requests without revealing its private half. For application data, AES-256 in Galois/Counter Mode provides authenticated encryption; every operation needs a fresh 96-bit IV and a new Cipher instance.

val generator = KeyGenerator.getInstance(
    KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore"
)
generator.init(
    KeyGenParameterSpec.Builder(
        "local_secret_v1",
        KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
    )
        .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
        .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
        .setKeySize(256)
        .build()
)
val key = generator.generateKey()

Give each key a descriptive, versioned alias and request only its required purposes. Key generation can block or fail, so perform it behind a repository API rather than in an Activity constructor. If a server verifies signatures, enrol the public key through an authenticated flow and define replacement and revocation procedures.

Protect data outside the key store

Create a payload containing a format version, random IV, and ciphertext. For example, store a one-byte version, 12-byte IV, and GCM output as Base64 in SharedPreferences or a Room column. Keep the version outside the encrypted portion so future code can select the correct decryption path.

Decrypt by loading the matching alias, initialising AES/GCM/NoPadding, and passing the stored IV. Treat an authentication-tag failure as corrupted or tampered data, never as permission to return partial plaintext. Never reuse an IV with the same key, and clear byte arrays when practical, while recognising that JVM strings and framework copies are difficult to erase.

Require authentication for sensitive actions

Set setUserAuthenticationRequired(true) when decryption should depend on a recent credential, PIN, pattern, or biometric check. Configure a suitable authentication validity window and use BiometricPrompt with a CryptoObject so the operation is bound to successful authentication. Offer the device-credential fallback supported by your minimum Android version.

For state-driven screens, observing LiveData changes keeps readiness and recoverable authentication errors visible without exposing key material. Expose state rather than plaintext, and distinguish user cancellation from corruption.

Commuters check work messages on Sydney trains and Melbourne trams, while Australian banking and mobile-wallet sessions demand quick access. A short authorisation window balances security with the need to approve a payment or open a document without friction. Background work should not silently repeat a protected operation.

Plan backups, upgrades, and key rotation

Keys held by AndroidKeyStore are tied to the app and device and are not restored by Android backup. Auto Backup may still copy ciphertext. Exclude secret-bearing preferences and files with backup or data-extraction rules, or make restoration fail deliberately, rather than restoring data that has no matching key.

Version key aliases. To rotate, create local_secret_v2, decrypt with the old key, re-encrypt with the new one, verify it, then remove the old alias. Make migration transactional so process death cannot strand records between formats.

Parts of regional Australia have intermittent connectivity, so local decryption should not depend on a server round trip. If cross-device recovery is required, use a documented envelope-encryption design with access controls meeting applicable Australian privacy duties, rather than exporting the raw device key.

Verify behaviour across real devices

Test on the oldest supported Android release and several manufacturers: hardware backing, StrongBox, biometrics, and keystore implementations vary. Cover missing screen locks, changed biometric enrolment, locked devices, app data clearing, reinstall, backup restoration, and rotation. Emulators validate functions, not hardware protection.

Confirm that repeated encryption produces different ciphertext, tampering fails authentication, and keys never appear in logs, saved state, preferences, or crash reports. Simulate process death during rotation. If secure material is unavailable, fail closed rather than falling back to plaintext.

Privacy compliance remains separate. The Privacy Act 1988 and Australian Privacy Principles apply to many organisations, while state health-records laws can add duties. Explain what is collected, restrict access and retention, and ensure recovery does not create an unlawful shadow copy of personal information.

Compare storage choices and finalise the design

For most local secrets, the strongest default is a non-exportable key in Android KeyStore plus separately stored AES-GCM ciphertext. Plain preferences remain suitable for public configuration, while a remote secret service is better for server credentials and centrally controlled deployment than for offline user records.

Option What it protects Device binding Best fit Main limitation
Android KeyStore Generated keys and signatures Yes Local encryption, signing, and authentication Hardware support and invalidation differ by device
Keystore-backed ciphertext Ciphertext at rest Usually Tokens and offline records Requires payload versioning and key rotation
Plain preferences or files No meaningful protection for secrets No Public settings or disposable cache Exposes content as soon as the file is read
Remote secret service Server-held credentials No Server-to-server and administrative workflows Adds network, availability, and backend complexity

Document key aliases, payload versions, authentication policy, backup exclusions, and revocation before release. That combination gives reviewers an auditable storage design with predictable failures and controlled migration.