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

    歷經一年多時間的系統整理合補充,《手機安全和可信應用開發指南:TrustZone與OP-TEE技術詳解 》一書得以出版,書中詳細介紹了TEE以及系統安全中的所有內容,全書按照從硬件到軟件,從用戶空間到內核空間的順序對TEE技術詳細闡述,讀者可從用戶空間到TEE內核一步一步瞭解系統安全的所有內容,同時書中也提供了相關的示例代碼,讀者可根據自身實際需求開發TA。

爲方便和及時的回覆讀者對書中或者TEE相關的問題的疑惑(每天必看一次),也爲了大家能有一個統一的交流平臺。我搭建了一個簡單的論壇,網址如下:

https://www.huangtengxq.com/discuz/forum.php

關於您的疑問可在“相關技術討論“”中發帖,我會逐一回復。也歡迎大家發帖,一起討論TEE相關的一些有意思的feature。共同交流。同時該論壇中也會添加關於移動端虛擬化的相關技術的板塊,歡迎各位共同交流學習

非常感謝在此期間大家的支持以及各位友人的支持和幫助!!!。

若覺得書中內容有錯誤的地方,歡迎大家指出,私信或者在博文中留言聯繫方式亦可發郵件至:[email protected],多謝各位了!!!!我會第一時間處理

  

在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;
}

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章