11. Keystore授权标签:TAG_PURPOSE、TAG_ALGORITHM、TAG_KEY_SIZE等关键标签详解

各位好,我是老张。今天我们来聊聊Keystore里那些「授权标签」。说白了,这些标签就是密钥的「使用说明书」——你生成一把密钥,它到底能干嘛?能加密还是能签名?用的是什么算法?密钥多长?全由这些标签说了算。

我刚开始接触Keystore时,觉得这些标签就是些常量,随便填填就行。直到有一次,我把签名密钥的TAG_PURPOSE配成了PURPOSE_ENCRYPT,结果线上签名一直失败,排查了半天……嗯,从那以后我再也不敢小看这些标签了。

核心观点:授权标签是Keystore的安全基石。它们决定了密钥的使用范围,一旦生成,不可更改。

11.1 TAG_PURPOSE:密钥的「职业」

TAG_PURPOSE定义了密钥的用途。你可以把它理解成密钥的「岗位职责」——是负责加密,还是负责签名,或者两者都干。

常见的取值有:

  • PURPOSE_ENCRYPT:加密用途
  • PURPOSE_DECRYPT:解密用途
  • PURPOSE_SIGN:签名用途
  • PURPOSE_VERIFY:验签用途
  • PURPOSE_WRAP_KEY:密钥包装用途
  • PURPOSE_AGREE_KEY:密钥协商用途

你可以组合使用,比如同时指定PURPOSE_ENCRYPT | PURPOSE_DECRYPT,让密钥既能加密也能解密。但注意,不要滥用组合。我个人习惯是:一个密钥只干一件事。签名密钥就只签名,加密密钥就只加密。这样即使某个密钥泄露,影响范围也有限。

避坑指南:我曾经在项目中把AES密钥的PURPOSE设成了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曲线)。
注意:密钥长度不是越大越好。RSA 4096位虽然安全,但加解密速度比2048位慢很多。移动端尤其要考虑性能。我一般建议:安全够用就行,别盲目追求大位数

11.4 其他关键标签

除了上面三个核心标签,还有几个我经常用的:

  • TAG_BLOCK_MODE:分组加密模式,比如GCMCBC。我个人强烈推荐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 标签组合的「潜规则」

标签之间不是随意组合的。我总结了几条铁律:

  1. 算法决定可用标签:AES不能用RSA的填充模式,EC不能用AES的密钥长度。
  2. PURPOSE限制其他标签:如果只设了PURPOSE_SIGN,那BLOCK_MODEENCRYPTION_PADDING就多余了。
  3. 安全策略优先:如果设了setUserAuthenticationRequired(true),那密钥只能在用户认证后才能使用。

我曾经遇到一个坑:给RSA密钥同时设了PURPOSE_ENCRYPTPURPOSE_SIGN,然后用了OAEP填充。结果签名时一直报错。后来才发现,RSA签名只能用PKCS1填充,不能混用。所以,组合标签时一定要查文档,别想当然。

11.6 知识体系总览

下面这张图总结了授权标签的核心关系:

Keystore授权标签核心体系 密钥 TAG_PURPOSE 加密/签名/密钥包装 TAG_ALGORITHM AES/RSA/EC/HMAC TAG_KEY_SIZE 128/256/2048/4096 TAG_BLOCK_MODE GCM / CBC / ECB TAG_ENCRYPTION_PADDING OAEP / PKCS1 / None TAG_DIGEST SHA256 / SHA512 安全约束:用户认证 / 时间窗口 / 硬件隔离 TAG_USER_AUTHENTICATION_REQUIRED / TAG_USER_AUTHENTICATION_VALIDITY_DURATION 标签组合决定密钥行为,安全约束提供最后防线

从图中可以看出,密钥是中心,三大核心标签定义基本属性,辅助标签细化行为,安全约束提供保护。每一层都在缩小密钥的使用范围,最终形成一个「最小权限」的密钥。

11.7 实战建议

最后,我分享几个实战中的习惯:

  • 先定算法,再定用途:别反过来。算法决定了你能用哪些标签。
  • 能用GCM就别用CBC:GCM自带认证,省去额外校验的麻烦。
  • 密钥长度写死,别动态计算:我见过有人用KeySize变量,结果线上配置错了,密钥生成失败。直接写2562048,简单可靠。
  • 测试时打印所有标签:用KeyStore.EntrygetAttributes()方法,确认生成的密钥符合预期。

好了,授权标签就讲到这里。这些标签看似简单,但组合起来威力巨大。记住一句话:标签越精确,密钥越安全


公众号:蓝海资料掘金营,微信deep3321