欢迎访问 生活随笔!

生活随笔

当前位置: 首页 >

Android Gatekeeper流程深度解剖

发布时间:2025/3/21 64 豆豆
生活随笔 收集整理的这篇文章主要介绍了 Android Gatekeeper流程深度解剖 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

快速链接:
.
👉👉👉 个人博客笔记导读目录(全部) 👈👈👈


相关推荐:
Android手机使用命令行增加/删除/修改密码(password/pin/pattern)
android密码解锁/指纹解锁返回的authToken深度解剖
LockSettingsService的setLockCredentialInternal函数详解


说明: 在无特别的说明下,本文讲述得是android10.0 !

gatekeeper目录

        • 1、gatekeeper是什么?
        • 2、gatekeeper的软件框图
        • 3、enroll和verify的调用流程
        • 4、重要的结构体
          • (1)、password_handle
          • (2)、authToken
        • 5、技术的细节
          • (1)、failure_record :记录失败信息
          • (2)、throttle : failed_counter和retry_time的规则
          • (3)、timestamp
            • a、在gatekeeper TA中的简单合法校验
            • b、 在android中,会对timestamp进行检查
        • 6、关键函数的介绍
          • LockSetting
            • (1)、writeCredentialHash //将enroll_handle保存到文件
          • Vendor Gatekeeper Hal
            • (1)、enroll
            • (2)、verify

1、gatekeeper是什么?

在android中,gatekeeper是密码锁或图案锁的一种服务. 主要支持的两个方法是:enroll(密码的录入)、verify(密码的验证).

调用流程:locksetting APP ----> IGatekeeperserivce ----> Hardware Gatekeeper HAL ----> Vendor Gatekeeper HAL ----> Gatekeeper TA

  • enroll录入密码时,locksetting APP将密码数据传送到TEE的gatekeeper TA,
    在TA中先计算signature,计算方法为:HMAC(密码数据,hmackey)=signature,
    然后再去填充password_handle结构体,最后再将password_handle返回给android,locksetting
    APP中再将password_handle保存到文件中.
  • verify验证密码时,locksetting
    APP将保存在文件中的password_handle和输入的密码数据一同传进TEE的gatekeeper
    TA,在TA中先计算signature,计算方法为:HMAC(密码数据,hmackey)=signature.
    然后再拿这个signature和password_handle中的signature相比较,如果一样,则返回authToken给android.
    在android的IGatekeeperserivce中,将authToken发送给keystore存储内存中.
    同时返回给locksetting APP结果failed或ok

2、gatekeeper的软件框图


(代码结构图)

3、enroll和verify的调用流程

4、重要的结构体

(1)、password_handle

在enroll的时候gatekeeper TA负责填充password_handle结构体,返回给android的locksetting保存到文件中.

(system/gatekeeper/include/gatekeeper/password_handle.h) struct __attribute__ ((__packed__)) password_handle_t {uint8_t version;secure_id_t user_id;uint64_t flags;salt_t salt;uint8_t signature[32];bool hardware_backed; };

gatekeeper TA是怎样填充password_handle结构体的?

enrolled_password_handle->version = handle_version enrolled_password_handle->salt = salt enrolled_password_handle->user_id = user_id enrolled_password_handle->flags = flags enrolled_password_handle->hardware_backed = gkbase->IsHardwareBacked() enrolled_password_handle->signature
  • handle_version:在tee中写死的2
  • salt:每次enroll时,在tee中GetRandom随机生成
  • user_id:第一次enroll时,在tee中GetRandom随机生成.其实就是SID
  • flags : throttle flag,写死1. 就是是否开启,失败密码次数计数功能.
  • hardware_backed:为1
  • signature: 对密码进行hmac hash运算得到. 即 HMAC(data,key) = signature
(2)、authToken

在verify通过时候gatekeeper TA填充authToken,返回给android的IGatekeeperService程序,再发送给keystore保存到内存中. (authToken的详细介绍可以参考这篇文章)

