1. 指纹框架UML


2. Fingerprint
2.1 Fingerprint数据流图

FingerprintManager API. 直接与应用程序交互的API,属于当前APP进程.

每个应用程序都可以获取FingerprintManager.

FingerprintManager主要是应用程序与FingerprintService的交互封装

FingerprintService. 一个运行在SystemServer进程中的单例service,主要负责与fingerprintd通讯.

fingerprintd (Fingerprint daemon). A C/C++ implementation of the binder interface from FingerprintService. The fingerprintd daemon operates in its own process and wraps the Fingerprint HAL vendor-specific library.

Fingerprint HAL vendor-specific library. A hardware vendor’s implementation of the Fingerprint HAL. The vendor-specific library communicates with the device-specific hardware.

Keystore API and Keymaster. These components provide hardware-backed cryptography for secure key storage in a Trusted Execution Environment (TEE).

2.2 HAL层的初始化工作
2.2.1 HAL初始化
每个Hal层库文件有一个入口,即HAL_MODULE_INFO_SYM,上层在调用hal层库文件时会在/system/lib/hw/下面寻找对应库文件,找到对应库文件后便从入口HAL_MODULE_INFO_SYM调用Hal层里面的open, init, write, read等接口,Hal层再通过这个接口去读写设备节点。

static struct hw_module_methods_t fingerprint_module_methods = {
    .open = fingerprint_open,
};
Fingerprintd 调用hw_get_module函数获取了一个fingerprint_module_t类型的数据结构。 这个就是在fingerprint.default.so中,由指纹芯片厂商填充实现的。
static int fingerprint_open(const hw_module_t* module, const char __unused *id,
hw_device_t** device) {
  if (fpc_init() < 0) {
ALOGE("Could not init FPC device");
return -EINVAL;
}
fingerprint_device_t *dev = malloc(sizeof(fingerprint_device_t));
memset(dev, 0, sizeof(fingerprint_device_t));
dev->common.tag = HARDWARE_DEVICE_TAG;
dev->common.version = FINGERPRINT_MODULE_API_VERSION_2_0;
dev->common.module = (struct hw_module_t*) module;
dev->common.close = fingerprint_close;
dev->pre_enroll = fingerprint_pre_enroll;
dev->enroll = fingerprint_enroll;
dev->get_authenticator_id = fingerprint_get_auth_id;
dev->cancel = fingerprint_cancel;
dev->remove = fingerprint_remove;
dev->set_active_group = fingerprint_set_active_group;
dev->enumerate = fingerprint_enumerate;
dev->authenticate = fingerprint_authenticate;
dev->set_notify = set_notify_callback;
dev->notify = NULL;
*device = (hw_device_t*) dev;
return 0;
}

fingerprint_open就是填充实现Android 在fingerprint.h定义fingerprint_device_t需要实现的这些接口。然后赋给指针device。上层,也就是fingerprintd,就能用这个device来操作hal层的指纹模块了。
fpc_init() 应该是初始化指纹驱动,并与Trusted Execution Environment (TEE)建立安全链接,TEE提供的一个安全的硬件运行环境。指纹就是运行在这样一个硬件安全环境下的程序。它保证了指纹敏感数据的安全性。

HAL必须通过TEE来与指纹建立通讯,一般是采用SPI通讯。指纹采集的生物图像必须在TEE中完成,不能传输到TEE外
指纹的采集、登记和认可都必须在TEE中指纹数据也必须是加密(比如采用对称加密AES等加密手段),并且不能拷贝
2.2.2 HAL主要接口
HAL主要接口函数都会在/hardware/libhardware/include/hardware/fingerprint.h 中,主要的接口主要是enroll和authenticate,以及相应的回调函数


其他的函数还有以下:

