Criptografia AES erro ao cifrar textos grandes

6 respostas
L

estou tendo problemas ao cifrar textos grandes com mais de 47 caracteres. eu poderia fazer uma rotina para quebrar essa string mas queria saber se estou errando em algum lugar do codigo. O sistema q estou desenvolvendo tem um chat, em XMPP integrado com o restante da aplicação, entaum precisao criar um historico dessas conversas do lado do cliente já que o servidor já tem o arquivamento proprio. entaum cada vez que uma mensagem é enviada ou recebida uma thread eh disparada pra fazer a gravação dessas mensagens em um arquivo, que precisa ser criptografado.

try {
                File file = new File(System.getProperty("user.dir") + "/system/" + usuario.getNome() + "/" + nome + ".wes");
                if (file.exists()){
                    BufferedReader in = new BufferedReader(new FileReader(file));
                    String str = "";
                    while (in.ready()) {
                        String line = in.readLine();
                        str= str.concat(CriptoManager.decifrar(line,chave.getBytes()));
                    }
                    area.setText(str + area.getText());
                    in.close();
                }
            } catch (Exception e) {e.printStackTrace();}

esse metodo eu chamo pra efetuar a leitura do arquivo linha a linha e a classe abaixo encapsula as funcionalidades de criptografia. pra gerar a chave AES utilizo o algoritomo SHA para gera-la.

package Componentes;

import com.sun.messaging.jmq.util.BASE64Decoder;
import com.sun.messaging.jmq.util.BASE64Encoder;
import java.math.BigInteger;
import java.security.MessageDigest;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

public class CriptoManager {

    private static final String metodo = "AES";

    public static String cifrar(String value,byte[] chave){

        String retorno = null;

        try{
            SecretKeySpec spec = new SecretKeySpec(chave, metodo);

            Cipher cifra = Cipher.getInstance(metodo);
            cifra.init(Cipher.ENCRYPT_MODE, spec);

            byte[] cifrado = cifra.doFinal(value.getBytes());

            retorno = new BASE64Encoder().encode(cifrado);
        }
        catch(Exception ex){ex.printStackTrace();}

        return retorno;        
    }

    public static String decifrar(String cifra,byte[] chave){

        String retorno = null;

        if (cifra.length() > 0){

            try{
                SecretKeySpec skeySpec = new SecretKeySpec(chave,metodo);

                byte[] decoded = new BASE64Decoder().decodeBuffer(cifra);
                
                Cipher cipher = Cipher.getInstance(metodo);
                cipher.init(Cipher.DECRYPT_MODE, skeySpec);
                retorno = new String(cipher.doFinal(decoded));
            }
            catch(Exception ex){ex.printStackTrace();}
        }

        return retorno;
    }

    public static String hash(String value){

        String retorno = null;
        try{
            MessageDigest md = MessageDigest.getInstance("SHA");
            md.update(value.getBytes());
            BigInteger hash = new BigInteger( 1, md.digest() );  

            retorno = new String(hash.toString(16));
        }
        catch(Exception ex){ex.printStackTrace();}

        return retorno;
    }

    private static byte[] finalizarString(byte[] cifra) {
        int resto = cifra.length % 16;
        
        if(resto!= 0){
            byte[] novo = new byte[cifra.length + resto];
           
            for(int x=0;x<novo.length;x++){
                if (x><cifra.length)
                    novo[x] = cifra[x];
                else
                    novo[x] = (char) 0;
            }
            cifra = novo;
        }

        return cifra;
    }
}

alguem poderia me dizer pq ao tentar decifrar a mensagem do arquivo, que tenha acima de 47 caracteres dah erro?

javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..) at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..) at com.sun.crypto.provider.AESCipher.engineDoFinal(DashoA13*..) at javax.crypto.Cipher.doFinal(DashoA13*..)

agradeço

>

mesmo tentando decifrar direto no programa, tb dah o mesmo erro

6 Respostas

E

Input length must be multiple of 16 when decrypting with padded cipher

E

Nunca use como nome da cifra só “AES”. O default (ECB e sem padding) não é adequado para aplicações onde o tamanho dos dados é diferente de um múltiplo do tamanho do bloco (no caso do AES, 16 bytes).