(hardware/libhardware/include/hardware/hw_auth_token.h) typedef struct __attribute__((__packed__)) {uint8_t version; // Current version is 0uint64_t challenge;uint64_t user_id; // secure user ID, not Android user IDuint64_t authenticator_id; // secure authenticator IDuint32_t authenticator_type; // hw_authenticator_type_t, in network orderuint64_t timestamp; // in network orderuint8_t hmac[32]; } hw_auth_token_t;typedef enum {HW_AUTH_NONE = 0,HW_AUTH_PASSWORD = 1 << 0,HW_AUTH_FINGERPRINT = 1 << 1,// Additional entries should be powers of 2.HW_AUTH_ANY = UINT32_MAX, } hw_authenticator_type_t;
  • 质询 : challenge
  • 用户SID :user_id
  • 身份验证程序 ID (ASID) : authenticator_id, 身份验证程序类型 : authenticator_type,00-gatekeeper,01-指纹

5、技术的细节

(1)、failure_record :记录失败信息

verify失败后,会将failure_counter和当前的timestamp同时记录下来,secure_user_id用于索引.

struct __attribute__((packed)) failure_record_t {uint64_t secure_user_id;uint64_t last_checked_timestamp;uint32_t failure_counter; };
(2)、throttle : failed_counter和retry_time的规则

在verify的失败的时候,需要将失败的次数记录下来,通常的做法是将这个failed_count保存到RPMB中。
在verify成功的时候,再去清除这个数据.
另外,在verify失败的时候,还会根据failed_count值来计算retry_timeout值,retry_timeout最终返回给android侧,对应的也就是输错一次密码后,还需再等待多数秒才能进行下一次的输入. retry_timeout的计算规则是:
它的计算方式:
(a)、failure_counter为0-4次时,retry_timeout = 0
(b)、failure_counter为5次时,retry_timeout = 30s
©、failure_counter为6-9次时,retry_timeout = 0
(d)、failure_counter为10-29次时,retry_timeout = 30
(e)、failure_counter大于等于30次时,retry_timeout变得更大了,有个指数增长的过程

(根据failed_counter计算timeout的源码) uint32_t GateKeeper::ComputeRetryTimeout(const failure_record_t *record) {static const int failure_timeout_ms = 30000;if (record->failure_counter == 0) return 0;if (record->failure_counter > 0 && record->failure_counter <= 10) {if (record->failure_counter % 5 == 0) {return failure_timeout_ms;} else {return 0;}} else if (record->failure_counter < 30) {return failure_timeout_ms;} else if (record->failure_counter < 140) {return failure_timeout_ms << ((record->failure_counter - 30) / 10);}return DAY_IN_MS; }

由于Gatekeeper TA闭源,我们这里就贴下google的软实现(写得不是很好哦)
这种做法意味着,每次verify成功,都会对failed_count操作两次,如果failed_count是保存在RPMB或某个固定分区中,那么频繁的verify显然容易对这块分区或RPMB造成损坏.
在项目设计中,我们还是建议尽量减少RPMB的读写次数

(3)、timestamp

timestamp是从开机到现在的时间,单位为毫秒. 在TA中是uint64_t timestamp = GetMillisecondsSinceBoot()获取的.

timestamp的功能有两个:

a、在gatekeeper TA中的简单合法校验

在verify中,比对两个signature之前,会先检查RPMB中存储的的timestamp、根据RPMB中的failure_counter计算而来的retry_time. 然后进行简单的逻辑判断

if (timeout > 0) {// we have a pending timeoutif (timestamp < last_checked + timeout && timestamp > last_checked) {// attempt before timeout expired, return remaining timeresponse->SetRetryTimeout(timeout - (timestamp - last_checked));return true;} else if (timestamp <= last_checked) {// device was rebooted or timer reset, don't count as new failure but// reset timeoutrecord->last_checked_timestamp = timestamp;if (!WriteFailureRecord(uid, record, secure)) {response->error = ERROR_UNKNOWN;return true;}response->SetRetryTimeout(timeout);return true;} }
b、 在android中,会对timestamp进行检查

verify成功后,会将此时的timestamp填充到authToken结构体,返回给android。 android在使用该authToken时,会对timestamp进行检查.

6、关键函数的介绍

LockSetting
(1)、writeCredentialHash //将enroll_handle保存到文件

如果是password,保存到passwordFilename, patterFilename写入空
如果是patter,保存到patterFilename, passwordFilename写入空

frameworks/base/services/core/java/com/android/server/locksettings/LockSettingsStorage.java public void writeCredentialHash(CredentialHash hash, int userId) {byte[] patternHash = null;byte[] passwordHash = null;if (hash.type == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD) {passwordHash = hash.hash;} else if (hash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN) {patternHash = hash.hash;}writeFile(getLockPasswordFilename(userId), passwordHash);writeFile(getLockPatternFilename(userId), patternHash); }

passwordFilename和patterFilename的文件名字分别是:“gatekeeper.password.key”、“gatekeeper.pattern.key”

frameworks/base/services/core/java/com/android/server/locksettings/LockSettingsStorage.java private static final String SYSTEM_DIRECTORY = "/system/"; private static final String LOCK_PATTERN_FILE = "gatekeeper.pattern.key"; private static final String BASE_ZERO_LOCK_PATTERN_FILE = "gatekeeper.gesture.key"; private static final String LEGACY_LOCK_PATTERN_FILE = "gesture.key"; private static final String LOCK_PASSWORD_FILE = "gatekeeper.password.key"; private static final String LEGACY_LOCK_PASSWORD_FILE = "password.key"; private static final String CHILD_PROFILE_LOCK_FILE = "gatekeeper.profile.key";private static final String SYNTHETIC_PASSWORD_DIRECTORY = "spblob/";
Vendor Gatekeeper Hal
(1)、enroll
(函数原型) int (*enroll)(const struct gatekeeper_device *dev, uint32_t uid,const uint8_t *current_password_handle, uint32_t current_password_handle_length,const uint8_t *current_password, uint32_t current_password_length,const uint8_t *desired_password, uint32_t desired_password_length,uint8_t **enrolled_password_handle, uint32_t *enrolled_password_handle_length);
  • current_password_handle : 输入参数,原来的包含signature的handle结构体,第一次录入密码时为空,
    修改密码时使用
  • current_password : 输入参数,原来的密码数据,第一次录入密码时为空, 修改密码时使用
  • desired_password : 输入参数,录入密码数据(修改后的密码数据)
  • enrolled_password_handle : 输出参数,
    返回包含signature的handle结构体,交由android保存到文件中.
(2)、verify
(函数原型) int (*verify)(const struct gatekeeper_device *dev, uint32_t uid, uint64_t challenge,const uint8_t *enrolled_password_handle, uint32_t enrolled_password_handle_length,const uint8_t *provided_password, uint32_t provided_password_length,uint8_t **auth_token, uint32_t *auth_token_length, bool *request_reenroll);
  • enrolled_password_handle : 输入参数,
    android中传来的从文件中读取的包含signature的handle结构体
  • provided_password : 输入参数, 需要验证的密码数据
  • auth_token : 输出参数 , 在gatekeeper TA
    verify成功后会填充authToken结构体返回给android,如果verify失败,则authToken为NULL

总结

以上是生活随笔为你收集整理的Android Gatekeeper流程深度解剖的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。