Skip to content

Recover unreadable legacy encrypted preferences and migrate to AGP 9 - #7

Open
minh-rakuten wants to merge 6 commits into
masterfrom
bugfix/keystore-keyset-recovery
Open

Recover unreadable legacy encrypted preferences and migrate to AGP 9#7
minh-rakuten wants to merge 6 commits into
masterfrom
bugfix/keystore-keyset-recovery

Conversation

@minh-rakuten

@minh-rakuten minh-rakuten commented Aug 18, 2026

Copy link
Copy Markdown
Collaborator

Cause

Legacy version-4 values keep their AES data keys in EncryptedSharedPreferences. After a device restore or OEM KeyStore failure, the Android KeyStore key may no longer match that preference keyset, causing AEADBadTagException and repeated crashes while reading old values.

Fix

  • Recover the unusable version-4 preference store.
  • Return LocalEncryptionKeyLostException when a legacy data key is gone.
  • Keep the existing version 1–4 behavior; no version-5 format is introduced.
  • Upgrade AndroidX Security to 1.1.0 and retain the Gradle 9.4.1/AGP 9.2.1 migration.

Result

The host app can catch one specific key-loss error and reuse its existing backup repair mechanism instead of crashing or retrying an unrecoverable decryption. Applications using VERSION_UNENCRYPTED remain unchanged.

minh-rakuten and others added 3 commits August 18, 2026 15:37
EncryptedSharedPreferences.create() was called straight from a lazy with
no error handling. When the AndroidKeyStore master key no longer matches
the Tink keyset stored in private_pref -- a device restore, a key
invalidation -- Tink throws AEADBadTagException and every encrypt and
decrypt through this class fails from then on, permanently.

Open the store through a three step recovery instead: retry after
clearing the keyset, then after replacing the master key. Only failures
that positively identify lost key material trigger it, so a locked
device or an unavailable keystore daemon still surfaces as an error
rather than discarding readable data.

Values written with VERSION_AES_KEY_ENCRYPTED_PREFERENCE before a reset
are gone, so report them as UnrecoverableCiphertextException and expose
wasEncryptedPreferenceReset() for callers that re-derive from a backup.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@minh-rakuten minh-rakuten changed the title Recover from an unreadable encrypted preference keyset Recover lost KeyStore keys and add AES-GCM v5 encryption Aug 18, 2026
@minh-rakuten minh-rakuten changed the title Recover lost KeyStore keys and add AES-GCM v5 encryption Fix lost KeyStore recovery, add AES-GCM v5, and migrate to AGP 9 Aug 18, 2026
@minh-rakuten minh-rakuten changed the title Fix lost KeyStore recovery, add AES-GCM v5, and migrate to AGP 9 Recover unreadable legacy encrypted preferences and migrate to AGP 9 Aug 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant