11. Keystore授权标签:TAG_PURPOSE、TAG_ALGORITHM、TAG_KEY_SIZE等关键标签详解
各位好,我是老张。今天我们来聊聊Keystore里那些「授权标签」。说白了,这些标签就是密钥的「使用说明书」——你生成一把密钥,它到底能干嘛?能加密还是能签名?用的是什么算法?密钥多长?全由这些标签说了算。
我刚开始接触Keystore时,觉得这些标签就是些常量,随便填填就行。直到有一次,我把签名密钥的TAG_PURPOSE配成了PURPOSE_ENCRYPT,结果线上签名一直失败,排查了半天……嗯,从那以后我再也不敢小看这些标签了。
11.1 TAG_PURPOSE:密钥的「职业」
TAG_PURPOSE定义了密钥的用途。你可以把它理解成密钥的「岗位职责」——是负责加密,还是负责签名,或者两者都干。
常见的取值有:
PURPOSE_ENCRYPT:加密用途PURPOSE_DECRYPT:解密用途PURPOSE_SIGN:签名用途PURPOSE_VERIFY:验签用途PURPOSE_WRAP_KEY:密钥包装用途PURPOSE_AGREE_KEY:密钥协商用途
你可以组合使用,比如同时指定PURPOSE_ENCRYPT | PURPOSE_DECRYPT,让密钥既能加密也能解密。但注意,不要滥用组合。我个人习惯是:一个密钥只干一件事。签名密钥就只签名,加密密钥就只加密。这样即使某个密钥泄露,影响范围也有限。
PURPOSE_SIGN,结果运行时直接抛异常。因为AES根本不支持签名操作。所以,PURPOSE必须与算法匹配。
11.2 TAG_ALGORITHM:密钥的「种族」
TAG_ALGORITHM指定密钥的算法类型。说白了,就是告诉Keystore:你要生成的是哪种密钥?
支持的算法包括:
| 算法常量 | 说明 | 常见用途 |
|---|---|---|
KeyProperties.KEY_ALGORITHM_AES |
AES对称密钥 | 数据加密/解密 |
KeyProperties.KEY_ALGORITHM_RSA |
RSA非对称密钥 | 加密/签名 |
KeyProperties.KEY_ALGORITHM_EC |
椭圆曲线密钥 | 签名(如ECDSA) |
KeyProperties.KEY_ALGORITHM_HMAC_SHA256 |
HMAC消息认证码 | 数据完整性校验 |
这里有个细节:算法和PURPOSE是绑定的。比如RSA既可以加密也可以签名,但AES只能加密/解密,不能签名。你想想看,如果让AES去签名,那就像让厨师去修车——不是不能干,是根本干不了。
11.3 TAG_KEY_SIZE:密钥的「力量」
TAG_KEY_SIZE定义密钥长度。这个参数直接影响安全性。我见过不少新手直接写128位AES,觉得够用了。但说实话,现在128位AES虽然还没被破解,但安全边际已经越来越窄了。
常见的推荐值:
- AES:推荐256位。128位勉强可用,但新项目建议直接上256。
- RSA:推荐2048位或4096位。1024位已被认为不安全。
- EC:推荐256位(对应P-256曲线)。
11.4 其他关键标签
除了上面三个核心标签,还有几个我经常用的:
TAG_BLOCK_MODE:分组加密模式,比如GCM、CBC。我个人强烈推荐GCM,因为它自带认证,能防篡改。TAG_ENCRYPTION_PADDING:填充模式。RSA加密常用OAEP,签名常用PKCS1。TAG_DIGEST:摘要算法。签名时指定,比如SHA256。TAG_USER_AUTHENTICATION_VALIDITY_DURATION:用户认证有效期。配合生物识别使用,可以设置一段时间内免重复认证。
这些标签组合起来,就能精确控制密钥的行为。举个例子:
KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(
"my_rsa_key",
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT
)
.setAlgorithmParameterSpec(new RSAKeyGenParameterSpec(2048, RSAKeyGenParameterSpec.F4))
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.setUserAuthenticationRequired(true)
.setUserAuthenticationValidityDurationSeconds(300);
这段代码生成了一把RSA 2048位密钥,只能用于GCM模式加密/解密,且需要用户认证,认证后5分钟内有效。你看,每个标签都在说「我能做什么,不能做什么」。
11.5 标签组合的「潜规则」
标签之间不是随意组合的。我总结了几条铁律:
- 算法决定可用标签:AES不能用RSA的填充模式,EC不能用AES的密钥长度。
- PURPOSE限制其他标签:如果只设了
PURPOSE_SIGN,那BLOCK_MODE和ENCRYPTION_PADDING就多余了。 - 安全策略优先:如果设了
setUserAuthenticationRequired(true),那密钥只能在用户认证后才能使用。
我曾经遇到一个坑:给RSA密钥同时设了PURPOSE_ENCRYPT和PURPOSE_SIGN,然后用了OAEP填充。结果签名时一直报错。后来才发现,RSA签名只能用PKCS1填充,不能混用。所以,组合标签时一定要查文档,别想当然。
11.6 知识体系总览
下面这张图总结了授权标签的核心关系:
从图中可以看出,密钥是中心,三大核心标签定义基本属性,辅助标签细化行为,安全约束提供保护。每一层都在缩小密钥的使用范围,最终形成一个「最小权限」的密钥。
11.7 实战建议
最后,我分享几个实战中的习惯:
- 先定算法,再定用途:别反过来。算法决定了你能用哪些标签。
- 能用GCM就别用CBC:GCM自带认证,省去额外校验的麻烦。
- 密钥长度写死,别动态计算:我见过有人用
KeySize变量,结果线上配置错了,密钥生成失败。直接写256或2048,简单可靠。 - 测试时打印所有标签:用
KeyStore.Entry的getAttributes()方法,确认生成的密钥符合预期。
好了,授权标签就讲到这里。这些标签看似简单,但组合起来威力巨大。记住一句话:标签越精确,密钥越安全。