Android Basis - Google Keybox

什么是Keybox

Android O 开始谷歌要求每台机器预制谷歌提供的 Attestion Key的需求,该需求要求,每台机器都预制谷歌提供的 key,因此需要 oem 厂商在工厂完成预制。没有预制该key 将直接导致机器 cts 相关测试项失败。Google attestation key的集合又称作为Google keybox。不同的attestation key通过DeviceID 来区分,在配置时选择不同的 DeviceID 可以进行不同的 attestion key 配置。Keybox包含若干组key, 每组key包含了ECDSA和RSA两种算法,KmInstallKeybox将每组key写入到手机的安全内存中,已知的地方有RPMB和Persist分区;
当Google GSM app或第三方APP需要使用key时,调用keymaster接口,使用该key进行签名、认证等

每条 Attestion key 由两条证书链组成,分别对应算法为 ECDSA和 RSA,证书链包括一个私钥和三级证书,以ECDSA算法为例,具体形式如下,其中有一个私钥和三组证书,具体内容如下:

通常我们会向Google申请keybox,结合可能得出货量,提供如下信息给到的Google。 

1. fingerprint : branch/deivce/product/user/build

2. device id 列表 : 这里的device id是一个临时定义的名称。

举个例子,我预计将要生产1KK的设备,并销往欧美。那么需要为10个device id申请keybox。由于单个device id的keybox可以生产并安装在100K的设备上,那么我们需要10个这样的device id。逻辑上讲,一种类型的设备,我为什么需要不同的device id?这里确实是个知识点,晚点提个google case 问一下。

Keybox内容

这里的DeviceID对应keybox中的DeviceID,通常就是对应key的名称。简单看一个我最新申请的keybox内容和简单的标注。

目前是单个Devcice ID可以在100K的设备上安装同一个keybox。那么n个Device ID也就是对应n*100K的设备。

Keybox 安装

KmInstallKeybox

由于使用的是QC code中自带的命令工具:KmInstallKeybox.

安装前提条件(RPMB 初始化)
在预制 attestion key 前需要保证 RPMB 已经初始化,否则 RPMB 无法使用会导致预制key 功能失效。

初始化 RPMB(手机连接电脑,确保 adb 可以使用)
adb root
adb shell

qseecom_sample_client smple64 v 14 1

一般情况下,安装步骤如下:

  1. adb root
  2. adb push keybox.xml data/
  3. adb shell LD_LIBIRARY_PATH=/vendor/lib64/hw KmInstallKeybox data/keybox.xml DeviceID false // 一共是5个参数,0,1,2,3,4

KminstallKeybox代码内容

