Erro: criptografia + banco dados

To tentando criptografar as senhas e gravar no banco, to usando o MD5, mas ta dando erro de incompatibilidade de caracteres. Coloquei o banco como LATIN1. Alguem sabe como soluciono isso? Tipo uma conversao e tals, e ai como faco?

public class Criptografia {
    
    public static String criptografar(String senha) {
        try {
            byte[] senhaCript;
            MessageDigest md = MessageDigest.getInstance("MD5");
            //md.reset();
            senhaCript = md.digest(senha.getBytes());
            char[] senhaConvert = new char[senhaCript.length];
            for (int i=0; i<senhaCript.length; i++)
                senhaConvert[i] = (char)senhaCript[i];
            String senhaConvert2 = String.valueOf(senhaConvert);
            return senhaConvert2;
        } catch (NoSuchAlgorithmException ex) {
            ex.printStackTrace();
            return null;
        }
    }
    
    public static void main(String[] args) {
        String teste = Criptografia.criptografar("heverton");
        System.out.println("Tamanho:" + teste.length() + "\n" + teste);
        Comunicacao.iniciaComunicacao();
        int result = Comunicacao.inserirBanco(teste);
        System.out.println("Resultado: " + result);
    }
}

No metodo main ele tenta gravar no banco atraves do metodo “Comunicacao.inserirBanco(teste);” mas dar o seguinte erro:

Erro: SQL Exception org.postgresql.util.PSQLException: ERROR: character 0xefbeb8 of encoding "UTF8" has no equivalent in "LATIN1" at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryEx ecutorImpl.java:1525) at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutor Impl.java:1309) at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.ja va:188) at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Stat ement.java:452) at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(Abstract Jdbc2Statement.java:340) at org.postgresql.jdbc2.AbstractJdbc2Statement.executeUpdate(AbstractJdb c2Statement.java:286) at catalogo_codata_servidor.Persistencia.inserirBanco(Persistencia.java: 148) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl. java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAcces sorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:585) at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:294) at sun.rmi.transport.Transport$1.run(Transport.java:153) at java.security.AccessController.doPrivileged(Native Method) at sun.rmi.transport.Transport.serviceCall(Transport.java:149) at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:4 60) at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport .java:701) at java.lang.Thread.run(Thread.java:595)

E ai como contorno isso? Vlws…

upa ai

Quando for gravar dados binários, tais como os 16 bytes retornados pelo MD5, transforme-os para hexadecimal (use um campo de 32 caracteres no seu banco de dados). Isso evita problemas com bytes fora do intervalo 32 a 126.

so tem jeito de gravar passando p hexa? deixando em byte n dar ne? o exemplo de conversao p hexa eh o do tutorial do guj msm ne? vlw…

Se você tiver um campo BLOB pode até tentar gravar os dados em binário mesmo, mas acho muito, muito mais fácil usar um campo CHAR ou VARCHAR de 32 caracteres. Se o seu DBA reclamar que está usando muito espaço, você pode:

  • Usar só os primeiros 8 bytes do MD5, e converter para 16 caracteres. O problema é que você vai ter de lembrar que você truncou o MD5 para 16 caracteres.
  • Converter para Base-64 - (como “z0ttKpRp5sO/3u9aEgX2Cg==”), isso dá 24 caracteres, ou como você é esperto e deve ter percebido que os últimos caracteres são sempre “==”, pode usar 22 caracteres, e então negociar com o seu DBA para aumentar o campo para 22.

esse negocio d tamanho, no caso dessa app n vai importar mto, ja q n serao mtos usuarios e o campo senha so estará presente nos usuarios, entao a tabela tera no maximo 20 linhas, n sera uma tabela q irá crescer gradativamente, confere? Ou seja, quero uma maneira mais facil de fazer uma conversao e do banco aceitar os dados da senha. Thingol, teria como vc explicar como ocorre essa conversoes, principalmente essa de base 64, achei interessante ela. vlw…

Para Base-64 use alguma coisa que já está pronta (no Jakarta Commons existe uma. )
Muita gente usa sun.misc.BASE64Encoder e BASE64Decoder, mas aí você pode ter o problema de seu código só funcionar na JVM da Sun, não da IBM (WebSphere)ou da BEA (WebLogic).

puts, pensei q so existia jvm da sun. mas n eh empecilio tb, pois aki eh td da sun, vo fundo nesse basse 64 msm.

so umas duvidas:

1- passando p esse base 64, o banco n dara incompatibilidade de caracteres c o latin1 ne?

2- p converter p base 64, eu vo converter direto a string q foi pega no textfiled ou terei q converter a string ja codificada do md5?

  • Não. Base-64 usa apenas os seguintes caracteres:
    0-9, A-Z, a-z, +, =, /

[quote]
2- p converter p base 64, eu vo converter direto a string q foi pega no textfiled ou terei q converter a string ja codificada do md5?[/quote]

Não, base-64 converte bytes para string, e string para bytes.
Tire esse troço que você criou (“new String”).
“new String” é a fonte e a raiz de todos os males (pelo menos de seu código :stuck_out_tongue: )

“new String” onde? n seria new char[]?

coloca ai q eu n vi, ou to c a cabeca mto cheia q passou despercebido :smiley:

