javax.crypto。IllegalBlockSizeException:输入长度必须是16的倍数,当使用padd密码解密时[复制]

时间:2023-01-13 18:33:07

This question already has an answer here:

这个问题已经有了答案:

I'm getting a decrypting error in java class:

我在java类中得到了一个解密错误:

javax.crypto.IllegalBlockSizeException : 
    Input length must be multiple of 16 when decrypting with padded cipher.

What can I do to solve this problem?

我能做些什么来解决这个问题呢?

UPDATE:

更新:

I forgot to mention it is working once and when the second time im trying to execute it again its throwing the above mentioned error.

我忘记提到它是工作一次,当第二次我试图执行它时,它抛出上面提到的错误。

package com.tb.module.service;
import java.security.Key;
import java.security.spec.InvalidKeySpecException;

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

import sun.misc.*;

/**
 * This class is used for encrypt and decrypt the  password field.
 *
 */
public class PswdEnc {

    private static final String ALGO = "AES";
    private static final byte[] keyValue = new byte[] { 'T', 'h', 'e', 'B', 'e', 's', 't','S', 'e', 'c', 'r','e', 't', 'K', 'e', 'y' };

    public static String encrypt(String Data) throws Exception {
        Key key = generateKey();
        Cipher c = Cipher.getInstance(ALGO);
        c.init(Cipher.ENCRYPT_MODE, key);
        byte[] encVal = c.doFinal(Data.getBytes());
        String encryptedValue = new BASE64Encoder().encode(encVal);
        return encryptedValue;
    }

    public static String decrypt(String encryptedData) throws Exception {
        Key key = generateKey(); 
        Cipher c = Cipher.getInstance(ALGO);
        c.init(Cipher.DECRYPT_MODE, key);
        byte[] decordedValue = new BASE64Decoder().decodeBuffer(encryptedData);
        byte[] decValue = c.doFinal(decordedValue);
        String decryptedValue = new String(decValue);
        return decryptedValue;
    }


    private static Key generateKey() throws Exception {
        Key key = new SecretKeySpec(keyValue, ALGO);
        return key;
    }

}

4 个解决方案

#1


58  

The algorithm you are using, "AES", is a shorthand for "AES/ECB/NoPadding". What this means is that you are using the AES algorithm with 128-bit key size and block size, with the ECB mode of operation and no padding.

你所使用的算法“AES”是“AES/ECB/ nopadd”的简写。这意味着您使用的AES算法具有128位密钥大小和块大小,使用欧洲央行的操作模式和不填充。

In other words: you are only able to encrypt data in blocks of 128 bits or 16 bytes. That's why you are getting that IllegalBlockSizeException exception.

换句话说:您只能以128位或16字节的块加密数据。这就是为什么你会得到IllegalBlockSizeException异常。

If you want to encrypt data in sizes that are not multiple of 16 bytes, you are either going to have to use some kind of padding, or a cipher-stream. For instance, you could use CBC mode (a mode of operation that effectively transforms a block cipher into a stream cipher) by specifying "AES/CBC/NoPadding" as the algorithm, or PKCS5 padding by specifying "AES/ECB/PKCS5", which will automatically add some bytes at the end of your data in a very specific format to make the size of the ciphertext multiple of 16 bytes, and in a way that the decryption algorithm will understand that it has to ignore some data.

如果您想要加密的数据大小不是16字节的倍数,那么您要么必须使用某种填充,要么使用cipher-stream。例如,您可以使用CBC模式(一种操作方式,有效地将一块密码转换成密文流)通过指定“AES / CBC / NoPadding”算法,或者PKCS5填充通过指定“AES /欧洲/ PKCS5”,将自动添加一些字节的数据在一个特定的格式进行密文的大小16字节的倍数,并以一种加密算法将明白,忽略一些数据。

In any case, I strongly suggest that you stop right now what you are doing and go study some very introductory material on cryptography. For instance, check Crypto I on Coursera. You should understand very well the implications of choosing one mode or another, what are their strengths and, most importantly, their weaknesses. Without this knowledge, it is very easy to build systems which are very easy to break.

无论如何,我强烈建议你现在停止你正在做的事情,去学习一些关于密码学的入门材料。例如,在Coursera上检查密码。你应该很清楚地理解选择一种模式或另一种模式的意义,他们的长处是什么,最重要的是他们的弱点。如果没有这些知识,构建非常容易中断的系统是非常容易的。


