Magisk/app/src/full/java/com/topjohnwu/magisk/utils/FingerprintHelper.java

183 lines
7.0 KiB
Java
Raw Normal View History

2018-01-12 01:53:49 +08:00
package com.topjohnwu.magisk.utils;
import android.annotation.TargetApi;
import android.app.Activity;
2018-01-12 01:53:49 +08:00
import android.app.KeyguardManager;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
2018-01-12 01:53:49 +08:00
import android.hardware.fingerprint.FingerprintManager;
import android.os.Build;
import android.os.CancellationSignal;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyPermanentlyInvalidatedException;
import android.security.keystore.KeyProperties;
import android.view.Gravity;
import android.widget.Toast;
2018-01-12 01:53:49 +08:00
2019-01-30 03:10:12 -05:00
import com.topjohnwu.magisk.App;
import com.topjohnwu.magisk.Config;
import com.topjohnwu.magisk.Const;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.components.CustomAlertDialog;
2018-01-12 01:53:49 +08:00
import java.security.KeyStore;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
@TargetApi(Build.VERSION_CODES.M)
2018-01-13 05:49:47 +08:00
public abstract class FingerprintHelper {
2018-01-12 01:53:49 +08:00
private FingerprintManager manager;
private Cipher cipher;
private CancellationSignal cancel;
2018-10-28 00:54:56 -04:00
public static boolean useFingerPrint() {
2019-01-21 15:49:03 -05:00
boolean fp = Config.get(Config.Key.SU_FINGERPRINT);
2018-10-28 00:54:56 -04:00
if (fp && !canUseFingerprint()) {
2019-01-21 15:49:03 -05:00
Config.set(Config.Key.SU_FINGERPRINT, false);
2018-10-28 00:54:56 -04:00
fp = false;
}
return fp;
}
2018-01-12 01:53:49 +08:00
public static boolean canUseFingerprint() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M)
return false;
KeyguardManager km = App.self.getSystemService(KeyguardManager.class);
FingerprintManager fm = App.self.getSystemService(FingerprintManager.class);
return km.isKeyguardSecure() && fm != null && fm.isHardwareDetected() && fm.hasEnrolledFingerprints();
2018-01-12 01:53:49 +08:00
}
public static void showAuthDialog(Activity activity, Runnable onSuccess) {
CustomAlertDialog dialog = new CustomAlertDialog(activity);
CustomAlertDialog.ViewHolder vh = dialog.getViewHolder();
try {
FingerprintHelper helper = new FingerprintHelper() {
@Override
public void onAuthenticationError(int errorCode, CharSequence errString) {
vh.messageView.setTextColor(Color.RED);
vh.messageView.setText(errString);
}
@Override
public void onAuthenticationHelp(int helpCode, CharSequence helpString) {
vh.messageView.setTextColor(Color.RED);
vh.messageView.setText(helpString);
}
@Override
public void onAuthenticationFailed() {
vh.messageView.setTextColor(Color.RED);
vh.messageView.setText(R.string.auth_fail);
}
@Override
public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) {
dialog.dismiss();
onSuccess.run();
}
};
Drawable fingerprint = activity.getResources().getDrawable(R.drawable.ic_fingerprint);
fingerprint.setBounds(0, 0, Utils.dpInPx(50), Utils.dpInPx(50));
Resources.Theme theme = activity.getTheme();
TypedArray ta = theme.obtainStyledAttributes(new int[] {R.attr.imageColorTint});
fingerprint.setTint(ta.getColor(0, Color.GRAY));
ta.recycle();
vh.messageView.setCompoundDrawables(null, null, null, fingerprint);
vh.messageView.setCompoundDrawablePadding(Utils.dpInPx(20));
vh.messageView.setGravity(Gravity.CENTER);
dialog.setMessage(R.string.auth_fingerprint)
.setNegativeButton(R.string.close, (d, w) -> helper.cancel())
.setOnCancelListener(d -> helper.cancel())
.show();
helper.authenticate();
} catch (Exception e) {
e.printStackTrace();
Utils.toast(R.string.auth_fail, Toast.LENGTH_SHORT);
}
}
2018-01-12 01:53:49 +08:00
protected FingerprintHelper() throws Exception {
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
manager = App.self.getSystemService(FingerprintManager.class);
2018-01-12 01:53:49 +08:00
cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/"
+ KeyProperties.BLOCK_MODE_CBC + "/"
+ KeyProperties.ENCRYPTION_PADDING_PKCS7);
keyStore.load(null);
SecretKey key = (SecretKey) keyStore.getKey(Const.SU_KEYSTORE_KEY, null);
if (key == null) {
key = generateKey();
}
try {
cipher.init(Cipher.ENCRYPT_MODE, key);
} catch (KeyPermanentlyInvalidatedException e) {
// Only happens on Marshmallow
key = generateKey();
cipher.init(Cipher.ENCRYPT_MODE, key);
}
}
2018-01-13 05:49:47 +08:00
public abstract void onAuthenticationError(int errorCode, CharSequence errString);
public abstract void onAuthenticationHelp(int helpCode, CharSequence helpString);
public abstract void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result);
public abstract void onAuthenticationFailed();
public void authenticate() {
2018-01-12 01:53:49 +08:00
cancel = new CancellationSignal();
FingerprintManager.CryptoObject cryptoObject = new FingerprintManager.CryptoObject(cipher);
manager.authenticate(cryptoObject, cancel, 0, new Callback(), null);
2018-01-12 01:53:49 +08:00
}
public void cancel() {
if (cancel != null)
cancel.cancel();
}
private SecretKey generateKey() throws Exception {
KeyGenerator keygen = KeyGenerator
.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(
Const.SU_KEYSTORE_KEY,
KeyProperties.PURPOSE_ENCRYPT | 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 class Callback extends FingerprintManager.AuthenticationCallback {
@Override
public void onAuthenticationError(int errorCode, CharSequence errString) {
FingerprintHelper.this.onAuthenticationError(errorCode, errString);
}
@Override
public void onAuthenticationHelp(int helpCode, CharSequence helpString) {
FingerprintHelper.this.onAuthenticationHelp(helpCode, helpString);
}
@Override
public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) {
FingerprintHelper.this.onAuthenticationSucceeded(result);
}
@Override
public void onAuthenticationFailed() {
FingerprintHelper.this.onAuthenticationFailed();
}
}
2018-01-12 01:53:49 +08:00
}