生成一个对称密钥看起来是两行代码,但默认长度会随 JDK 版本变化,各算法接受的长度各不相同,随机源也完全由调用者决定。这篇逐项实测。
[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 [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 密钥每个字节的奇校验位: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)