做者 / 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 进行文件加密。
祝你们加密愉快!