Android端用密码与生物识别生成密钥加密本地数据方案咨询
实现双认证(密码+生物识别)的本地数据加密方案
行业里通用的做法是分层加密:用一个临时的主密钥(Data Encryption Key, DEK)加密实际业务数据,再分别用生物识别密钥和密码派生的密钥(Key Encryption Key, KEK)加密这个DEK,把加密后的DEK存在本地私有文件中。这样不管用户用密码还是生物识别认证,只要能解密出DEK,就能解密核心数据。
1. 核心分层逻辑拆解
- DEK(数据加密密钥):直接加密你的业务数据,不存储在本地,仅在解密时临时生成/解密获取,用完立即从内存清除。
- KEK1(生物识别密钥):通过AndroidKeyStore生成,绑定生物识别认证,仅在用户完成生物识别后才能用来解密加密后的DEK。
- KEK2(密码派生密钥):从用户密码通过PBKDF2/Argon2算法派生而来,用来加密DEK,用户输入密码后可派生密钥解密DEK。
2. 代码实现示例
生成主密钥(DEK)
fun generateDataEncryptionKey(): SecretKey { val keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore") val spec = KeyGenParameterSpec.Builder( "data_encryption_key", KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT ) .setBlockModes(KeyProperties.BLOCK_MODE_GCM) .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) .setKeySize(256) .build() keyGenerator.init(spec) return keyGenerator.generateKey() }
生成生物识别绑定密钥(KEK1)
fun generateBiometricKey(): SecretKey { val keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore") val spec = KeyGenParameterSpec.Builder( "biometric_protected_key", KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT ) .setBlockModes(KeyProperties.BLOCK_MODE_GCM) .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) .setKeySize(256) .setUserAuthenticationRequired(true) .setUserAuthenticationValidityDurationSeconds(-1) // 每次使用必须重新认证 .setInvalidatedByBiometricEnrollment(true) // 用户新增/删除指纹时自动失效 .build() keyGenerator.init(spec) return keyGenerator.generateKey() }
从密码派生密钥(KEK2)
fun deriveKeyFromPassword(password: CharArray, salt: ByteArray): SecretKey { // 迭代次数建议65536以上,密钥长度256位 val passwordSpec = PBEKeySpec(password, salt, 65536, 256) val keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256") val keyBytes = keyFactory.generateSecret(passwordSpec).encoded // 清空密码数组,避免内存残留 Arrays.fill(password, ' ') return SecretKeySpec(keyBytes, KeyProperties.KEY_ALGORITHM_AES) } // 注意:salt需要随机生成一次后存储在本地私有文件,后续派生密钥必须复用同一salt
加密流程
- 生成DEK,用DEK加密业务数据,将加密后的数据+GCM的IV写入本地文件
- 用生物识别密钥加密DEK,得到
encrypted_dek_bio并写入本地文件 - 用密码派生密钥加密DEK,得到
encrypted_dek_pass并写入本地文件 - 立即清除内存中的DEK
解密流程(生物识别方式)
- 调用BiometricPrompt发起生物识别认证
- 认证通过后,用生物识别密钥解密
encrypted_dek_bio得到DEK - 用DEK+之前存储的IV解密业务数据
- 立即清除内存中的DEK
解密流程(密码方式)
- 获取用户输入的密码
- 读取本地存储的salt,派生得到KEK2
- 用KEK2解密
encrypted_dek_pass得到DEK - 用DEK+IV解密业务数据
- 立即清除内存中的密码、DEK
3. 关键安全细节
- 内存清理:所有敏感数据(密码、密钥字节数组)用完后必须用
Arrays.fill清空,避免被内存dump窃取 - 存储位置:加密后的DEK、salt必须存在App私有文件目录(
context.filesDir),禁止用SharedPreferences/DataStore - 密钥轮换:用户修改密码或生物识别信息变更时,需重新生成对应的KEK,并用新KEK重新加密DEK
- 算法选择:API 30+优先用Argon2替代PBKDF2,前者抗暴力破解能力更强
4. 行业应用参考
像1Password、Bitwarden这类安全应用都是这套逻辑:
- 用主密钥加密所有用户核心数据
- 分别用生物识别密钥、设备PIN、用户密码派生密钥来加密主密钥
- 用户可通过任意一种认证方式解锁主密钥,进而访问数据
内容的提问来源于stack exchange,提问作者Wolf
相关产品推荐
相关产品推荐

