日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > Android >内容正文

Android

Android KeyStore流程

發(fā)布時(shí)間:2025/3/15 Android 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android KeyStore流程 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章目錄

  • 一、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ù)原型:

begin(KeyPurpose purpose, vec<uint8_t> keyBlob, vec<KeyParameter> inParams,HardwareAuthToken authToken)generates (ErrorCode error, vec<KeyParameter> outParams, OperationHandle operationHandle);

2.2 update函數(shù)

作用:向正在進(jìn)行的加密操作提供數(shù)據(jù)并可能從begin()接收輸出。
函數(shù)原型:

update(OperationHandle operationHandle, vec<KeyParameter> inParams, vec<uint8_t> input,HardwareAuthToken authToken, VerificationToken verificationToken)generates (ErrorCode error, uint32_t inputConsumed, vec<KeyParameter> outParams,vec<uint8_t> output);

說(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ù)原型:

finish(OperationHandle operationHandle, vec<KeyParameter> inParams, vec<uint8_t> input,vec<uint8_t> signature, HardwareAuthToken authToken, VerificationToken verificationToken)generates (ErrorCode error, vec<KeyParameter> outParams, vec<uint8_t> output);

2.4 abort函數(shù)

中止以 begin() 開(kāi)始的加密操作,釋放所有內(nèi)部資源并使操作句柄無(wú)效。
函數(shù)原型:

abort(OperationHandle operationHandle) generates (ErrorCode error);

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 TA

2.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)
  • Framework KeyStore API
    BlockCipherTestBase.java的assertDoFinalResetsCipher函數(shù)如下:
  • private void assertDoFinalResetsCipher(int opmode) throws Exception {byte[] input = getKatInput(opmode);byte[] expectedOutput = getKatOutput(opmode);createCipher();initKat(opmode);assertEquals(expectedOutput, doFinal(input));if ((opmode == Cipher.ENCRYPT_MODE) && (getKatIv() != null)) {// Assert that this cipher cannot be reused (thus making IV reuse harder)try {doFinal(input);fail();} catch (IllegalStateException expected) {}return;}// Assert that the same output is produced after the above resetassertEquals(expectedOutput, doFinal(input));assertEquals(expectedOutput, concat(update(subarray(input, 0, getBlockSize() * 3 / 2)),doFinal(subarray(input, getBlockSize() * 3 / 2, input.length))));assertEquals(expectedOutput, doFinal(input));// Assert that the IV with which the cipher was initialized is still there after the resets.assertEquals(getKatIv(), mCipher.getIV());assertAlgoritmParametersIv(getKatIv());}

    getBlockSize()返回的是16字節(jié),剛好是AES128的128bit, concat將兩個(gè)24字節(jié)update和final送入,一共48個(gè)字節(jié)。
    關(guān)于AES算法以及工作模式,請(qǐng)參考我寫的另一博客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

    public OperationResult update(IBinder token, KeymasterArguments arguments, byte[] input) {OperationPromise promise = new OperationPromise();try {mBinder.asBinder().linkToDeath(promise, 0);int errorCode = mBinder.update(promise, token, arguments, input);if (errorCode == NO_ERROR) {return interruptedPreservingGet(promise.getFuture());} else {return new OperationResult(errorCode);}} catch (RemoteException e) { ,,,}

    到這里的整個(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)程通訊。

    @system/security/keystore/key_store_service.cpp Status KeyStoreService::update(const ::android::sp<IKeystoreOperationResultCallback>& cb,const ::android::sp<::android::IBinder>& token,const ::android::security::keymaster::KeymasterArguments& params,const ::std::vector<uint8_t>& input, int32_t* _aidl_return) {ALOGE("key_store_service update entry");if (!checkAllowedOperationParams(params.getParameters())) {return AIDL_RETURN(ErrorCode::INVALID_ARGUMENT);}auto dev = mKeyStore->getOperationDevice(token);dev->update(token, params.getParameters(), input, [this, cb, token](OperationResult result_) {if (!result_.resultCode.isOk()) {mKeyStore->removeOperationDevice(token);}cb->onFinished(result_);});ALOGE("key_store_service update done");return AIDL_RETURN(ResponseCode::NO_ERROR); }

    因?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)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。