做者 / Jon Markoff, Staff Developer Advocate, Android Securityhtml
您是否嘗試過對應用中的數據進行加密?做爲開發者,您想要保護數據安全,並確保數據掌握在其合理使用者的手中。可是,大多數 Android 開發者沒有專門的安全團隊來幫助他們正確地加密應用數據。就算經過網絡來搜索如何加密數據,您獲得的答案也可能已通過時好幾年了,找到的示例也難以保證準確性。android
Jetpack Security (JetSec) 加密庫爲 Files 和 SharedPreferences 對象的加密操做提供了抽象支持。該庫使用了安全且運用普遍的 密碼學原語 (cryptographic primitives),強化了 AndroidKeyStore 的使用。使用 EncryptedFile 和 EncryptedSharedPreferences 可讓您在本地保護可能包含敏感數據、API 密鑰、OAuth 令牌和其餘類型機密信息的文件。git
從 5.0 開始,Android 會默認 對用戶數據分區的內容進行加密,那您爲何還須要加密應用中的數據呢?這是由於在某些場合中,您可能須要額外的保護。若是您的應用使用 共享存儲 (shared storage),則應該對數據進行加密。若是您的應用處理敏感信息,包括但不限於我的身份可識別信息 (Personally Identifiable Information, PII)、健康記錄、財務信息或企業數據,那麼您的應用應該對其主目錄中的數據進行加密。若是可能,咱們建議您將此類信息與生物驗證操做綁定,以提供額外的保護。github
Jetpack Security 基於 Tink,而 Tink 是 Google 的一個開源並支持跨平臺的安全項目。若是您須要常規加密、混合加密或相似的安全措施,那麼 Tink 可能適用於您的項目。Jetpack Security 的數據結構與 Tink 徹底兼容。安全
在開始加密數據以前,首先要了解您的加密密鑰是如何被保護的。Jetpack Security 使用一個主密鑰 (master key) 對全部的子密鑰 (subkey) 進行加密,子密鑰則被用於每一個加密操做。JetSec 在 MasterKeys 類中提供了建議的默認主密鑰。這個類使用基礎的 AES256-GCM 密鑰,該密鑰在 AndroidKeyStore 中生成並存儲。AndroidKeyStore 是一個在 TEE 或 StrongBox 中存儲加密密鑰的容器,這使得其內容很難被提取。子密鑰則存儲在可配置的 SharedPreferences 對象中。網絡
咱們在 Jetpack Security 中主要使用 AES256_GCM_SPEC 規範,在通常的用例中很推薦使用該規範。AES256-GCM 是對稱的,而且在現代設備上運算的速度一般很快。數據結構
val keyAlias = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC)
對於配置更多樣或處理很是敏感數據的應用,咱們建議您構建本身的 KeyGenParameterSpec,選擇適合您需求的選項。針對設備被 root 或遭到篡改的狀況,帶有 BiometricPrompt 生物驗證步驟的限時密鑰能夠提供更高級別的保護。app
重要選項:ide
注意: 若是您的應用須要在後臺加密數據,則不該使用限時密鑰或要求設備處於解鎖狀態,由於若是沒有用戶在場,您的操做將沒法完成。性能
// Custom Advanced Master Key val advancedSpec = KeyGenParameterSpec.Builder( "master_key", KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT ).apply { setBlockModes(KeyProperties.BLOCK_MODE_GCM) setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) setKeySize(256) setUserAuthenticationRequired(true) setUserAuthenticationValidityDurationSeconds(15) // must be larger than 0 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { setUnlockedDeviceRequired(true) setIsStrongBoxBacked(true) } }.build() val advancedKeyAlias = MasterKeys.getOrCreate(advancedSpec)
解鎖限時密鑰
若是您的密鑰是使用如下選項建立的,則必須使用 BiometricPrompt 對設備進行受權:
在用戶進行驗證後,將基於有效秒數字段中給出時長解鎖密鑰。AndroidKeystore 沒有用於查詢密鑰設置的 API,所以您的應用必須本身記錄這些設置。您應該在展現受權界面的 Activity 的 onCreate() 方法中構建 BiometricPrompt 實例,以引導用戶進行受權操做。
用來解鎖限時密鑰的 BiometricPrompt 代碼:
// Activity.onCreate val promptInfo = PromptInfo.Builder() .setTitle("Unlock?") .setDescription("Would you like to unlock this key?") .setDeviceCredentialAllowed(true) .build() val biometricPrompt = BiometricPrompt( this, // Activity ContextCompat.getMainExecutor(this), authenticationCallback ) private val authenticationCallback = object : AuthenticationCallback() { override fun onAuthenticationSucceeded( result: AuthenticationResult ) { super.onAuthenticationSucceeded(result) // Unlocked -- do work here. } override fun onAuthenticationError( errorCode: Int, errString: CharSequence ) { super.onAuthenticationError(errorCode, errString) // Handle error. } } To use: biometricPrompt.authenticate(promptInfo)
Jetpack Security 包含一個 EncryptedFile 類,它解決了加密文件數據的問題。與 File 類似,EncryptedFile 提供一個 FileInputStream 對象用於讀取,一個 FileOutputStream 對象用於寫入。咱們使用遵循 OAE2 定義的 Streaming AHEAD 對文件進行加密。數據被分爲多個區塊,並使用 AES256-GCM 進行加密,使得外界沒法對其進行重組。
val secretFile = File(filesDir, "super_secret") val encryptedFile = EncryptedFile.Builder( secretFile, applicationContext, advancedKeyAlias, FileEncryptionScheme.AES256_GCM_HKDF_4KB) .setKeysetAlias("file_key") // optional .setKeysetPrefName("secret_shared_prefs") // optional .build() encryptedFile.openFileOutput().use { outputStream -> // Write data to your encrypted file } encryptedFile.openFileInput().use { inputStream -> // Read data from your encrypted file
若是您的應用須要保存鍵值對 (例如 API 密鑰),JetSec 提供了 EncryptedSharedPreferences 類,該類使用的是您所熟知的 SharedPreferences 接口。
鍵和值均會被加密。鍵使用能提供肯定性密文的 AES256-SIV-CMAC 進行加密;值則使用 AES256-GCM 進行加密,並綁定到加密的鍵。該方案容許對機要數據進行安全加密,同時仍然便於查詢。
EncryptedSharedPreferences.create( "my_secret_prefs", advancedKeyAlias, applicationContext, PrefKeyEncryptionScheme.AES256_SIV, PrefValueEncryptionScheme.AES256_GCM ).edit { // Update secret values }
FileLocker 是咱們準備的一個示例應用,您能夠在 Android Security GitHub 示例頁面上找到它。這個應用很好地展現了應該如何使用 Jetpack Security 進行文件加密。
祝你們加密愉快!