主要用到的是FingerprintManager这个类,此类是访问指纹硬件的便捷类,通过

Context#getSystemService(Context.FINGERPRINT_SERVICE)获取相应的单例。

应用场景:在指纹加密模块中对一个具有某种特定功能的数据(比如密码等)进行加密;在其他需要进行密码验证的地方,通过指纹解密模块将加密的数据还原后验证。

首先在Manifest.xml中添加权限申请:
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
注意:该权限为基础权限,只需要在Manifest.xml中添加即可,不需要动态权限申请。

一般情况下,在开启指纹功能时,系统会要求用户添加备用PIN码、图案或密码。因为有时候(例如重启设备或系统无法识别指纹时),将需要使用这种方式来解锁设备。

先按照系统提示录入指纹。

1. 判断是否支持指纹

需要了解的是,系统的指纹功能是从Android6.0开始正式引入的,所以在使用指纹功能之前进行必要的需要判断。

if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.M) {showDialog("该手机不支持指纹功能");return;
}Context mContext = this;
if (checkSelfPermission(Manifest.permission.USE_FINGERPRINT) != PackageManager.PERMISSION_GRANTED) {showDialog("需要获取使用指纹的权限");return;
}else {FingerprintManager manager = (FingerprintManager) mContext.getSystemService(Context.FINGERPRINT_SERVICE);KeyguardManager keyManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);//硬件设备是否支持指纹解锁功能if (!manager.isHardwareDetected()) {showDialog("该手机不支持指纹解锁");return;}//判断是否有锁屏密码else if (!keyManager.isKeyguardSecure()) {showDialog("请先设置锁屏密码");return;}//判断是否录入指纹else if (!manager.hasEnrolledFingerprints()) {showDialog("没有录入指纹,请录入指纹后重试");return;}
}

此demo UI比较简单,在MainActivity中有两个按钮,一个的功能为跳转到设置指纹密码页面FingerPrintSettingActivity,另一个为指纹解码功能 :

设置指纹密码页面为:

  未添加指纹密码时,如图

添加后,可以删除和重置

LocalSharedPreference 类为通过sp储存必要数据的便捷类:

public class LocalSharedPreference {final String dataKeyName = "data";final String IVKeyName = "IV";  //Initialization Vector (IV) 初始化向量private SharedPreferences preferences;LocalSharedPreference(Context context) {preferences = context.getSharedPreferences("sample", Activity.MODE_PRIVATE);}String getData(String keyName) {//同样,在读取SharedPreferences数据前要实例化出一个SharedPreferences对象return preferences.getString(keyName, "");}boolean storeData(String key, String data) {SharedPreferences.Editor editor = preferences.edit();editor.putString(key, data);return editor.commit();}boolean containsKey(String key) {return !TextUtils.isEmpty(getData(key));}
}

LocalSharedPreference类主要用于 获取类型为"AndroidKeyStore"的KeyStore、生成Key和CryptoObject。