Use “AES/CBC/PKCS5Padding”, por exemplo.

L

opa obrigado pela resposta!! eu modifiquei akilo q vc tinha dito para colocar

try {
            SecretKeySpec spec = new SecretKeySpec(chave, "AES");

            Cipher cifra = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cifra.init(Cipher.ENCRYPT_MODE, spec);

            byte[] cifrado = cifra.doFinal(value.getBytes());

            retorno = new BASE64Encoder().encode(cifrado);
        }

mas agora o erro mudou

java.security.InvalidKeyException: Parameters missing
        at com.sun.crypto.provider.SunJCE_f.a(DashoA13*..)
        at com.sun.crypto.provider.AESCipher.engineInit(DashoA13*..)
        at javax.crypto.Cipher.a(DashoA13*..)
        at javax.crypto.Cipher.a(DashoA13*..)
        at javax.crypto.Cipher.init(DashoA13*..)
        at javax.crypto.Cipher.init(DashoA13*..)
        at Componentes.CriptoManager.decifrar(CriptoManager.java:39)

agradeço!!!

E

Se você for usar o método CBC, é necessário também passar o vetor de inicialização (IV). Procure por “IVParameterSpec”.

L

entaum…naum sei mto bem como usar IVParameterSpec, pesquisei na net, pode ser qq conjunto de dados mesmo? mesmo “0”?

fiz assim:

//metodo que cifra
try {
            SecretKeySpec spec = new SecretKeySpec(chave, "AES");
            //coloquei aki 
            AlgorithmParameterSpec paramSpec = new IvParameterSpec(new byte[16]);

            Cipher cifra = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cifra.init(Cipher.ENCRYPT_MODE, spec,paramSpec);

            byte[] cifrado = cifra.doFinal(value.getBytes());

            retorno = new BASE64Encoder().encode(cifrado);
}
//metodo que decifra
try {
            SecretKeySpec skeySpec = new SecretKeySpec(chave, "AES");
            //coloquei aki 
            AlgorithmParameterSpec paramSpec = new IvParameterSpec(new byte[16]);

            byte[] decoded = new BASE64Decoder().decodeBuffer(cifra);

            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, skeySpec,paramSpec);
            
            retorno = new String(cipher.doFinal(decoded));
}

e agora na cifração não dá erro mesmo com dados maior q 47, mas na decifração acorre o seguinte erro:

javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher
        at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)
        at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)
        at com.sun.crypto.provider.AESCipher.engineDoFinal(DashoA13*..)
        at javax.crypto.Cipher.doFinal(DashoA13*..)

agradeço

L

esse ultimo erro q deu eu consegui consertar…o problema era o importe da classe BASE64Decoder e BASE64Encoder: ao inves de ser

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

ele tava colocando:

import com.sun.messaging.jmq.util.BASE64Decoder;
import com.sun.messaging.jmq.util.BASE64Encoder;

colocando o import certo deu certinho o exemplo inteiro ficou assim:

package Componentes;


import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.spec.AlgorithmParameterSpec;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;


public class CriptoManager {

    public static String cifrar(String value, byte[] chave) {
        String retorno = null;
        try {
            SecretKeySpec spec = new SecretKeySpec(chave, "AES");

            AlgorithmParameterSpec paramSpec = new IvParameterSpec(new byte[16]);

            Cipher cifra = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cifra.init(Cipher.ENCRYPT_MODE, spec,paramSpec);

            byte[] cifrado = cifra.doFinal(value.getBytes());

            retorno = new BASE64Encoder().encode(cifrado);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return retorno;
    }

    public static String decifrar(String cifra, byte[] chave) {
        String retorno = null;
        try {
            SecretKeySpec skeySpec = new SecretKeySpec(chave, "AES");

            AlgorithmParameterSpec paramSpec = new IvParameterSpec(new byte[16]);

            byte[] decoded = new BASE64Decoder().decodeBuffer(cifra);

            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, skeySpec,paramSpec);
            
            retorno = new String(cipher.doFinal(decoded));
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return retorno;
    }

}
Criado 5 de agosto de 2010
Ultima resposta 24 de ago. de 2010
Respostas 6
Participantes 2