加密需要的不只有密钥:IV、tag 长度、盐、迭代次数、曲线,都属于「算法参数」。这篇逐个看 AlgorithmParameters 保存什么、编码成什么样、错的时候报什么。
[services]
JDK 21.0.12.1;AlgorithmParameters 服务 34 个:[AES, Blowfish, ChaCha20-Poly1305, DES, DESede, DSA, DiffieHellman, EC, GCM, OAEP, PBES2, PBEWithHmacSHA1AndAES_128, PBEWithHmacSHA1AndAES_256, PBEWithHmacSHA224AndAES_128, PBEWithHmacSHA224AndAES_256, PBEWithHmacSHA256AndAES_128, PBEWithHmacSHA256AndAES_256, PBEWithHmacSHA384AndAES_128, PBEWithHmacSHA384AndAES_256, PBEWithHmacSHA512/224AndAES_128, PBEWithHmacSHA512/224AndA [gcm]
c.getParameters():算法 GCM;提供者 SunJCE;toString = “
iv:
[0000: 44 37 FB 39 16 8E DD A9 03 25 82 7F D7.9.....%..
]
tLen(bits):
128
”
getEncoded() 长度 19:3011040c4437fb39168edda90325827f020110(30 11 04 0c <12 字节 IV> 02 01 10:SEQUENCE{OCTET STRING IV,INTEGER 16 = tag 字节数})
getParameterSpec(GCMParameterSpec):IV 4437fb39168edda90325827f(12 字节),tLen = 128 位
getEncoded("ASN.1") 与 getEncoded() 相同? true;getEncoded("JSON") → 19
另一方只拿到编码后的参数 + 密钥解密:hello gcm
解密时不给参数(没有 IV):InvalidKeyException: No GCMParameterSpec specified
解密时 tag 长度写成 96 位(加密时是 128):AEADBadTagException: Tag mismatch
解密时 IV 错了一位:AEADBadTagException: Tag mismatch
同一个 Cipher 对象第二次 init 加密、IV 重复(同一密钥):InvalidAlgorithmParameterException: Cannot reuse iv for GCM encryption
同一个 Cipher 对象 doFinal 之后再 doFinal(未重新 init):IllegalStateException: Must use either different key or iv for GCM encryption
新建的 Cipher + 同一个固定 IV 加密两次(同一个密钥):两个 Cipher 都成功;密文相同? true(IV 复用没有被拦截,明文相同时密文相同)
不指定 IV 时每次 init 生成的 IV:75b7707d2e9fcd88351b748b 与 e8e1eb476933d9783ee04a9d [cbc]
CBC:ap.getAlgorithm = AES;toString = “
iv:
[0000: DA D6 A8 8E D0 6A CD 43 57 2E C2 C8 0B 8D C7 95 .....j.CW.......
]
”;getEncoded 长度 18:0410dad6a88ed06acd43572ec2c80b8dc795
getParameterSpec(IvParameterSpec).IV = dad6a88ed06acd43572ec2c80b8dc795
getParameterSpec(AlgorithmParameterSpec.class) 的实际类型:IvParameterSpec
getParameterSpec(GCMParameterSpec.class)(类型不符):InvalidParameterSpecException: Inappropriate parameter specification
CBC 解密时不给 IV:InvalidKeyException: Parameters missing
CBC 解密时 IV 全 0(错误的 IV):????J?!4??c?is a longer message(消息 34 字节,共 3 块;只有第一块被错误的 IV 破坏)
CBC 加密时指定了 8 字节 IV:InvalidAlgorithmParameterException: Wrong IV length: must be 16 bytes long
ECB 的 getParameters() = null(没有参数)
ECB 加密时传 IvParameterSpec:InvalidAlgorithmParameterException: ECB mode cannot use IV
ChaCha20-Poly1305:getParameters 算法 ChaCha20-Poly1305;编码 040cb85277df7fa62899ba83a888(OCTET STRING nonce,12 字节)
AlgorithmParameters.getInstance("AES") 未 init 就 getEncoded:IOException: not initialized;getParameterSpec:InvalidParameterSpecException: not initialized
init 一次后再 init:InvalidParameterSpecException: already initialized
init(byte[]) 的数据格式不对:EOFException: not enough content
AES 参数的 init(GCMParameterSpec):InvalidParameterSpecException: Inappropriate parameter specification [ec]
getInstance(EC).init(ECGenParameterSpec("secp256r1" )) → 名称 secp256r1 [NIST P-256,X9.62 prime256v1] (1.2.840.10045.3.1.7);阶 256 位;余因子 1;曲线域 256 位;编码 06082a8648ce3d030107
getInstance(EC).init(ECGenParameterSpec("NIST P-256" )) → 名称 secp256r1 [NIST P-256,X9.62 prime256v1] (1.2.840.10045.3.1.7);阶 256 位;余因子 1;曲线域 256 位;编码 06082a8648ce3d030107
getInstance(EC).init(ECGenParameterSpec("prime256v1" )) → InvalidParameterSpecException: Not a supported curve: java.security.spec.ECGenParameterSpec@799f7e29
getInstance(EC).init(ECGenParameterSpec("1.2.840.10045.3.1.7")) → 名称 secp256r1 [NIST P-256,X9.62 prime256v1] (1.2.840.10045.3.1.7);阶 256 位;余因子 1;曲线域 256 位;编码 06082a8648ce3d030107
getInstance(EC).init(ECGenParameterSpec("secp384r1" )) → 名称 secp384r1 [NIST P-384] (1.3.132.0.34);阶 384 位;余因子 1;曲线域 384 位;编码 06052b81040022
getInstance(EC).init(ECGenParameterSpec("secp521r1" )) → 名称 secp521r1 [NIST P-521] (1.3.132.0.35);阶 521 位;余因子 1;曲线域 521 位;编码 06052b81040023
getInstance(EC).init(ECGenParameterSpec("secp256k1" )) → 名称 secp256k1 (1.3.132.0.10);阶 256 位;余因子 1;曲线域 256 位;编码 06052b8104000a
getInstance(EC).init(ECGenParameterSpec("x25519" )) → InvalidParameterSpecException: Not a supported curve: java.security.spec.ECGenParameterSpec@4b9af9a9
getInstance(EC).init(ECGenParameterSpec("nope" )) → InvalidParameterSpecException: Not a supported curve: java.security.spec.ECGenParameterSpec@5387f9e0
EC 公钥的 getParams():ECPublicKeyImpl;参数 toString = secp256r1 [NIST P-256,X9.62 prime256v1] (1.2.840.10045.3.1.7)
从密钥的 ECParameterSpec 构造 AlgorithmParameters,toString = secp256r1 [NIST P-256,X9.62 prime256v1] (1.2.840.10045.3.1.7);编码 06082a8648ce3d030107
用 secp384r1 的 OID(06 05 2b 81 04 00 22)的编码 init:secp384r1 [NIST P-384] (1.3.132.0.34);getParameterSpec(ECGenParameterSpec) = 1.3.132.0.34
DiffieHellman 的 AlgorithmParameters.init(DHGenParameterSpec(512, 160)):InvalidParameterSpecException: Inappropriate parameter specification
AlgorithmParameterGenerator(DH, 1024) 生成的参数:p 1024 位,g 的位数 1023,l = 0;编码长度 267 [pbe]
PBE 的 getParameters():算法 PBEWithHmacSHA256AndAES_256;toString 摘要 “PBEWithHmacSHA256AndAES_256”
getEncoded 长度 79:304d302c06092a864886f70d01050c301f0408010203040506070802022710020120300c06082a864886f70d02090500301d060960864801650304012a0410ef79c2a629bbddcc260738cc9bfd81ae
getParameterSpec(PBEParameterSpec):salt 0102030405060708,迭代 10000,参数 IvParameterSpec IV ef79c2a629bbddcc260738cc9bfd81ae
只用编码后的参数 + 口令解密:secret text
口令错误:BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.
PBEParameterSpec 迭代次数 0 / 负数 / 1:0 / -1 / 迭代 1 可用
PBEParameterSpec 的 salt 为空数组:InvalidAlgorithmParameterException: Salt must be at least 8 bytes long;salt 为 7 字节:InvalidAlgorithmParameterException: Salt must be at least 8 bytes long
加密时不给 PBEParameterSpec:成功;参数 salt 长度 20,迭代 4096 [persist]
保存参数文件 19 字节;密文长度 23(明文 7 字节 + 16 字节 tag)
从文件读回参数后解密(AAD 一致):payload
AAD 不一致:AEADBadTagException: Tag mismatch
密文被改动一位:AEADBadTagException: Tag mismatch
用 AlgorithmParameters("AES") 去 init GCM 编码的参数:IOException: DER input not an octet string
把 GCM 的参数交给 CBC 的 Cipher:InvalidAlgorithmParameterException: Wrong parameter type: IV expected