2010-04-02 105 views
9

我想创建一个AES加密方法,但由于某些原因,我不断收到AES加密的Java密钥长度无效

java.security.InvalidKeyException: Key length not 128/192/256 bits

下面是代码:

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); 
} 

任何人都可以看到我做错了什么?我认为它可能与SecretKeyFactory算法有关,但这是我能找到的唯一一个在我正在开发的终端系统上支持的算法。任何帮助,将不胜感激。谢谢。使用任何填充机制

+1

您能否粘贴例外? – 2010-04-02 19:59:32

+0

在[此链接]的早期文章中有一个答案(http://stackoverflow.com/questions/992019/java-256bit-aes-encryption/992413#992413)。希望这可以帮助! – 2010-04-02 20:23:02

+0

因此,似乎Java实例不支持我所需要的: '带有消息“非法密钥大小或默认参数”的消息java.security.InvalidKeyException' – wuntee 2010-04-02 20:42:29

回答

-1

填补空位

Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
+0

哎呀,对不起这个填充输入不是关键 – 2010-04-02 20:03:58

8

对于一个更强的密钥强度的加密,你需要下载Java加密扩展(JCE)无限强度权限策略文件。

http://java.sun.com/javase/downloads/index.jsp(检查其他下载)。

+0

我已经下载了额外的罐子,将它们添加到项目中,但我仍然得到异常... – wuntee 2010-04-03 22:48:19

+0

您不要将它们添加到项目中,那些是运行时库。 README.txt文件指出,您必须将它们安装到运行时安全文件夹(覆盖那里的文件) 如果您使用JDK,则:/ path/to/jdk/jre/libs/security/ 如果您使用JRE :/ path/to/jre/libs/security/ – 2010-04-06 23:46:30

+0

这是否解决了您的问题? – 2010-05-09 23:18:50

-1

当我把下面的代码并运行它,我没有收到任何例外:

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); 
    } 
} 

我从来没有能够重新创建你有例外。我正在运行J2SE 1.6并在Eclipse上开发。

难道你的密码不是16字节长吗?

+0

密码不是关键。用户正确使用基于密码的密钥推导函数(PBKDF)。您已删除必需的保护。提示:存在'GeneralSecurityException'这样的事情,通常情况下,您要么将其抛出到您的方法中,要么您创建运行时异常(例如,如果找不到算法,则为“IllegalStateException”)。 – 2014-01-05 16:57:23

+0

我没有删除任何保护。 encrypt()方法调用getSecretKey(),它调用PBEKeySpec(),就像OP在其原始代码中一样。 – Chopstick 2014-01-05 18:01:49

2

您可以按照几个其他类似问题的建议来安装JCE Unlimited Strength jars,或者尝试在主函数或驱动程序中包含此代码。

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(); 
} 
+0

在java 8中不起作用 – 2016-05-18 22:10:16

2

这里的问题是密钥导出函数和给定密码的密钥大小不匹配。您使用的PBKDF是"PBEWithMD5AndDES",在此字符串中,DES部分指示输出的类型。由于众所周知,单个DES仅使用8个字节的密钥(64位,56个有效位大小和奇偶校验位)。 AES密钥应该是128,192和256位,不应该包含奇偶校验位。

要创建AES强度密钥大小,至少应该使用PBKDF2而不是PBKDF1,最好使用SHA-256或SHA-512来获得更高的密钥大小。对于128位密钥,您应该可以使用SHA-1。因此请使用"PBKDF2WithHmacSHA1"SecretKeyFactory中的内部版本。请注意,键值超过160位的PBKDF2/SHA1将导致操作不理想。如果您想创建更多数据(例如单独的IV),您可能希望在输出上使用基于密钥的简单密钥导出函数(KBKDF)。

正如其他人所指出的,如果您使用超过128位的密钥,您将需要无限加密权限文件。以下代码


注:

  • 没有完整性保护,你可能甚至需要使用零IV保持机密
  • CBC,这可能是确定的,但只有在盐完全随机(用密文存储盐)
  • 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); 
}