You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JDK11中AES/CTR/PKCS5PADDING可用,JDK17报错的解决方法

JDK17中AES/CTR/PKCS5PADDING组合报错问题解决

问题背景

给定以下代码:

byte[] lDecoded = Base64.getDecoder().decode(pValueBase64Encoded);
Cipher lCipher = Cipher.getInstance("AES/CTR/PKCS5PADDING");

在JDK17中调用Cipher.getInstance()时抛出异常:

Exception in thread "main" java.security.NoSuchAlgorithmException: Cannot find any provider supporting AES/CTR/PKCS5PADDING
    at java.base/javax.crypto.Cipher.getInstance(Cipher.java:571)
Pop3Handler.main(Pop3Handler.java:81)
Caused by: javax.crypto.NoSuchPaddingException: CTR mode must be used with NoPadding
    at java.base/com.sun.crypto.provider.CipherCore.setPadding(CipherCore.java:258)
    at java.base/com.sun.crypto.provider.AESCipher.engineSetPadding(AESCipher.java:206)
    at java.base/javax.crypto.Cipher$Transform.setModePadding(Cipher.java:388)
    at java.base/javax.crypto.Cipher.getInstance(Cipher.java:564)
    ... 4 more

但该代码在JDK11中可正常运行。

为排查问题,编写测试代码检查加密提供者支持的模式和填充:

@Test
public void testProviders() {
   Provider[] provs = Security.getProviders();
   for (Provider provider : provs) {
       Service service = provider.getService("Cipher", "AES");
       if (service == null) {
           continue;
       }

       String modes = service.getAttribute("SupportedModes");
       if (modes != null && modes.matches("(?i).*CTR.*")) {
          System.out.println("CTR found:");
           System.out.println(service);
       } else {
          System.out.println("CTR NOT found:");
       }
       
       String paddings = service.getAttribute("SupportedPaddings");
       if (paddings != null && paddings.matches("(?i).*PKCS5PADDING.*")) {
          System.out.println("PKCS5PADDING found:");
          System.out.println(service);
       } else {
          System.out.println("PKCS5PADDING NOT found:");
      }
   }
}

JDK17测试输出:

CTR found:
SunJCE: Cipher.AES -> com.sun.crypto.provider.AESCipher$General
  aliases: [OID.2.16.840.1.101.3.4.1, 2.16.840.1.101.3.4.1]
  attributes: {SupportedKeyFormats=RAW, SupportedModes=ECB|CBC|PCBC|CTR|CTS|CFB|OFB|CFB8|CFB16|CFB24|CFB32|CFB40|CFB48|CFB56|CFB64|OFB8|OFB16|OFB24|OFB32|OFB40|OFB48|OFB56|OFB64|CFB72|CFB80|CFB88|CFB96|CFB104|CFB112|CFB120|CFB128|OFB72|OFB80|OFB88|OFB96|OFB104|OFB112|OFB120|OFB128, SupportedPaddings=NOPADDING|PKCS5PADDING|ISO10126PADDING}

PKCS5PADDING found:
SunJCE: Cipher.AES -> com.sun.crypto.provider.AESCipher$General
  aliases: [OID.2.16.840.1.101.3.4.1, 2.16.840.1.101.3.4.1]
  attributes: {SupportedKeyFormats=RAW, SupportedModes=ECB|CBC|PCBC|CTR|CTS|CFB|OFB|CFB8|CFB16|CFB24|CFB32|CFB40|CFB48|CFB56|CFB64|OFB8|OFB16|OFB24|OFB32|OFB40|OFB48|OFB56|OFB64|CFB72|CFB80|CFB88|CFB96|CFB104|CFB112|CFB120|CFB128|OFB72|OFB80|OFB88|OFB96|OFB104|OFB112|OFB120|OFB128, SupportedPaddings=NOPADDING|PKCS5PADDING|ISO10126PADDING}

JDK11测试输出:

CTR found:
SunJCE: Cipher.AES -> com.sun.crypto.provider.AESCipher$General
  aliases: [Rijndael]
  attributes: {SupportedKeyFormats=RAW, SupportedModes=ECB|CBC|PCBC|CTR|CTS|CFB|OFB|CFB8|CFB16|CFB24|CFB32|CFB40|CFB48|CFB56|CFB64|OFB8|OFB16|OFB24|OFB32|OFB40|OFB48|OFB56|OFB64|GCM|CFB72|CFB80|CFB88|CFB96|CFB104|CFB112|CFB120|CFB128|OFB72|OFB80|OFB88|OFB96|OFB104|OFB112|OFB120|OFB128, SupportedPaddings=NOPADDING|PKCS5PADDING|ISO10126PADDING}

PKCS5PADDING found:
SunJCE: Cipher.AES -> com.sun.crypto.provider.AESCipher$General
  aliases: [Rijndael]
  attributes: {SupportedKeyFormats=RAW, SupportedModes=ECB|CBC|PCBC|CTR|CTS|CFB|OFB|CFB8|CFB16|CFB24|CFB32|CFB40|CFB48|CFB56|CFB64|OFB8|OFB16|OFB24|OFB32|OFB40|OFB48|OFB56|OFB64|GCM|CFB72|CFB80|CFB88|CFB96|CFB104|CFB112|CFB120|CFB128|OFB72|OFB80|OFB88|OFB96|OFB104|OFB112|OFB120|OFB128, SupportedPaddings=NOPADDING|PKCS5PADDING|ISO10126PADDING}

从输出看,CTR模式和PKCS5PADDING均被支持,但组合使用时JDK17报错,该如何解决?

解决方案

  • 本质原因:CTR属于流密码模式,这类模式本身要求明文长度是分组大小的整数倍,不需要额外填充。JDK11之前的SunJCE提供者没有严格校验这种非法组合,允许了AES/CTR/PKCS5PADDING的存在,但这不符合密码学规范。JDK17开始严格遵循规范,禁止了这种错误组合。

  • 正确的修改方式:将Cipher实例化的代码改为使用NoPadding:

    Cipher lCipher = Cipher.getInstance("AES/CTR/NoPadding");
    

    同时需要确保:

    • 加密时,明文长度必须是AES分组大小(16字节)的整数倍;如果原代码依赖PKCS5Padding自动填充,需要在加密逻辑中手动处理明文填充,再使用CTR模式加密。
    • 解密时,先通过CTR模式解密,再手动移除填充(如果原加密数据带PKCS5Padding的话)。
  • 兼容JDK11和JDK17的临时方案(不推荐):如果暂时无法修改加密逻辑,可以指定使用BouncyCastle等第三方加密提供者,这类提供者可能允许这种非规范组合。但这种方式不符合密码学最佳实践,存在安全风险,不建议长期使用:

    // 需先引入BouncyCastle依赖
    Cipher lCipher = Cipher.getInstance("AES/CTR/PKCS5PADDING", "BC");
    

内容的提问来源于stack exchange,提问作者cilap

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 10:24:49