AES 加密 Java 无效密钥长度
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2568841/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
AES Encryption Java Invalid Key length
提问by wuntee
I am trying to create an AES encryption method, but for some reason I keep getting
我正在尝试创建一种 AES 加密方法,但由于某种原因,我不断收到
java.security.InvalidKeyException: Key length not 128/192/256 bits
java.security.InvalidKeyException: Key length not 128/192/256 bits
Here is the code:
这是代码:
public static SecretKey getSecretKey(char[] password, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException{
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
// NOTE: last argument is the key length, and it is 256
KeySpec spec = new PBEKeySpec(password, salt, 1024, 256);
SecretKey tmp = factory.generateSecret(spec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
return(secret);
}
public static byte[] encrypt(char[] password, byte[] salt, String text) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, InvalidParameterSpecException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException{
SecretKey secret = getSecretKey(password, salt);
Cipher cipher = Cipher.getInstance("AES");
// NOTE: This is where the Exception is being thrown
cipher.init(Cipher.ENCRYPT_MODE, secret);
byte[] ciphertext = cipher.doFinal(text.getBytes("UTF-8"));
return(ciphertext);
}
Can anyone see what I am doing wrong? I am thinking it may have something to do with the SecretKeyFactory algorithm, but that is the only one I can find that is supported on the end system I am developing against. Any help would be appreciated. Thanks.
谁能看到我做错了什么?我认为它可能与 SecretKeyFactory 算法有关,但这是我能找到的唯一一种在我正在开发的终端系统上受支持的算法。任何帮助,将不胜感激。谢谢。
回答by Wajdy Essam
using any padding mechanisms to fill the empty bits
使用任何填充机制来填充空位
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
回答by Mohamed Mansour
For a stronger key strength encryption you would need to download Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files.
要获得更强的密钥强度加密,您需要下载 Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files。
http://java.sun.com/javase/downloads/index.jsp(Check Other Downloads).
回答by Chopstick
When I place the following code and run it, I don't receive any exceptions:
当我放置以下代码并运行它时,我没有收到任何异常:
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.InvalidParameterSpecException;
import java.security.spec.KeySpec;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
public class Main
{
public static void main(String[] args)
{
String pass = "this is the pass";
char[] pw = new char[pass.length()];
for(int k=0; k<pass.length();++k)
{
pw[k] = pass.charAt(k);
}
try {
byte[] q = encrypt(pw,"asdf".getBytes(),"der text");
System.out.println(new String(q));
} catch (InvalidKeyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvalidKeySpecException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvalidParameterSpecException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (BadPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static SecretKey getSecretKey(char[] password, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException{
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
// NOTE: last argument is the key length, and it is 256
KeySpec spec = new PBEKeySpec(password, salt, 1024, 256);
SecretKey tmp = factory.generateSecret(spec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
return(secret);
}
public static byte[] encrypt(char[] password, byte[] salt, String text) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, InvalidParameterSpecException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException{
SecretKey secret = getSecretKey(password, salt);
Cipher cipher = Cipher.getInstance("AES");
// NOTE: This is where the Exception is being thrown
cipher.init(Cipher.ENCRYPT_MODE, secret);
byte[] ciphertext = cipher.doFinal(text.getBytes("UTF-8"));
return(ciphertext);
}
}
I was never able to recreate the exception that you had. I'm running J2SE 1.6 and developing on Eclipse.
我永远无法重新创建您拥有的异常。我正在运行 J2SE 1.6 并在 Eclipse 上进行开发。
Could it be that your password is not 16 bytes long?
会不会是你的密码不是 16 字节长?
回答by Sean
You can install the JCE Unlimited Strength jars, as is suggested on several other similar questions, or just try including this code in your main function or driver.
您可以按照其他几个类似问题的建议安装 JCE Unlimited Strength jar,或者尝试将此代码包含在您的主函数或驱动程序中。
try {
java.lang.reflect.Field field = Class.forName("javax.crypto.JceSecurity").getDeclaredField("isRestricted");
field.setAccessible(true);
field.set(null, java.lang.Boolean.FALSE);
} catch (Exception ex) {
ex.printStackTrace();
}
回答by Maarten Bodewes
The problem here is the mismatch between key sizes for your key derivation function and the given ciphers. The PBKDF you use is "PBEWithMD5AndDES"
and in this string the DES
part indicates the type of output. As single DES as it is known uses only 8 byte keys (64 bit, 56 effective bit size with parity bits). AES keys should be either 128, 192 and 256 bit and should not include parity bits.
这里的问题是您的密钥派生函数的密钥大小与给定密码之间的不匹配。您使用的 PBKDF 是,"PBEWithMD5AndDES"
并且在此字符串中,该DES
部分指示输出的类型。众所周知,单个 DES 仅使用 8 个字节的密钥(64 位,56 位有效位大小,带奇偶校验位)。AES 密钥应该是 128、192 和 256 位,并且不应包括奇偶校验位。
To create AES strength key sizes you should at least use PBKDF2 instead of PBKDF1, preferably with SHA-256 or SHA-512 for higher key sizes. For 128 bit keys you should however be fine with SHA-1. So use the build in "PBKDF2WithHmacSHA1"
SecretKeyFactory
instead. Note that PBKDF2 / SHA1 with keys over 160 bit will result in suboptimal operation. You may want to use a simple key based key derivation function (KBKDF) over the output if you want to create more data (such as a separate IV).
要创建 AES 强度密钥大小,您至少应该使用 PBKDF2 而不是 PBKDF1,对于更高的密钥大小,最好使用 SHA-256 或 SHA-512。但是,对于 128 位密钥,您应该可以使用 SHA-1。所以改用内置 "PBKDF2WithHmacSHA1"
SecretKeyFactory
。请注意,密钥超过 160 位的 PBKDF2 / SHA1 将导致次优操作。如果您想创建更多数据(例如单独的 IV),您可能希望在输出上使用简单的基于密钥的密钥派生函数 (KBKDF)。
As others have indicated, if you use keys of over 128 bit you will need the unlimited crypto jurisdiction files.
正如其他人所指出的,如果您使用超过 128 位的密钥,您将需要无限的加密权限文件。
Notes on the following code:
以下代码的注意事项:
- No integrity protection, which you may need even for maintaining confidentiality
- CBC using a zero IV, this may be OK but only if the salt is fully random (store the salt with the ciphertext)
- 1024 is a relatively low number of iterations for the PBKDF2
- PBKDF2 is incompatible with PBKDF1 which you were using
- 没有完整性保护,您甚至可能需要保护机密性
- CBC 使用零 IV,这可能没问题,但前提是盐是完全随机的(将盐与密文一起存储)
- 1024 是 PBKDF2 的相对较少的迭代次数
- PBKDF2 与您使用的 PBKDF1 不兼容
public static SecretKey getSecretKey(char[] password, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException{
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
// NOTE: last argument is the key length, and it is 128
KeySpec spec = new PBEKeySpec(password, salt, 1024, 128);
SecretKey tmp = factory.generateSecret(spec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
return(secret);
}
public static byte[] encrypt(char[] password, byte[] salt, String text) throws GeneralSecurityException {
SecretKey secret = getSecretKey(password, salt);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret, new IvParameterSpec(new byte[cipher.getBlockSize()]));
byte[] ciphertext = cipher.doFinal(text.getBytes(StandardCharsets.UTF_8));
return(ciphertext);
}