特徵

本頁面提供有關 Android Keystore 加密編譯功能的資訊,這些功能是由基礎 KeyMint (或 Keymaster) 實作提供。

密碼編譯基元

Keystore 提供下列作業類別:

  • 建立金鑰,產生私密金鑰或密鑰內容,只有安全環境才能存取。用戶端可以透過下列方式建立金鑰:
    • 產生新的金鑰
    • 匯入未加密的金鑰內容
    • 匯入已加密的金鑰內容
  • 金鑰認證:建立非對稱金鑰時,系統會產生憑證,其中包含金鑰組的公開金鑰部分。這個憑證可視需要儲存金鑰和裝置狀態的中繼資料資訊,所有簽署都會連結回信任的根金鑰。
  • 密碼編譯作業:
    • 對稱式加密和解密 (AES、3DES)
    • 非對稱式解密 (RSA)
    • 非對稱式簽署 (ECDSA、RSA)
    • 對稱簽署和驗證 (HMAC)
    • 非對稱式金鑰協議 (ECDH)

請注意,Keystore 和 KeyMint 不會處理非對稱金鑰的公開金鑰作業。

產生或匯入金鑰時,系統會指定用途、模式和填充等通訊協定元素,並永久綁定至金鑰,確保金鑰無法以任何其他方式使用。存取控制限制

IKeyMintDevice HAL 介面規格說明瞭 KeyMint 實作項目必須支援的基元和模式。

基礎 KeyMint 實作項目必須執行隨機號碼產生作業,才能支援金鑰產生作業,並建立隨機填充或初始化向量 (IV)。為支援此功能,Android 系統會定期為 KeyMint 實作提供額外的隨機性。

金鑰存取權控管

如果攻擊者可以隨意使用硬體金鑰,那麼從裝置中提取的硬體金鑰就無法提供太多安全性 (雖然比可擷取的金鑰安全)。因此,Keystore 必須強制執行存取權控管機制。

存取控制項的定義是標記/值組合的「授權清單」。授權標記是 32 位元整數,值則有多種類型。部分代碼可重複使用,用於指定多個值。標記是否可重複使用,是由 KeyMint (先前稱為 Keymaster) HAL 介面指定。

支援的標記值會在 Tag.aidl 檔案中定義,且每個標記都會與 TagType 相關聯,用於指出相關聯值的類型 (例如整數或位元組),以及是否可以重複使用來指定多個支援的值。

當 KeyMint 建立金鑰時,呼叫端會為金鑰指定授權清單。Keystore 和 KeyMint 會修改這份清單,以便新增額外限制,而基礎 KeyMint 實作會將最終授權清單編碼至傳回的 keyblob。經過編碼的授權清單會以加密方式繫結至金鑰 blob,因此任何嘗試修改授權清單 (包括排序) 的動作都會導致無效的金鑰 blob,無法用於加密作業。

硬體與軟體執行機制

並非所有安全硬體實作都包含相同的功能。為了支援各種方法,KeyMint 會區分安全和非安全的存取控制強制執行,或分別執行硬體和軟體強制執行。

在 KeyMint API 中,此值會以 KeyCharacteristics 類型的 securityLevel 欄位公開。安全硬體負責根據可強制執行的內容,在 KeyCharacteristics 中放置適當的安全層級授權。這項資訊也會顯示在非對稱金鑰的認證記錄中:SecurityLevel::TRUSTED_ENVIRONMENTSecurityLevel::STRONGBOX 的金鑰特性會顯示在 hardwareEnforced 清單中,而 SecurityLevel::SOFTWARESecurityLevel::KEYSTORE 的特性會顯示在 softwareEnforced 清單中。

舉例來說,安全環境通常不會強制執行金鑰可使用的日期和時間間隔限制,因為它無法可靠地存取日期和時間資訊。因此,Android 中的 Keystore 會強制執行 Tag::ORIGINATION_EXPIRE_DATETIME 這類授權,並會提供 SecurityLevel::KEYSTORE

如要進一步瞭解如何判斷金鑰及其授權是否有硬體支援,請參閱「金鑰認證」。

加密訊息結構授權

下列代碼用於定義使用關聯金鑰的作業的加密編譯特性:

  • Tag::ALGORITHM
  • Tag::KEY_SIZE
  • Tag::BLOCK_MODE
  • Tag::PADDING
  • Tag::CALLER_NONCE
  • Tag::DIGEST
  • Tag::MGF_DIGEST

下列標記可重複使用,也就是說,單一鍵可與多個值建立關聯:

  • Tag::BLOCK_MODE
  • Tag::PADDING
  • Tag::DIGEST
  • Tag::MGF_DIGEST

要使用的值會在運算時指定。

目的

鍵會與一組相關用途建立關聯,並以 Tag::PURPOSE 標記表示一或多個授權項目,藉此定義這些項目的使用方式。目的定義請見 KeyPurpose.aidl

