37. OP-TEE中secure stroage------安全存储使用的key的产生

    历经一年多时间的系统整理合补充,《手机安全和可信应用开发指南:TrustZone与OP-TEE技术详解 》一书得以出版,书中详细介绍了TEE以及系统安全中的所有内容,全书按照从硬件到软件,从用户空间到内核空间的顺序对TEE技术详细阐述,读者可从用户空间到TEE内核一步一步了解系统安全的所有内容,同时书中也提供了相关的示例代码,读者可根据自身实际需求开发TA。目前该书已在天猫、京东、当当同步上线,链接如下:

当当购买地址

京东购买地址

天猫购买地址

非常感谢在此期间大家的支持以及各位友人的支持和帮助!!!。

  

在OP-TEE中使用secure storage功能保存的数据都是经过AES加密之后被保存在文件系统或者是RPMB中的,使用AES算法进行加密或者解密的时候需要提供加密使用的key和初始化向量IV值。每个TA在使用secure storage功能保存数据的时候都会生成一个随机数作为IV值,使用FEK的值作为AES的key。而FEK的值是由一系列HMAC操作得到的。FEK值的生成牵扯到SSK和TSK,本文将介绍这些key的使用和生成,key之间的关系如下图所示:

1. SSK(Secure Storage Key)

  在每台设备中的SSK的值不一样,在OP-TEE启动的时候会使用chip ID和HUK经过HMAC算法计算获取SSK的值,并见SSK的值保存在一般该值在结构体变量tee_fs_ssk的key成员成,以备生成其他key使用。工厂生产的时候会将HUK写入到OTP/efuse中,并且在normal world端是无法读取到HUK的值的,而chip ID在芯片出厂之后就会被写入到芯片中。

  在OP-TEE启动的时候会执行tee_fs_init_key_manager函数,该函数就是用来根据SSK = HMAC(HUK, message)的方式来生成SSK,并保存在tee_fs_ssk的key成员中。该函数的内容如下:

static TEE_Result tee_fs_init_key_manager(void)
{
	int res = TEE_SUCCESS;
	struct tee_hw_unique_key huk;
	uint8_t chip_id[TEE_FS_KM_CHIP_ID_LENGTH];
	uint8_t message[sizeof(chip_id) + sizeof(string_for_ssk_gen)];

	/* Secure Storage Key Generation:
	 *
	 *     SSK = HMAC(HUK, message)
	 *     message := concatenate(chip_id, static string)
	 * */
/* 获取HUK的值(该接口的实现与平台有关,不同的芯片具有不同的读取HUK值的方式) */
	tee_otp_get_hw_unique_key(&huk);

/*  获取chip ID的值(不同的芯片具有不同的读取chip id值的方式)*/
	tee_otp_get_die_id(chip_id, sizeof(chip_id));

/* 将chip id + string_for_ssk_gen连接后的值保存到message中,string_for_ssk_gen是一个
静态的字符串,该值被hard code在代码中 */
	memcpy(message, chip_id, sizeof(chip_id));
	memcpy(message + sizeof(chip_id), string_for_ssk_gen,
			sizeof(string_for_ssk_gen));

/* 使用huk的值对message的内容做HMAC运算,将获取到数据作为SSK,保存到tee_fs_ssk
变量的key成员中 */
	res = do_hmac(tee_fs_ssk.key, sizeof(tee_fs_ssk.key),
			huk.data, sizeof(huk.data),
			message, sizeof(message));

/* 标记ssk已经生产 */
	if (res == TEE_SUCCESS)
		tee_fs_ssk.is_init = 1;

	return res;
}

2. TSK(Trusted Applicant Storage Key)

  TSK是用来生成FEK使用到的key,TSK的值由TA的UUID使用SSK作为key,经过HMAC计算获得,类似于HMAC(SSK, UUID)的方式得到TSK的值,在调用tee_fs_fek_crypt函数的时候就会去计算TSK的值。TSK最终会被用来生成FEK,FEK将会在使用secure storage功能保存数据的时候被用来加密数据。

