How to fix Invalid AES key length?
我正在研究文本加密和解密项目(遵循Struts 2)
每当我输入密码和纯文本时,我都会收到无效的AES密钥长度错误。
服务类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | package com.anoncrypt.services; import java.security.Key; import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; import sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder; public class SymAES { private static final String ALGORITHM ="AES"; private static byte[] keyValue= new byte[] { 'T', 'h', 'i', 's', 'I', 's', 'A', 'S', 'e', 'c', 'r', 'e', 't', 'K', 'e', 'y' }; public String encode(String valueToEnc) throws Exception { Key key = new SecretKeySpec(keyValue, ALGORITHM); Cipher c = Cipher.getInstance(ALGORITHM); c.init(Cipher.ENCRYPT_MODE, key); byte[] encValue = c.doFinal(valueToEnc.getBytes()); String encryptedValue = new BASE64Encoder().encode(encValue); return encryptedValue; } public String decode(String encryptedValue) throws Exception { Key key = new SecretKeySpec(keyValue, ALGORITHM); Cipher c = Cipher.getInstance(ALGORITHM); c.init(Cipher.DECRYPT_MODE, key); byte[] decordedValue = new BASE64Decoder().decodeBuffer(encryptedValue); byte[] decValue = c.doFinal(decordedValue); String decryptedValue = new String(decValue); return decryptedValue; } public void start(String passcode)throws Exception { keyValue = passcode.getBytes(); } } |
这就是错误
1 2 3 4 5 6 7 8 9 10 11 12 | java.security.InvalidKeyException: Invalid AES key length: 6 bytes com.sun.crypto.provider.AESCrypt.init(AESCrypt.java:87) com.sun.crypto.provider.ElectronicCodeBook.init(ElectronicCodeBook.java:93) com.sun.crypto.provider.CipherCore.init(CipherCore.java:582) com.sun.crypto.provider.CipherCore.init(CipherCore.java:458) com.sun.crypto.provider.AESCipher.engineInit(AESCipher.java:307) javax.crypto.Cipher.implInit(Cipher.java:797) javax.crypto.Cipher.chooseProvider(Cipher.java:859) javax.crypto.Cipher.init(Cipher.java:1229) javax.crypto.Cipher.init(Cipher.java:1166) com.anoncrypt.services.SymAES.encode(SymAES.java:35) com.anoncrypt.actions.SymEncrypt.execute(SymEncrypt.java:24) |
一般要了解的事情:
-
SecretKeySpec 需要密钥,而不是密码。见下文
在你的情况下
问题是数字1:您传递的是密码而不是密钥。
AES仅支持16,24或32字节的密钥大小。您需要准确提供该金额,或者从键入的内容中获取密钥。
从密码短语中导出密钥的方法有很多种。 Java为此目的提供了PBKDF2实现。
我使用erickson的答案绘制完整的图片(仅加密,因为解密类似,但包括拆分密文):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | SecureRandom random = new SecureRandom(); byte[] salt=new byte[16]; random.nextBytes(salt); KeySpec spec = new PBEKeySpec("password".toCharArray(), salt, 65536, 256); // AES-256 SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); byte[] key = f.generateSecret(spec).getEncoded(); SecretKeySpec keySpec = new SecretKeySpec(key,"AES"); byte[] ivBytes = new byte[16]; random.nextBytes(ivBytes); IvParameterSpec iv = new IvParameterSpec(ivBytes); Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding"); c.init(Cipher.ENCRYPT_MODE, keySpec, iv); byte[] encValue = c.doFinal(valueToEnc.getBytes()); 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); return finalCiphertext; |
其他要记住的事项:
-
始终使用完全限定的密码名称。在这种情况下,
AES 不合适,因为不同的JVM / JCE提供程序可能会对操作模式和填充使用不同的默认值。使用AES/CBC/PKCS5Padding 。不要使用ECB模式,因为它在语义上不安全。 -
如果您不使用ECB模式,则需要将IV与密文一起发送。这通常通过将IV添加到密文字节数组来完成。 IV会自动为您创建,您可以通过
cipherInstance.getIV() 获取它。 - 每当你发送东西时,你需要确保它一直没有改变。很难用MAC正确实现加密。我建议您使用CCM或GCM等经过身份验证的模式。
您可以验证密钥长度限制:
1 2 | int maxKeyLen = Cipher.getMaxAllowedKeyLength("AES"); System.out.println("MaxAllowedKeyLength=[" + maxKeyLen +"]."); |
我遇到了同样的问题,然后我把我的密钥设为16字节,现在它正常工作。准确地创建16字节的密钥。它肯定会奏效。