請注意,某些用途值組合會造成安全性問題。舉例來說,RSA 金鑰可用於加密和簽署,因此攻擊者可說服系統解密任意資料,進而產生簽章。

金鑰匯入

KeyMint 支援以下匯入作業:

  • 採用 DER 編碼 PKCS#8 格式的非對稱金鑰組 (不含密碼加密)
  • 對稱金鑰為原始位元組

為確保匯入的金鑰可與安全產生的金鑰區分開,Tag::ORIGIN 會納入適當的金鑰授權清單。舉例來說,如果金鑰是在安全硬體中產生,則金鑰特性的 hw_enforced 清單中會找到值為 KeyOrigin::GENERATEDTag::ORIGIN,而匯入安全硬體的金鑰則會具有 KeyOrigin::IMPORTED 值。

使用者驗證

Secure KeyMint 實作項目不會實作使用者驗證,而是依賴其他可信任的應用程式來執行驗證。如要瞭解這些應用程式實作的介面,請參閱「閘道管理員」頁面。

使用者驗證要求會透過兩組標記指定。第一組會指出哪些驗證方法可使用金鑰:

  • Tag::USER_SECURE_ID 包含 64 位元數值,可指定安全驗證權杖中提供的安全使用者 ID,以解鎖金鑰使用權。如果重複,只要安全驗證權杖中提供任何值,即可使用該金鑰。

第二組則指出使用者是否需要驗證,以及驗證的時間。如果這兩個標記都沒有,但 Tag::USER_SECURE_ID 存在,則每次使用索引鍵時都需要驗證。

  • Tag::NO_AUTHENTICATION_REQUIRED 表示不需要使用者驗證,但金鑰的存取權仍限於擁有應用程式 (以及授予存取權的任何應用程式)。
  • Tag::AUTH_TIMEOUT 是一個以秒為單位的數值,用於指定使用者驗證需要多新,才能授權使用金鑰。逾時不會跨越重新啟動;重新啟動後,所有驗證都會失效。您可以將逾時時間設為較大的值,表示每次啟動都需要驗證 (2^32 秒約為 136 年,Android 裝置的重新啟動頻率可能會超過這個值)。

需要解鎖裝置

含有 Tag::UNLOCKED_DEVICE_REQUIRED 的鍵只能在裝置解鎖時使用。如需詳細語意說明,請參閱 KeyProtection.Builder#setUnlockedDeviceRequired(boolean)

UNLOCKED_DEVICE_REQUIRED 是由 Keystore 而非 KeyMint 強制執行。不過,在 Android 12 以上版本中,Keystore 會在裝置鎖定時以加密方式保護 UNLOCKED_DEVICE_REQUIRED 金鑰,以確保在大多數情況下,即使 Keystore 在裝置鎖定時遭到入侵,也無法使用這些金鑰。

為達成這項目標,Keystore 會在將所有 UNLOCKED_DEVICE_REQUIRED 金鑰儲存到資料庫前,先「超級加密」這些金鑰,並盡可能在裝置鎖定時保護超級加密金鑰 (超級金鑰),以便在裝置解鎖後才能復原這些金鑰。(之所以使用「超級加密」一詞,是因為 KeyMint 已將加密機制套用至所有金鑰,因此這個加密層是「額外」套用的。)

每個使用者 (包括設定檔) 都有兩個與 UNLOCKED_DEVICE_REQUIRED 相關聯的超級金鑰:

  • UnlockedDeviceRequired 對稱式超級金鑰。這是 AES-256-GCM 金鑰。它會在裝置為使用者解鎖時,加密匯入或產生的 UNLOCKED_DEVICE_REQUIRED 金鑰。
  • UnlockedDeviceRequired 非對稱超級金鑰。這是 ECDH P-521 金鑰組。這項功能會為使用者在裝置鎖定時匯入或產生的 UNLOCKED_DEVICE_REQUIRED 金鑰加密。使用這個非對稱金鑰加密的金鑰,會在首次使用時以對稱式金鑰重新加密 (這只能在裝置解鎖時發生)。

Keystore 會在使用者建立時產生這些超級金鑰,並將這些金鑰儲存在資料庫中,並以使用者綜合密碼加密。這樣一來,您就能使用 PIN 碼、解鎖圖案或密碼來復原這些項目。

