# BiometricsHelper.kt

    /*
     * The MIT License
     *
     * Original work sponsored and donated by The Danish Health Data Authority (http://www.sundhedsdatastyrelsen.dk)
     *
     * Copyright (C) 2021 The Danish Health Data Authority (http://www.sundhedsdatastyrelsen.dk)
     *
     *
     * Permission is hereby granted, free of charge, to any person obtaining a copy of
     * this software and associated documentation files (the "Software"), to deal in
     * the Software without restriction, including without limitation the rights to
     * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
     * of the Software, and to permit persons to whom the Software is furnished to do
     * so, subject to the following conditions:
     *
     *
     * The above copyright notice and this permission notice shall be included in all
     * copies or substantial portions of the Software.
     *
     *
     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     * SOFTWARE.
     */

    package dk.nsp.domain.auth

    import android.security.keystore.KeyGenParameterSpec
    import android.security.keystore.KeyProperties
    import java.security.KeyStore
    import java.security.NoSuchAlgorithmException
    import java.security.NoSuchProviderException
    import javax.crypto.Cipher
    import javax.crypto.KeyGenerator
    import javax.crypto.NoSuchPaddingException

    const val keyStoreName = "AndroidKeyStore"

    class BiometricsHelper {

        @Throws(NoSuchAlgorithmException::class, NoSuchPaddingException::class)
        fun createKeyStoreCipher(): Cipher = Cipher.getInstance(getAesAlgorithm())

        private fun getAesAlgorithm(): String {
            return "${KeyProperties.KEY_ALGORITHM_AES}/${KeyProperties.BLOCK_MODE_CBC}/${KeyProperties.ENCRYPTION_PADDING_PKCS7}"
        }

        @Throws(Exception::class)
        fun getKeystore(): KeyStore {
            val store = KeyStore.getInstance(keyStoreName)
            store.load(null)
            return store
        }

        @Throws(Exception::class)
        fun createCipherKeyGenerator(): KeyGenerator {
            try {
                val cipherKeyGenerator =
                    KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, keyStoreName)
                val keyProperties = KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT

                val builder = KeyGenParameterSpec.Builder("alias", keyProperties)
                    .setBlockModes(KeyProperties.BLOCK_MODE_CBC)
                    .setUserAuthenticationRequired(true)
                    .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)

                cipherKeyGenerator.init(builder.build())
                return cipherKeyGenerator
            } catch (e: Exception) {
                throw when (e) {
                    is NoSuchAlgorithmException,
                    is NoSuchProviderException ->
                        Exception("Failed to get instance of KeyGenerator", e)
                    else -> e
                }
            }
        }

        companion object {
            private var instance: BiometricsHelper? = null

            fun get(): BiometricsHelper = instance
                ?: BiometricsHelper().apply {
                    instance = this
                }
        }
    }