using namespace keymasterdevice;
int main(int argc, char** argv) {
    if ((argc != 4) && (argc != 5) && (argc != 7) && (argc != 8)) {
        cout << "usage: LD_LIBRARY_PATH=/vendor/lib64/hw KmInstallKeybox Keybox_file Device_ID "
                "provision_device_ids(true/false)"
                "Strongbox_Keybox_file Strongbox_Device_ID "
                "strongbox_provision_device_ids(true/false)"
             << endl;
        cout << "e.g.,: LD_LIBRARY_PATH=/vendor/lib64/hw KmInstallKeybox keybox.xml "
                "mfgID_xxxx_0000 true"
                "strongbox_keybox.xml strongbox_mfgID_xxxx_0000 true"
             << endl;
        cout << "KmInstallKeybox will install the attestation"
                "keys (both RSA and ECC) along with all the device identifiers\n"
                "(brand, device, product, serial#, IMEI, MEID (if available), model"
                "and manufacturer).\n"
                "\n"
                "The tool will use KM HAL API's to genrate RSA / ECC keys and\n"
                "verify the attestation certificate signed with the provisioned keys.\n"
                "If the validation is successful, the tool will set 'Provisioning Success'"
                "to KM TA / KM Strongbox.\n"
                "Else all the provisioned keys are deleted and it can be re-provisioned"
                "\n"
                "Once 'Provisioning Success' state is set in KM TA / Strongbox,\n"
                "attestation keys / Device ID's cannot be re-provisioned\n"
                "\n"
                "\n"
                "**RMA Use Case **\n"
                "For RMA use case, OEM's can set the following devcfg parameter in "
                "'keymaster_oem_config.xml'\n"
                "Please ensure to sign this debug devcfg with the serial# of the device as this "
                "will enable\n"
                "re-provisioning of keys and if used incorrectly can open up the device to be "
                "re-provisioned.\n"
                "<props name=\"allow_reprovision\" type=DALPROP_ATTR_TYPE_UINT32>\n"
                "1"
                "Strongbox provisioning is optional and is only supported on chipsets SPU/ "
                "strongbox is supported."
             << endl;

        exit(-1);
    }

    std::string deviceId(argv[2]);
    // TEE
    bool provision_device_id = false;
    if (!memcmp(argv[3], "true", strlen("true")))
        provision_device_id = true;
    else if (!memcmp(argv[3], "false", strlen("false")))
        provision_device_id = false;
    else
        return GENERIC_FAILURE;

    bool provision_only_device_id = false;
    if (argc==5 && !memcmp(argv[4], "rkp", strlen("rkp")))
        provision_only_device_id = true;
    else if (argc==8 && !memcmp(argv[7], "rkp", strlen("rkp")))
        provision_only_device_id = true;

    int ret = GENERIC_FAILURE;

    // This is required only for offtarget emulator, will be compiled out.
    SetUpOffTarget();
    KeymasterHalDevice device(KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT);
    SetUpOffTargetConfig(&device, 0, 0, 0);

    InstallKeybox installer(argv[1], deviceId, provision_device_id,
                            KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT);
    PROV_EXIT(installer.ParseFile(provision_only_device_id));
    if (!provision_only_device_id)
        PROV_EXIT(installer.ValidateProvisionedKeys());

    cout << "TEE done" << endl;
    if (argc == 7 || argc == 8) {
        std::string deviceIdSb(argv[5]);
        // SB
        bool provision_device_sb_id = false;
        if (!memcmp(argv[6], "true", strlen("true")))
            provision_device_sb_id = true;
        else if (!memcmp(argv[6], "false", strlen("false")))
            provision_device_sb_id = false;
        else
            return GENERIC_FAILURE;

        InstallKeybox installer_sb(argv[4], deviceIdSb, provision_device_sb_id,
                                   keymaster::KM_SECURITY_LEVEL_STRONGBOX);
        PROV_EXIT(installer_sb.ParseFile(false));
        PROV_EXIT(installer_sb.ValidateProvisionedKeys());
    }
    cout << "InstallKeybox is done!" << endl;
    return 0;
}

针对这个工具,其实我们也可以结合实际进行定制。

Attestation Key的相关使用

简单例子如下:

// 导入相关库
import android.hardware.biometrics.BiometricManager;
import android.security.KeyCharacteristics;
import android.security.keystore.KeyProperties;
import android.util.Base64;

// ...
BiometricManager biometricManager = BiometricManager.from(context);
KeymasterArguments keygenArgs = new KeymasterArguments.Builder()
    .setOperation(KeymasterOperation.KEY_GEN)
    .setAlias("my_key")
    .setLabels("application-specific", "encryption")
    .setKeyProperties(new KeyProperties.Builder()
        .setAlgorithm(KeyProperties.AES)
        .setKeySize(256)
        .setUserAuthenticationRequired(true)
        .build())
    .build();

// 请求用户输入密码
String password = getPasswordFromUser();

// 执行密钥生成
try {
    KeymasterOperationResult result = KeymasterHelper.generateKey(context, keygenArgs, password);
    if (result.getResult()) {
        // 如果成功,获取并保存密钥
        byte[] key = result.getKey();
        String encryptedData = Base64.encodeToString(encryptData(key), Base64.DEFAULT);
        saveEncryptedDataToFile(encryptedData);
    } else {
        handleEncryptionError(result.getErrorCode());
    }
} catch (Exception e) {
    logError(e);
}

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值