Java 解密字符串会生成IllegalBlockSizeException

Java 解密字符串会生成IllegalBlockSizeException,java,encryption,cryptography,Java,Encryption,Cryptography,我在处理解密方法时遇到问题。加密产生正确的输出,但当我解密完全相同的加密字符串时(应该返回到纯文本字符串),它不起作用 import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; public class Samp { private static String IV = "aaaaaaaaaaaaaaaa"; pri

我在处理解密方法时遇到问题。加密产生正确的输出,但当我解密完全相同的加密字符串时(应该返回到纯文本字符串),它不起作用

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class Samp {

    private static String IV = "aaaaaaaaaaaaaaaa";
    private static final String UNICODE_FORMAT = "UTF8";

    private String padd(String plaintext) {
        while (plaintext.length() % 16 != 0) {
            plaintext += "\0";
        }
        return plaintext;
    }

    public String encryptString(String plaintext, String encryptionKey) {
        try {
            byte[] cipher = encrypt(padd(plaintext), encryptionKey);
            return new String(cipher, UNICODE_FORMAT);
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        return null;
    }

    public String decryptString(String encString, String encryptionKey) {
        try {
            System.out.println("**** decryptString ****");
            System.out.println("enc = " + encString);
            System.out.println("key = " + encryptionKey);

            String decrypted = decrypt(encString.getBytes(UNICODE_FORMAT), encryptionKey);
            return decrypted;
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        return null;
    }

    private static byte[] encrypt(String plainText, String encryptionKey) throws Exception {
        Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding", "SunJCE");
        SecretKeySpec key = new SecretKeySpec(encryptionKey.getBytes(UNICODE_FORMAT), "AES");
        cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(IV.getBytes(UNICODE_FORMAT)));
        return cipher.doFinal(plainText.getBytes(UNICODE_FORMAT));
    }

    private static String decrypt(byte[] cipherText, String encryptionKey) throws Exception {
        Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding", "SunJCE");
        SecretKeySpec key = new SecretKeySpec(encryptionKey.getBytes(UNICODE_FORMAT), "AES");
        cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(IV.getBytes(UNICODE_FORMAT)));
        return new String(cipher.doFinal(cipherText), UNICODE_FORMAT);
    }
    // implement methods here
    // using AES simple encryption

    public static void main(String[] args){
        String plaintext = "Hello World!";
        String key = "asdfqaqwsaerdqsw";

        Samp s = new Samp();
        String enc = s.encryptString(plaintext, key);
        System.out.println("encrypted string = " + enc);
        String dec = s.decryptString(enc, key);
        System.out.println("decrypted string = " + dec);
    }
}

我已经看过了,它和我的问题一样。我遵循了建议(更改getBytes()->getBytes(UNICODE_格式)),但仍然是一样的。我仍然得到一个异常(javax.crypto.IllegalBlockSizeException:输入长度不是16字节的倍数)

这是我的代码

public static String encrypt(String data) throws Exception {

        SecretKeySpec key = generateKey();
        final Cipher c = Cipher.getInstance("AES/EAX/NoPadding", "BC");

        c.init(Cipher.ENCRYPT_MODE, key, ivSpec);

        byte[] encVal = c.doFinal(data.getBytes("UTF8"));       

        String encryptedValue = Hex.toHexString(encVal);
        return encryptedValue;
    }

    public static String decrypt(String encryptedData) throws Exception {

        Key key = generateKey();
        final Cipher c = Cipher.getInstance("AES/EAX/NoPadding", "BC");

        c.init(Cipher.DECRYPT_MODE, key, ivSpec);
        byte[] ba = Hex.decode(encryptedData);

        byte[] encVal = c.doFinal(ba);  

        return new String (encVal);

    }

这是我的代码

public static String encrypt(String data) throws Exception {

        SecretKeySpec key = generateKey();
        final Cipher c = Cipher.getInstance("AES/EAX/NoPadding", "BC");

        c.init(Cipher.ENCRYPT_MODE, key, ivSpec);

        byte[] encVal = c.doFinal(data.getBytes("UTF8"));       

        String encryptedValue = Hex.toHexString(encVal);
        return encryptedValue;
    }

    public static String decrypt(String encryptedData) throws Exception {

        Key key = generateKey();
        final Cipher c = Cipher.getInstance("AES/EAX/NoPadding", "BC");

        c.init(Cipher.DECRYPT_MODE, key, ivSpec);
        byte[] ba = Hex.decode(encryptedData);

        byte[] encVal = c.doFinal(ba);  

        return new String (encVal);

    }

您应该使用字符和字节之间1对1映射的编码,例如“ISO-8859-1”。所以把你的代码改成

private static final String UNICODE_FORMAT = "ISO-8859-1";

解决了这个问题。

您应该使用字符和字节之间1:1映射的编码,例如“ISO-8859-1”。所以把你的代码改成

private static final String UNICODE_FORMAT = "ISO-8859-1";
  public String encryptString(String plaintext, String encryptionKey)
解决了这个问题

  public String encryptString(String plaintext, String encryptionKey)
问题就在这里。字符串不是二进制数据的容器。此方法应返回一个字节[]。类似地,decrypt()方法应该将byte[]作为密文参数,而不是字符串


问题就在这里。字符串不是二进制数据的容器。此方法应返回一个字节[]。类似地,decrypt()方法应该将byte[]作为密文参数,而不是字符串。

如果使用
NoPadding
算法,为什么要在
padd
中填充到16个字节,如果我不填充,那么效果不好,所以我决定填充纯文本,它起作用了注意,用零字符填充是不明确的:在解密时,没有办法分辨尾随的零是原始字符串的一部分还是填充的一部分。是的,我也注意到了这一点。您认为@JeffreyHantin的建议是明确的:填充由n个尾随字节组成,所有值均为n。如果您使用的是
NoPadding
算法,为什么要在
padd
中填充到16个字节,如果我不填充,则效果不好,所以我决定填充纯文本,它起作用了注意,用零字符填充是不明确的:在解密时,没有办法分辨尾随的零是原始字符串的一部分还是填充的一部分。是的,我也注意到了这一点。您认为@JeffreyHantin的建议是明确的:填充由n个尾随字节组成,所有值均为n.nice!!它解决了问题,但如何解决?你能解释一下吗?用纯文本来表示加密的数据是完全错误的。加密数据可以并将包含0到255之间的所有字节值,这些字节值并非都是可打印字符。您必须使用十六进制或Base64编码,而不是简单地将字节数组转换为字符串。@OlegEstekhin感谢您指出这一点。OP无论如何都会这么做,我无意改变他处理加密数据的方式。出于学习或练习的目的,我认为这没关系。@krato您需要1对1映射编码,因此
encString.getBytes(UNICODE\u格式)
为您提供正确的密码nice!!它解决了问题,但如何解决?你能解释一下吗?用纯文本来表示加密的数据是完全错误的。加密数据可以并将包含0到255之间的所有字节值,这些字节值并非都是可打印字符。您必须使用十六进制或Base64编码,而不是简单地将字节数组转换为字符串。@OlegEstekhin感谢您指出这一点。OP无论如何都会这么做,我无意改变他处理加密数据的方式。出于学习或练习的目的,我认为这是可以的。@krato您需要1对1映射编码,因此
encString.getBytes(UNICODE\u格式)
为您提供正确的cipher@ScaryWombat或者不对字节进行编码,完全消除出现问题的机会,并通过以后不知情的修补完全防止问题再次发生,首先正确地设计方法签名。@ScaryWombat或don't encoded the bytes,并完全消除问题发生的机会,然后通过在第一位置正确地设计方法签名,通过不知情的修补完全防止问题再次发生。