javax.crypto.IllegalBlockSizeException:输入长度不是16个字节的倍数

时间:2021-03-12 18:35:27

I have an ArrayList which contains some objects. Object is a container for login/pass.
I try to decode them because i have to serialize them into local file for recreation after another launch.
Problem is during encryption I recieve

我有一个包含一些对象的ArrayList。 Object是登录/传递的容器。我尝试解码它们,因为我必须在另一次启动后将它们序列化为本地文件以进行娱乐。问题是我收到的加密过程中

javax.crypto.IllegalBlockSizeException: Input length not multiple of 16 bytes
    at com.sun.crypto.provider.CipherCore.finalNoPadding(CipherCore.java:1039)
    at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:983)
    at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:845)
    at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:446)

And I completely don't understand why. In my opinion Base64 should deal with this. But maybe I don't understand properly its meaning.
I use to encrypt/deccode

我完全不明白为什么。在我看来,Base64应该处理这个问题。但也许我不明白它的含义。我用来加密/解码

public class Move
{
    private static Move instance;

    String key = "pT5IkWNR90gJo5YM";
    String initVector = "RandomInitVector";
    Cipher cipher;


    private Move()
    {
//      try
//      {
//          cipher = Cipher.getInstance("AES/CBC/NoPadding");
//      }
//      catch (NoSuchAlgorithmException | NoSuchPaddingException e)
//      {
//          e.printStackTrace();
//      }
    }


    public void saveData(ArrayList<Account> dataToSave)
    {
        try
        {
            FileOutputStream fileOut = new FileOutputStream(Config.SERIAL_FILE);
            ObjectOutputStream out = new ObjectOutputStream(fileOut);
            out.writeObject(encrypt(dataToSave));
            out.close();
            fileOut.close();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }


    @SuppressWarnings("unchecked")
    public ArrayList<Account> loadData()
    {
        ArrayList<Account> loadedData = new ArrayList<Account>();
        File f = new File(Config.SERIAL_FILE);
        if (f.exists())
        {
            try
            {
                FileInputStream fileIn = new FileInputStream(Config.SERIAL_FILE);
                ObjectInputStream in = new ObjectInputStream(fileIn);
                loadedData = (ArrayList<Account>) in.readObject();
                in.close();
                fileIn.close();
            }
            catch (IOException | ClassNotFoundException e)
            {
                e.printStackTrace();
            }
            loadedData = decrypt(loadedData);
        }
        else
        {
            loadedData = new ArrayList<Account>();
        }
        return loadedData;
    }


    private ArrayList<Account> encrypt(List<Account> decrypted)
    {
        ArrayList<Account> encrypted = new ArrayList<Account>();

        try
        {
            IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));
            SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
            cipher = Cipher.getInstance("AES/CBC/NoPadding");
            cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
            for (int i = 0; i < decrypted.size(); i++)
            {
                try
                {
                    byte[] login = cipher.doFinal(Base64.getDecoder().decode(decrypted.get(i).getLogin().getBytes()));
                    encrypted.add(new Account(login.toString(), "pass"));
                }
                catch (Exception ex)
                {
                    ex.printStackTrace();
                }
            }
        }
        catch (InvalidKeyException | InvalidAlgorithmParameterException | UnsupportedEncodingException | NoSuchAlgorithmException | NoSuchPaddingException e)
        {
            e.printStackTrace();
        }
        return encrypted;
    }


    private ArrayList<Account> decrypt(List<Account> encrypted)
    {
        ArrayList<Account> decrypted = new ArrayList<Account>();

        try
        {
            SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
            IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));
            cipher = Cipher.getInstance("AES/CBC/NoPadding");
            cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);

            for (int i = 0; i < encrypted.size(); i++)
            {
                byte[] login = cipher.doFinal(Base64.getDecoder().decode(encrypted.get(i).getLogin()));
                decrypted.add(new Account(new String(login), "pass"));
            }
        }
        catch (InvalidKeyException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException | UnsupportedEncodingException | NoSuchAlgorithmException | NoSuchPaddingException e)
        {
            e.printStackTrace();
        }
        return decrypted;
    }


    public static Move getMove()
    {
        if (instance == null)
        {
            instance = new Move();
        }
        return instance;
    }
}

1 个解决方案

#1


2  

AES block size is always 128bit, it must receive input in multiples of this number.

AES块大小始终为128位,它必须以此数字的倍数接收输入。

Smaller input must be padded to 16 bytes, and the type of padding specified to the algorithm.

较小的输入必须填充到16个字节,以及为算法指定的填充类型。

Using "AES/CBC/PKCS5Padding" will do the trick.

使用“AES / CBC / PKCS5Padding”就可以了。

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

If you use NoPadding, then you must implement your own padding for encryption, and make sure to remove it from the resulting string in decryption.

如果使用NoPadding,则必须实现自己的填充以进行加密,并确保在解密时将其从生成的字符串中删除。

#1


2  

AES block size is always 128bit, it must receive input in multiples of this number.

AES块大小始终为128位,它必须以此数字的倍数接收输入。

Smaller input must be padded to 16 bytes, and the type of padding specified to the algorithm.

较小的输入必须填充到16个字节,以及为算法指定的填充类型。

Using "AES/CBC/PKCS5Padding" will do the trick.

使用“AES / CBC / PKCS5Padding”就可以了。

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

If you use NoPadding, then you must implement your own padding for encryption, and make sure to remove it from the resulting string in decryption.

如果使用NoPadding,则必须实现自己的填充以进行加密,并确保在解密时将其从生成的字符串中删除。