Update: based on your comments on the question, don't ever encrypt passwords when storing them at a database!!!!! You should never, ever do this. You must HASH the passwords, properly salted, which is completely different from encrypting. Really, please, don't do what you are trying to do... By encrypting the passwords, they can be decrypted. What this means is that you, as the database manager and who knows the secret key, you will be able to read every password stored in your database. Either you knew this and are doing something very, very bad, or you didn't know this, and should get shocked and stop it.

更新:基于你对这个问题的评论,不要在把密码储存在一个数据库时加密!!!!!你永远不应该这样做。您必须对密码进行哈希处理,适当地加盐,这与加密完全不同。真的,拜托,不要做你想做的……通过对密码进行加密,它们可以被解密。这意味着,作为数据库管理器,并且知道密钥,您将能够读取存储在数据库中的每个密码。要么你知道这些,要么做一些非常非常糟糕的事情,或者你不知道这些,你应该感到震惊并停止它。

#2


2  

A few comments:

一些评论:

import sun.misc.*; Don't do this. It is non-standard and not guaranteed to be the same between implementations. There are other libraries with Base64 conversion available.

进口sun.misc。*;不要这样做。它是非标准的,在实现之间不保证是相同的。还有其他库,有Base64转换可用。

byte[] encVal = c.doFinal(Data.getBytes()); You are relying on the default character encoding here. Always specify what character encoding you are using: byte[] encVal = c.doFinal(Data.getBytes("UTF-8")); Defaults might be different in different places.

byte[]encVal = c.doFinal(Data.getBytes());您需要依赖这里的默认字符编码。始终指定使用的字符编码:byte[] encVal = c.doFinal(Data.getBytes("UTF-8"));不同地方的默认值可能不同。

As @thegrinner pointed out, you need to explicitly check the length of your byte arrays. If there is a discrepancy, then compare them byte by byte to see where the difference is creeping in.

正如@thegrinner所指出的,您需要显式地检查字节数组的长度。如果存在差异,那么将它们按字节进行比较,看看差异在哪里。

#3


2  

To solve problem few changes you have to do in your code just make return type of encrypt() API of your class is byte[] array and in decrypt() API of your class pass byte[] array so by doing this you can solve input length multiple of 16 exception.

为了解决问题,你必须在代码中做一些修改,只需要在你的类中使用加密()的返回类型,你的类是byte[]数组,在解密()的API中,你可以通过这样做,你可以解决16个异常的输入长度倍数。

Please refer below working code :

请参阅以下工作守则:

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

#4


0  

Well that is Because of

那是因为。

you are only able to encrypt data in blocks of 128 bits or 16 bytes. That's why you are getting that IllegalBlockSizeException exception. and the one way is to encrypt that data Directly into the String.

您只能以128位或16字节的块加密数据。这就是为什么你会得到IllegalBlockSizeException异常。一种方法是将数据直接加密到字符串中。

look this. Try and u will be able to resolve this

看这个。你可以试着解决这个问题。

public static String decrypt(String encryptedData) throws Exception {

    Key key = generateKey();
    Cipher c = Cipher.getInstance(ALGO);
    c.init(Cipher.DECRYPT_MODE, key);
    String decordedValue = new BASE64Decoder().decodeBuffer(encryptedData).toString().trim();
    System.out.println("This is Data to be Decrypted" + decordedValue);
    return decordedValue;
}

hope that will help.

希望会有所帮助。

#1


58  

The algorithm you are using, "AES", is a shorthand for "AES/ECB/NoPadding". What this means is that you are using the AES algorithm with 128-bit key size and block size, with the ECB mode of operation and no padding.

你所使用的算法“AES”是“AES/ECB/ nopadd”的简写。这意味着您使用的AES算法具有128位密钥大小和块大小,使用欧洲央行的操作模式和不填充。

In other words: you are only able to encrypt data in blocks of 128 bits or 16 bytes. That's why you are getting that IllegalBlockSizeException exception.

换句话说:您只能以128位或16字节的块加密数据。这就是为什么你会得到IllegalBlockSizeException异常。

If you want to encrypt data in sizes that are not multiple of 16 bytes, you are either going to have to use some kind of padding, or a cipher-stream. For instance, you could use CBC mode (a mode of operation that effectively transforms a block cipher into a stream cipher) by specifying "AES/CBC/NoPadding" as the algorithm, or PKCS5 padding by specifying "AES/ECB/PKCS5", which will automatically add some bytes at the end of your data in a very specific format to make the size of the ciphertext multiple of 16 bytes, and in a way that the decryption algorithm will understand that it has to ignore some data.

