DatabaseKeyCipher copy-pastes ~60 of its ~142 lines from the pre-existing KeystoreCrypto: doEncrypt/decrypt bodies, existingKey/getOrCreateKey (a split of KeystoreCrypto.secretKey), the keyLock idiom, and 5 identical constants (ANDROID_KEYSTORE, TRANSFORMATION, IV_LENGTH, TAG_BITS, AES_KEY_SIZE_BITS). The two copies already disagree on missing-key handling: KeystoreCrypto.decrypt silently generates a key when the alias is absent (later failing with an opaque AEADBadTagException), while DatabaseKeyCipher.decrypt fails fast with error("auth-bound database key is missing"). Any future change (StrongBox opt-in, IV handling, error mapping) applied to one copy silently misses the other.
Separately, the accepted-authenticator policy is encoded twice with no cross-reference: AppLockManager.AUTHENTICATORS (BIOMETRIC_STRONG or DEVICE_CREDENTIAL, BiometricManager terms) and DatabaseKeyCipher.buildSpec (AUTH_BIOMETRIC_STRONG or AUTH_DEVICE_CREDENTIAL, KeyProperties terms). Loosening one without the other yields prompts that succeed but keys that throw UserNotAuthenticatedException at use — a drift only observable on device.
Suggested fix
Extract a shared alias-parameterized AES-256-GCM Keystore base (encrypt/decrypt/exists/delete + constants), leaving only the auth-bound spec and invalidation classification as DatabaseKeyCipher's delta; reconcile the missing-key behavior deliberately. Tie the two authenticator constants to one definition (or a documented mapping).
Origin: code review of PR #45 (screen-lock app gate). Reuse/maintainability cleanup.
## Problem
`DatabaseKeyCipher` copy-pastes ~60 of its ~142 lines from the pre-existing `KeystoreCrypto`: `doEncrypt`/`decrypt` bodies, `existingKey`/`getOrCreateKey` (a split of `KeystoreCrypto.secretKey`), the `keyLock` idiom, and 5 identical constants (`ANDROID_KEYSTORE`, `TRANSFORMATION`, `IV_LENGTH`, `TAG_BITS`, `AES_KEY_SIZE_BITS`). The two copies already **disagree** on missing-key handling: `KeystoreCrypto.decrypt` silently generates a key when the alias is absent (later failing with an opaque `AEADBadTagException`), while `DatabaseKeyCipher.decrypt` fails fast with `error("auth-bound database key is missing")`. Any future change (StrongBox opt-in, IV handling, error mapping) applied to one copy silently misses the other.
Separately, the accepted-authenticator policy is encoded twice with no cross-reference: `AppLockManager.AUTHENTICATORS` (`BIOMETRIC_STRONG or DEVICE_CREDENTIAL`, BiometricManager terms) and `DatabaseKeyCipher.buildSpec` (`AUTH_BIOMETRIC_STRONG or AUTH_DEVICE_CREDENTIAL`, KeyProperties terms). Loosening one without the other yields prompts that succeed but keys that throw `UserNotAuthenticatedException` at use — a drift only observable on device.
## Suggested fix
Extract a shared alias-parameterized AES-256-GCM Keystore base (encrypt/decrypt/exists/delete + constants), leaving only the auth-bound spec and invalidation classification as `DatabaseKeyCipher`'s delta; reconcile the missing-key behavior deliberately. Tie the two authenticator constants to one definition (or a documented mapping).
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Origin: code review of PR #45 (screen-lock app gate). Reuse/maintainability cleanup.
Problem
DatabaseKeyCiphercopy-pastes ~60 of its ~142 lines from the pre-existingKeystoreCrypto:doEncrypt/decryptbodies,existingKey/getOrCreateKey(a split ofKeystoreCrypto.secretKey), thekeyLockidiom, and 5 identical constants (ANDROID_KEYSTORE,TRANSFORMATION,IV_LENGTH,TAG_BITS,AES_KEY_SIZE_BITS). The two copies already disagree on missing-key handling:KeystoreCrypto.decryptsilently generates a key when the alias is absent (later failing with an opaqueAEADBadTagException), whileDatabaseKeyCipher.decryptfails fast witherror("auth-bound database key is missing"). Any future change (StrongBox opt-in, IV handling, error mapping) applied to one copy silently misses the other.Separately, the accepted-authenticator policy is encoded twice with no cross-reference:
AppLockManager.AUTHENTICATORS(BIOMETRIC_STRONG or DEVICE_CREDENTIAL, BiometricManager terms) andDatabaseKeyCipher.buildSpec(AUTH_BIOMETRIC_STRONG or AUTH_DEVICE_CREDENTIAL, KeyProperties terms). Loosening one without the other yields prompts that succeed but keys that throwUserNotAuthenticatedExceptionat use — a drift only observable on device.Suggested fix
Extract a shared alias-parameterized AES-256-GCM Keystore base (encrypt/decrypt/exists/delete + constants), leaving only the auth-bound spec and invalidation classification as
DatabaseKeyCipher's delta; reconcile the missing-key behavior deliberately. Tie the two authenticator constants to one definition (or a documented mapping).