javax.crypto.IllegalBlockSizeException:使用填充密码解密时,输入长度必须是16的倍数

时间:2016-11-06 03:40:05

标签: java base64 aes

我正在开展一个我正在进行加密的项目,该项目使用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)

1 个答案:

答案 0 :(得分:0)

我正在和我分享我宝贵的加密课程,我的英国朋友。

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