session-android/app/src/main/java/org/thoughtcrime/securesms/crypto/BiometricSecretProvider.kt

76 lines
2.8 KiB
Kotlin

package org.thoughtcrime.securesms.crypto
import android.content.Context
import android.os.Build
import android.security.keystore.KeyGenParameterSpec
import android.security.keystore.KeyProperties
import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsession.utilities.Util
import java.security.KeyPairGenerator
import java.security.KeyStore
import java.security.PrivateKey
import java.security.Signature
class BiometricSecretProvider {
companion object {
private const val BIOMETRIC_ASYM_KEY_ALIAS = "Session-biometric-asym"
private const val ANDROID_KEYSTORE = "AndroidKeyStore"
private const val SIGNATURE_ALGORITHM = "SHA512withECDSA"
}
fun getRandomData() = Util.getSecretBytes(32)
private fun createAsymmetricKey(context: Context) {
val keyGenerator = KeyPairGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_EC, ANDROID_KEYSTORE
)
val builder = KeyGenParameterSpec.Builder(BIOMETRIC_ASYM_KEY_ALIAS,
KeyProperties.PURPOSE_SIGN or KeyProperties.PURPOSE_VERIFY
)
.setDigests(
KeyProperties.DIGEST_SHA256,
KeyProperties.DIGEST_SHA512
)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_OAEP)
.setUserAuthenticationRequired(true)
.setUserAuthenticationValidityDurationSeconds(-1)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
builder.setUnlockedDeviceRequired(true)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
builder.setInvalidatedByBiometricEnrollment(true)
}
keyGenerator.initialize(builder.build())
keyGenerator.generateKeyPair()
}
fun getOrCreateBiometricSignature(context: Context): Signature {
val ks = KeyStore.getInstance(ANDROID_KEYSTORE)
ks.load(null)
if (!ks.containsAlias(BIOMETRIC_ASYM_KEY_ALIAS)
|| !ks.entryInstanceOf(BIOMETRIC_ASYM_KEY_ALIAS, KeyStore.PrivateKeyEntry::class.java)
|| !TextSecurePreferences.getFingerprintKeyGenerated(context)
) {
createAsymmetricKey(context)
TextSecurePreferences.setFingerprintKeyGenerated(context)
}
val key = ks.getKey(BIOMETRIC_ASYM_KEY_ALIAS, null) as PrivateKey
val signature = Signature.getInstance(SIGNATURE_ALGORITHM)
signature.initSign(key)
return signature
}
fun verifySignature(data: ByteArray, signedData: ByteArray): Boolean {
val ks = KeyStore.getInstance(ANDROID_KEYSTORE)
ks.load(null)
val certificate = ks.getCertificate(BIOMETRIC_ASYM_KEY_ALIAS)
val signature = Signature.getInstance(SIGNATURE_ALGORITHM)
signature.initVerify(certificate)
signature.update(data)
return signature.verify(signedData)
}
}