enroll. Switches the HAL state machine to start the collection and storage of a fingerprint template. As soon as enrollment is complete, or after a timeout, the HAL state machine is returned to the idle state.
pre_enroll. Generates a unique token to indicate the start of a fingerprint enrollment. Provides a token to the enroll function to ensure there was prior authentication, e.g. using a password. The token is wrapped and, for example, HMAC’d, once the device credential is confirmed, to prevent tampering. The token must be checked during enrollment to verify that the token is still valid.
get_authenticator_id. Returns a token associated with the current fingerprint set.
cancel. Cancels any pending enroll or authenticate operations. The HAL state machine is returned to the idle state.
enumerate. Synchronous call for enumerating all known fingerprint templates.
remove. Deletes a fingerprint template.
set_active_group. Restricts a HAL operation to a set of fingerprints that belong to a specified group (identified by a group identifier, or GID).
authenticate. Authenticates a fingerprint-related operation (identified by an operation ID).
set_notify. Registers a user function that will get notifications from the HAL. If the HAL state machine is in a busy state, the function is blocked until the HAL leaves the busy state.
Enroll流程
2.3.1 preEnroll点击设置中的添加指纹,setting就会调到fingerprintd的preEnroll接口。
preEnroll会在指纹设备中生成并保存一个64位的随机数。这个随机数有两个用途:返回给上层,用于填充enroll中的authenticated token challenge.
指纹设备会用它对下次enroll做初步校验,保证enroll没有被第三方篡改。
2.3.2 enroll
1 、对enroll接口的定义
int (*enroll)(struct fingerprint_device *dev, const hw_auth_token_t *hat,uint32_t gid, uint32_t timeout_sec);
hw_auth_token_t:保证此次enroll的合法性,我们具体看一下android怎么定义此结构。

AuthToken version :此token的版本号

Challenge:就是前面调用preEnroll的到的64位随机数,防止此次enroll被第三方假冒

User SID : 安全性id,不是android user id

Athenticator ID: 用于标明不同的认证权限

Authenticator Type:0x00表示Gatekeeper,0x01表示Fingerprint

Timestamp:最近一次开机时间戳

AuthToken HMAC key: 用一个特殊的key和SHA-256算法去计算前面一堆参数后,得到的一个 hmac值,保证前面参数的合法性和安全性。

gid:说明是哪个用户注册指纹(anroid支持多用户),在FingerprintService中通过UserManager拿到的。

timeout_sec:超时设置。

2、上层调用enroll接口,一直将上述参数传递到指纹设备中。指纹设备拿到参数之后会先检查参数是否合法。

3、验证完参数合法之后,指纹设备会将指纹IC切换到一种等待手指按下采图的工作模式。此时一旦手指按下,会进入中断处理函数,该函数主要的工作流程如下图:


4、注册成功后会将获取到相应的type,gid,fingerid, samples_ remaining回传给fingerprintd,samples_ remaining是录入指纹剩余次数。

void *enroll_thread_loop() {
fingerprint_msg_t msg;
msg.type = FINGERPRINT_TEMPLATE_ENROLLING;
msg.data.enroll.finger.fid = print_id;
msg.data.enroll.finger.gid = fpc_gid;
msg.data.enroll.samples_remaining = 0;
msg.data.enroll.msg = 0;
callback(&msg);
}

最终会在FingerprintService保存一份Fingerprint,Fingerprint包含以下数据,主要用于FingerprintService判断是否有指纹template存在。

2.3.3 postEnroll
postEnroll主要工作是更新一下指纹设备中保存的Challenge。

2.4 Authenticate流程
当按下power键锁屏时,APP会调用FingerprintManager api,进入到authenticate流程。和enroll一样,框架层工作工作很少,基本就是一个简单的接口调用。其中CryptoObject是加密对象,这是由于验证结果有可能被第三方软件篡改,这个加密对象会随着验证结果返回并验证。
void authenticate (FingerprintManager.CryptoObject crypto,CancellationSignal cancel,int flags,FingerprintManager.AuthenticationCallback callback,Handler handler)

parameter    
crypto    FingerprintManager.CryptoObject: object associated with the call or null if none required.
cancel    CancellationSignal: an object that can be used to cancel authentication
flags    int: optional flags; should be 0
callback    FingerprintManager.AuthenticationCallback: an object to receive authentication events
handler    Handler: an optional handler to handle callback events
主要工作还是在hal层以下完成。重点看hal层之下的部分。authenticate一直调用到指纹服务进程fingerprintd。在有fingerprintd根据加载的fingerprint module调用hal层的接口。我们看看HAl怎样定义authenticate接口的,在fingerprint.h中
int (*authenticate)(struct fingerprint_device *dev, uint64_t operation_id, uint32_t gid);

