如何在AndroidKeyStore中结合密码安全存储密钥?及相关实现疑问
密码验证加密方案的安全实践建议
一、核心安全方案:KeyStore + PBKDF2 双重保护
1. 密码验证加密的标准流程
不要直接用PBE加密用户存储的账号密码,而是通过用户设置的验证密码派生密钥,再用该密钥加密实际存储数据,同时将派生密钥安全托管在AndroidKeyStore中:
- 密钥派生:用户设置验证密码时,使用
PBKDF2WithHmacSHA256算法,搭配随机生成的盐(salt)和至少10万次的迭代次数,派生一个256位的加密密钥。 - 密钥存储:将派生密钥存入AndroidKeyStore,用
KeyStore.PasswordProtection以用户的验证密码作为保护条件。 - 数据加密:用派生密钥加密用户的账号密码数据后存入RoomDB,盐可以明文存储在DB中(盐仅用于密钥派生,无敏感信息)。
2. 首次启动的密码验证解决办法
首次设置密码时,额外生成一段随机的"验证令牌",用派生密钥加密后存入DB。后续验证密码时:
- 用输入的密码+存储的盐重新派生密钥
- 尝试解密验证令牌,解密成功则密码正确,失败则密码错误
二、KeyStore.PasswordProtection 的安全性评估
该方案符合Android安全最佳实践,是可靠的,但需注意以下细节:
- 强制用户设置强密码:要求至少8位,包含大小写字母、数字、特殊符号,降低暴力破解风险。
- 固定密钥派生参数:迭代次数、密钥长度等参数需在APP内固定,禁止从外部获取或硬编码易被逆向的数值。
- 适配高版本系统:Android 10及以上设备,优先使用
KeyProtection替代PasswordProtection,它支持绑定设备、限制密钥使用场景等更严格的安全特性。
三、更优方案:分层加密架构
若追求更高安全性和可维护性,可采用"主密钥+数据密钥"的分层模式:
- 主密钥:存储在AndroidKeyStore,由用户验证密码或生物识别保护,仅用于加密数据密钥。
- 数据密钥:随机生成的独立密钥,用于加密用户的账号密码数据,加密后存入RoomDB。
优势:即使数据密钥泄露,只要主密钥安全,攻击者无法解密数据;更换验证密码时,仅需重新加密数据密钥,无需遍历加密所有用户存储的密码,性能更优。
四、关键代码示例
1. PBKDF2密钥派生
fun deriveKey(password: CharArray, salt: ByteArray): SecretKey { val spec = PBEKeySpec(password, salt, 100000, 256) val factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256") return factory.generateSecret(spec) }
2. 密钥存入KeyStore
fun saveKeyToKeyStore(keyAlias: String, key: SecretKey, password: CharArray) { val keyStore = KeyStore.getInstance("AndroidKeyStore") keyStore.load(null) val protection = KeyStore.PasswordProtection(password) keyStore.setEntry(keyAlias, KeyStore.SecretKeyEntry(key), protection) }
3. 密码验证逻辑
fun verifyPassword(inputPassword: CharArray, storedSalt: ByteArray, encryptedToken: ByteArray): Boolean { val derivedKey = deriveKey(inputPassword, storedSalt) val cipher = Cipher.getInstance("AES/GCM/NoPadding") cipher.init(Cipher.DECRYPT_MODE, derivedKey) return try { cipher.doFinal(encryptedToken) true } catch (e: Exception) { false } }
内容的提问来源于stack exchange,提问作者TheFishTheySay
相关产品推荐
相关产品推荐

