bigywater.tech
Java · 360

KeyGenerator:生成对称密钥的参数边界

生成一个对称密钥看起来是两行代码,但默认长度会随 JDK 版本变化,各算法接受的长度各不相同,随机源也完全由调用者决定。这篇逐项实测。

128 → 256 位
AES 不调用 init 时的默认密钥长度:JDK 17 与 JDK 21 / 27
同一个密钥
种子固定的 SHA1PRNG 作为随机源时,两个全新的 KeyGenerator 生成的 AES 密钥
0 个重复
8 线程共用一个 KeyGenerator 生成的 20 万个密钥中的重复数

有哪些 KeyGenerator

实测 · 本机执行输出
  [services]
    JDK 21.0.12.1;KeyGenerator 服务 24 个:[SunJCE:AES, SunJCE:ARCFOUR, SunJCE:Blowfish, SunJCE:ChaCha20, SunJCE:DES, SunJCE:DESede, SunJCE:HmacMD5, SunJCE:HmacSHA1, SunJCE:HmacSHA224, SunJCE:HmacSHA256, SunJCE:HmacSHA3-224, SunJCE:HmacSHA3-256, SunJCE:HmacSHA3-384, SunJCE:HmacSHA3-512, SunJCE:HmacSHA384, SunJCE:HmacSHA512, SunJCE:HmacSHA512/224, SunJCE:HmacSHA512/256, SunJCE:RC2, SunJCE:SunTls12Prf, Su
    Cipher.getMaxAllowedKeyLength("AES") = 2147483647

默认密钥长度

实测 · 本机执行输出
  [defaults]
        AES              → 默认密钥 32 字节(256 位);getAlgorithm = AES;getFormat = RAW;provider = SunJCE;类 SecretKeySpec
        DES              → 默认密钥 8 字节(64 位);getAlgorithm = DES;getFormat = RAW;provider = SunJCE;类 DESKey
        DESede           → 默认密钥 24 字节(192 位);getAlgorithm = DESede;getFormat = RAW;provider = SunJCE;类 DESedeKey
        Blowfish         → 默认密钥 16 字节(128 位);getAlgorithm = Blowfish;getFormat = RAW;provider = SunJCE;类 SecretKeySpec
        RC2              → 默认密钥 16 字节(128 位);getAlgorithm = RC2;getFormat = RAW;provider = SunJCE;类 SecretKeySpec
        ARCFOUR          → 默认密钥 16 字节(128 位);getAlgorithm = ARCFOUR;getFormat = RAW;provider = SunJCE;类 SecretKeySpec
        ChaCha20         → 默认密钥 32 字节(256 位);getAlgorithm = ChaCha20;getFormat = RAW;provider = SunJCE;类 SecretKeySpec
        HmacMD5          → 默认密钥 64 字节(512 位);getAlgorithm = HmacMD5;getFormat = RAW;provider = SunJCE;类 SecretKeySpec
        HmacSHA1         → 默认密钥 64 字节(512 位);getAlgorithm = HmacSHA1;getFormat = RAW;provider = SunJCE;类 SecretKeySpec
        HmacSHA224       → 默认密钥 28 字节(224 位);getAlgorithm = HmacSHA224;getFormat = RAW;provider = SunJCE;类 SecretKeySpec
        HmacSHA256       → 默认密钥 32 字节(256 位);getAlgorithm = HmacSHA256;getFormat = RAW;provider = SunJCE;类 SecretKeySpec
        HmacSHA384       → 默认密钥 48 字节(384 位);getAlgorithm = HmacSHA384;getFormat = RAW;provider = SunJCE;类 SecretKeySpec
        HmacSHA512       → 默认密钥 64 字节(512 位);getAlgorithm = HmacSHA512;getFormat = RAW;provider = SunJCE;类 SecretKeySpec
        HmacSHA3-256     → 默认密钥 32 字节(256 位);getAlgorithm = HmacSHA3-256;getFormat = RAW;provider = SunJCE;类 SecretKeySpec
        HmacSHA512/256   → 默认密钥 32 字节(256 位);getAlgorithm = HmacSHA512/256;getFormat = RAW;provider = SunJCE;类 SecretKeySpec
        SunTls12Prf      → IllegalStateException: TlsPrfGenerator must be initialized
  [JDK 17(只看 AES / HmacSHA256 / DESede)]
        AES              → 默认密钥 16 字节(128 位);getAlgorithm = AES;getFormat = RAW;provider = SunJCE;类 SecretKeySpec
        DES              → 默认密钥 8 字节(64 位);getAlgorithm = DES;getFormat = RAW;provider = SunJCE;类 DESKey
        DESede           → 默认密钥 24 字节(192 位);getAlgorithm = DESede;getFormat = RAW;provider = SunJCE;类 DESedeKey
        Blowfish         → 默认密钥 16 字节(128 位);getAlgorithm = Blowfish;getFormat = RAW;provider = SunJCE;类 SecretKeySpec
        RC2              → 默认密钥 16 字节(128 位);getAlgorithm = RC2;getFormat = RAW;provider = SunJCE;类 SecretKeySpec
        ARCFOUR          → 默认密钥 16 字节(128 位);getAlgorithm = ARCFOUR;getFormat = RAW;provider = SunJCE;类 SecretKeySpec
        ChaCha20         → 默认密钥 32 字节(256 位);getAlgorithm = ChaCha20;getFormat = RAW;provider = SunJCE;类 SecretKeySpec
        HmacMD5          → 默认密钥 64 字节(512 位);getAlgorithm = HmacMD5;getFormat = RAW;provider = SunJCE;类 SecretKeySpec
        HmacSHA1         → 默认密钥 64 字节(512 位);getAlgorithm = HmacSHA1;getFormat = RAW;provider = SunJCE;类 SecretKeySpec
        HmacSHA224       → 默认密钥 28 字节(224 位);getAlgorithm = HmacSHA224;getFormat = RAW;provider = SunJCE;类 SecretKeySpec
        HmacSHA256       → 默认密钥 32 字节(256 位);getAlgorithm = HmacSHA256;getFormat = RAW;provider = SunJCE;类 SecretKeySpec
        HmacSHA384       → 默认密钥 48 字节(384 位);getAlgorithm = HmacSHA384;getFormat = RAW;provider = SunJCE;类 SecretKeySpec
        HmacSHA512       → 默认密钥 64 字节(512 位);getAlgorithm = HmacSHA512;getFormat = RAW;provider = SunJCE;类 SecretKeySpec
        HmacSHA3-256     → 默认密钥 32 字节(256 位);getAlgorithm = HmacSHA3-256;getFormat = RAW;provider = SunJCE;类 SecretKeySpec
        HmacSHA512/256   → 默认密钥 32 字节(256 位);getAlgorithm = HmacSHA512/256;getFormat = RAW;provider = SunJCE;类 SecretKeySpec
        SunTls12Prf      → IllegalStateException: TlsPrfGenerator must be initialized
  [JDK 27(只看 AES / HmacSHA256 / DESede)]
        AES              → 默认密钥 32 字节(256 位);getAlgorithm = AES;getFormat = RAW;provider = SunJCE;类 SecretKeySpec
        DES              → 默认密钥 8 字节(64 位);getAlgorithm = DES;getFormat = RAW;provider = SunJCE;类 DESKey
        DESede           → 默认密钥 24 字节(192 位);getAlgorithm = DESede;getFormat = RAW;provider = SunJCE;类 DESedeKey
        Blowfish         → 默认密钥 16 字节(128 位);getAlgorithm = Blowfish;getFormat = RAW;provider = SunJCE;类 SecretKeySpec
        RC2              → 默认密钥 16 字节(128 位);getAlgorithm = RC2;getFormat = RAW;provider = SunJCE;类 SecretKeySpec
        ARCFOUR          → 默认密钥 16 字节(128 位);getAlgorithm = ARCFOUR;getFormat = RAW;provider = SunJCE;类 SecretKeySpec
        ChaCha20         → 默认密钥 32 字节(256 位);getAlgorithm = ChaCha20;getFormat = RAW;provider = SunJCE;类 SecretKeySpec
        HmacMD5          → 默认密钥 64 字节(512 位);getAlgorithm = HmacMD5;getFormat = RAW;provider = SunJCE;类 SecretKeySpec
        HmacSHA1         → 默认密钥 64 字节(512 位);getAlgorithm = HmacSHA1;getFormat = RAW;provider = SunJCE;类 SecretKeySpec
        HmacSHA224       → 默认密钥 28 字节(224 位);getAlgorithm = HmacSHA224;getFormat = RAW;provider = SunJCE;类 SecretKeySpec
        HmacSHA256       → 默认密钥 32 字节(256 位);getAlgorithm = HmacSHA256;getFormat = RAW;provider = SunJCE;类 SecretKeySpec
        HmacSHA384       → 默认密钥 48 字节(384 位);getAlgorithm = HmacSHA384;getFormat = RAW;provider = SunJCE;类 SecretKeySpec
        HmacSHA512       → 默认密钥 64 字节(512 位);getAlgorithm = HmacSHA512;getFormat = RAW;provider = SunJCE;类 SecretKeySpec
        HmacSHA3-256     → 默认密钥 32 字节(256 位);getAlgorithm = HmacSHA3-256;getFormat = RAW;provider = SunJCE;类 SecretKeySpec
        HmacSHA512/256   → 默认密钥 32 字节(256 位);getAlgorithm = HmacSHA512/256;getFormat = RAW;provider = SunJCE;类 SecretKeySpec
        SunTls12Prf      → IllegalStateException: TlsPrfGenerator must be initialized

init(int) 的边界

实测 · 本机执行输出
  [sizes]
        AES        接受:[128→16B, 192→24B, 256→32B]
                   第一个被拒绝的:0: InvalidParameterException: Wrong keysize: must be equal to 128, 192 or 256
        DES        接受:[56→8B]
                   第一个被拒绝的:0: InvalidParameterException: Wrong keysize: must be equal to 56
        DESede     接受:[112→24B, 168→24B]
                   第一个被拒绝的:0: InvalidParameterException: Wrong keysize: must be equal to 112 or 168
        Blowfish   接受:[40→5B, 56→7B, 64→8B, 112→14B, 128→16B, 168→21B, 192→24B, 200→25B, 256→32B, 384→48B, 448→56B]
                   第一个被拒绝的:0: InvalidParameterException: Keysize must be multiple of 8, and can only range from 32 to 448 (inclusive)
        RC2        接受:[40→5B, 56→7B, 64→8B, 100→13B, 112→14B, 128→16B, 168→21B, 192→24B, 200→25B, 256→32B, 384→48B, 448→56B, 512→64B, 1024→128B]
                   第一个被拒绝的:0: InvalidParameterException: Key length for RC2 must be between 40 and 1024 bits
        ARCFOUR    接受:[40→5B, 56→7B, 64→8B, 100→13B, 112→14B, 128→16B, 168→21B, 192→24B, 200→25B, 256→32B, 384→48B, 448→56B, 512→64B, 1024→128B]
                   第一个被拒绝的:0: InvalidParameterException: Key length for ARCFOUR must be between 40 and 1024 bits
        ChaCha20   接受:[256→32B]
                   第一个被拒绝的:0: InvalidParameterException: Key length for ChaCha20 must be 256 bits
        HmacSHA256 接受:[40→5B, 56→7B, 64→8B, 100→13B, 112→14B, 128→16B, 168→21B, 192→24B, 200→25B, 256→32B, 384→48B, 448→56B, 512→64B, 1024→128B, 2048→256B]
                   第一个被拒绝的:0: InvalidParameterException: Key length must be at least 40 bits
    DES init(56) 与 init(64) 生成的密钥长度:InvalidParameterException: Wrong keysize: must be equal to 56
    DESede init(112) 与 init(168) 的密钥长度:24 / 24
    init(AlgorithmParameterSpec):AES → InvalidAlgorithmParameterException: AES key generation does not take any parameters;HmacSHA256 → InvalidAlgorithmParameterException: HmacSHA256 key generation does not take any parameters
    没有调用 init 就 generateKey 的密钥长度见上一节(使用默认长度);init 两次,后一次生效:256 位
    不存在的算法:NoSuchAlgorithmException: AES256 KeyGenerator not available;名字大小写:aes;指定不存在的提供者:NoSuchProviderException: no such provider: Nope

随机性与随机源

实测 · 本机执行输出
  [random]
    同一个 KeyGenerator 连续生成 100000 个 AES-256 密钥:重复 0 个
    20000 个密钥共 5120000 位,其中 1 的比例 0.4998(期望 0.5)
    用 SHA1PRNG(种子 42)作为 SecureRandom 生成的密钥(第 1 个新生成器):d50ac288b90ede2e311b02376bca7c70
    用 SHA1PRNG(种子 42)作为 SecureRandom 生成的密钥(第 2 个新生成器):d50ac288b90ede2e311b02376bca7c70
    new SecureRandom(种子 1 字节) 默认实现(NativePRNG)生成的两个密钥是否相同:false
    默认 SecureRandom 的算法:NativePRNG;KeyGenerator 默认使用它的提供者:SunJCE
    自定义 SecureRandom 总是填 0x07:生成的密钥 = 07070707070707070707070707070707(KeyGenerator 直接使用调用者给的随机源,不做检查)
    DES 在随机源给 0x07 时的密钥字节:0707070707070707;是否是弱密钥由 provider 处理?(这里看到的就是返回值)

DES 的校验位与弱密钥

实测 · 本机执行输出
  [des]
    DES 密钥每个字节的奇校验位:10000 个密钥里有 0 个含偶数个 1 的字节
    DESKeySpec.isWeak(01 01 01 01 01 01 01 01) = true;随机生成的密钥是弱密钥的有 0 / 20000
    SecretKeySpec(01 02 … 08)的类 SecretKeySpec;经 SecretKeyFactory(DES) 转出的 DESKey;原始字节 0102030405060708;转出后字节 0102020404070708;相同? false
    DESKeySpec.isParityAdjusted(原始字节) = false;isParityAdjusted(转出后字节) = true
    用两个密钥加密同一段明文,密文是否相同(DES 忽略校验位):true

并发与耗时

实测 · 本机执行输出
  [thread]
    8 个线程共用同一个 KeyGenerator 各生成 25000 个 AES-128 密钥:重复 0 个,异常 0 个,不同密钥数 200000
        AES        generateKey 约 263 ns / 次
        HmacSHA256 generateKey 约 276 ns / 次
        DESede     generateKey 约 518 ns / 次
        ChaCha20   generateKey 约 262 ns / 次
        KeyGenerator.getInstance("AES") 约 325 ns / 次(自写计时,不是 JMH;sink=true)

分步演示

KeyGenerator
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / OpenJDK(Temurin 17.0.20、Homebrew 21.0.12 与 27,每篇注明实际用的版本);用 javac 编译、java 直接运行,需要第三方库时用 Maven 解析依赖;计时用 System.nanoTime,数字每次运行会有小幅抖动。JDK 17.0.20.1 / 21.0.12.1 / 27,SunJCE 提供者;耗时为自写计时循环,不是 JMH
    • 没有验证:PKCS#11 / FIPS 等其它提供者的 KeyGenerator、HKDF 与 KDF API(JDK 24+)、KeyGenerator 与 SecureRandom 在容器启动初期的熵与阻塞行为、Windows / Linux 上 NativePRNG 之外的默认 SecureRandom、RC2 / ARCFOUR 的实际安全性、密钥材料在内存中的清理(SecretKey.destroy)
    京ICP备2026067502号-1京公网安备11010502063487号