Boa tarde!
Na minha aplicação, envio um email ao usuário com uma chave identificadora, utilizada pelo mesmo para validar o cadastro. Esta chave é criptografada - estou utilizando MD5.
O link que o usuário recebe é semelhante ao seguinte:
http://localhost:8080/MeuProjeto/usuario/confirmacao/2k+1xuk+dNPfhSdZn6YmQg==
onde “2k+1xuk+dNPfhSdZn6YmQg==” é a tal chave.
O problema é que, ao passar a chave acima pela URL, no meu Controller os caracteres “+” somem, e assim não iguala com o que está armazenado no banco de dados, e não valida o usuário.
Meu Controller está assim:
@Public
@Get("/usuario/confirmacao/{chaveIdentificacao}")
public void confirmar(String chaveIdentificacao) {
[codigo]
}
Existe alguma forma de conseguir capturar todos os caracteres no Controller, ou existe algum tipo de criptografia que gere apenas letras e números?
Obrigada,
Se você está usando MD5, o mesmo deveria gerar somente caracteres hexadecimais (0 à 9 e A à F)…
Verifique o método que gera esse MD5…
Minha classe de Criptografia está assim:
package br.com.projeto.utils;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import sun.misc.BASE64Encoder;
public class Criptografia {
public static String criptografar(String valor) {
try {
MessageDigest digest = MessageDigest.getInstance("MD5");
digest.update(valor.getBytes());
BASE64Encoder encoder = new BASE64Encoder();
return encoder.encode(digest.digest());
} catch (NoSuchAlgorithmException ns) {
ns.printStackTrace();
return valor;
}
}
}
Criei isso com base em coisas que vi por aí na internet. É a primeira vez que uso algoritmos de criptografia em java, então não faço idéia se está correto. :?
O que se pode fazer é, antes de criar a URL, converter “+” para “%2B”, “=” para “%3D”, e “/” para “%2F”. São esses os caracteres especiais em Base-64.
Você está usando MD5 e Base64 encoder… O Base64 não deve ser usado dessa forma como criptografia pois ele só codifica (pode ser decodificado)…
Uma coisa legal que você pode fazer é usar o MD5 com um salt. Ou seja, você salga a String de uma forma que só você sabe como deve ser…
É uma forma de criptografia por obscuridade… Ou seja, alguém pode vir a descobrir, mas eu não me preocuparia com isso agora…
Essa aqui é uma forma de criptografia que usa o SHA-256 (parece o MD5, mas tem muito mais caracteres…)
Se você analisar, a forma que eu usei de "salgar" o meu valor é com o método shuffle e digest duas vezes… (linha 9)
[code]
public class Encrypter {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
public String digest(String value) {
if (value == null)
throw new IllegalArgumentException("The value cannot be empty.");
return digest(shuffle(digest(shuffle(value))));
}
private String shuffle(String value) {
int length = value.length();
length = getMiddle(length);
return reverse(value.substring(0, length)).append(
reverse(value.substring(length))).toString();
}
private StringBuilder reverse(String value) {
return new StringBuilder(value).reverse();
}
private int getMiddle(int length) {
if (length % 2 == 1)
length = (length - 1) / 2;
else
length /= 2;
return length;
}
private String digest(String value) {
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(value.getBytes());
return byteToHex(md.digest());
} catch (NoSuchAlgorithmException e) {
logger.error("Unable to digest this value.", e);
return "";
}
}
private String byteToHex(byte[] bytes) {
if (bytes != null) {
StringBuilder s = new StringBuilder();
for (byte b : bytes) {
int high = ((b >> 4) & 0xf) << 4;
int low = b & 0xf;
if (high == 0)
s.append('0');
s.append(Integer.toHexString(high | low));
}
return s.toString();
}
return "";
}[/code]
Analise esse código e sinta-se livre para alterá-lo à sua necessidade… Se quiser fazer com o MD5, é só trocar nessa linha MessageDigest.getInstance("SHA-256" );
Hum, legal!
Valeu pela dica!
Nesta parte do código
private String digest(String value) {
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(value.getBytes());
return byteToHex(md.digest());
} catch (NoSuchAlgorithmException e) {
logger.error("Unable to digest this value.", e);
return "";
}
}
você chama o método byteToHex(md.digest()). Este método também é algo que você implementou para “reforçar”, ou faz parte da criptografia em si?
(tipo, se eu pesquisar sobre o Criptografia, sobre MessageDigest por exemplo, encontrarei este método disponível nas documentações de como implementar?).
na verdade trocar de MD5 pra SHA-256 não vai resolver o seu problema…
se vc quer que faça parte de uma url vc tem que fazer um URL encode na string… e o respectivo decode…
quem tá gerando a URL é o VRaptor ou você?
tipo, vc tem na jsp algo do tipo:
<a href="..../confirmacao/${hashMaroto}">...</a>
Se sim, vc precisa fazer o url encode.
Na verdade esta solução do Rafael resolveu meu problema, pois passou a gerar a chave criptografada apenas com letras e números.
Mas o que seria isso de “URL encode”?
o url encode converteria os caracteres especiais pra %xx que são aceitos normalmente em urls…
Certo. Bom, neste caso não vou mais precisar, mas deixarei anotado pra próximas necessidades.
Obrigada!
Só para reforçar…
Lucas, eu coloquei SHA-256 só por que eu copiei de um exemplo que eu tinha aqui… Mas a questão em si é remover o Base64 que ela estava usando junto com o MD5… O Base64 estava colocando os caracteres especiais.
Talita, eu chamo o método byteToHex por que ele converte de array de byte para String foi colocado Hex no nome por que os bytes são convertidos para os respectivos valores em Hexadecimal (0-9 e a-f)…
Eu diria que faz parte da criptografia pois precisamos dos dados em String, nesse caso…
O guava, que é uma lib obrigatória no vraptor, possui métodos para criptografia, assim não é necessário métodos caseiros.
Um simples Hashing.md5().putString("blah blah blah").hash()
já faz o trabalho 
Garcia, eu procurei e não encontrei a classe Hashing…
Isso vem junto com o Guava que o VRaptor tem como dependência ou é um jar separado?
Legal, simplifica bastante. Vou deixar anotado pra dar uma olhada, assim que sobrar um tempo.