Ah, é verdade - você criou um array de caracteres. Vou explicar o que pode ter ocorrido para dar aquele erro esquisito:

  • O MD5 pode gerar bytes de 0 a 255 (ou melhor, de -128 a +127 - afinal de contas estamos falando em Java)
  • Quando você efetuou o cast de byte para char, então ele converteu os bytes de 0 a 127 para os caracteres de 0 a 127 (OK), e os bytes de -128 a -1 para os caracteres de 65408 até 65535.
  • Vários daqueles caracteres (0 a 31, 127, 65408 a 65535) não podem ser diretamente inseridos em bancos de dados, já que não representam caracteres válidos ASCII (no caso 65408 a 65535) ou então são caracteres de controle (0 a 31).

eu vo tirar essa conversao, mas eu so fiz isso pq eu precisava converter os byter p String p salvar no banco, como n dar p converter diretamente byter -> String (pelo menos eu n achei solucao p convresao direta), ai eu fiz Byte-> char[] -> String e passei p banco, mas vo tirar qnd refazer. Entendeu?

tu tens 1 exemplo de uso desse Base64? Vo ve se faco isso logo.

Use o Jakarta Commons, para evitar que você use a tal classe sun.misc. BASE64Encoder e BASE64Decoder. É só baixar e ver os exemplos que deve haver no tal pacote.

(Para exemplos com as mal-fadadas classes BASE64Encoder e Decoder, é só procurar no Google - acho que no próprio Java Almanac, ou então no java2s, deve haver um exemplo.

eh essa classe aki ne?
org.apache.commons.codec.binary.Base64

tipo, to dando uma olhada na api, e vi q ele criptografa(encode) e descriptografa(decode), n precisa definir chave publica nem privada, ne isso? Como n tem uso de chaves, se alguem pegar as senhas criptografadas no banco e tacar um decode nelas, ja vai ter a sanha do povo ne isso?

Acho que você não entendeu como funciona o MD5.

Digamos que você seja fanático pela Gisele Bündchen e use como senha:

GiseleBundchen2007

Se você for calcular o MD5 dos bytes que compõem essa senha, vai obter os seguintes bytes (imprimo em hexadecimal para facilitar):

515723cd1e9ebe6442e52c96a7b649fe

Agora pegue o seu colega, que sabe que você é fanático pela dona Gisele mas não acompanhou você digitando direito a sua senha. Ele acha que sua senha é:

giselebundchen2007

O MD5 é 4bc817a4af67ead0e4e402e46b5c72b9, que não se parece nem um pouquinho com o MD5 de sua senha.
A sua colega, aquela que você acha que é uma mala total e quer ver trancada com o Agostinho do Big Brother 6 para ver se ela deixa de ser xarope, é menos analfabeta que você e sabe que Bündchen se escreve com trema. Ela acha que sua senha é GiseleBündchen2007

O MD5 é 9a2bd5ad559bb4c92cce381ff70659b5.

Você viu que o MD5 nunca bate, exceto se você digitar corretamente sua senha.

Mas não é possível recuperar a senha a partir do MD5, a menos que você já a saiba de antemão.

eu saquei, eh pq eu vo usar o md5 + base 64 p passar p banco, confere?

eh pq pensei q ia usar so o base 64, mas ele eh meramente 1 encoding e n 1 “criptografador” (inventei isso agora, ehehe), eh +ou- isso ne?

AE thingol, vlw a ajuda finalmente resolvi, o problema era c conversao d byte -> char msm, qnd converti de byte -> string pegou blz. vo dx o codigo, caso alguem tenha msm problema:

[code]public class Criptografia {

public static byte[] criptografar(String senha) {
    try {
        byte[] senhaCript;
                               
        MessageDigest md = MessageDigest.getInstance("MD5");
        //md.reset();
        senhaCript = md.digest(senha.getBytes());           
        //String senhaConvertida = txt2Hexa(senhaCript);
        return senhaCript;
    } catch (NoSuchAlgorithmException ex) {
        ex.printStackTrace();
        return null;
    }
}

public static String toBase64 (byte[] senhaBytes) {
    String senhaStr = new String(Base64.encodeBase64(senhaBytes));
    return senhaStr;
}

public static String txt2Hexa(byte[] bytes) {
    if( bytes == null ) return null;
    String hexDigits = "0123456789abcdef";
    StringBuffer sbuffer = new StringBuffer();
    for (int i = 0; i < bytes.length; i++) {
         int j = ((int) bytes[i]) & 0xFF;
         sbuffer.append(hexDigits.charAt(j / 16));
         sbuffer.append(hexDigits.charAt(j % 16));
    }
    return sbuffer.toString();
}

public static void main(String[] args) {
    byte[] teste2 = Criptografia.criptografar("heverton");
    String teste = Criptografia.toBase64(teste2);
    System.out.println("Tamanho:" + teste.length() + "\n" + teste);
    //Comunicacao.iniciaComunicacao();
    //int result = Comunicacao.inserirBanco(teste3);
    //System.out.println("Resultado: " + result);
}

}[/code]

converte tanto d md5 -> base64, qto md5 -> hexa, bem util :smiley: