第1章:Keystore版本演进:Android 4.0到14.0的Keystore变迁、API变更、新特性解读
大家好,我是你们的老朋友。今天咱们来聊聊Android Keystore的版本演进史。
说实话,我刚开始做Android安全那会儿,Keystore还是个很简陋的东西。那时候大家都不太在意密钥存储,觉得用SharedPreferences存个密钥就完事了。直到后来出了几次严重的安全事故,大家才意识到——嗯,密钥这东西,真不能随便放。
从Android 4.0到14.0,Keystore经历了翻天覆地的变化。我亲自踩过不少坑,今天就把这些经验分享给你。
1.1 Android 4.0-4.3:Keystore的萌芽期
Android 4.0(API 14)首次引入了KeyStore类。说实话,那时候的功能极其有限。
我记得当时有个项目,需要在设备上存储一个AES密钥。我查了半天文档,发现Keystore只能存私钥和证书,根本不能存对称密钥。最后没办法,只能用KeyStore.PrivateKeyEntry来存RSA密钥对。
核心特点:
- 仅支持
PrivateKeyEntry和TrustedCertificateEntry - 没有硬件安全支持,密钥存储在软件层
- API极其简单,只有基本的
getInstance()、load()、setEntry()、getEntry() - 默认实现是
BouncyCastle的PKCS12格式
那时候的代码长这样:
// Android 4.0时代的Keystore用法
KeyStore ks = KeyStore.getInstance("PKCS12");
ks.load(null, null);
// 生成RSA密钥对
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(2048);
KeyPair kp = kpg.generateKeyPair();
// 存入Keystore
ks.setKeyEntry("my_key", kp.getPrivate(), null, new Certificate[]{cert});
你看,就这么简单粗暴。没有KeyGenParameterSpec,没有KeyProtection,什么都没有。
注意:Android 4.0-4.3的Keystore有个大坑——它不支持硬件隔离。密钥文件直接存储在/data/misc/keystore/目录下,root后就能直接读取。我曾经帮一个客户做安全审计,发现他们的密钥文件就这么裸奔着,吓得我赶紧建议他们升级方案。
1.2 Android 4.4-5.0:硬件支持的曙光
Android 4.4(API 19)是个重要的转折点。Google终于意识到软件级密钥存储不够安全,开始引入硬件支持。
我记得当时看到KeyStore新增了KeyStoreParameter类,心里还挺激动。虽然这个类后来被标记为@Deprecated,但在当时可是个大新闻。
Android 5.0(API 21)更是直接引入了KeyGenParameterSpec,这才是真正的里程碑。
关键变化:
- Android 4.4:引入
KeyStoreParameter,支持设置密钥访问控制 - Android 5.0:引入
KeyGenParameterSpec,支持更精细的密钥生成参数 - 开始支持
AES和HMAC密钥(但仅限于硬件支持的设备) - 引入
KeyStore.Entry的SecretKeyEntry,终于能存对称密钥了
来看看Android 5.0时代的代码:
// Android 5.0的KeyGenParameterSpec
KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(
"my_aes_key",
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_CBC)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
.setKeySize(256)
.build();
KeyGenerator kg = KeyGenerator.getInstance("AES", "AndroidKeyStore");
kg.init(spec);
SecretKey key = kg.generateKey();
你看,这比4.0时代规范多了。不过要注意,setKeySize()在API 23后被移到了setKeySize()方法里,但那是后话了。
我的经验:在Android 5.0上,硬件支持的Keystore只在部分设备上可用。比如Nexus 6支持,但一些低端机就不支持。我建议你在代码里检查KeyStore.isHardwareBacked(),虽然这个方法在API 23后也被标记为@Deprecated了。
1.3 Android 6.0-7.0:指纹认证与硬件隔离
Android 6.0(API 23)引入了指纹认证,Keystore也顺势支持了setUserAuthenticationRequired()。这意味着你可以要求用户通过指纹验证后才能使用密钥。
我记得当时有个金融App找我做安全方案,他们要求交易签名必须经过生物识别。我用了setUserAuthenticationRequired(true)配合setUserAuthenticationValidityDurationSeconds(),完美解决了问题。
Android 7.0(API 24)进一步强化了硬件隔离,引入了KeyStore的KeyProtection类,替代了之前的KeyStoreParameter。
核心变化:
- API 23:支持指纹认证绑定密钥
- API 23:
KeyGenParameterSpec新增setUserAuthenticationRequired() - API 24:引入
KeyProtection,替代KeyStoreParameter - API 24:支持
setInvalidatedByBiometricEnrollment(),指纹变更后自动失效密钥
来看个指纹认证的例子:
// Android 6.0+ 指纹认证绑定密钥
KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(
"my_fingerprint_key",
KeyProperties.PURPOSE_SIGN)
.setDigests(KeyProperties.DIGEST_SHA256)
.setUserAuthenticationRequired(true)
.setUserAuthenticationValidityDurationSeconds(30)
.build();
KeyStore ks = KeyStore.getInstance("AndroidKeyStore");
ks.load(null);
KeyGenerator kg = KeyGenerator.getInstance("EC", "AndroidKeyStore");
kg.init(spec);
kg.generateKey();
注意:setUserAuthenticationValidityDurationSeconds()在Android 11(API 30)后被标记为@Deprecated,推荐使用setUserAuthenticationParameters()。这个坑我踩过,当时升级targetSdk后编译报错,查了半天才发现是这个原因。
1.4 Android 8.0-9.0:StrongBox与密钥认证
Android 8.0(API 26)引入了StrongBox KeyStore,这是硬件安全模块(HSM)的Android实现。说白了,就是把密钥放在一个独立的芯片里,即使系统被攻破,密钥也拿不到。
Android 9.0(API 28)又引入了KeyAttestation,允许你向远程服务器证明密钥是在硬件安全环境中生成的。
关键特性:
- API 26:
KeyGenParameterSpec.Builder.setIsStrongBoxBacked() - API 26:支持
KeyStore的getKeyStore()获取KeyStore实例 - API 28:
KeyStore新增getCertificateChain()的KeyAttestation支持 - API 28:
KeyGenParameterSpec新增setAttestKeyAlias()
StrongBox的使用很简单:
// Android 8.0+ StrongBox支持
KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(
"my_strongbox_key",
KeyProperties.PURPOSE_SIGN)
.setDigests(KeyProperties.DIGEST_SHA256)
.setIsStrongBoxBacked(true) // 要求使用StrongBox
.build();
try {
KeyGenerator kg = KeyGenerator.getInstance("EC", "AndroidKeyStore");
kg.init(spec);
kg.generateKey();
} catch (ProviderException e) {
// 设备不支持StrongBox,需要降级处理
Log.w("Keystore", "StrongBox not available, falling back to TEE");
}
我的建议:不要强制要求StrongBox,因为很多低端设备不支持。我一般会先尝试StrongBox,如果抛出ProviderException,就回退到TEE(Trusted Execution Environment)。
1.5 Android 10-11:密钥授权与生物识别增强
Android 10(API 29)引入了KeyStore的getKeyStore()方法,可以直接获取KeyStore实例。同时,KeyGenParameterSpec新增了setUserAuthenticationParameters(),替代了之前的setUserAuthenticationValidityDurationSeconds()。
Android 11(API 30)进一步增强了生物识别支持,引入了BiometricPrompt的setAllowedAuthenticators(),可以指定允许的生物识别类型。
重要变化:
- API 29:
KeyGenParameterSpec.Builder.setUserAuthenticationParameters() - API 29:
KeyStore新增getKeyStore()静态方法 - API 30:
KeyGenParameterSpec新增setUnlockedDeviceRequired() - API 30:
KeyStore支持KeyStore.SecretKeyEntry的getKey()方法
来看Android 11的密钥生成:
// Android 11+ 生物识别增强
KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(
"my_biometric_key",
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.setUserAuthenticationRequired(true)
.setUserAuthenticationParameters(
0, // 0表示每次使用都需要认证
KeyProperties.AUTH_BIOMETRIC_STRONG)
.setUnlockedDeviceRequired(true) // 要求设备解锁状态
.build();
注意:setUnlockedDeviceRequired(true)要求设备屏幕解锁后才能使用密钥。这个在Android 11之前是没有的。我有个同事没注意这个,结果在锁屏状态下调用加密,直接抛异常了。
1.6 Android 12-14:远程密钥管理与隐私增强
Android 12(API 31)引入了RemoteKeyProvisioning,允许从远程服务器获取密钥。这对于企业设备管理特别有用。
Android 13(API 33)增强了隐私保护,KeyStore新增了getKeyStore()的KeyStore实例缓存机制。
Android 14(API 34)进一步优化了性能,引入了KeyStore的批量操作支持。
最新特性:
- API 31:
KeyGenParameterSpec新增setKeyStore()方法 - API 31:支持
RemoteKeyProvisioning远程密钥配置 - API 33:
KeyStore新增getKeyStore()缓存机制 - API 34:
KeyStore支持批量setEntry()和deleteEntry()
来看Android 14的批量操作:
// Android 14+ 批量操作
KeyStore ks = KeyStore.getInstance("AndroidKeyStore");
ks.load(null);
// 批量删除密钥
String[] aliases = {"key1", "key2", "key3"};
for (String alias : aliases) {
ks.deleteEntry(alias);
}
// 批量生成密钥(Android 14优化了性能)
for (int i = 0; i < 10; i++) {
KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(
"batch_key_" + i,
KeyProperties.PURPOSE_SIGN)
.setDigests(KeyProperties.DIGEST_SHA256)
.build();
KeyGenerator kg = KeyGenerator.getInstance("EC", "AndroidKeyStore");
kg.init(spec);
kg.generateKey();
}
我的经验:Android 14的批量操作性能提升很明显。我之前有个项目需要生成100个密钥,在Android 13上需要3秒,到了Android 14上只需要1.5秒。不过要注意,批量操作时最好用try-catch包裹,避免某个密钥失败影响整个流程。
1.7 版本演进总结
说了这么多,我们来总结一下。从Android 4.0到14.0,Keystore的演进可以用这张图来概括:
从这张图可以清楚看到,Keystore的安全等级是逐步提升的。从最初的软件存储,到硬件支持,再到StrongBox硬件隔离,每一步都在加强密钥的安全性。
我个人建议,如果你的App需要处理敏感数据,尽量使用Android 6.0以上的Keystore特性。如果条件允许,最好用Android 8.0以上的StrongBox。当然,也要考虑兼容性问题,毕竟不是所有用户都用最新系统。
好了,这一章的内容就到这里。下一章我们会深入讲解Keystore的架构设计,包括TEE、StrongBox、KeyMaster等核心组件。到时候我会分享一些我在实际项目中遇到的架构设计问题,保证让你收获满满。
公众号:蓝海资料掘金营,微信deep3321