作者 / Jon Markoff, Staff Developer Advocate, Android Security
您是否嘗試過對應用中的數據進行加密?作為開發者,您想要保護數據安全,并确保數據掌握在其合理使用者的手中。但是,大多數 Android 開發者沒有專門的安全團隊來幫助他們正确地加密應用數據。就算通過網絡來搜索如何加密數據,您得到的答案也可能已經過時好幾年了,找到的示例也難以保證準确性。
Jetpack Security (JetSec) 加密庫為 Files 和 SharedPreferences 對象的加密操作提供了抽象支持。該庫使用了安全且運用廣泛的 密碼學原語 (cryptographic primitives),強化了 AndroidKeyStore 的使用。使用 EncryptedFile 和 EncryptedSharedPreferences 可以讓您在本地保護可能包含敏感數據、API 密鑰、OAuth 令牌和其他類型機密信息的文件。
從 5.0 開始,Android 會默認 對用戶數據分區的内容進行加密,那您為什麼還需要加密應用中的數據呢?這是因為在某些場合中,您可能需要額外的保護。如果您的應用使用 共享存儲 (shared storage),則應該對數據進行加密。如果您的應用處理敏感信息,包括但不限于個人身份可識别信息 (Personally Identifiable Information, PII)、健康記錄、财務信息或企業數據,那麼您的應用應該對其主目錄中的數據進行加密。如果可能,我們建議您将此類信息與生物驗證操作綁定,以提供額外的保護。
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 是對稱的,并且在現代設備上運算的速度通常很快。
valkeyAlias=MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC)
對于配置更多樣或處理非常敏感數據的應用,我們建議您構建自己的 KeyGenParameterSpec,選擇适合您需求的選項。針對設備被 root 或遭到篡改的情況,帶有 BiometricPrompt 生物驗證步驟的限時密鑰可以提供更高級别的保護。
重要選項:
注意: 如果您的應用需要在後台加密數據,則不應使用限時密鑰或要求設備處于解鎖狀态,因為如果沒有用戶在場,您的操作将無法完成。
//CustomAdvancedMasterKey
valadvancedSpec=KeyGenParameterSpec.Builder(
"master_key",
KeyProperties.PURPOSE_ENCRYPTorKeyProperties.PURPOSE_DECRYPT
).apply{
setBlockModes(KeyProperties.BLOCK_MODE_GCM)
setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
setKeySize(256)
setUserAuthenticationRequired(true)
setUserAuthenticationValidityDurationSeconds(15)//mustbelargerthan0
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.P){
setUnlockedDeviceRequired(true)
setIsStrongBoxBacked(true)
}
}.build()
valadvancedKeyAlias=MasterKeys.getOrCreate(advancedSpec)
解鎖限時密鑰
如果您的密鑰是使用以下選項創建的,則必須使用 BiometricPrompt 對設備進行授權:
在用戶進行驗證後,将基于有效秒數字段中給出時長解鎖密鑰。AndroidKeystore 沒有用于查詢密鑰設置的 API,因此您的應用必須自己記錄這些設置。您應該在展示授權界面的 Activity 的 onCreate() 方法中構建 BiometricPrompt 實例,以引導用戶進行授權操作。
用來解鎖限時密鑰的 BiometricPrompt 代碼:
//Activity.onCreate
valpromptInfo=PromptInfo.Builder()
.setTitle("Unlock?")
.setDescription("Wouldyouliketounlockthiskey?")
.setDeviceCredentialAllowed(true)
.build()
valbiometricPrompt=BiometricPrompt(
this,//Activity
ContextCompat.getMainExecutor(this),
authenticationCallback
)
privatevalauthenticationCallback=object:AuthenticationCallback(){
overridefunonAuthenticationSucceeded(
result:AuthenticationResult
){
super.onAuthenticationSucceeded(result)
//Unlocked--doworkhere.
}
overridefunonAuthenticationError(
errorCode:Int,errString:CharSequence
){
super.onAuthenticationError(errorCode,errString)
//Handleerror.
}
}
Touse:
biometricPrompt.authenticate(promptInfo)
Jetpack Security 包含一個 EncryptedFile 類,它解決了加密文件數據的問題。與 File 相似,EncryptedFile 提供一個 FileInputStream 對象用于讀取,一個 FileOutputStream 對象用于寫入。我們使用遵循 OAE2 定義的 Streaming AHEAD 對文件進行加密。數據被分為多個區塊,并使用 AES256-GCM 進行加密,使得外界無法對其進行重組。
valsecretFile=File(filesDir,"super_secret")
valencryptedFile=EncryptedFile.Builder(
secretFile,
applicationContext,
advancedKeyAlias,
FileEncryptionScheme.AES256_GCM_HKDF_4KB)
.setKeysetAlias("file_key")//optional
.setKeysetPrefName("secret_shared_prefs")//optional
.build()
encryptedFile.openFileOutput().use{outputStream->
//Writedatatoyourencryptedfile
}
encryptedFile.openFileInput().use{inputStream->
//Readdatafromyourencryptedfile
如果您的應用需要保存鍵值對 (例如 API 密鑰),JetSec 提供了 EncryptedSharedPreferences 類,該類使用的是您所熟知的 SharedPreferences 接口。
鍵和值均會被加密。鍵使用能提供确定性密文的 AES256-SIV-CMAC 進行加密;值則使用 AES256-GCM 進行加密,并綁定到加密的鍵。該方案允許對機要數據進行安全加密,同時仍然便于查詢。
EncryptedSharedPreferences.create(
"my_secret_prefs",
advancedKeyAlias,
applicationContext,
PrefKeyEncryptionScheme.AES256_SIV,
PrefValueEncryptionScheme.AES256_GCM
).edit{
//Updatesecretvalues
}
FileLocker 是我們準備的一個示例應用,您可以在 Android Security GitHub 示例頁面上找到它。這個應用很好地展示了應該如何使用 Jetpack Security 進行文件加密。
祝大家加密愉快!
,更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!