【问题标题】:javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipherjavax.crypto.IllegalBlockSizeException:使用填充密码解密时,输入长度必须是 16 的倍数
【发布时间】:2016-11-07 06:40:44
【问题描述】:

我正在做一个加密项目,该项目使用 AES 获取密钥和密码器,然后执行 base64。问题发生在将 base64 解密回 AES 和 AES 并返回到 String 时。下面的错误和代码

import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

import javax.crypto.*;
import javax.crypto.spec.*;

public class Criptografia {
    byte[] chave = "chave de 16bytes".getBytes();

    public String encriptaAES(String chaveCriptografada)
            throws InvalidKeyException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException {
        try {

            Cipher cipher = Cipher.getInstance("AES");
            byte[] mensagem = chaveCriptografada.getBytes();
            cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(chave, "AES"));
            chaveCriptografada = cipher.doFinal(mensagem).toString();



            chaveCriptografada  =Base64.getUrlEncoder().encodeToString(chaveCriptografada.getBytes("utf-8"));


        } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {

            e.printStackTrace();
        }

        return chaveCriptografada;

    }


    public String descriptografaAES(String chaveCriptografada) throws NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException{
        Cipher cipher = Cipher.getInstance("AES");

        byte[] base64decodedBytes = Base64.getUrlDecoder().decode(chaveCriptografada);

        chaveCriptografada= base64decodedBytes.toString();


         try {
            cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(this.chave, "AES"));
             byte[] decrypted = cipher.doFinal(chaveCriptografada.getBytes("UTF-8"));
             chaveCriptografada=decrypted.toString();

        } catch (InvalidKeyException e) {

            e.printStackTrace();
        }



        return chaveCriptografada;


    }   

}

Exception in thread "main" javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher
    at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:922)
    at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:833)
    at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:446)
    at javax.crypto.Cipher.doFinal(Cipher.java:2165)
    at Criptografia.descriptografaAES(Criptografia.java:47)
    at Run.main(Run.java:15)

