此頁麵包含有關 Android 6.0 及更高版本中Keystore的加密功能的信息。
密碼原語
Keystore 提供以下幾類操作:
- 密鑰生成
- 非對稱密鑰的導入和導出(無密鑰包裝)
- 導入原始對稱密鑰(無密鑰包裝)
- 具有適當填充模式的非對稱加密和解密
- 具有摘要和適當填充模式的非對稱簽名和驗證
- 適當模式下的對稱加密和解密,包括 AEAD 模式
- 對稱消息認證碼的生成和驗證
在生成或導入密鑰時指定協議元素,例如用途、模式和填充以及訪問控制約束,並永久綁定到密鑰,確保密鑰不能以任何其他方式使用。
除了上面的列表之外,Keymaster 實現還提供了另外一項服務,但並未作為 API 公開:隨機數生成。這在內部用於生成密鑰、初始化向量 (IV)、隨機填充和其他需要隨機性的安全協議元素。
必要的原語
所有 Keymaster 實現都提供:
- RSA
- 2048、3072 和 4096 位密鑰支持
- 支持公共指數 F4 (2^16+1)
- RSA 簽名的填充模式:
- RSASSA-PSS (
PaddingMode::RSA_PSS
) - RSASSA-PKCS1-v1_5 (
PaddingMode::RSA_PKCS1_1_5_SIGN
)
- RSASSA-PSS (
- RSA 簽名的摘要模式:
- SHA-256
- RSA加密/解密的填充模式:
- 無填充
- RSAES-OAEP (
PaddingMode::RSA_OAEP
) - RSAES-PKCS1-v1_5 (
PaddingMode::RSA_PKCS1_1_5_ENCRYPT
)
- ECDSA
- 支持 224、256、384 和 521 位密鑰支持,分別使用 NIST P-224、P-256、P-384 和 P-521 曲線
- ECDSA 的摘要模式:
- 無摘要(已棄用,將來會刪除)
- SHA-256
- AES
- 支持 128 位和 256 位密鑰
- CBC 、CTR、ECB 和 GCM。 GCM 實現不允許使用小於 96 位的標籤或非 96 位的隨機數長度。
- 填充模式 CBC 和 ECB 模式支持
PaddingMode::NONE
和PaddingMode::PKCS7
。在沒有填充的情況下,如果輸入不是塊大小的倍數,CBC 或 ECB 模式加密將失敗。
- HMAC SHA-256 ,任何密鑰大小至少為 32 字節。
強烈建議將 SHA1 和 SHA2 系列的其他成員(SHA-224、SHA384 和 SHA512)用於 Keymaster 實施。如果硬件 Keymaster 實現不提供它們,則 Keystore 在軟件中提供它們。
一些原語也被推薦用於與其他系統的互操作性:
- RSA 的較小密鑰大小
- RSA 的任意公共指數
鑰匙訪問控制
永遠無法從設備中提取的基於硬件的密鑰如果攻擊者可以隨意使用它們並不能提供太多安全性(儘管它們比可以被洩露的密鑰更安全)。因此,Keystore 強制執行訪問控制至關重要。
訪問控制被定義為標籤/值對的“授權列表”。授權標籤是 32 位整數,值有多種類型。某些標籤可能會重複以指定多個值。標籤是否可以重複在標籤的文檔中指定。創建密鑰時,調用者會指定一個授權列表。 Keystore 底層的 Keymaster 實現會修改列表以指定一些附加信息,例如密鑰是否具有回滾保護,並返回一個“最終”授權列表,編碼到返回的密鑰 blob 中。如果修改了最終授權列表,則任何嘗試將密鑰用於任何加密操作都會失敗。
對於 Keymaster 2 和更早版本,可能的標籤集在枚舉keymaster_authorization_tag_t
中定義,並且是永久固定的(儘管可以擴展)。名稱以KM_TAG
為前綴。標籤 ID 的前四位用於表示類型。
Keymaster 3 將KM_TAG
前綴更改為Tag::
。
可能的類型包括:
ENUM
:許多標籤的值是在枚舉中定義的。例如, TAG::PURPOSE
的可能值在 enum keymaster_purpose_t
中定義。
ENUM_REP
:與ENUM
相同,除了標籤可以在授權列表中重複。重複表示多個授權值。例如,加密密鑰可能具有KeyPurpose::ENCRYPT
和KeyPurpose::DECRYPT
。
UINT
: 32 位無符號整數。示例: TAG::KEY_SIZE
UINT_REP
:與UINT
相同,除了標籤可以在授權列表中重複。重複表示多個授權值。
ULONG
:64 位無符號整數。示例: TAG::RSA_PUBLIC_EXPONENT
ULONG_REP
:與ULONG
相同,只是標籤可以在授權列表中重複。重複表示多個授權值。
DATE
:日期/時間值,以 1970 年 1 月 1 日以來的毫秒數表示。示例: TAG::PRIVKEY_EXPIRE_DATETIME
BOOL
:真或假。如果標籤不存在,則假定BOOL
類型的標籤為“假”,如果存在,則假定為“真”。示例: TAG::ROLLBACK_RESISTANT
BIGNUM
:任意長度的整數,以大端順序表示為字節數組。示例: TAG::RSA_PUBLIC_EXPONENT
BYTES
:字節序列。示例: TAG::ROOT_OF_TRUST
硬件與軟件執行
並非所有安全硬件實現都包含相同的功能。為了支持各種方法,Keymaster 分別區分了安全和非安全世界訪問控制實施,或硬件和軟件實施。
所有實現:
- 強制執行所有授權的完全匹配(而不是強制執行)。密鑰 Blob 中的授權列表與密鑰生成期間返回的授權完全匹配,包括排序。任何不匹配都會導致錯誤診斷。
- 聲明其語義值被強制執行的授權。
聲明硬件強制授權的 API 機制位於keymaster_key_characteristics_t
結構中。它將授權列表分為兩個子列表, hw_enforced
和sw_enforced
。安全硬件負責根據它可以強制執行的內容在每個中放置適當的值。
此外,Keystore 對所有授權實施基於軟件的實施,無論它們是否由安全硬件實施。
例如,考慮一個不支持密鑰過期的基於 TrustZone 的實現。仍然可以創建具有到期日期的密鑰。該密鑰的授權列表將包含標籤TAG::ORIGINATION_EXPIRE_DATETIME
和到期日期。向 Keystore 請求密鑰特性將在sw_enforced
列表中找到此標記,並且安全硬件不會強制執行過期要求。但是,過期後嘗試使用密鑰將被 Keystore 拒絕。
如果隨後使用支持過期的安全硬件升級設備,則對密鑰特徵的請求將在hw_enforced
列表中找到TAG::ORIGINATION_EXPIRE_DATETIME
,並且即使密鑰庫以某種方式被破壞或繞過,過期後嘗試使用密鑰也會失敗.
有關確定密鑰是否由硬件支持的詳細信息,請參閱密鑰證明。
加密消息構造授權
以下標籤用於定義使用關聯密鑰的操作的加密特徵: TAG::ALGORITHM
、 TAG::KEY_SIZE
、 TAG::BLOCK_MODE
、 TAG::PADDING
、 TAG::CALLER_NONCE
和TAG::DIGEST
TAG::PADDING
、 TAG::DIGEST
和PaddingMode::BLOCK_MODE
是可重複的,這意味著多個值可能與單個鍵相關聯,並且要使用的值在操作時指定。
目的
密鑰具有一組關聯的用途,表示為一個或多個帶有標籤TAG::PURPOSE
的授權條目,它定義瞭如何使用它們。目的是:
-
KeyPurpose::ENCRYPT
-
KeyPurpose::DECRYPT
-
KeyPurpose::SIGN
-
KeyPurpose::VERIFY
任何密鑰都可以具有這些用途的任何子集。請注意,某些組合會產生安全問題。例如,可用於加密和簽名的 RSA 密鑰允許攻擊者說服系統解密任意數據以生成簽名。
進出口
Keymaster 僅支持以 X.509 格式導出公鑰,以及導入:
- DER 編碼的 PKCS#8 格式的公鑰和私鑰對,沒有基於密碼的加密
- 作為原始字節的對稱密鑰
為確保導入的密鑰可以與安全生成的密鑰區分開來, TAG::ORIGIN
包含在適當的密鑰授權列表中。例如,如果一個密鑰是在安全硬件中生成的,帶有值KeyOrigin::GENERATED
的TAG::ORIGIN
將在密鑰特徵的hw_enforced
列表中找到,而導入到安全硬件中的密鑰將具有值KeyOrigin::IMPORTED
。
用戶認證
Secure Keymaster 實現不實現用戶身份驗證,但依賴於其他受信任的應用程序。有關這些應用程序實現的接口,請參閱Gatekeeper 頁面。
用戶身份驗證要求通過兩組標籤指定。第一組指示哪個用戶可以使用密鑰:
-
TAG::ALL_USERS
表示密鑰可供所有用戶使用。如果存在,則TAG::USER_ID
和TAG::USER_SECURE_ID
不存在。 -
TAG::USER_ID
具有指定授權用戶 ID 的數值。請注意,這是 Android 用戶 ID(用於多用戶),而不是應用程序 UID,並且僅由非安全軟件強制執行。如果存在,則TAG::ALL_USERS
不存在。 -
TAG::USER_SECURE_ID
有一個 64 位數值,用於指定安全身份驗證令牌中提供的安全用戶 ID,以解鎖密鑰的使用。如果重複,則如果在安全身份驗證令牌中提供了任何值,則可以使用該密鑰。
第二組指示是否以及何時需要對用戶進行身份驗證。如果這些標籤都不存在,但TAG::USER_SECURE_ID
存在,則每次使用密鑰都需要進行身份驗證。
-
NO_AUTHENTICATION_REQUIRED
表示不需要用戶身份驗證,儘管該密鑰仍然只能由以TAG::USER_ID
指定的用戶身份運行的應用程序使用。 -
TAG::AUTH_TIMEOUT
是一個數值,以秒為單位指定用戶身份驗證需要多長時間才能授權密鑰使用。這僅適用於私鑰/密鑰操作。公鑰操作不需要身份驗證。超時不會交叉重啟;重新啟動後,所有密鑰都“從未經過身份驗證”。超時可以設置為較大的值,以指示每次啟動都需要進行一次身份驗證(2^32 秒約為 136 年;可能 Android 設備的重啟頻率比這更頻繁)。
客戶端綁定
客戶端綁定,即密鑰與特定客戶端應用程序的關聯,是通過可選的客戶端 ID 和一些可選的客戶端數據(分別為TAG::APPLICATION_ID
和TAG::APPLICATION_DATA
)完成的。 Keystore 將這些值視為不透明的 blob,僅確保在密鑰生成/導入期間呈現的相同 blob 用於每次使用並且逐字節相同。 Keymaster 不返回客戶端綁定數據。調用者必須知道它才能使用密鑰。
此功能不向應用程序公開。
到期
Keystore 支持按日期限制密鑰使用。密鑰的有效性開始和密鑰到期可以與密鑰相關聯,如果當前日期/時間超出有效範圍,則 Keymaster 拒絕執行密鑰操作。密鑰有效範圍由標籤TAG::ACTIVE_DATETIME
、 TAG::ORIGINATION_EXPIRE_DATETIME
和TAG::USAGE_EXPIRE_DATETIME
。 “起源”和“使用”之間的區別基於密鑰是用於“起源”新的密文/簽名/等,還是“使用”現有的密文/簽名/等。請注意,這種區別不會暴露給應用程序。
TAG::ACTIVE_DATETIME
、 TAG::ORIGINATION_EXPIRE_DATETIME
和TAG::USAGE_EXPIRE_DATETIME
標籤是可選的。如果標籤不存在,則假定所討論的密鑰始終可用於解密/驗證消息。
因為掛鐘時間是由非安全世界提供的,所以與過期相關的標籤不太可能出現在硬件強制列表中。到期的硬件強制要求安全世界以某種方式獲得可信時間和數據,例如通過具有可信遠程時間服務器的質詢響應協議。
信任根綁定
Keystore 要求將密鑰綁定到信任根,這是在啟動期間提供給 Keymaster 安全硬件的位串,最好由引導加載程序提供。此位串以加密方式綁定到 Keymaster 管理的每個密鑰。
信任根由用於驗證啟動映像上的簽名和設備鎖定狀態的公鑰組成。如果更改公鑰以允許使用不同的系統映像或更改鎖定狀態,則先前系統創建的受 Keymaster 保護的密鑰均不可用,除非先前的信任根已恢復並且系統由該密鑰簽名的被引導。目標是通過使攻擊者安裝的操作系統無法使用 Keymaster 密鑰來增加軟件強制密鑰訪問控制的價值。
獨立鍵
一些 Keymaster 安全硬件可能會選擇在內部存儲密鑰材料並返回句柄而不是加密的密鑰材料。或者在其他一些非安全或安全世界系統組件可用之前,可能存在無法使用密鑰的其他情況。 Keymaster HAL 允許調用者通過TAG::STANDALONE
標記請求“獨立”密鑰,這意味著除了 blob 和正在運行的 Keymaster 系統之外不需要任何資源。可以檢查與鍵關聯的標籤以查看鍵是否是獨立的。目前只定義了兩個值:
-
KeyBlobUsageRequirements::STANDALONE
-
KeyBlobUsageRequirements::REQUIRES_FILE_SYSTEM
此功能不向應用程序公開。
速度
創建時,可以使用TAG::MIN_SECONDS_BETWEEN_OPS
指定最大使用速度。如果操作執行時間少於TAG::MIN_SECONDS_BETWEEN_OPS
秒,則 TrustZone 實現拒絕使用該密鑰執行加密操作。
實現速度限制的簡單方法是使用密鑰 ID 和最後使用時間戳的表。該表的大小可能有限,但至少可容納 16 個條目。在表已滿並且沒有條目可以更新或丟棄的情況下,安全硬件實現“故障安全”,傾向於拒絕所有速度受限的密鑰操作,直到其中一個條目過期。重新啟動後所有條目都過期是可以接受的。
也可以使用TAG::MAX_USES_PER_BOOT
將密鑰限制為每次引導的n次使用。這還需要一個跟踪表,該表至少可容納四個密鑰,並且還具有故障安全性。請注意,應用程序將無法創建每次啟動受限的密鑰。此功能不通過 Keystore 公開,保留用於系統操作。
此功能不向應用程序公開。
隨機數發生器重新播種
因為安全硬件會為密鑰材料和初始化向量 (IV) 生成隨機數,並且硬件隨機數生成器可能並不總是完全值得信賴,所以 Keymaster HAL 提供了一個接口,允許客戶端提供額外的熵,這些熵將混合到隨機數中產生的數字。
使用硬件隨機數生成器作為主要種子源。通過外部 API 提供的種子數據不能作為用於數字生成的唯一隨機源。此外,如果任何一個種子源不可預測,則所使用的混合操作需要確保隨機輸出不可預測。
此功能不向應用程序公開,但由框架使用,該框架定期向安全硬件提供從 Java SecureRandom 實例檢索的額外熵。