无效的AES密钥长度:20字节(Java 11)



我正在尝试使用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)

Trial.java:47为行:cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);

是否有一个一刀切的解决方案?还是因为我不够理解?

如有任何帮助,不胜感激。

您的密钥长度为20字节,因为secretKeyFactory.generateSecret(keySpec).getEncoded()返回密码some_random_password

修复代码的简单方法是使用密钥派生PBKDF2WithHmacSHA512而不是PBEWITHHMACSHA512ANDAES_256。这将根据密码和salt生成指定长度的密钥:

...
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");
...

但是,PBEWITHHMACSHA512ANDAES_256也可以应用。该算法指定了一个具有PBKDF2WithHmacSHA512和随后的AES加密的密钥派生。该实现在功能上与您的相同,但需要对代码进行一些更改:

...
IvParameterSpec ivParameterSpec = new IvParameterSpec(ivBytes);
PBEParameterSpec parameterSpec = new PBEParameterSpec(salt, 65536, ivParameterSpec);
PBEKeySpec keySpec = new PBEKeySpec("some_random_password".toCharArray());
SecretKeyFactory kf = SecretKeyFactory.getInstance("PBEWITHHMACSHA512ANDAES_256");
SecretKey secretKey = kf.generateSecret(keySpec);       
Cipher cipher = Cipher.getInstance("PBEWITHHMACSHA512ANDAES_256");
cipher.init(Cipher.ENCRYPT_MODE, secretKey, parameterSpec);
byte[] encValue = cipher.doFinal(valueToEncode.getBytes(StandardCharsets.UTF_8));
...

另外两个问题是:

  • 您正在使用256字节的盐,但在连接时仅存储16字节。为了与串联一致,应用16字节的salt:byte[] salt = new byte[16]
  • 输出finalCiphertext.toString()只返回对象的类和十六进制哈希码,如下所示。对于有意义的输出,使用Base64或十六进制编码的byte[]代替,例如Base64.getEncoder().encodeToString(finalCiphertext)

最新更新