package dev.privacyllc.period.core.security

/**
 * The one operation that needs hardware, behind an interface so everything else
 * can be tested in a second on the JVM.
 *
 * The split is deliberate and follows this project's stated reason for keeping
 * the `domain` modules free of Android: the interesting logic here — the
 * record format, the stretching, the domain separation, the constant-time
 * compare, the
 * rehash-on-unlock rule — is arithmetic, and arithmetic tested on an emulator is
 * arithmetic tested when somebody remembers to boot one. Only
 * [AndroidKeyStoreMacProvider] needs a device, and it is deliberately thin.
 *
 * There is no Robolectric shortcut available: 4.16.1 ships `ShadowBiometricManager`
 * and `ShadowKeyguardManager` and no crypto shadows at all, so
 * `KeyStore.getInstance("AndroidKeyStore")` cannot work on the host JVM. That is
 * a reason to make this seam small, not a reason to skip the device test.
 */
interface MacProvider {

    /** True when the signing key exists. False after [deleteKey], or on a fresh install. */
    fun hasKey(): Boolean

    /**
     * Create the signing key if it is absent.
     *
     * Called once, at enrolment. **Never call this to recover from a failure.**
     * A new key cannot verify an old record, so minting one in a `catch` turns
     * "we could not check your PIN" into "your PIN is now wrong forever", and
     * under the no-recovery policy that is the user's history gone.
     */
    fun ensureKey()

    /** HMAC-SHA256 over [data] with the non-exportable key. */
    fun mac(data: ByteArray): ByteArray

    /**
     * Destroy the signing key.
     *
     * Only the erase path calls this, and it must, or a user who erases
     * everything is left with a working lock over an empty database — erased
     * *and* still locked out, which is the worst outcome this feature can
     * produce.
     */
    fun deleteKey()
}
