由于使用指纹识别功能需要一个加密对象(
CryptoObject)该对象一般是由对称加密或者非对称加密获得。
* 纯本地的使用指纹识别功能,只需要对称加密即可;
* 使用指纹识别的对称加密功能的主要流程如下:
* 1、使用
KeyGenerator 创建一个对称密钥,存放在
KeyStore 里。
* 2、设置
KeyGenParameterSpec.Builder.setUserAuthenticationRequired() 为
true,
* 3、使用创建好的对称密钥初始化一个
Cipher对象,并用该对象调用
FingerprintManager.authenticate() 方法
* 启动指纹传感器并开始监听。
* 4、重写
FingerprintManager.AuthenticationCallback 的几个回调方法,以处理指纹识别成功(
onAuthenticationSucceeded())、
* 失败(
onAuthenticationFailed() 和
onAuthenticationError())等情况。
/**
* 指纹秘钥生成工具
* KeyGenerator产生密钥
* KeyStore存放获取密钥
* Cipher,是一个按照一定的加密规则,将数据进行加密后的一个对象
*/
@RequiresApi(api = Build.VERSION_CODES.M)
public class FingerPrintKeyHelper {
private static KeyGenerator mKeyGenerator;
private static KeyStore mKeyStore;
public FingerPrintKeyHelper() {
AppParam.getInstance().setKeyName("finger_key");
AppParam.getInstance().setSecretMsg("finger content");
try {
mKeyStore = KeyStore.getInstance("AndroidKeyStore");
} catch (KeyStoreException e) {
throw new RuntimeException("Failed to get an instance of KeyStore", e);
}
}
/**
* 创建密钥
* invalidatedByBiometricEnrollment是false的话,录入新的指纹创建的密钥不会失效
* 默认是true,true的话,注册新指纹,密钥将失效
* 7.0以上的系统这个参数才有效
*/
public void createKey(boolean invalidatedByBiometricEnrollment) {
try {
mKeyStore.load(null);
final KeyGenerator generator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
final int purpose = KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT;
final KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(AppParam.getInstance().getKeyName(), purpose);
builder.setBlockModes(KeyProperties.BLOCK_MODE_CBC);
builder.setUserAuthenticationRequired(true);//每次使用这个密钥,需要指纹验证
builder.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7);
//添加这个会报错:android.security.KeyStoreException: Key user not authenticated
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
// builder.setInvalidatedByBiometricEnrollment(invalidatedByBiometricEnrollment);
// }
generator.init(builder.build());
generator.generateKey();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 获取密钥对象
*
* @return
*/
public FingerprintManagerCompat.CryptoObject getCryptoObject(boolean isEncrypt, byte[] IV) {
try {
mKeyStore.load(null);
final SecretKey key = (SecretKey) mKeyStore.getKey(AppParam.getInstance().getKeyName(), null);
if (null == key) {
return null;
}
final Cipher cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/" + KeyProperties.BLOCK_MODE_CBC
+ "/" + KeyProperties.ENCRYPTION_PADDING_PKCS7);
if (isEncrypt) {
cipher.init(Cipher.ENCRYPT_MODE, key);
} else {
cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(IV));
}
return new FingerprintManagerCompat.CryptoObject(cipher);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
/**
* 指纹解密需要的初始化向量参数
*/
String IV = "iv";
/**
* 用来指纹加密的字符串
*/
String SECRET_MESSAGE = "Very secret message";
/**
* 指纹加密后的字符串
*/
String ENCRYPT_STR = "encrypt_str";
/**
* 指纹密码生成的密钥
*/
String KEY_NAME = "key_name";
指纹秘钥工具类使用:
private FingerPrintKeyHelper keyHelper;
keyHelper = new FingerPrintKeyHelper();
//加密模式,创建key
keyHelper.createKey(false);
//初始化加密对象
private boolean initCrypto() {
mCryptoObject = keyHelper.getCryptoObject(isEncrypt, Base64.decode(AppParam.getInstance().getIV(), Base64.URL_SAFE));
if (null != mCryptoObject) {
return true;
} else {
return false;
}
}
//加密解密字符串
Cipher cipher = result.getCryptoObject().getCipher();
if (null == cipher) {
return;
}
if (isEncrypt) {
try {
byte[] secretMsg = cipher.doFinal((AppParam.getInstance().getSecretMsg()).getBytes());
byte[] IV = cipher.getIV();
AppParam.getInstance().setIV(Base64.encodeToString(IV, Base64.URL_SAFE));
AppParam.getInstance().setEncryptStr(Base64.encodeToString(secretMsg, Base64.URL_SAFE));
if (null != listener) {
listener.onSuccess();
}
} catch (IllegalBlockSizeException | BadPaddingException e) {
e.printStackTrace();
}
} else {
String encryptStr = AppParam.getInstance().getEncryptStr();
if (null == encryptStr) {
listener.onFail();
}
try {
byte[] decryptMsg = cipher.doFinal(Base64.decode(encryptStr, Base64.URL_SAFE));
String decryStr = new String(decryptMsg);
if (null != listener) {
if (decryStr.equals(AppParam.getInstance().getSecretMsg())) {
listener.onSuccess();
} else {
listener.onFail();
}
}
} catch (IllegalBlockSizeException | BadPaddingException e) {
e.printStackTrace();
}
}