网站首页 > 技术教程 正文
作者 / 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 是对称的,并且在现代设备上运算的速度通常很快。
val keyAlias = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC)
对于配置更多样或处理非常敏感数据的应用,我们建议您构建自己的 KeyGenParameterSpec,选择适合您需求的选项。针对设备被 root 或遭到篡改的情况,带有 BiometricPrompt 生物验证步骤的限时密钥可以提供更高级别的保护。
重要选项:
- userAuthenticationRequired() 和 userAuthenticationValiditySeconds() 可以用来创建限时密钥。限时密钥需要通过 BiometricPrompt 获得授权,才能对对称密钥进行加密和解密。
- unlockedDeviceRequired() 可以设置一个标志,用于确保在设备未解锁时不会发生密钥访问。该开关值在 Android 9 及更高版本上可用。
- 使用 setIsStrongBoxBacked(),即可在更强大的独立芯片上运行加密操作。这会对性能带来轻微的影响,但更加安全。此功能在运行 Android 9 或更高版本的某些设备上可用。
注意: 如果您的应用需要在后台加密数据,则不应使用限时密钥或要求设备处于解锁状态,因为如果没有用户在场,您的操作将无法完成。
// 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 对设备进行授权:
- userAuthenticationRequired 值为 true
- userAuthenticationValiditySeconds > 0
在用户进行验证后,将基于有效秒数字段中给出时长解锁密钥。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
加密 SharedPreferences
如果您的应用需要保存键值对 (例如 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 进行文件加密。
祝大家加密愉快!
猜你喜欢
- 2024-10-23 点盾云视频加密软件如何实现防录屏?
- 2024-10-23 安卓勒索病毒来袭!加密文件、篡改密码、按下Home键系统锁死
- 2024-10-23 Android 的全盘加密容易破解 安卓系统强制开启全盘加密
- 2024-10-23 安卓手机5个隐藏功能,实用且强大,真是太爱了
- 2024-10-23 Android 14 QPR2 Beta 2新功能:Wi-Fi密码分享更便捷
- 2024-10-23 信号试加密的视频和语音电话 信号加密原理
- 2024-10-23 资深开发者教你如何破解 Android 手机锁屏密码
- 2024-10-23 您在 Android 上保存的密码可能会被泄露?
- 2024-10-23 Android密码仅用一张SIM卡就能攻破!?
- 2024-10-23 基于hls视频加密方案 hn加密视频
你 发表评论:
欢迎- 05-05从virsh当中学习QEMU/KVM启动命令
- 05-05Win10 BCD文件损坏怎么修复?(bcd文件损坏win7)
- 05-05亚马逊春节假期期间的店铺管理设置
- 05-051分钟总结常用k8s常用诊断教程(k8s常见故障)
- 05-05VisiPics重复图片查找软件中文汉化教程
- 05-05微服务的发布实现方式1灰度实现(微服务实现原理)
- 05-05轻松掌握Java多线程 - 第二章:线程的生命周期
- 05-05德拉诺之王邪DK报告:PVE向小测试及分析
- 最近发表
- 标签列表
-
- sd分区 (65)
- raid5数据恢复 (81)
- 地址转换 (73)
- 手机存储卡根目录 (55)
- tcp端口 (74)
- project server (59)
- 双击ctrl (55)
- 鼠标 单击变双击 (67)
- debugview (59)
- 字符动画 (65)
- flushdns (57)
- ps复制快捷键 (57)
- 清除系统垃圾代码 (58)
- web服务器的架设 (67)
- 16进制转换 (69)
- xclient (55)
- ps源文件 (67)
- filezilla server (59)
- 句柄无效 (56)
- word页眉页脚设置 (59)
- ansys实例 (56)
- 6 1 3固件 (59)
- sqlserver2000挂起 (59)
- vm虚拟主机 (55)
- config (61)
本文暂时没有评论,来添加一个吧(●'◡'●)