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

Java 11中AES密钥长度无效(20字节)问题求助

问题:Java AES加密时出现「无效密钥长度」错误

我正在尝试使用Java生成密钥,本人对密钥、密码、密码算法及加密技术并不熟悉。通过查阅资料修改了一段代码后,仍遇到「无效密钥长度」错误。

代码示例

Security.setProperty("crypto.policy", "unlimited");

String valueToEncode = "some_random_text";

SecureRandom secureRandom = new SecureRandom();
byte[] salt = new byte[256];

secureRandom.nextBytes(salt);

KeySpec keySpec = new PBEKeySpec("some_random_password".toCharArray(), salt, 65536, 256); // AES-256
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBEWITHHMACSHA512ANDAES_256");
byte[] key = secretKeyFactory.generateSecret(keySpec).getEncoded();
SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");

byte[] ivBytes = new byte[16];

secureRandom.nextBytes(ivBytes);

IvParameterSpec ivParameterSpec = new IvParameterSpec(ivBytes);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");

cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);

byte[] encValue = cipher.doFinal(valueToEncode.getBytes(StandardCharsets.UTF_8));
byte[] finalCiphertext = new byte[encValue.length + 2 * 16];

System.arraycopy(ivBytes, 0, finalCiphertext, 0, 16);
System.arraycopy(salt, 0, finalCiphertext, 16, 16);
System.arraycopy(encValue, 0, finalCiphertext, 32, encValue.length);

System.out.println(finalCiphertext.toString());

错误信息

Exception in thread "main" java.security.InvalidKeyException: Invalid AES key length: 20 bytes
    at com.sun.crypto.provider.AESCrypt.init(AESCrypt.java:87)
    at com.sun.crypto.provider.CipherBlockChaining.init(CipherBlockChaining.java:93)
    at com.sun.crypto.provider.CipherCore.init(CipherCore.java:591)
    at com.sun.crypto.provider.AESCipher.engineInit(AESCipher.java:346)
    at javax.crypto.Cipher.implInit(Cipher.java:805)
    at javax.crypto.Cipher.chooseProvider(Cipher.java:863)
    at javax.crypto.Cipher.init(Cipher.java:1395)
    at javax.crypto.Cipher.init(Cipher.java:1326)
    at com.att.logicalprovisioning.simulators.Trial.main(Trial.java:47)

错误发生在cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);行(对应Trial.java第47行),希望得到通用解决方案。


解决方案

错误核心原因

你使用的PBEWITHHMACSHA512ANDAES_256算法生成的SecretKey本身就是符合AES-256要求的密钥,但错误地调用getEncoded()后再用SecretKeySpec重新包装,导致密钥长度异常。该PBE算法生成的密钥内部已包含AES所需的正确长度密钥,无需额外转换。

修正后的代码

import java.security.SecureRandom;
import java.security.Security;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;

public class Trial {
    public static void main(String[] args) throws Exception {
        Security.setProperty("crypto.policy", "unlimited");

        String valueToEncode = "some_random_text";

        SecureRandom secureRandom = new SecureRandom();
        byte[] salt = new byte[16]; // 盐值通用长度为16字节,无需256字节
        secureRandom.nextBytes(salt);

        // 初始化PBE密钥规范
        KeySpec keySpec = new PBEKeySpec("some_random_password".toCharArray(), salt, 65536, 256);
        SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBEWITHHMACSHA512ANDAES_256");
        // 直接使用生成的SecretKey,跳过不必要的SecretKeySpec转换
        SecretKey secretKey = secretKeyFactory.generateSecret(keySpec);

        byte[] ivBytes = new byte[16];
        secureRandom.nextBytes(ivBytes);
        IvParameterSpec ivParameterSpec = new IvParameterSpec(ivBytes);

        // 初始化Cipher时直接传入生成的SecretKey
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec);

        byte[] encValue = cipher.doFinal(valueToEncode.getBytes(java.nio.charset.StandardCharsets.UTF_8));
        // 调整结果数组长度,匹配实际盐值长度
        byte[] finalCiphertext = new byte[encValue.length + ivBytes.length + salt.length];
        System.arraycopy(ivBytes, 0, finalCiphertext, 0, ivBytes.length);
        System.arraycopy(salt, 0, finalCiphertext, ivBytes.length, salt.length);
        System.arraycopy(encValue, 0, finalCiphertext, ivBytes.length + salt.length, encValue.length);

        // 使用Base64转换为可读字符串,避免打印内存地址
        System.out.println(Base64.getEncoder().encodeToString(finalCiphertext));
    }
}

额外优化点

  • 盐值长度调整:原代码定义256字节盐值但仅拷贝16字节到结果,改为通用的16字节盐值更合理。
  • 加密结果输出:原代码直接打印byte[]的toString()会输出内存地址,改用Base64编码可得到可读的加密字符串。
  • 无限制加密策略:确保JDK已启用无限制加密策略(代码中已设置crypto.policy为unlimited),否则AES-256会因权限限制无法使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 03:45:35