operation_id:64位的session id标识本次识别流程。
gid:用户id,android是多用户系统,每个用户可以录入多个指纹(一般是5个)TEE也会根据gid来加载不同的用户模板。
2.4.1 加载用户模板、切换采图模式
调用authenticate接口之后,会在TEE中保存好operation_id,这个operation_id 会被用来做authenticate token的challenge保存到keystore service中去指纹支付会用到。然后TEE会根据gid从安全存储区加载之前该用户注册好的模板。
通过spi发送指令到指纹IC,让其切换到采图模式,最后等待手指按压。
2.4.2 采图与识别
之后的主要工作流程如下图

手指按压IC后,会报一个中断给主控
主控驱动层接收到中断脚的脉冲信号,通过netlink或者信号量等跨进程通信方式将这个中断信息上报给hal层
hal层收到中断,根据当前状态机的工作模式,开始执行识别工作
识别工作包括,从IC读取一帧指纹图像,然后将图像预处理为算法需要的格式
算法模块接收到预处理后的图像,开始匹配模板库
生成识别结果,向上用binder回调给fingerprintService,向下将本次识别的finger id同步给其他安全应用,譬如支付宝,微信。
更新模板库
识别成功后,会构造一个message,具体包括type,gid,fingerid和auth_token。

void *enroll_thread_loop() {
fingerprint_msg_t msg;
msg.type = FINGERPRINT_AUTHENTICATED;
msg.data.authenticated.finger.gid = fpc_gid;
msg.data.authenticated.finger.fid = print_id;
msg.data.authenticated.hat = hat;
callback(&msg);
}

其中auth_token会在fingerprintd中同步到keystore service中。

void FingerprintDaemonProxy::hal_notify_callback(const fingerprint_msg_t *msg) {
switch (msg->type) {
case FINGERPRINT_AUTHENTICATED:
if (msg->data.authenticated.finger.fid != 0) {
const uint8_t* hat = reinterpret_cast<const uint8_t *>(&msg->data.authenticated.hat);
instance->notifyKeystore(hat, sizeof(msg->data.authenticated.hat));
}
callback->onAuthenticated(device,
msg->data.authenticated.finger.fid,
msg->data.authenticated.finger.gid);
break;
}
}

void FingerprintDaemonProxy::notifyKeystore(const uint8_t *auth_token, const size_t auth_token_length) {
if (auth_token != NULL && auth_token_length > 0) {
// TODO: cache service?
sp < IServiceManager > sm = defaultServiceManager();
sp < IBinder > binder = sm->getService(String16("android.security.keystore"));
sp < IKeystoreService > service = interface_cast < IKeystoreService > (binder);
if (service != NULL) {
          status_t ret = service->addAuthToken(auth_token, auth_token_length);
}
}
}

2.4.3 AuthToken数据流


安全框架
指纹安全框架一般有两种方案,一种是Fingerprint without TrustZone 和Fingerprint with TrustZone。在root情况下without TrustZone是非常危险的,所有的数据都可以轻松获取到。但是在有了TrustZone的情况下,hacker在获取了root以后依然无法读取TrustZone中的指纹信息。如果想要获取指纹信息,理论上还需要破解TrustZone才行。TrustZone是arm支持的一种安全运行环境空间,有自己运行操作系统。

Fingerprint可能存在的安全漏洞
1)Replacing fingerprintd
替换fngerprintd这个Daemon,因为指纹识别成功与否是在APP向fingerprintd注册的回调来获取结果的,只要能替换fngerprintd,将其中指纹识别成功与否,修改成无论什么时候验证都返回success即可

2)Modied IPC
由于FingerprintService与fngerprintd是通过binder获取验证结果的,同时在FingerprintService中判断是否验证成功是靠获取到的fid(finger Id)是否为0(为0则验证失败)来判断的,修改binder传输过程中的fid即可达到无论什么时候都返回success的目的。

3)Replaying authentication tokens
可以提前截取之前验证通过的auth_token,然后用此auth_token来作为身份验证的凭据。

