Can an Android app reliably determine after a crash whether a maxUsageCount=1 Keystore key was consumed?
Title:
Can an Android app reliably determine after a crash whether a software-enforced maxUsageCount=1 Keystore key was consumed?
I am investigating the crash semantics of Android Keystore keys created with KeyGenParameterSpec.Builder.setMaxUsageCount(1).
Assume a device where:
Android Keystore is available.
The cryptographic key itself may be hardware-backed.
PackageManager.FEATURE_KEYSTORE_SINGLE_USE_KEY is not advertised, so the usage-count restriction may be enforced by Android/keystore2 rather than secure hardware.
The application uses the key for a security-sensitive state transition.
Consider this sequence:
A key has maxUsageCount = 1.
The app starts a cryptographic operation.
The operation reaches or may have reached successful completion.
The app/process/device crashes before the application can durably record the result.
After restart, the key may be exhausted, deleted, unavailable, or otherwise inaccessible.
My questions are:
1. Using only public Android APIs, is there a non-consuming way after restart to reliably distinguish between:
the key was successfully used and its usage count reached zero;
the key still has one use remaining;
the key was deleted/missing for some unrelated reason; and
the Keystore is temporarily or permanently unable to provide the key?
2. Can KeyInfo.getRemainingUsageCount() provide authoritative evidence for this purpose, or should it only be treated as best-effort information?
3. Once a usage-limited key reaches zero and Android removes/unreferences it, is there any public API exposing a persistent reason/tombstone indicating that the key disappeared specifically because its usage count was exhausted?
4. Is there any guarantee about crash ordering between successful completion of the cryptographic operation and persistence of the software-enforced usage-count decrement?
I am specifically interested in the software-enforced usage-count case, not devices advertising hardware-enforced single-use keys.
The security requirement is fail-closed: an ambiguous result can be rejected. I am trying to determine whether the consumed/not-consumed state can be established reliably after a crash, rather than attempting another cryptographic operation to find out.
References I have already reviewed include KeyGenParameterSpec.Builder.setMaxUsageCount(), KeyInfo.getRemainingUsageCount(), and the AOSP keystore2 limited-use enforcement implementation.
Is there a public API guarantee or AOSP behavior that makes this distinction reliable?