【OP-TEE】 TA的加密与解密简介

TA的加密与解密简介

TA的加密

TA在被编译的时候会在optee_os/ta/arch/arm/link.mk里进行一些操作,包括调用脚本对编译出的elf文件进行签名加密生成.ta。
而签名加密的核心在于调用optee_os/scripts/sign_encrypt.py脚本。采用RSA签名,AES加密。当CFG_ENCRYPT_TA变量为y时,TA加密功能被打开。
在这里插入图片描述
TA加密功能打开后,在optee开源代码中存放的加密密钥是默认的上图中的TA_ENC_KEY,这个密钥只是作为演示功能,用在自己的工程中替换为自己的密钥。在调用签名加密脚本时候,传入签名私钥,加密的密钥。
在这里插入图片描述
在这里插入图片描述
目前的从git下载的optee代码中没有打开TA加密功能,只有TA签名功能。如何增加TA的加密功能,以optee_examples工程下的hello_world TA为例。我将CFG_ENCRYPT_TA变量定义在makefile里。CFG_ENCRYPT_TA ?= y 编译时就会调用脚本对hello_world的TA进行了AES加密。加密后其镜像头部会增加ehdr的数据。存放在shdr_encrypte_ta类型的结构体里。

struct shdr_encrypte_ta {
	uint32_t enc_algo;
	uint32_t flags;
	uint16_t iv_size;
	uint16_t tag_size;
};

在这里插入图片描述

签名加密后的TA文件变成了 uuid.ta,比如hello_world编译签名加密后变成了8aaaf200-2450-11e4-abe2-0002a5d5c51b.ta,其通过sig_encrypto.py脚本添加的头部信息如上图。
shdr是与签名有关的信息。
magic:需要与optee-os里的匹配。
img_type:TA镜像类型,是否加密。
img_siez:TA镜像大小。
alg:签名算法,默认RSA。
hash_size::TA签名的摘要大小。此摘要是除去sig和hash后对整个ta文件的摘要
sig_size:TA签名的大小。签名是对前面摘要的签名。

bs_hdr是和TA相关的信息
uuid:此TA的uuid.
ta_version:TA的版本号

ehdr是和加密相关的信息
enc_alg:加密算法,默认是AES。
flag:加密的标识,代表密钥类型。
iv_size:加密iv值的大小。
tag_size:tag的大小。

TA的解密

加密功能使能的TA其头部shdr会存放签名相关的信息。shdr里的img_type变量存放TA镜像类别,是否加密。optee-os加载TA时会判断其是否加密,没有加密则只验签,加密则先验签和解密。

解密TA依赖于 tee_ta_decrypt_init函数。其调用tee_otp_get_ta_enc_key函数获取TA加密的密钥用于解密。此函数在optee里默认从固定的数组(也就是optee-os里保存的用于验签TA的公钥)里派生。用于自己的工程需要修改为自己获取密钥的方式。
在这里插入图片描述
那么默认的密钥是如何派生的呢?
通过huk_subkey_derive函数,将用于派生的数组传入函数,进行HAMC_SHA256计算,得到digest就是派生出的密钥,此密钥和link.mk里的一样,不一样则TA解密失败。此处可以替换为自己的密钥获取方式,但是需要和link.mk里的一致。

const uint8_t ta_pub_key_modulus[] = {
0xa6, 0x5a, 0x18, 0xad, 0xc0, 0xb3, 0xce, 0xe3,
....
};

得到密钥后调用

res = crypto_authenc_init(*enc_ctx, TEE_MODE_DECRYPT, key, sizeof(key),
			SHDR_ENC_GET_IV(ehdr), ehdr->iv_size,
			ehdr->tag_size, 0, len);

传入密钥,初始化解密上下文。
在后面的TA已经加载完成后,ree_fs_ta_read时进行解密的工作。因为TA是分段加载的,所以解密也是分段的,需要多次解密。

static TEE_Result ree_fs_ta_read(struct user_ta_store_handle *h, void *data,
				 size_t len)
{
	struct ree_fs_ta_handle *handle = (struct ree_fs_ta_handle *)h;
	/*获取TA镜像除去头之后的elf格式所在位置*/
	uint8_t *src = (uint8_t *)handle->nw_ta + handle->offs;
	size_t next_offs = 0;
	uint8_t *dst = src;
	TEE_Result res = TEE_SUCCESS;

	if (ADD_OVERFLOW(handle->offs, len, &next_offs) ||
	    next_offs > handle->nw_ta_size)
		return TEE_ERROR_BAD_PARAMETERS;
	/*判断TA类型*/
	if (handle->shdr->img_type == SHDR_ENCRYPTED_TA) {
		if (data) {
			dst = data; /* Hash secure buffer */
			/*解密len长度的数据到安全内存中,加载多长的数据就解密多长的数据*/
			res = tee_ta_decrypt_update(handle->enc_ctx, dst, src,
						    len);
			if (res != TEE_SUCCESS)
				return TEE_ERROR_SECURITY;
		} else {
			size_t num_bytes = 0;
			size_t b_size = MIN(1024U, len);
			uint8_t *b = malloc(b_size);

			if (!b)
				return TEE_ERROR_OUT_OF_MEMORY;

			dst = NULL;
			while (num_bytes < len) {
				size_t n = MIN(b_size, len - num_bytes);

				res = tee_ta_decrypt_update(handle->enc_ctx, b,
							    src + num_bytes, n);
				if (res)
					break;
				num_bytes += n;

				res = crypto_hash_update(handle->hash_ctx, b,
							 n);
				if (res)
					break;
			}

			free(b);
			if (res != TEE_SUCCESS)
				return TEE_ERROR_SECURITY;
		}
	} else if (data) { /*不是加密的TA则直接拷贝*/
		dst = data; /* Hash secure buffer (shm might be modified) */
		memcpy(dst, src, len);
	}

	if (dst) {
		/*更新hash_ctx,以便后面计算出TA的hash值使用*/
		res = crypto_hash_update(handle->hash_ctx, dst, len);
		if (res != TEE_SUCCESS)
			return TEE_ERROR_SECURITY;
	}
	/*将句柄的偏移更新*/
	handle->offs = next_offs;
	if (handle->offs == handle->nw_ta_size) {/*判断当前是否已经加载了所有的segment*/
		if (handle->shdr->img_type == SHDR_ENCRYPTED_TA) {
			/*
			 * Last read: time to finalize authenticated
			 * decryption.
			 */
			 /*加载所有segment之后进行ctx final收尾工作*/
			res = tee_ta_decrypt_final(handle->enc_ctx,
						   handle->ehdr, NULL, NULL, 0);
			if (res != TEE_SUCCESS)
				return TEE_ERROR_SECURITY;
		}
		/*
		 * Last read: time to check if our digest matches the expected
		 * one (from the signed header)
		 */
		res = check_digest(handle);/*加载所有segment之后进行hash校验与shdr里的比较*/
		if (res != TEE_SUCCESS)
			return res;

		if (handle->bs_hdr)
			res = check_update_version(handle->bs_hdr);
	}
	return res;
}

镜像的解密是随着TA的elf文件的加载进行的,TA的elf是分段多次加载,先加载elf head,所以就先解密elf head,所以TA的elf每次加载都会触发解密操作。直到TA elf文件完全加载完成。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值