【问题讨论】:

    标签: java base64 aes


    【解决方案1】:

    我正在与我的英语朋友分享我宝贵的加密课程。

    package Encriptacion;
    import javax.crypto.*;
    import java.io.*;
    import java.nio.*;
    import java.nio.channels.*;
    import javax.crypto.spec.*;
    public class EncriptadorAES {
        private SecretKey CLAVESECRETA=null;
        private final int AES_KEYLENGTH = 128;
        private IvParameterSpec IV=null;
        public EncriptadorAES() throws Exception{
            //generarIV();
            if(new File("initvectoraes.iv").exists()){
                this.IV=new IvParameterSpec(obtenerIV());
            }
        }
        public void setCLAVESECRETA(String clave){
            this.CLAVESECRETA=generarClaveSecreta(clave);
        }
        public void guardarClave(String clave,String ruta)throws Exception{
            try{
                byte[]bytesClave=generarClaveSecreta(clave).getEncoded();
                FileChannel canalSalida=new RandomAccessFile(new File(ruta), "rw").getChannel();
                ByteBuffer bufferSalida=ByteBuffer.wrap(bytesClave);
                canalSalida.write(bufferSalida);
                canalSalida.close();
            }catch(Exception ex){
                throw new Exception("No se pudo guardar la clave\n"+ex);
            }
        }
        public SecretKey cargarClave(String ruta)throws Exception{
            try{
                File archivo=new File(ruta);
                byte[]bytesClave=new byte[(int)archivo.length()];
                FileChannel canalEntrada=new RandomAccessFile(archivo, "r").getChannel();
                ByteBuffer bufferEntrada=ByteBuffer.allocate(bytesClave.length);
                canalEntrada.read(bufferEntrada);
                bufferEntrada.flip();
                bufferEntrada.get(bytesClave);
                canalEntrada.close();
                return new SecretKeySpec(bytesClave, "AES");
            }catch(Exception ex){
                throw new Exception("No se pudo cargar la clave secreta\n"+ex);
            }
        }
        public void encriptarArchivo(String ruta,SecretKey clave) throws Exception{
            File archivo=null;
            try {
                archivo=new File(ruta);
                if(archivo.isFile()&&archivo.exists()&&archivo.length()<=700248752){
                    //LECTURA
                    byte[] bytesArchivo=new byte[(int)archivo.length()];
                    int tamañoBloque=AES_KEYLENGTH/8;
                    int numBloques=((int)archivo.length()%tamañoBloque==0)?(int)archivo.length()/tamañoBloque:((int)archivo.length()/tamañoBloque)+1;
                    int tamañoEncriptado=((bytesArchivo.length/tamañoBloque)+1)*tamañoBloque;
                    FileChannel canalEntrada=new RandomAccessFile(archivo, "r").getChannel();
                    ByteBuffer bufferEntrada=ByteBuffer.allocate((int)archivo.length());
                    canalEntrada.read(bufferEntrada);
                    bufferEntrada.flip();
                    bufferEntrada.get(bytesArchivo);
                    canalEntrada.close();
                    //CIFRADO clave simétrica
                    ByteBuffer bufferSalida=ByteBuffer.allocate(tamañoEncriptado);
                    Cipher cifradorAES = Cipher.getInstance("AES/CBC/PKCS5Padding");
                    cifradorAES.init(Cipher.ENCRYPT_MODE, clave,this.IV);
                    bufferSalida.put(cifradorAES.doFinal(bytesArchivo));
                    bufferSalida.flip();
                    //ESCRITURA
                    if(archivo.delete()){
                        FileChannel canalSalida=new RandomAccessFile(archivo,"rw").getChannel();
                        canalSalida.write(bufferSalida);
                        canalSalida.close();
                    }else throw new Exception("No se pudo borrar el archivo "+archivo.getName()+", si lo tiene abierto, ciérrelo.");
                }else{
                    if(!archivo.exists())throw new Exception("El archivo "+archivo.getName()+" no existe");
                    if(!archivo.isFile())throw new Exception("No puede encriptar un directorio, trate\nde comprimirlo antes para luego encriptar los archivos");
                    if(archivo.length()>700248752)throw new Exception("No se puede encriptar el archivo "+archivo.getName()+" porque ha superado el tamaño máximo\nde capacidad de memoria del JVM");
                }
            }
            catch (Exception ex){
                throw new Exception("Hubo un error al encriptar el archivo\n"+ archivo.getName() +"\n"+ex);
            }
        }
        public void desencriptarArchivo(String ruta,SecretKey clave)throws Exception{
            File archivoEncriptado=null;
            try{
                archivoEncriptado=new File(ruta);
                if(archivoEncriptado.exists()){
                    //LECTURA
                    byte[]bytesArchivoEncriptado=new byte[(int)archivoEncriptado.length()];
                    int tamañoBloque=AES_KEYLENGTH/8;
                    int numBloques=((int)archivoEncriptado.length()%tamañoBloque==0)?(int)archivoEncriptado.length()/tamañoBloque:((int)archivoEncriptado.length()/tamañoBloque)+1;
                    FileChannel canalEntrada=new RandomAccessFile(archivoEncriptado, "r").getChannel();
                    ByteBuffer bufferEntrada=ByteBuffer.allocate((int)archivoEncriptado.length());
                    canalEntrada.read(bufferEntrada);
                    bufferEntrada.flip();
                    bufferEntrada.get(bytesArchivoEncriptado);
                    canalEntrada.close();
                    //DESCRIFRADO
                    ByteBuffer bufferSalida=ByteBuffer.allocate((int)archivoEncriptado.length());
                    if(comprobarKeys(clave)){
                        Cipher descifradorAES = Cipher.getInstance("AES/CBC/PKCS5Padding");
                        descifradorAES.init(Cipher.DECRYPT_MODE,clave,this.IV);
                        bufferSalida.put(descifradorAES.doFinal(bytesArchivoEncriptado));
                        bufferSalida.flip();
                    }
                    else{
                        System.gc();
                        throw new Exception("La clave ingresada es incorrecta");
                    }
                    //ESCRITURA            
                    if(archivoEncriptado.delete()){
                        FileChannel canalSalida=new RandomAccessFile(ruta, "rw").getChannel();
                        canalSalida.write(bufferSalida);
                        canalSalida.close();
                    }else throw new Exception("No se pudo eliminar el archivo "+archivoEncriptado.getName()+", si lo tiene abierto, ciérrelo.");
                }else{
                    if(!archivoEncriptado.exists())throw new Exception("El archivo "+archivoEncriptado.getName()+" no existe");
                }
            }
            catch (Exception ex){
                System.gc();
                throw new Exception("Hubo un error al desencriptar\n"+archivoEncriptado.getName()+":\n"+ex.getMessage());
            }
        }    
        public SecretKey generarClaveSecreta(String clave){
            byte[]key=rellenarBytesClave(clave);
            SecretKey claveGenerada=new SecretKeySpec(key, "AES");
            return claveGenerada;
        }
        private byte[] rellenarBytesClave(String clave){
            byte[]key=clave.getBytes();
            while(key.length!=AES_KEYLENGTH/8){
                if(key.length<AES_KEYLENGTH/8){
                    clave+="0";
                    key=clave.getBytes();
                }
                if(key.length>AES_KEYLENGTH/8){
                    clave=clave.substring(0,AES_KEYLENGTH/8);
                    key=clave.getBytes();
                }
            }
            return key;
        }
        private boolean comprobarKeys(SecretKey clave){
            return this.CLAVESECRETA.equals(clave);
        }
        public void generarIV() throws Exception{
            try{
                byte[]VECTOR={1,6,1,2,1,9,9,7,7,9,9,1,2,1,6,1};
                FileChannel canalsalida=new RandomAccessFile(new File("initvectoraes.iv"), "rw").getChannel();
                MappedByteBuffer buffersalida=canalsalida.map(FileChannel.MapMode.READ_WRITE, 0, 16);
                buffersalida.put(VECTOR);
                buffersalida.force();
                canalsalida.close();
            }catch(Exception ex){
                throw new Exception("Error al generar el Vector de Inicialización de AES\n"+ex.getMessage());
            }
        }
        private byte[]obtenerIV()throws Exception{
            byte[]vectorcargado=null;
            try{
                FileChannel canalentrada=new RandomAccessFile(new File("initvectoraes.iv"), "r").getChannel();
                MappedByteBuffer bufferentrada=canalentrada.map(FileChannel.MapMode.READ_ONLY, 0, 16);
                vectorcargado=new byte[16];
                bufferentrada.get(vectorcargado);
                bufferentrada.load();
                canalentrada.close();
            }
            catch(Exception ex){
                throw new Exception("Error al obtener el Vector de Inicialización de AES\n"+ex.getMessage());
            }
            return vectorcargado;
        }
    }
    

    编辑 这段代码不能解决问题,但我认为这可以在某种程度上有所帮助

    byte[] chave = "chave de 16bytes".getBytes();
    IvParameterSpec IV = new IvParameterSpec(new byte[]{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16});
    String TEST = "TEST";
    
        public String encriptaAES(String chaveCriptografada) throws InvalidKeyException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException, InvalidAlgorithmParameterException {
            try {
                Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
                System.out.println("MENSAJE: "+chaveCriptografada);
                byte[] mensagem = chaveCriptografada.getBytes();
                cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(chave, "AES"), this.IV);
                chaveCriptografada = new String(cipher.doFinal(mensagem));
                System.out.println("Mensaje encriptado: "+chaveCriptografada);
    
                chaveCriptografada = DatatypeConverter.printBase64Binary(chaveCriptografada.getBytes());
                this.TEST = DatatypeConverter.printBase64Binary(TEST.getBytes());
                System.out.println("TEST: "+TEST);
            } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
                e.printStackTrace();
            }
            return chaveCriptografada;
    
        }
    
        public String descriptografaAES(String chaveCriptografada) throws NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException, InvalidAlgorithmParameterException {
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    
            System.out.println("Mensaje Encriptado CON BASE 64: "+chaveCriptografada);
            byte[] base64decodedBytes = DatatypeConverter.parseBase64Binary(chaveCriptografada);
            this.DATA=new String(DatatypeConverter.parseBase64Binary(this.DATA));
            System.out.println("TEST: "+TEST);
            System.out.println("Mensaje Encriptado: "+new String(base64decodedBytes));
            try {
                cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(this.chave, "AES") , this.IV);
                byte[] decrypted = cipher.doFinal(base64decodedBytes);
                chaveCriptografada = new String(decrypted);
            } catch (InvalidKeyException e) {
                e.printStackTrace();
            }
            return chaveCriptografada;
        }
        public static void main(String[] args) throws Exception{
            AESCipher cipher = new AESCipher();
            String mensajeEncriptado = cipher.encriptaAES("mensaje");
            System.out.println("Mensaje encriptado CON BASE 64: "+mensajeEncriptado);
            System.out.println("Mensaje desencriptado: "+cipher.descriptografaAES(mensajeEncriptado));
        }
    

    【讨论】:

    • 谢谢,但是光看你的课还是不能解决,我的返回base64也是一样的问题。
    • 哇,我一直在尝试这么多方法,我只是在这一点上被卡住了。如果您最终解决了,请通知我。
    • 我可以看看这个例子howtodoinjava.com/security/java-aes-encryption-example,希望对你也有帮助。
    • 那里的示例仅使用 AES,而您不使用。在您的情况下是否有必要使用base64?我认为base64在您发布的算法中纠缠了字节转换,因此descriptografaAES函数接收到的字符串长度与原始base64编码和AES加密字符串(由encriptaAES返回)不匹配
    • 是的,正是我遇到了问题
    猜你喜欢
    • 1970-01-01
    • 2013-06-18
    • 2012-06-05
    • 1970-01-01
    • 1970-01-01
    • 2012-05-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多