3. FEK(File Encryption Key)

  FEK是secure storage用来对数据进行加密使用的AES key,该key在生成文件的时候会使用PRNG来随机产生,产生的FEK会使用TSK进行加密,然后保存到head.enc_fek变量中,一个TA每次在使用secure storage创建一个安全文件时就生成一个随机数作为FEK,也即是每个TA中的每个安全文件都有一个FEK用于加密对应的文件数据。关于FEK值的产生可以简单理解为如下公式,使用的初始化向量IV值为0:

AES_CBC(in_key, TSK)

  通过调用tee_fs_fek_crypt函数就能生成一个FEK的值,该函数代码如下:

TEE_Result tee_fs_fek_crypt(const TEE_UUID *uuid, TEE_OperationMode mode,
			    const uint8_t *in_key, size_t size,
			    uint8_t *out_key)
{
	TEE_Result res;
	uint8_t *ctx = NULL;
	size_t ctx_size;
	uint8_t tsk[TEE_FS_KM_TSK_SIZE];
	uint8_t dst_key[size];

/* 检查输入的用于生成FEK的随机数in_key和用于存放生成的out_key地址是否合法 */
	if (!in_key || !out_key)
		return TEE_ERROR_BAD_PARAMETERS;

/* 检查in_key长度 */
	if (size != TEE_FS_KM_FEK_SIZE)
		return TEE_ERROR_BAD_PARAMETERS;

/* 判定SSK是否已经被初始化 */
	if (tee_fs_ssk.is_init == 0)
		return TEE_ERROR_GENERIC;

/* 如果调用的时候参数uuid不为0,则调用HMAC算法生成TSK。如果UUID的值为0,则
默认生成TSK使用的原始数据为0 */
	if (uuid) {
		res = do_hmac(tsk, sizeof(tsk), tee_fs_ssk.key,
			      TEE_FS_KM_SSK_SIZE, uuid, sizeof(*uuid));
		if (res != TEE_SUCCESS)
			return res;
	} else {
		/*
		 * Pick something of a different size than TEE_UUID to
		 * guarantee that there's never a conflict.
		 */
		uint8_t dummy[1] = { 0 };

		res = do_hmac(tsk, sizeof(tsk), tee_fs_ssk.key,
			      TEE_FS_KM_SSK_SIZE, dummy, sizeof(dummy));
		if (res != TEE_SUCCESS)
			return res;
	}

/* 获取调用AEC_CBC操作需要的context的大小 */
	res = crypto_ops.cipher.get_ctx_size(TEE_FS_KM_ENC_FEK_ALG, &ctx_size);
	if (res != TEE_SUCCESS)
		return res;

/* 分配一份进行AES_CBC操作时需要的context空间 */
	ctx = malloc(ctx_size);
	if (!ctx)
		return TEE_ERROR_OUT_OF_MEMORY;

/* 使用TSK作为进行AES_CBC计算使用的key,而IV值默认为0 */
	res = crypto_ops.cipher.init(ctx, TEE_FS_KM_ENC_FEK_ALG, mode, tsk,
				     sizeof(tsk), NULL, 0, NULL, 0);
	if (res != TEE_SUCCESS)
		goto exit;

/* 将输入的in_key填充到context中,做完AES_CBC操作之后,输出的数据将会被保存到
dst_key中 */
	res = crypto_ops.cipher.update(ctx, TEE_FS_KM_ENC_FEK_ALG,
			mode, true, in_key, size, dst_key);
	if (res != TEE_SUCCESS)
		goto exit;

/* 执行AES_CBC的加密运算,生成FEK */
	crypto_ops.cipher.final(ctx, TEE_FS_KM_ENC_FEK_ALG);

/* 将生成的FEK的值拷贝到输出参数中 */
	memcpy(out_key, dst_key, sizeof(dst_key));

exit:
	free(ctx);

	return res;
}

猜你喜欢

转载自blog.csdn.net/shuaifengyun/article/details/73555193
今日推荐