mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-01-10 14:03:38 +00:00
122 lines
4.4 KiB
Kotlin
122 lines
4.4 KiB
Kotlin
package com.topjohnwu.magisk.utils
|
|
|
|
import android.annotation.TargetApi
|
|
import android.app.KeyguardManager
|
|
import android.content.Context
|
|
import android.hardware.fingerprint.FingerprintManager
|
|
import android.os.Build
|
|
import android.os.CancellationSignal
|
|
import android.security.keystore.KeyGenParameterSpec
|
|
import android.security.keystore.KeyProperties
|
|
import com.topjohnwu.magisk.Config
|
|
import com.topjohnwu.magisk.extensions.get
|
|
import com.topjohnwu.magisk.extensions.inject
|
|
import java.security.KeyStore
|
|
import javax.crypto.Cipher
|
|
import javax.crypto.KeyGenerator
|
|
import javax.crypto.SecretKey
|
|
|
|
@TargetApi(Build.VERSION_CODES.M)
|
|
abstract class FingerprintHelper @Throws(Exception::class)
|
|
protected constructor() {
|
|
|
|
private val manager: FingerprintManager?
|
|
private val cipher: Cipher
|
|
private var cancel: CancellationSignal? = null
|
|
private val context: Context by inject()
|
|
|
|
init {
|
|
val keyStore = KeyStore.getInstance("AndroidKeyStore")
|
|
manager = context.getSystemService(FingerprintManager::class.java)
|
|
cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/"
|
|
+ KeyProperties.BLOCK_MODE_CBC + "/"
|
|
+ KeyProperties.ENCRYPTION_PADDING_PKCS7)
|
|
keyStore.load(null)
|
|
var key = keyStore.getKey(SU_KEYSTORE_KEY, null) as SecretKey? ?: generateKey()
|
|
runCatching {
|
|
cipher.init(Cipher.ENCRYPT_MODE, key)
|
|
}.onFailure {
|
|
// Only happens on Marshmallow
|
|
key = generateKey()
|
|
cipher.init(Cipher.ENCRYPT_MODE, key)
|
|
}
|
|
}
|
|
|
|
abstract fun onAuthenticationError(errorCode: Int, errString: CharSequence)
|
|
|
|
abstract fun onAuthenticationHelp(helpCode: Int, helpString: CharSequence)
|
|
|
|
abstract fun onAuthenticationSucceeded(result: FingerprintManager.AuthenticationResult)
|
|
|
|
abstract fun onAuthenticationFailed()
|
|
|
|
fun authenticate() {
|
|
cancel = CancellationSignal()
|
|
val cryptoObject = FingerprintManager.CryptoObject(cipher)
|
|
manager!!.authenticate(cryptoObject, cancel, 0, Callback(), null)
|
|
}
|
|
|
|
fun cancel() {
|
|
if (cancel != null)
|
|
cancel!!.cancel()
|
|
}
|
|
|
|
@Throws(Exception::class)
|
|
private fun generateKey(): SecretKey {
|
|
val keygen = KeyGenerator
|
|
.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore")
|
|
val builder = KeyGenParameterSpec.Builder(
|
|
SU_KEYSTORE_KEY,
|
|
KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT)
|
|
.setBlockModes(KeyProperties.BLOCK_MODE_CBC)
|
|
.setUserAuthenticationRequired(true)
|
|
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
|
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
|
builder.setInvalidatedByBiometricEnrollment(false)
|
|
}
|
|
keygen.init(builder.build())
|
|
return keygen.generateKey()
|
|
}
|
|
|
|
private inner class Callback : FingerprintManager.AuthenticationCallback() {
|
|
override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
|
|
this@FingerprintHelper.onAuthenticationError(errorCode, errString)
|
|
}
|
|
|
|
override fun onAuthenticationHelp(helpCode: Int, helpString: CharSequence) {
|
|
this@FingerprintHelper.onAuthenticationHelp(helpCode, helpString)
|
|
}
|
|
|
|
override fun onAuthenticationSucceeded(result: FingerprintManager.AuthenticationResult) {
|
|
this@FingerprintHelper.onAuthenticationSucceeded(result)
|
|
}
|
|
|
|
override fun onAuthenticationFailed() {
|
|
this@FingerprintHelper.onAuthenticationFailed()
|
|
}
|
|
}
|
|
|
|
companion object {
|
|
private const val SU_KEYSTORE_KEY = "su_key"
|
|
|
|
fun useFingerprint(): Boolean {
|
|
var fp = Config.suFingerprint
|
|
if (fp && !canUseFingerprint()) {
|
|
Config.suFingerprint = false
|
|
fp = false
|
|
}
|
|
return fp
|
|
}
|
|
|
|
fun canUseFingerprint(context: Context = get()): Boolean {
|
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M)
|
|
return false
|
|
val km = context.getSystemService(KeyguardManager::class.java)
|
|
val fm = context.getSystemService(FingerprintManager::class.java)
|
|
return km?.isKeyguardSecure ?: false &&
|
|
fm != null && fm.isHardwareDetected && fm.hasEnrolledFingerprints()
|
|
}
|
|
}
|
|
}
|