错误的原因是什么;java.security.InvalidKeyException:缺少参数“;?

错误的原因是什么;java.security.InvalidKeyException:缺少参数“;?,java,aes,encryption,Java,Aes,Encryption,我正在尝试使用AES加密和解密字符串,但遇到了一个错误,我不知道如何解决。代码如下: public class EncryptionTest{ public static void main(String[] args) { String encrypt = new String(encrypt("1234567890123456")); System.out.println("decrypted value:" + (decrypt("ThisIsASecre

我正在尝试使用AES加密和解密字符串,但遇到了一个错误,我不知道如何解决。代码如下:

public class EncryptionTest{

public static void main(String[] args) {        
    String encrypt = new String(encrypt("1234567890123456"));
    System.out.println("decrypted value:" + (decrypt("ThisIsASecretKey",encrypt)));
}

public static String encrypt(String value) {
    try {
        byte[] raw = new byte[]{'T', 'h', 'i', 's', 'I', 's', 'A', 'S', 'e', 'c', 'r', 'e', 't', 'K', 'e', 'y'};
        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
        byte[] encrypted = cipher.doFinal(value.getBytes());
        System.out.println("encrypted string:" + (new String(encrypted)));
        return new String(skeySpec.getEncoded());
    } catch (Exception ex) {
        ex.printStackTrace();
    }
    return null;
}

public static String decrypt(String key, String encrypted) {
    try {
        SecretKeySpec skeySpec = new SecretKeySpec(Base64.decodeBase64(key), "AES");
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(skeySpec.getEncoded(),"AES"));
            (*)
        byte[] original = cipher.doFinal(Base64.decodeBase64(encrypted));
        original.toString();
    } catch (Exception ex) {
        ex.printStackTrace();
    }
    return null;
}  
}
当我运行它时,“描述”值为空。它在(***)之前失败

这给了我一个例外:

java.security.InvalidKeyException: Parameters missing at com.sun.crypto.provider.CipherCore.init(CipherCore.java:388) at com.sun.crypto.provider.AESCipher.engineInit(AESCipher.java:186) at javax.crypto.Cipher.implInit(Cipher.java:787) at javax.crypto.Cipher.chooseProvider(Cipher.java:849) at javax.crypto.Cipher.init(Cipher.java:1213) at javax.crypto.Cipher.init(Cipher.java:1153) at firma.XmlEncryptionTest.decrypt(EncryptionTest.java:63) at firma.XmlEncryptionTest.main(EncryptionTest.java:41) java.security.InvalidKeyException:缺少参数 位于com.sun.crypto.provider.CipherCore.init(CipherCore.java:388) 位于com.sun.crypto.provider.aesciper.engineInit(aesciper.java:186) 位于javax.crypto.Cipher.implInit(Cipher.java:787) 在javax.crypto.Cipher.chooseProvider(Cipher.java:849) 位于javax.crypto.Cipher.init(Cipher.java:1213) 位于javax.crypto.Cipher.init(Cipher.java:1153) 在firma.XmlEncryptionTest.decrypt(EncryptionTest.java:63) 在firma.XmlEncryptionTest.main(EncryptionTest.java:41)
其中第63行是(***)前面的一行。我不知道我做错了什么,也不知道如何解决。我在互联网上四处查看,但没有找到丢失的参数可能是什么,代码中的主要问题是由于未能指定IV值而导致的。在执行CBC模式加密时必须指定IV值,并在执行CBC模式解密时使用相同的值

另一个问题是从字节数组和base64编码创建字符串的混合和匹配。每次从解密方法返回
null
。即使您的意思是
返回original.toString()
,这仍然是错误的(因为
toString()
在字节数组上做不到您希望的事情)

下面是代码的改进版本。这远不是最优的,但它可以编译并工作。您需要改进这一点,以使用随机IV。此外,如果您计划从密码派生密钥,而不仅仅是获取字节,请使用派生函数,如PBKDF2。您可以在中看到使用PBKDF2的示例


如果使用像CBC这样的块链接模式,那么还需要为密码提供IvParameterSpec

public class EncryptionTest {

static byte[] raw = new byte[]{'T', 'h', 'i', 's', 'I', 's', 'A', 'S', 'e', 'c', 'r', 'e', 't', 'K', 'e', 'y'};

static SecureRandom rnd = new SecureRandom();

static IvParameterSpec iv = new IvParameterSpec(rnd.generateSeed(16));

public static void main(String[] args) {
    String encrypt = encrypt("1234567890123456");
    System.out.println("decrypted value:" + (decrypt("ThisIsASecretKey", encrypt)));
}

public static String encrypt(String value) {
    try {

        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec,iv);
        byte[] encrypted = cipher.doFinal(value.getBytes());
        System.out.println("encrypted string:" + Base64.encodeBase64String(encrypted));
        return Base64.encodeBase64String(encrypted);
    } catch (Exception ex) {
        ex.printStackTrace();
    }
    return null;
}

public static String decrypt(String key, String encrypted) {
    try {
        SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes(), "AES");
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
        cipher.init(Cipher.DECRYPT_MODE, skeySpec,iv);
        byte[] original = cipher.doFinal(Base64.decodeBase64(encrypted));

        return new String(original);
    } catch (Exception ex) {
        ex.printStackTrace();
    }
    return null;
}

}

尽管为时已晚,但我仍在为其他人提供解决方案。请参阅下面的工作代码以加密和解密数据

public static byte[] encrypt(String value) {
        byte[] encrypted = null;
        try {

            byte[] raw = new byte[]{'T', 'h', 'i', 's', 'I', 's', 'A', 'S', 'e', 'c', 'r', 'e', 't', 'K', 'e', 'y'};
            Key skeySpec = new SecretKeySpec(raw, "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            byte[] iv = new byte[cipher.getBlockSize()];

            IvParameterSpec ivParams = new IvParameterSpec(iv);
            cipher.init(Cipher.ENCRYPT_MODE, skeySpec,ivParams);
            encrypted  = cipher.doFinal(value.getBytes());
            System.out.println("encrypted string:" + encrypted.length);

        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return encrypted;
    }

    public static  byte[]  decrypt(byte[] encrypted) {
         byte[] original = null;
         Cipher cipher = null;
        try {
            byte[] raw = new byte[]{'T', 'h', 'i', 's', 'I', 's', 'A', 'S', 'e', 'c', 'r', 'e', 't', 'K', 'e', 'y'};
            Key key = new SecretKeySpec(raw, "AES");
            cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            //the block size (in bytes), or 0 if the underlying algorithm is not a block cipher
            byte[] ivByte = new byte[cipher.getBlockSize()];
            //This class specifies an initialization vector (IV). Examples which use
            //IVs are ciphers in feedback mode, e.g., DES in CBC mode and RSA ciphers with OAEP encoding operation.
            IvParameterSpec ivParamsSpec = new IvParameterSpec(ivByte);
            cipher.init(Cipher.DECRYPT_MODE, key, ivParamsSpec);
            original= cipher.doFinal(encrypted);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return original;
    }  

您正在为密码使用两个不同的init()。。。尝试使用相同的。是的,这部分
newsecretkeyspec(skeySpec.getEncoded(),“AES”)
看起来很奇怪-为什么不直接使用
skeySpec
?@DuncanJones,如果我用“skeySpec”代替“newsecretkeyspec(skeySpec.getEncoded(),“AES”)”,我会得到一个新错误:无效的AES密钥长度:12字节,在同一行…@Shark我使用了相同的init()对于两个密码“cipher.init(cipher.DECRYPT_MODE,skeySpec);”我得到了一个例外:无效的AES密钥长度:12字节它不一样。。。查看是否创建了随机或零IV(如果有)取决于特定的JCE提供程序。明智的做法是不使用提供程序默认值,而是始终为需要的模式提供IV。出于同样的原因,您应该始终明确请求正确的分组密码模式和填充模式。您写道“在进行CBC模式加密时必须指定一个IV值,并在执行CBC模式解密时使用相同的值。”然后是“您需要改进以使用随机IV”。问题:如果我需要相同的IV进行解密,如何使用“随机”值?@user999999 IV不是一个敏感值,因此您通常使用密文存储/发送它。Hello@simpleuser,因为
IV
需要匹配,那么一种方法是让每一方都有一个可能的
IV
值列表,然后双方必须就一个索引达成一致,以决定使用哪个
IV
。此索引必须在通信的初始握手期间进行通信。感谢您的解决方案!它起作用了,帮了我的忙:D
public static byte[] encrypt(String value) {
        byte[] encrypted = null;
        try {

            byte[] raw = new byte[]{'T', 'h', 'i', 's', 'I', 's', 'A', 'S', 'e', 'c', 'r', 'e', 't', 'K', 'e', 'y'};
            Key skeySpec = new SecretKeySpec(raw, "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            byte[] iv = new byte[cipher.getBlockSize()];

            IvParameterSpec ivParams = new IvParameterSpec(iv);
            cipher.init(Cipher.ENCRYPT_MODE, skeySpec,ivParams);
            encrypted  = cipher.doFinal(value.getBytes());
            System.out.println("encrypted string:" + encrypted.length);

        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return encrypted;
    }

    public static  byte[]  decrypt(byte[] encrypted) {
         byte[] original = null;
         Cipher cipher = null;
        try {
            byte[] raw = new byte[]{'T', 'h', 'i', 's', 'I', 's', 'A', 'S', 'e', 'c', 'r', 'e', 't', 'K', 'e', 'y'};
            Key key = new SecretKeySpec(raw, "AES");
            cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            //the block size (in bytes), or 0 if the underlying algorithm is not a block cipher
            byte[] ivByte = new byte[cipher.getBlockSize()];
            //This class specifies an initialization vector (IV). Examples which use
            //IVs are ciphers in feedback mode, e.g., DES in CBC mode and RSA ciphers with OAEP encoding operation.
            IvParameterSpec ivParamsSpec = new IvParameterSpec(ivByte);
            cipher.init(Cipher.DECRYPT_MODE, key, ivParamsSpec);
            original= cipher.doFinal(encrypted);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return original;
    }