Android KeyStore流程
文章目錄
- 一、Keystore
- 二、Keystore架構(gòu)及接口函數(shù)
- 1. Keystore組件架構(gòu)
- 2. IKeymasterDevice.hal中的幾個(gè)重要接口函數(shù)
- 2.1 begin函數(shù)
- 2.2 update函數(shù)
- 2.3 finish函數(shù)
- 2.4 abort函數(shù)
- 3. Keymaster TA
- 4. 對(duì)稱密碼函數(shù)API
- 三、從Keystore到Keymaster的完整分析
- 1. cts問(wèn)題
- 2. 代碼流程分析
- 2.1 模塊調(diào)用關(guān)系
- 2.2 代碼分析
一、Keystore
keystore主要是對(duì)密鑰庫(kù)的控制操作,包括密鑰的生成導(dǎo)入導(dǎo)出、加解密、簽名驗(yàn)簽、訪問(wèn)控制等。
概念的詳細(xì)介紹就請(qǐng)看看google官網(wǎng)的介紹。本篇主要是想總結(jié)一下keystore的使用流程,貌似其他博客講這個(gè)流程的不多,就整理一篇出來(lái)。
原創(chuàng)不易,轉(zhuǎn)載請(qǐng)標(biāo)明出處 https://blog.csdn.net/jackone12347/article/details/122252644
二、Keystore架構(gòu)及接口函數(shù)
1. Keystore組件架構(gòu)
keystore涉及到的模塊之間的關(guān)系,一共有四個(gè)角色:
Andriod Keystore: 提供Android framework API,封裝密鑰庫(kù)相關(guān)的接口; Keystore:守護(hù)進(jìn)程,通過(guò)Binder提供密鑰庫(kù)功能,通過(guò)AIDL與Framework keystore通訊; HIDL Keymaster: HIDL進(jìn)程,封裝調(diào)用keymaster TA的密鑰函數(shù)接口;如android.hardware.keymaster@xxx-xxx KeyMaster TA: TEE中的TA,提供安全的密鑰庫(kù)操作和安全環(huán)境架構(gòu)圖如下:
2. IKeymasterDevice.hal中的幾個(gè)重要接口函數(shù)
需要看一下這幾個(gè)相關(guān)的接口,HAL層的IKeymasterDevice.hal都有介紹,下面是我理解的幾個(gè),因?yàn)楹徒酉聛?lái)的章節(jié)中分析CTS問(wèn)題是相關(guān)的。
2.1 begin函數(shù)
作用:使用指定的密鑰開(kāi)始加密操作。 如果一切順利,begin() 必須返回 ErrorCode::OK 并創(chuàng)建一個(gè)操作句柄,該句柄必須傳遞給后續(xù)對(duì) update()、finish() 或 abort() 的調(diào)用。
函數(shù)原型:
2.2 update函數(shù)
作用:向正在進(jìn)行的加密操作提供數(shù)據(jù)并可能從begin()接收輸出。
函數(shù)原型:
說(shuō)明:
1、為了為緩沖區(qū)處理提供更大的靈活性,此方法的實(shí)現(xiàn)具有使用比提供的更少的數(shù)據(jù)的選項(xiàng)。
調(diào)用者負(fù)責(zé)循環(huán)到在后續(xù)調(diào)用中提供其余數(shù)據(jù)。 必須返回consumed的輸入量在 inputConsumed 參數(shù)中。
實(shí)現(xiàn)必須始終至少消耗一個(gè)字節(jié),除非operation不能再接受;
如果提供的字節(jié)多于0且0字節(jié)是消耗,調(diào)用者必須認(rèn)為這是一個(gè)錯(cuò)誤并中止操作。
2、作為update的結(jié)果,實(shí)現(xiàn)還可以選擇返回多少數(shù)據(jù)。 這僅與加密和解密操作相關(guān),因?yàn)楹灻万?yàn)證在完成之前不會(huì)返回任何數(shù)據(jù)。 建議盡早返回?cái)?shù)據(jù),而不是緩沖它。
2.3 finish函數(shù)
作用:完成以 begin() 開(kāi)始的加密操作并使 operationHandle 無(wú)效。此方法是操作中最后調(diào)用的方法,因此必須返回所有處理過(guò)的數(shù)據(jù)。
函數(shù)原型:
2.4 abort函數(shù)
中止以 begin() 開(kāi)始的加密操作,釋放所有內(nèi)部資源并使操作句柄無(wú)效。
函數(shù)原型:
3. Keymaster TA
keymaster_operation_t結(jié)構(gòu)體,TA中會(huì)反復(fù)用到這個(gè)結(jié)構(gòu)體中的數(shù)據(jù)。
@ ta/include/operations.h typedef struct {uint8_t key_id[TAG_LENGTH];keymaster_key_blob_t *key;keymaster_blob_t nonce;keymaster_blob_t last_block;keymaster_operation_handle_t op_handle;keymaster_purpose_t purpose;keymaster_padding_t padding;keymaster_block_mode_t mode;keymaster_blob_list_item_t *sf_item;/*sign/verify data*/TEE_Time *last_access;TEE_OperationHandle *operation;TEE_OperationHandle *digest_op;size_t prev_in_size;uint32_t min_sec;uint32_t mac_length;uint32_t digestLength;uint32_t a_data_length;uint8_t *a_data;bool do_auth;bool got_input;bool buffering;bool padded;bool first; } keymaster_operation_t;keymaster_blob_t結(jié)構(gòu)體
typedef struct {uint8_t* data;size_t data_length; } keymaster_blob_t;4. 對(duì)稱密碼函數(shù)API
Cryptographic API調(diào)用流程
- some_function() (Trusted App) - [1] TEE_*() User space (libutee.a) ------- utee_*() ---------------------------------------------- [2] tee_svc_*() Kernel space [3] crypto_*() (libtomcrypt.a and crypto.c) [4] /* LibTomCrypt */ (libtomcrypt.a)對(duì)稱密碼函數(shù)定義了執(zhí)行對(duì)稱密碼操作(例如AES)的方式,涵蓋分組密碼和流密碼。
Cryptographic Operations API - Symmetric Cipher Functions
void TEE_CipherInit(TEE_OperationHandle operation, const void *IV,uint32_t IVLen)該函數(shù)啟動(dòng)對(duì)稱密碼操作,操作必須關(guān)聯(lián)一個(gè)密鑰。
TEE_Result TEE_CipherUpdate(TEE_OperationHandle operation, const void *srcData,uint32_t srcLen, void *destData, uint32_t *destLen)該函數(shù)用來(lái)加密或解密輸入數(shù)據(jù),輸入數(shù)據(jù)不必是塊大小的倍數(shù),除非對(duì)此函數(shù)的一個(gè)或多個(gè)調(diào)用提供了足夠的輸入數(shù)據(jù),否則不會(huì)生成任何輸出。
TEE_Result TEE_CipherDoFinal(TEE_OperationHandle operation,const void *srcData, uint32_t srcLen,void *destData, uint32_t *destLen)完成密碼操作,處理以前未通過(guò)調(diào)用TEE_CipherUpdate函數(shù)處理的數(shù)據(jù)以及srcData中提供的數(shù)據(jù)。隨后操作句柄可以重用或重新初始化。
三、從Keystore到Keymaster的完整分析
直接干巴巴地看源碼,有時(shí)候也不是很直觀地看出這幾大模塊是如何串聯(lián)起來(lái) 及如何完成從上到下的功能串調(diào)。
我們帶著一個(gè)cts的問(wèn)題來(lái)分析一下相關(guān)的流程吧。
1. cts問(wèn)題
運(yùn)行
adb shell am instrument -r -e class android.keystore.cts.AES128CBCNoPaddingCipherTest#testDoFinalResets -w android.keystore.cts/androidx.test.runner.AndroidJUnitRunner報(bào)錯(cuò):
javax.crypto.IllegalBlockSizeExceptionat android.security.keystore.AndroidKeyStoreCipherSpiBase.engineDoFinal(AndroidKeyStoreCipherSpiBase.java:490)at javax.crypto.Cipher.doFinal(Cipher.java:2055)at android.keystore.cts.BlockCipherTestBase.doFinal(BlockCipherTestBase.java:1400)at android.keystore.cts.BlockCipherTestBase.assertDoFinalResetsCipher(BlockCipherTestBase.java:594)at android.keystore.cts.BlockCipherTestBase.testDoFinalResets(BlockCipherTestBase.java:563)at android.keystore.cts.AES128CBCNoPaddingCipherTest.testDoFinalResets(AES128CBCNoPaddingCipherTest.java:19)at java.lang.reflect.Method.invoke(Native Method)at junit.framework.TestCase.runTest(TestCase.java:168)at junit.framework.TestCase.runBare(TestCase.java:134)at junit.framework.TestResult$1.protect(TestResult.java:115)at androidx.test.internal.runner.junit3.AndroidTestResult.runProtected(AndroidTestResult.java:73)at junit.framework.TestResult.run(TestResult.java:118)at androidx.test.internal.runner.junit3.AndroidTestResult.run(AndroidTestResult.java:51)at junit.framework.TestCase.run(TestCase.java:124)at androidx.test.internal.runner.junit3.NonLeakyTestSuite$NonLeakyTest.run(NonLeakyTestSuite.java:62)at androidx.test.internal.runner.junit3.AndroidTestSuite$2.run(AndroidTestSuite.java:101)at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:462)at java.util.concurrent.FutureTask.run(FutureTask.java:266)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)at java.lang.Thread.run(Thread.java:923) Caused by: android.security.KeyStoreException: Keystore consumed 0 of 8 bytes provided.at android.security.keystore.KeyStoreCryptoOperationChunkedStreamer.update(KeyStoreCryptoOperationChunkedStreamer.java:143)at android.security.keystore.AndroidKeyStoreCipherSpiBase.engineUpdate(AndroidKeyStoreCipherSpiBase.java:338)at javax.crypto.Cipher.update(Cipher.java:1682)at android.keystore.cts.BlockCipherTestBase.update(BlockCipherTestBase.java:1454)at android.keystore.cts.BlockCipherTestBase.assertDoFinalResetsCipher(BlockCipherTestBase.java:593)2. 代碼流程分析
下面針對(duì)以上報(bào)錯(cuò)內(nèi)容,進(jìn)行詳細(xì)的分析,包含涉及到哪些模塊,以及是怎么完成這項(xiàng)AES測(cè)試的。
2.1 模塊調(diào)用關(guān)系
根據(jù)前面的內(nèi)容得知一共有四個(gè)角色,其實(shí)還應(yīng)該包含一個(gè)角色,就是JAVA應(yīng)用程序APK,即keystore調(diào)用者。
所以五個(gè)角色為如下:
應(yīng)用程序APK android.keystore.cts
Framework Keystore API
Keystore守護(hù)進(jìn)程
Keymaster: HIDL進(jìn)程:android.hardware.keymaster@xxx-xxx
Keymaster TA程序
五個(gè)角色的調(diào)用關(guān)系:
cts apk進(jìn)程通過(guò)API ==> Framework Keystore API Framework Keystore API 通過(guò)Binder調(diào)用 ==> Keystore進(jìn)程 Keystore進(jìn)程通過(guò)HIDL ==> Keymaster HAL進(jìn)程 Keymaster HAL進(jìn)程 ==> 調(diào)用TEE中的keymaster TA2.2 代碼分析
順著cts報(bào)錯(cuò),我們分析一下相關(guān)代碼。
報(bào)錯(cuò)內(nèi)容:
12-29 13:39:04.818 3206 3228 E TestRunner: Caused by: android.security.KeyStoreException: Keystore consumed 0 of 8 bytes provided. 12-29 13:39:04.818 3206 3228 E TestRunner: at android.security.keystore.KeyStoreCryptoOperationChunkedStreamer.update(KeyStoreCryptoOperationChunkedStreamer.java:143) 12-29 13:39:04.818 3206 3228 E TestRunner: at android.security.keystore.AndroidKeyStoreCipherSpiBase.engineUpdate(AndroidKeyStoreCipherSpiBase.java:338) 12-29 13:39:04.818 3206 3228 E TestRunner: at javax.crypto.Cipher.update(Cipher.java:1682) 12-29 13:39:04.818 3206 3228 E TestRunner: at android.keystore.cts.BlockCipherTestBase.update(BlockCipherTestBase.java:1454) 12-29 13:39:04.818 3206 3228 E TestRunner: at android.keystore.cts.BlockCipherTestBase.assertDoFinalResetsCipher(BlockCipherTestBase.java:593)BlockCipherTestBase.java的assertDoFinalResetsCipher函數(shù)如下:
getBlockSize()返回的是16字節(jié),剛好是AES128的128bit, concat將兩個(gè)24字節(jié)update和final送入,一共48個(gè)字節(jié)。
關(guān)于AES算法以及工作模式,請(qǐng)參考我寫(xiě)的另一博客AES及其工作模式詳解
如果送入的數(shù)據(jù)是48字節(jié),剛好是16字節(jié)的整數(shù)倍,沒(méi)有問(wèn)題;
但如果一次送入的數(shù)據(jù)是24字節(jié),這樣需要分多次送入,第一次先送入16字節(jié),然后第二次送入8字節(jié)進(jìn)行存儲(chǔ),然后再送入8字節(jié),能拼成一個(gè)Blocksize 16字節(jié)進(jìn)行處理。
這項(xiàng)cts測(cè)試大概就是這么個(gè)目的,想看一下設(shè)備中能否處理這種不是16字節(jié)整數(shù)倍的情況。
=》調(diào)用 mCipher.update函數(shù)
protected byte[] update(byte[] input) {byte[] output = mCipher.update(input);assertUpdateOutputSize((input != null) ? input.length : 0, (output != null) ? output.length : 0);return output;}內(nèi)部的調(diào)用流程如下:
=》android.security.keystore.AndroidKeyStoreCipherSpiBase.engineUpdate
=》KeyStoreCryptoOperationChunkedStreamer.update
=》內(nèi)部類MainDataStream的update實(shí)現(xiàn)
=》調(diào)用KeyStore.java的update方法
KeyStore》java的update方法,開(kāi)始binder調(diào)用到守護(hù)進(jìn)程Keystore
到這里的整個(gè)過(guò)程基本上都是AOSP的流程,所以問(wèn)題一般不會(huì)出現(xiàn)在原生的代碼流程中。
需要繼續(xù)分析HAL層的調(diào)用。
Keystore服務(wù)端返回的流程在key_store_service.cpp中,能看到AIDL相關(guān)內(nèi)容了。
調(diào)用dev->update函數(shù)和HAL keymaster進(jìn)程通訊。
因?yàn)槊考业膋eymaster方案,基本上都屬于定制,為什么呢?因?yàn)镠AL封裝了和keymaster TA交互的接口。所以每家遇到的CTS問(wèn)題可能都不大相同,需要具體問(wèn)題具體分析了。
但各家基本上都會(huì)參考GP標(biāo)準(zhǔn)來(lái)開(kāi)發(fā)
CA調(diào)用接口
TEEC_InvokeCommand(&sess, cmd, &op, &err_origin);
TA調(diào)用接口
TEE_CipherUpdate
最后這個(gè)CTS的修改是在keymaster TA中修復(fù),具體code就不方便貼了,遇到類似問(wèn)題時(shí)請(qǐng)具體看各家的keymaster TA及TEE中對(duì)應(yīng)的libutee中封裝的函數(shù)實(shí)現(xiàn)。
修復(fù)后的復(fù)測(cè)結(jié)果:
# adb shell am instrument -r -e class android.keystore.cts.AES128CBCNoPaddingCipherTest#testDoFinalResets -w android.keystore.cts/androidx.test.runner.AndroidJUnitRunner INSTRUMENTATION_STATUS: class=android.keystore.cts.AES128CBCNoPaddingCipherTest INSTRUMENTATION_STATUS: current=1 INSTRUMENTATION_STATUS: id=AndroidJUnitRunner INSTRUMENTATION_STATUS: numtests=1 INSTRUMENTATION_STATUS: stream= android.keystore.cts.AES128CBCNoPaddingCipherTest: INSTRUMENTATION_STATUS: test=testDoFinalResets INSTRUMENTATION_STATUS_CODE: 1 INSTRUMENTATION_STATUS: class=android.keystore.cts.AES128CBCNoPaddingCipherTest INSTRUMENTATION_STATUS: current=1 INSTRUMENTATION_STATUS: id=AndroidJUnitRunner INSTRUMENTATION_STATUS: numtests=1 INSTRUMENTATION_STATUS: stream=. INSTRUMENTATION_STATUS: test=testDoFinalResets INSTRUMENTATION_STATUS_CODE: 0 INSTRUMENTATION_RESULT: stream=Time: 8.063OK (1 test)總結(jié)
以上是生活随笔為你收集整理的Android KeyStore流程的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 面试资料三
- 下一篇: c++中的explicit关键字