如果您想要加密的数据大小不是16字节的倍数,那么您要么必须使用某种填充,要么使用cipher-stream。例如,您可以使用CBC模式(一种操作方式,有效地将一块密码转换成密文流)通过指定“AES / CBC / NoPadding”算法,或者PKCS5填充通过指定“AES /欧洲/ PKCS5”,将自动添加一些字节的数据在一个特定的格式进行密文的大小16字节的倍数,并以一种加密算法将明白,忽略一些数据。

In any case, I strongly suggest that you stop right now what you are doing and go study some very introductory material on cryptography. For instance, check Crypto I on Coursera. You should understand very well the implications of choosing one mode or another, what are their strengths and, most importantly, their weaknesses. Without this knowledge, it is very easy to build systems which are very easy to break.

无论如何,我强烈建议你现在停止你正在做的事情,去学习一些关于密码学的入门材料。例如,在Coursera上检查密码。你应该很清楚地理解选择一种模式或另一种模式的意义,他们的长处是什么,最重要的是他们的弱点。如果没有这些知识,构建非常容易中断的系统是非常容易的。


Update: based on your comments on the question, don't ever encrypt passwords when storing them at a database!!!!! You should never, ever do this. You must HASH the passwords, properly salted, which is completely different from encrypting. Really, please, don't do what you are trying to do... By encrypting the passwords, they can be decrypted. What this means is that you, as the database manager and who knows the secret key, you will be able to read every password stored in your database. Either you knew this and are doing something very, very bad, or you didn't know this, and should get shocked and stop it.

更新:基于你对这个问题的评论,不要在把密码储存在一个数据库时加密!!!!!你永远不应该这样做。您必须对密码进行哈希处理,适当地加盐,这与加密完全不同。真的,拜托,不要做你想做的……通过对密码进行加密,它们可以被解密。这意味着,作为数据库管理器,并且知道密钥,您将能够读取存储在数据库中的每个密码。要么你知道这些,要么做一些非常非常糟糕的事情,或者你不知道这些,你应该感到震惊并停止它。

#2


2  

A few comments:

一些评论:

import sun.misc.*; Don't do this. It is non-standard and not guaranteed to be the same between implementations. There are other libraries with Base64 conversion available.

进口sun.misc。*;不要这样做。它是非标准的,在实现之间不保证是相同的。还有其他库,有Base64转换可用。

byte[] encVal = c.doFinal(Data.getBytes()); You are relying on the default character encoding here. Always specify what character encoding you are using: byte[] encVal = c.doFinal(Data.getBytes("UTF-8")); Defaults might be different in different places.

byte[]encVal = c.doFinal(Data.getBytes());您需要依赖这里的默认字符编码。始终指定使用的字符编码:byte[] encVal = c.doFinal(Data.getBytes("UTF-8"));不同地方的默认值可能不同。

As @thegrinner pointed out, you need to explicitly check the length of your byte arrays. If there is a discrepancy, then compare them byte by byte to see where the difference is creeping in.

正如@thegrinner所指出的,您需要显式地检查字节数组的长度。如果存在差异,那么将它们按字节进行比较,看看差异在哪里。

#3


2  

To solve problem few changes you have to do in your code just make return type of encrypt() API of your class is byte[] array and in decrypt() API of your class pass byte[] array so by doing this you can solve input length multiple of 16 exception.

为了解决问题,你必须在代码中做一些修改,只需要在你的类中使用加密()的返回类型,你的类是byte[]数组,在解密()的API中,你可以通过这样做,你可以解决16个异常的输入长度倍数。

Please refer below working code :

请参阅以下工作守则:

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

#4


0  

Well that is Because of

那是因为。

you are only able to encrypt data in blocks of 128 bits or 16 bytes. That's why you are getting that IllegalBlockSizeException exception. and the one way is to encrypt that data Directly into the String.

您只能以128位或16字节的块加密数据。这就是为什么你会得到IllegalBlockSizeException异常。一种方法是将数据直接加密到字符串中。

look this. Try and u will be able to resolve this

看这个。你可以试着解决这个问题。

public static String decrypt(String encryptedData) throws Exception {

    Key key = generateKey();
    Cipher c = Cipher.getInstance(ALGO);
    c.init(Cipher.DECRYPT_MODE, key);
    String decordedValue = new BASE64Decoder().decodeBuffer(encryptedData).toString().trim();
    System.out.println("This is Data to be Decrypted" + decordedValue);
    return decordedValue;
}

hope that will help.

希望会有所帮助。