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_versionenrolled_password_handle->salt = saltenrolled_password_handle->user_id = user_idenrolled_password_handle->flags = flagsenrolled_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 0    uint64_t challenge;    uint64_t user_id;             // secure user ID, not Android user ID    uint64_t authenticator_id;    // secure authenticator ID    uint32_t authenticator_type;  // hw_authenticator_type_t, in network order    uint64_t timestamp;           // in network order    uint8_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 timeout    if (timestamp < last_checked + timeout && timestamp > last_checked) {        // attempt before timeout expired, return remaining time        response->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 timeout        record->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.javapublic 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.javaprivate 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

更多相关文章

  1. android开发之路04(初级android工程师必会,你懂得!)
  2. 今天更新SDK到11
  3. 密码输入框
  4. Android(安卓)中传递 json 的问题
  5. Android(安卓)boot.img 结构
  6. Android实现图片单点旋转缩放保存-仿百度魔图
  7. Android(安卓)实现简单的画画版一
  8. Android中如何保存cookie
  9. Android实现登录界面记住密码的存储

随机推荐

  1. Android背景设置
  2. Android Choreographer
  3. 重新签名Android pre-install APK
  4. Android文件管理器与media数据库的同步问
  5. Android 删除再创建导致open failed: EBU
  6. 在eclipse中将android工程打包成apk
  7. Android开发者指南(19) ―― Guide Index
  8. Android基础02
  9. Android 键盘布局总结
  10. android开发每日汇总【2011-10-07】