Android KeyStore金鑰儲存
KeyStore簡介
利用 Android KeyStore System,您可以在容器中儲存加密金鑰,從而提高從裝置中提取金鑰的難度。在金鑰進入金鑰庫後,可以將它們用於加密操作,而金鑰材料仍不可匯出。此外,它提供了金鑰使用的時間和方式限制措施,例如要求進行使用者身份驗證才能使用金鑰,或者限制為只能在某些加密模式中使用。
金鑰庫系統由 KeyChain API 以及在 Android 4.3(API 級別 18)中引入的 Android 金鑰庫提供程式功能使用。本文說明了何時以及如何使用 Android 金鑰庫提供程式。
應用場景
1、 儲存密匙:Android提供的這個KeyStore最大的作用就是不需要開發者去維護這個密匙的儲存問題,相比起儲存在使用者的資料空間或者是外部儲存器都更加安全。注意的是這個密匙隨著使用者清除資料或者解除安裝應用都會被清除掉。
2、得益於Android獨立的一套密匙庫系統,可以提高安全性
安全功能
Android 金鑰庫系統可以保護金鑰材料免遭未經授權的使用。首先,Android 金鑰庫可以防止從應用程序和 Android 裝置中整體提取金鑰材料,從而避免了在 Android 裝置之外以未經授權的方式使用金鑰材料。其次,Android 金鑰庫可以讓應用指定金鑰的授權使用方式,並在應用程序之外強制實施這些限制,從而避免了在 Android 裝置上以未經授權的方式使用金鑰材料。
提取防範
Android 金鑰庫金鑰使用兩項安全措施來避免金鑰材料被提取:
- 金鑰材料永不進入應用程序。通過 Android 金鑰庫金鑰執行加密操作時,應用會將待簽署或驗證的明文、密文和訊息饋送到執行加密操作的系統程序。如果應用程序受攻擊,攻擊者也許能使用應用金鑰,但無法提取金鑰材料(例如,在 Android 裝置以外使用)。
- 您可以將金鑰材料繫結至 Android 裝置的安全硬體,例如可信執行環境 (TEE) 和安全元素 (SE)。為金鑰啟用此功能時,其金鑰材料永遠不會暴露於安全硬體之外。如果 Android 作業系統受到攻擊或者攻擊者可以讀取裝置內部儲存空間,攻擊者也許能在 Android 裝置上使用應用的 Android 金鑰庫,但無法從裝置上提取這些資料。只有裝置的安全硬體支援金鑰演算法、區塊模式、填充方案和金鑰有權使用的摘要的特定組合時,才可啟用此功能。要檢查是否為金鑰啟用了此功能,請獲取金鑰的 KeyInfo 並檢查 KeyInfo.isInsideSecurityHardware() 的返回值。
金鑰使用授權
為了避免在 Android 裝置上以未經授權的方式使用金鑰材料,在生成或匯入金鑰時 Android 金鑰庫會讓應用指定金鑰的授權使用方式。一旦生成或匯入金鑰,其授權將無法更改。然後,每次使用金鑰時,都會由 Android 金鑰庫強制執行授權。這是一項高階安全功能,通常僅用於有以下要求的情形:在生成/匯入金鑰後(而不是之前或當中),應用程序受到攻擊不會導致金鑰以未經授權的方式使用。
支援的金鑰使用授權可歸為以下幾個類別:
- 加密:授權金鑰演算法、運算或目的(加密、解密、簽署、驗證)、填充方案、區塊模式以及可與金鑰搭配使用的摘要;
- 時間有效性間隔:金鑰獲得使用授權的時間間隔;
- 使用者身份驗證:金鑰只能在使用者最近進行身份驗證時使用。請參閱要求進行使用者身份驗證才能使用金鑰。
作為一項額外的安全措施,對於金鑰材料位於安全硬體內部的金鑰(請參閱 KeyInfo.isInsideSecurityHardware()),某些金鑰使用授權可能由安全硬體實施,具體取決於 Android 裝置。加密和使用者身份驗證授權可能由安全硬體實施。由於安全硬體一般不具備獨立的安全實時時鐘,時間有效性間隔授權不可能由其實施。
您可以使用 KeyInfo.isUserAuthenticationRequirementEnforcedBySecureHardware() 查詢金鑰的使用者身份驗證授權是否由安全硬體實施。
選擇金鑰鏈或 Android 金鑰庫提供程式
在需要系統級憑據時請使用 KeyChain API。在應用通過 KeyChain API 請求使用任何憑據時,使用者需要通過系統提供的 UI 選擇應用可以訪問已安裝的哪些憑據。因此,在使用者同意的情況下多個應用可以使用同一套憑據。
使用 Android 金鑰庫提供程式讓各個應用儲存自己的憑據,並且只允許應用自身訪問。這樣,應用可以管理僅能由自己使用的憑據,同時又可以提供等同於 KeyChain API 為系統級憑據提供的安全優勢。這一方法不需要使用者選擇憑據。
使用 Android 金鑰庫提供程式
要使用此功能,請使用標準的 KeyStore 和 KeyPairGenerator 或 KeyGenerator 類,以及在 Android 4.3(API 級別 18)中引入的 AndroidKeyStore 提供程式。
AndroidKeyStore 註冊為 KeyStore 型別以用於 KeyStore.getInstance(type) 方法,而在用於 KeyPairGenerator.getInstance(algorithm, provider) 和 KeyGenerator.getInstance(algorithm, provider) 方法時則註冊為提供程式。
生成新私鑰
生成新的 PrivateKey 要求您同時指定自簽署證書具備的初始 X.509 屬性。之後,您可以使用 KeyStore.setKeyEntry 將證書替換為由證書頒發機構 (CA) 簽署的證書。
要生成金鑰,請使用 KeyPairGenerator 和 KeyPairGeneratorSpec:
/* * Generate a new EC key pair entry in the Android Keystore by * using the KeyPairGenerator API. The private key can only be * used for signing or verification and only with SHA-256 or * SHA-512 as the message digest. */ KeyPairGenerator kpg = KeyPairGenerator.getInstance( KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore"); kpg.initialize(new KeyGenParameterSpec.Builder( alias, KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY) .setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512) .build()); KeyPair kp = kpg.generateKeyPair();
生成新金鑰
要生成金鑰,請使用 KeyGenerator 和 KeyGenParameterSpec。
使用金鑰庫條目
AndroidKeyStore 提供程式的使用通過所有的標準 KeyStore API 加以實現。
列出條目
通過呼叫 aliases() 方法列出金鑰庫中的條目:
/* * Load the Android KeyStore instance using the the * "AndroidKeyStore" provider to list out what entries are * currently stored. */ KeyStore ks = KeyStore.getInstance("AndroidKeyStore"); ks.load(null); Enumeration<String> aliases = ks.aliases();
簽署和驗證資料
通過從金鑰庫提取 KeyStore.Entry 並使用 Signature API(例如 sign())簽署資料:
/* * Use a PrivateKey in the KeyStore to create a signature over * some data. */ KeyStore ks = KeyStore.getInstance("AndroidKeyStore"); ks.load(null); KeyStore.Entry entry = ks.getEntry(alias, null); if (!(entry instanceof PrivateKeyEntry)) { Log.w(TAG, "Not an instance of a PrivateKeyEntry"); return null; } Signature s = Signature.getInstance("SHA256withECDSA"); s.initSign(((PrivateKeyEntry) entry).getPrivateKey()); s.update(data); byte[] signature = s.sign();
類似地,請使用 verify(byte[]) 方法驗證資料:
/* * Verify a signature previously made by a PrivateKey in our * KeyStore. This uses the X.509 certificate attached to our * private key in the KeyStore to validate a previously * generated signature. */ KeyStore ks = KeyStore.getInstance("AndroidKeyStore"); ks.load(null); KeyStore.Entry entry = ks.getEntry(alias, null); if (!(entry instanceof PrivateKeyEntry)) { Log.w(TAG, "Not an instance of a PrivateKeyEntry"); return false; } Signature s = Signature.getInstance("SHA256withECDSA"); s.initVerify(((PrivateKeyEntry) entry).getCertificate()); s.update(data); boolean valid = s.verify(signature);
要求進行使用者身份驗證才能使用金鑰
生成金鑰或將金鑰匯入到 AndroidKeyStore 時,您可以指定金鑰僅授權給經過身份驗證的使用者使用。使用者使用安全鎖定螢幕憑據(模式/PIN/密碼、指紋)的子集進行身份驗證。
這是一項高階安全功能,通常僅用於有以下要求的情形:在生成/匯入金鑰後(而不是之前或當中),應用程序受到攻擊不會導致金鑰被未經身份驗證的使用者使用。
如果金鑰僅授權給經過身份驗證的使用者使用,可以將其配置為以下列兩種模式之一執行:
- 經過身份驗證的使用者可以在一段時間內使用金鑰。在使用者解鎖安全鎖定螢幕或使用 KeyguardManager.createConfirmDeviceCredentialIntent 流程確認其安全鎖定螢幕憑據後,即可使用此模式中的所有金鑰。每個金鑰的授權持續時間各不相同,並由 setUserAuthenticationValidityDurationSeconds 在金鑰生成或匯入時指定。此類金鑰只能在啟用安全鎖定螢幕時生成或匯入(請參閱 KeyguardManager.isDeviceSecure())。在安全鎖定螢幕停用(重新配置為“無”、“滑動”或不驗證使用者身份的其他模式)或被強制重置(例如由裝置管理員執行)時,這些金鑰將永久失效。
- 使用者身份驗證會授權與某一金鑰關聯的特定加密操作。在此模式中,涉及此類金鑰的每個操作都需要使用者單獨授權。目前,此類授權的唯一方式是指紋身份驗證:FingerprintManager.authenticate。此類金鑰只能在至少註冊一個指紋時生成或匯入(請參閱 FingerprintManager.hasEnrolledFingerprints)。一旦註冊新指紋或取消註冊所有指紋,這些金鑰將永久失效。