public class LocalAndroidKeyStore {private KeyStore mStore;public static final String keyName = "key";LocalAndroidKeyStore() {try {mStore = KeyStore.getInstance("AndroidKeyStore");} catch (Exception e) {e.printStackTrace();}}@TargetApi(23)void generateKey(String keyAlias) {
try {final KeyGenerator generator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");mStore.load(null);//先取值,取不到时才生成新的keyfinal SecretKey key = (SecretKey) mStore.getKey(keyName, null);if (key != null) {return ;}    final int purpose = KeyProperties.PURPOSE_DECRYPT | KeyProperties.PURPOSE_ENCRYPT;final KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(keyAlias, purpose);builder.setUserAuthenticationRequired(true);builder.setBlockModes(KeyProperties.BLOCK_MODE_CBC);builder.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7);generator.init(builder.build());generator.generateKey();} catch (Exception e) {e.printStackTrace();}

}

@TargetApi(23)
FingerprintManager.CryptoObject getCryptoObject(int purpose, byte[] IV) {try {mStore.load(null);final SecretKey key = (SecretKey) mStore.getKey(keyName, null);if (key == null) {return null;}final Cipher cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/" + KeyProperties.BLOCK_MODE_CBC+ "/" + KeyProperties.ENCRYPTION_PADDING_PKCS7);if (purpose == KeyProperties.PURPOSE_ENCRYPT) {cipher.init(purpose, key);} else {cipher.init(purpose, key, new IvParameterSpec(IV));}return new FingerprintManager.CryptoObject(cipher);      } catch (Exception e) {e.printStackTrace();return null;}    }

FingerPrintHelper为对FingerprintManager的封装类,加解密的处理逻辑在这里:

@TargetApi(23)
public class FingerPrintHelper extends FingerprintManager.AuthenticationCallback {private FingerprintManager manager;private CancellationSignal mCancellationSignal;private SimpleAuthenticationCallback callback;private LocalSharedPreference mLocalSharedPreference;private LocalAndroidKeyStore mLocalAndroidKeyStore;//PURPOSE_ENCRYPT,则表示生成token,否则为取出tokenprivate int purpose = KeyProperties.PURPOSE_ENCRYPT;private String data = "";private static FingerPrintHelper mFingerHelper;public void setData(String data) {this.data = data;}public static synchronized FingerPrintHelper getInstance(Context context){if(mFingerHelper == null){mFingerHelper = new FingerPrintHelper(context);}return mFingerHelper;}@TargetApi(23)public FingerPrintHelper(Context context) {manager = context.getSystemService(FingerprintManager.class);mLocalSharedPreference = new LocalSharedPreference(context);mLocalAndroidKeyStore = new LocalAndroidKeyStore();generateKey();}public void generateKey() {//在keystore中生成加密密钥mLocalAndroidKeyStore.generateKey(LocalAndroidKeyStore.keyName);}public void setCallback(SimpleAuthenticationCallback callback) {this.callback = callback;}public void setPurpose(int purpose) {this.purpose = purpose;}@TargetApi(23)public boolean authenticate() {try {FingerprintManager.CryptoObject object;if (purpose == KeyProperties.PURPOSE_DECRYPT) {String IV = mLocalSharedPreference.getData(mLocalSharedPreference.IVKeyName);object = mLocalAndroidKeyStore.getCryptoObject(Cipher.DECRYPT_MODE, Base64.decode(IV, Base64.URL_SAFE));if (object == null) {return false;}} else {object = mLocalAndroidKeyStore.getCryptoObject(Cipher.ENCRYPT_MODE, null);}mCancellationSignal = new CancellationSignal();manager.authenticate(object, mCancellationSignal, 0, this, null);return true;} catch (SecurityException e) {e.printStackTrace();return false;}}@TargetApi(16)public void stopAuthenticate() {if (mCancellationSignal != null) {mCancellationSignal.cancel();mCancellationSignal = null;}callback = null;}@TargetApi(23)@Overridepublic void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) {if (callback == null) {return;}if (result.getCryptoObject() == null) {callback.onAuthenticationFail();return;}final Cipher cipher = result.getCryptoObject().getCipher();if (purpose == KeyProperties.PURPOSE_DECRYPT) {//取出secret key并返回String data = mLocalSharedPreference.getData(mLocalSharedPreference.dataKeyName);if (TextUtils.isEmpty(data)) {callback.onAuthenticationFail();return;}try {byte[] decrypted = cipher.doFinal(Base64.decode(data, Base64.URL_SAFE));callback.onAuthenticationSucceeded(new String(decrypted));} catch (BadPaddingException | IllegalBlockSizeException e) {e.printStackTrace();callback.onAuthenticationFail();}} else {//将前面生成的data包装成secret key,存入沙盒try {byte[] encrypted = cipher.doFinal(data.getBytes());byte[] IV = cipher.getIV();String se = Base64.encodeToString(encrypted, Base64.URL_SAFE);//保存解密需要的IV变量String siv = Base64.encodeToString(IV, Base64.URL_SAFE);if (mLocalSharedPreference.storeData(mLocalSharedPreference.dataKeyName, se) &&mLocalSharedPreference.storeData(mLocalSharedPreference.IVKeyName, siv)) {callback.onAuthenticationSucceeded(se);}else{callback.onAuthenticationFail();}} catch (BadPaddingException | IllegalBlockSizeException e) {e.printStackTrace();callback.onAuthenticationFail();}}}public void clearData(){mLocalSharedPreference.storeData(mLocalSharedPreference.dataKeyName, null);mLocalSharedPreference.storeData(mLocalSharedPreference.IVKeyName, null);}@Overridepublic void onAuthenticationError(int errorCode, CharSequence errString) {if (callback != null) {callback.onAuthenticationFail();}}@Overridepublic void onAuthenticationHelp(int helpCode, CharSequence helpString) {}@Overridepublic void onAuthenticationFailed() {}public interface SimpleAuthenticationCallback {void onAuthenticationSucceeded(String value);void onAuthenticationFail();}
}

这样,在FingerPrintSettingActivity中,实例化FingerPrintHelper类对象helper:

      helper = FingerPrintHelper.getInstance(context);helper.setCallback(context);

并实现FingerPrintHelper.SimpleAuthenticationCallback接口:

    @Overridepublic void onAuthenticationSucceeded(String value) {CommonFunction.dismissProgressDialog();sp.edit().putString("FingerprintPwd", value).commit();CommonFunction.showToast("指纹密码设置成功");finish();}@Overridepublic void onAuthenticationFail() {CommonFunction.dismissProgressDialog();showDialog("指纹密码设置失败");}

其他变量设置:

sp = getSharedPreferences("fingerprint", MODE_PRIVATE);
pwd = sp.getString("FingerprintPwd", "");
if(!TextUtils.isEmpty(pwd)) {finger_list_layout.setVisibility(View.VISIBLE);reset_pwd.setText("重置指纹密码");
}
    /*** 对密码加密*/private void encodePwdOperation(String pwd){CommonFunction.showProgressDialog(context, "开始验证指纹,请将手指贴与指纹区域...");helper.setPurpose(KeyProperties.PURPOSE_ENCRYPT);helper.setData(pwd);helper.authenticate();}
    /*** 删除密码*/private void delPwdOperation(){CustomConfirmDialog.Builder builder = new CustomConfirmDialog.Builder(this);builder.setTitle("确认");builder.setMessage("确定删除该指纹密码?");builder.setPositiveBtn("确定",new DialogInterface.OnClickListener() {public void onClick(DialogInterface dialog, int which) {dialog.dismiss();finger_list_layout.setVisibility(View.GONE);//TODO 删除已加密数据sp.edit().putString("FingerprintPwd", "").commit();pwd = "";reset_pwd.setText("添加指纹密码");helper.clearData();}});builder.setNegativeBtn("取消", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {dialog.dismiss();}});builder.create().show();}
 /*** 设置/重置密码*/private void setPwdOperation(){if(TextUtils.isEmpty(pwd)) {encodePwdOperation();}else {CustomConfirmDialog.Builder builder = new CustomConfirmDialog.Builder(this);builder.setTitle("确认");builder.setMessage("确定重置指纹密码?");builder.setPositiveBtn("确定",new DialogInterface.OnClickListener() {public void onClick(DialogInterface dialog, int which) {dialog.dismiss();//TODO 删除已加密数据sp.edit().putString("FingerprintPwd", "").commit();pwd = "";helper.clearData();encodePwdOperation();}});builder.setNegativeBtn("取消", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {dialog.dismiss();}});builder.create().show();}
}

解码页面,同样实现FingerPrintHelper.SimpleAuthenticationCallback接口:

/*解码过程*/
helper = FingerPrintHelper.getInstance(context);helper.setCallback(this);helper.setPurpose(KeyProperties.PURPOSE_DECRYPT);if(helper != null) {helper.authenticate();}

效果图:

一. 首次添加密码时:

二. 删除密码再添加时:

版权声明:本文为博主原创文章,未经博主允许不得转载;来自https://blog.csdn.net/milanac007/article/details/79714843

Android 指纹识别加解密相关推荐

  1. android指纹识别源码

    随着科技的进步,不仅是软件方面,安卓系统在硬件发展上也有了日新月异的发展.2015年下半年出的安卓手机基本上都带指纹识别功能,不管是炒得很热的360奇酷手机.魅族手机,还是"中华酷联&quo ...

  2. Android指纹识别

    Android指纹识别 原文:Android指纹识别 上一篇讲了通过FingerprintManager验证手机是否支持指纹识别,以及是否录入了指纹,这里进行指纹的验证. //获取Fingerprin ...

  3. android 指纹识别支付 secure os,Android指纹登录/指纹支付简述

    一.简述 业务需求,需要指纹登录,鉴于市面上的资料不是特别齐全,走了不少弯路.现在通了,写点东西给大伙做个参考.末尾会提供demo和参考资料 二.指纹登录/支付工作流程 指纹验证加密流程.png 最新 ...

  4. Android 指纹识别(Touch ID)实例

    指纹识别   指纹识别的支持是Android6.0以后才开始的,Google也为指纹识别提供了一些列接口,指纹识别将要用到的核心API为FingerprintManager,其中还有三个核心内部类:F ...

  5. Android指纹识别,看这一篇就够了

    在Android6.0(Api23)的时候,Android系统加入了指纹识别的api接口,即FingerprintManager,定义了最基础的指纹识别接口.不过,在AndroidP(Api28)的时 ...

  6. android指纹识别开发公司,FingerDemo实现Android指纹识别

    FingerDemo 指纹识别 最近在研究android的指纹,因为做的项目是金融类,所有想要把指纹添加到项目中, 但是Android手机有很多种类,有些有指纹,有些没有指纹.这就需要各种判断了. 1 ...

  7. android获取指纹信息最新,# android 指纹识别并检测指纹库是否变更

    android API 23时新增的功能,指纹识别 主要类:FingerpringManager 在API28后,FingerpringManager被遗弃,使用BiometricPrompt,此时授 ...

  8. android 指纹识别支付 secure os,Android指纹识别

    常用开发工具类和自定义view,无耻的求个star: https://github.com/AbrahamCaiJin/CommonUtilLibrary 最近开始做项目的时候,需要用到Android ...

  9. Android - 指纹识别API示例

    – 前言 需求说明:app经常要验证码验证用户手机号保证安全性,现在想接入指纹识别来代替验证码验证,不支持指纹识别的设备照常用验证码. 了解API Android在23(Android M 6.0)新 ...

最新文章

  1. [Asp.net mvc]OutputCacheAttribute
  2. canvas-js贝塞尔曲线代码在线生成工具
  3. AlwaysOn只读路由配置
  4. 拟17.56亿控股江南集成 海陆重工加码光伏产业链
  5. linux ubuntu文件浏览器如何显示隐藏文件?(快捷键ctrl+h)
  6. C#红包波动系数·高可用性,适合企业级开发
  7. 3四则运算软件2016011992
  8. C++ STL 容器之stack简单使用
  9. 青蛙换位java_青蛙换位
  10. 面试 | #面试面试面试 做#Java 就是要这种不要脸的…
  11. Atitit 图像指纹识别匹配sift算法 atlks总结
  12. 病毒肆虐,宅在家里的时候,作为企业经营者的我在想些什么
  13. 信息内容安全-图像文字识别OCR
  14. 都是肿瘤模型,凭什么说肿瘤类器官是“试药替身”?
  15. 腾讯云图-一次性加载全部数据
  16. 王者荣耀英雄选择系统项目
  17. 各大程序员兼职平台靠谱嘛?这一篇文章就够了
  18. uni-app中如何引入uview-ui?
  19. 【深度学习】非常详细 | 用 Pytorch 理解卷积网络
  20. 拍照应用竞争升级,坐拥15亿用户的美图如何打好防御战?

热门文章

  1. 有限元在游乐设施中的应用-焊缝计算
  2. vscode画UML图
  3. 研效优化实践:WeTest提效测试
  4. 输入压缩空间量是分区量吗_如何安全、简便的对固态硬盘分区?
  5. QML ListView 实现下拉刷新 上拉加载
  6. 【PTA-训练day17】L2-029 特立独行的幸福 + L1-071 前世档案
  7. ssl证书到期时间查询的三种方法
  8. Android设置铃声实现代码
  9. java的多态性_java中多态性什么意思?
  10. python mysql源码安装_源码包安装(Python mysql redis)