Keystore 也會在記憶體中快取這些超級金鑰,讓 Keystore 能夠對 UNLOCKED_DEVICE_REQUIRED 金鑰運作。不過,只有在裝置為使用者解鎖時,系統才會嘗試快取這些金鑰的機密部分。當裝置為使用者上鎖時,Keystore 會盡可能將這些超級金鑰的秘密部分快取副本設為零。具體來說,當裝置為使用者鎖定時,Keystore 會為使用者的 UnlockedDeviceRequired 超級金鑰選取並套用以下三種保護層級之一:

  • 如果使用者只啟用 PIN 碼、解鎖圖案或密碼,Keystore 就會將快取超級金鑰的機密部分設為零。這樣一來,超級金鑰只能透過資料庫中的加密副本復原,而該副本只能透過 PIN 碼、圖案或密碼解密。
  • 如果使用者只啟用了 第 3 類 (「強式」) 生物特徵辨識和 PIN 碼、解鎖圖案或密碼,Keystore 就會安排超級金鑰可透過使用者註冊的任何第 3 類生物特徵辨識資訊 (通常是指紋) 復原,做為 PIN 碼、解鎖圖案或密碼的替代方案。為此,它會產生新的 AES‑256‑GCM 金鑰,並使用該金鑰加密超級金鑰的機密部分,然後將 AES‑256‑GCM 金鑰匯入 KeyMint,做為需要在過去 15 秒內成功通過生物特徵辨識驗證的生物特徵辨識綁定金鑰,並將所有這些金鑰的明文副本歸零。
  • 如果使用者啟用了第 1 級 (「便利」) 生物特徵辨識、第 2 級 (「弱」) 生物特徵辨識或有效的解鎖信任代理程式,Keystore 就會將超級金鑰快取到明文中。在這種情況下,系統不會提供 UNLOCKED_DEVICE_REQUIRED 金鑰的加密編譯安全性。使用者可以選擇不啟用這些解鎖方法,避免使用安全性較低的備用方法。這類最常見的解鎖方法包括許多裝置上的臉部辨識解鎖,以及透過配對的智慧手錶解鎖。

當裝置為使用者解鎖時,Keystore 會盡可能復原使用者的 UnlockedDeviceRequired 超級金鑰。對於 PIN 碼、圖案或密碼等同於解鎖功能,系統會解密儲存在資料庫中的這些金鑰副本。否則,系統會檢查是否已儲存使用生物特徵綁定金鑰加密的這些金鑰副本,如果有,則會嘗試解密。只有在使用者在過去 15 秒內成功使用第 3 級生物特徵辨識驗證 (由 KeyMint 而非 Keystore 強制執行) 時,此操作才會成功。

用戶端繫結

用戶端繫結 (將金鑰與特定用戶端應用程式建立關聯) 是透過選用的用戶端 ID 和部分選用的用戶端資料 (分別為 Tag::APPLICATION_IDTag::APPLICATION_DATA) 完成。Keystore 會將這些值視為不透明的 blob,只確保在每個用途中,鍵產生/匯入期間顯示的 blob 都相同,且每個位元組都相同。KeyMint 不會傳回用戶端繫結資料。呼叫端必須知道這項資訊,才能使用金鑰。

這項功能不會公開給應用程式。

到期日

KeyStore 支援依日期限制金鑰用量。金鑰有效開始時間和金鑰到期時間可與金鑰建立關聯,如果目前日期/時間不在有效範圍內,Keystore 就會拒絕執行金鑰作業。鍵的有效範圍會使用 Tag::ACTIVE_DATETIMETag::ORIGINATION_EXPIRE_DATETIMETag::USAGE_EXPIRE_DATETIME 標記指定。「產生」和「使用」的差異在於金鑰是否用於「產生」新的密文/簽章/等,或是用於「使用」現有的密文/簽章/等。請注意,這項差異不會公開給應用程式。

Tag::ACTIVE_DATETIMETag::ORIGINATION_EXPIRE_DATETIMETag::USAGE_EXPIRE_DATETIME 標記為選用項目。如果沒有標記,系統會假設該金鑰一律可用於解密/驗證訊息。

由於真實時間是由非安全世界提供,因此與到期日相關的標記會列在軟體強制執行清單中。

信任根繫結

KeyStore 要求金鑰繫結至信任根,這是在啟動期間提供給 KeyMint 安全硬體的位元字串,最好由啟動載入程式提供。這個位元字串會以密碼學方式繫結至 KeyMint 管理的每個金鑰。

信任根包含用於驗證開機映像檔簽名和裝置鎖定狀態的公開金鑰雜湊。如果您變更了可用於使用其他系統映像檔的公開金鑰,或是變更了鎖定狀態,則除非還原先前的信任根,並啟動由該金鑰簽署的系統,否則先前系統建立的 KeyMint 保護金鑰都無法使用。目標是讓攻擊者安裝的作業系統無法使用 KeyMint 金鑰,藉此提高軟體強制執行的金鑰存取控管機制價值。

隨機號碼產生器重新設定種子

由於安全硬體會為金鑰素材和初始化向量 (IV) 產生隨機號碼,且硬體隨機號碼產生器不一定完全可信,因此 KeyMint HAL 提供介面,允許 KeyStore 提供額外的資訊熵,並將其混入產生的隨機號碼。

使用硬體隨機號碼產生器做為主要的種子來源。透過外部 API 提供的種子資料,並非用於產生號碼的唯一隨機來源。此外,如果任何一個種子來源無法預測,則使用的混合運算需要確保隨機輸出結果無法預測。