参考

安卓指纹验证官方指南
Keystore
指纹验证APP Demo

Android N 指纹框架相关推荐

  1. Android开发技术框架和编码规范

    Android开发技术框架和编码规范   2017年11月23日       目录 第一章 绪论.................................................... ...

  2. Android12指纹框架完全解析(一)

    前言:自从Android6.0开始Google官方出了标准的Android指纹框架,结束了各家指纹厂商各自为政的局面,推动了电容指纹在Android的发展:自从2017年新思的屏下指纹方案横空出世,后 ...

  3. Android O指纹识别解析

    版权声明:本文为梦想全栈程序猿原创文章,转载请附上原文出处链接和本声明 前面一片文章--Android Fingerprint完全解析(三) :Fingerprint Hal层分析 Android O ...

  4. 关于Android adb实现框架和应用

    关于Android adb实现框架和应用 链接: https://pan.baidu.com/s/1tMSw6OnbgQz5GH2E8i6JKw 提取码: 7a5u 另外我的相关培训视频请看: 欢迎观 ...

  5. Android图片缓存框架Glide

    Android图片缓存框架Glide Glide是Google提供的一个组件.它具有获取.解码和展示视频剧照.图片.动画等功能.它提供了灵活的API,帮助开发者将Glide应用在几乎任何网络协议栈中. ...

  6. 15类Android通用流行框架

    15类Android通用流行框架 Android流行框架 缓存 DiskLruCache Java实现基于LRU的磁盘缓存 图片加载 Android Universal Image Loader 一个 ...

  7. Android接口和框架学习

    Android接口和框架学习 缩写: HAL:HardwareAbstraction Layer,硬件抽象层 CTS:CompatibilityTest Suite,兼容性测试套件 Android让你 ...

  8. [Android]Android端ORM框架——RapidORM(v2.1)

    以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/6020412.html [Android]Android端ORM ...

  9. android原生组件,XUI: 一个简洁而优雅的Android原生UI框架,解放你的双手!

    XUI 一个简洁而又优雅的Android原生UI框架,解放你的双手!还不赶紧点击使用说明文档,体验一下吧! 涵盖绝大部分的UI组件:TextView.Button.EditText.ImageView ...

最新文章

  1. R语言ggplot2可视化:为层次聚类树状图dendrogram中的簇进行着色、在树状图dendrogram中为不同的层次聚类簇配置不同的色彩
  2. 函数作用域,闭包,数据类型的题目
  3. 腾讯2013年校园招聘笔试试题
  4. java applet配置_配置Java Applet的运行环境
  5. CSS常用的元素居中方法
  6. python中while语句的用法_全面解析Python的While循环语句的使用方法
  7. Python编辑统一缩进(Pycharm)
  8. 矩阵论作业13,14,15讲
  9. 【数学建模】论文模板和latex模板
  10. android系统解压zip文件,如何在Android手机上解压缩rar / zip文件
  11. Elasticsearch-7(全文搜索应用分享)
  12. 全国短消息服务中心号码
  13. Android中插件化实现的原理,宿主app运行插件中的类 (一)
  14. 电子会计问题及Propects
  15. 三分搜索--hdu2241 考研路茫茫——早起看书
  16. 系统架构设计师论文历年考题(2015-2017)考前冲刺来一波真题
  17. 深入 WEP和 WPA密码原理 1
  18. [安装fastfds中的nginx执行make命令报错]src/core/ngx_murmurhash.c:37:11: error
  19. win10系统mongodb 5.0安装配置+自动启动
  20. 运行时读取PAK文件

热门文章

  1. 系统集成项目管理工程师学习
  2. 手机访问WEB项目图片404
  3. MIUI10自助更换主题和字体
  4. 蓝桥杯2017国赛 瓷砖样式 dfs+hush
  5. 从源码看ANDROID中SQLITE是怎么通过CURSORWINDOW读DB的
  6. 2019年2月1日训练日记
  7. LoadRunner测试结果分析重要环节:合并图
  8. Excel表格规范录入数据
  9. PermissionError: [WinError 5] 拒绝访问。
  10. js与数组有关的函数:splice(),concat(),slice(),unshift()