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).
每个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主要接口函数都会在/hardware/libhardware/include/hardware/fingerprint.h 中,主要的接口主要是enroll和authenticate,以及相应的回调函数
其他的函数还有以下:
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存在。
postEnroll主要工作是更新一下指纹设备中保存的Challenge。
当按下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);
之后的主要工作流程如下图
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(&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);
}
}
}
指纹安全框架一般有两种方案,一种是Fingerprint without TrustZone 和Fingerprint with TrustZone。在root情况下without TrustZone是非常危险的,所有的数据都可以轻松获取到。但是在有了TrustZone的情况下,hacker在获取了root以后依然无法读取TrustZone中的指纹信息。如果想要获取指纹信息,理论上还需要破解TrustZone才行。TrustZone是arm支持的一种安全运行环境空间,有自己运行操作系统。
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