Criptografia

Ola gente,

preciso de uma ajuda, é possivel criar um codigo utilizando essa biblioteca (javax.crypto) que ao digitar uma chave (senha) para encriptografar um texto, eu consigo desincriptografar esse texto colocando uma senha diferente?

por exemplo:

coloco a chave (senha) = “senhasecreta”;
e encriptografo um texto qualquer.

para desincriptografar eu coloca a chave(senha) = “senhasecretas”;
e desincriptografo o texto.

o resultado disso vai ser um texto diferente do texto original pois a chave(senha) tem 1 bit de diferença.

Porem é isso mesmo que preciso fazer…

so que eu vi exemplos por ai que “amarram” a chave(senha) ao texto, nao deixando desincriptografar se a chave nao for a mesma utilizada para encriptografar.

meu algoritmo precisa descriptografar mesmo a senha sendo diferente, alguem pode me dar um help…?
:slight_smile:

Como já disse o thingol uma vez: criptografia não é para amadores.

Entenda que todo algoritmo de criptografia é simplesmente uma equação matemática em que uma das variáveis é a chave. Então se você mudar a chave, simplesmente o resultado da equação vai ser diferente. Em Java, se você usa uma chave diferente para criptografar e decriptografar (usando um algoritmo simétrico), o resultado vai ser diferente. Outra coisa que você tem que prestar atenção que uma chave é um número, que em linguagem de programação é transformado em uma sequencia de bytes. Nem sempre uma senha de login é uma chave, pois dependendo do algoritmo a chave vai ter que ter um tamanho fixo. A senha é simplemente um “pass phrase” para proteger uma chave.

Segue um exemplo usando DES:
http://www.exampledepot.com/egs/javax.crypto/DesString.html

Ola, obrigada pela resposta.

Concerteza utilizando uma chave diferente para decriptografar o resultado será diferente, é isso que preciso fazer, porem eu vi que se eu informo uma chave diferente da que eu usei para encriptografar, ele nao decriptografa, simplesmente cai no catch e ja era… eu queria que ele continuasse q me mostrasse o resultado diferente.

por isso pergunto se é possivel isso! pois pelos exemplos que eu vi por ai e fiz, o algoritmo nao me mostra o resultado…

vou dar uma olhada nesse link que tu me passou…

thanks

[quote=oyama]Como já disse o thingol uma vez: criptografia não é para amadores.
[/quote]
Obrigado pela citação.

Se você quiser construir um algoritmo em que você possa decifrar um texto, mesmo que a senha seja “ligeiramente” diferente (como “Saulo” e “Paulo”, que se referem à mesma pessoa em diferentes etapas de sua vida), então você pode usar um algoritmo normal, como os definidos pelo javax.crypto, mas precisa tratar a senha primeiro, para gerar a mesma chave para senhas “ligeiramente” diferentes. O que é “ligeiramente diferente” para você?

  • Uma letra é diferente (como Saulo e Paulo)
  • Uma letra a mais (como senhasecreta e senhasecretas)
  • A palavra significa a mesma coisa (como macaxeira, aipim e mandioca)

Mesmo isso não é um problema simples - não é fácil definir uma função que dê o mesmo resultado para entradas “ligeiramente” diferentes.

Você queria ver o resultado da criptografia (que é um lixo binário, quase sempre) quando a senha deu problemas?
Isso é relativamente fácil se você usar um método de criptografia que não checa isso. Por exemplo, se você usar a cifra “DES/ECB/NoPadding” isso não é checado e não vai cair no “catch”.
Mas se você usar “DES/CBC/PKCS5Padding” ele faz uma verificação bastante grosseira (cuja probabilidade de falhar é um pouco menor que 1/256).

segue o codigo



public class PWSec {

	
	    private static SecretKey skey1;  
	    private static SecretKey skey2;	     
	    private static KeySpec ks;   
	    private static PBEParameterSpec ps;   
	    private static final String algorithm = "PBEWithMD5AndDES";	     
	    private static BASE64Encoder enc = new BASE64Encoder();   
	    private static BASE64Decoder dec = new BASE64Decoder(); 
	    private static String senhaSecreta = new String();
	    private static String  ret = new String();
	    static { 
	    	
	        try { 
	        	        	
	        	SecretKeyFactory skf = SecretKeyFactory.getInstance(algorithm);   
	            ps = new PBEParameterSpec (new byte[]{3,1,4,1,5,9,2,6}, 20); 
	            
	        	for(int i = 0; i < 2; i++){
	        		if(i == 0 ){
	        			// definimos uma chave secreta (nosso algoritmo é simetrico, ou
	        			//seja, tu usa a mesma chave para encriptografar e decriptografar)
	        			senhaSecreta = "senhasecreta";
	        			//transformo essa string em um array de char
	        			 ks = new PBEKeySpec (senhaSecreta.toCharArray());
	        			 // crio a chave com base na chave que eu setei na variavel senhaSecreta acima.	        			 
	        			 skey1 = skf.generateSecret (ks);
	        		}else{
	        			// defino outra chave "ligeiramente" diferente da original
	        			senhaSecreta = "senhaxecreta";
	        			//transformo em um array de char
	        			ks = new PBEKeySpec (senhaSecreta.toCharArray());
	        			//gero uma chave baseado na senhaSecreta que defini acima.
	        			skey2 = skf.generateSecret (ks);
	        		}       
	        	}
	        } catch (java.security.NoSuchAlgorithmException ex) {   
	            ex.printStackTrace();   
	        } catch (java.security.spec.InvalidKeySpecException ex) {   
	            ex.printStackTrace();   
	        }   
	    }   
	    public static final String encrypt(final String text, SecretKey skey)   
	        throws   
	        BadPaddingException,   
	        NoSuchPaddingException,   
	        IllegalBlockSizeException,   
	        InvalidKeyException,   
	        NoSuchAlgorithmException,   
	        InvalidAlgorithmParameterException {   
	               
	        final Cipher cipher = Cipher.getInstance(algorithm);   
	        cipher.init(Cipher.ENCRYPT_MODE, skey, ps);   
	        return enc.encode (cipher.doFinal(text.getBytes()));   
	    }   
	    public static final String decrypt(final String text, SecretKey skey)   
	        throws   
	        BadPaddingException,   
	        NoSuchPaddingException,   
	        IllegalBlockSizeException,   
	        InvalidKeyException,   
	        NoSuchAlgorithmException,   
	        InvalidAlgorithmParameterException { 	               
	        
	        try {  
	        	final Cipher cipher = Cipher.getInstance(algorithm); 
	        	cipher.init(Cipher.DECRYPT_MODE, skey, ps);   
	        	    
	            ret = new String(cipher.doFinal(dec.decodeBuffer (text)));   
	        } catch (Exception ex) {   
	        }   
	        return ret;   
	    }   
	    public static void main(String[] args) throws Exception {	    	
	    		
	        String texto = "textodeexemploparacriptografia";
	        System.out.println("texto original = " +texto);
	        // encriptografo passando a primeira chave gerada.
	        String encoded = PWSec.encrypt (texto, skey1);   
	        System.out.println ("texto encriptografado = " + encoded);    
	        //System.out.println (PWSec.decrypt (encoded).equals (texto)); // imprime "true"
	        // decriptografo passando a chave "ligeiramente" diferente da chave original.
	        PWSec.decrypt (encoded, skey2);
	        //porem o retorno disso é vazio, ele nao me retorna nada, porque nao fez nada, pois a chave nao é a mesma.
	        System.out.println("texto descriptografado = "+ret);
	        //porem eu preciso que gere um resultado, mesmo que diferente do original... 
	        
	        
	   }
}   
 

thanks

Esse código foi baseado em um que postei há algum tempo no fórum.
O algoritmo usado (PBEWithMD5AndDES) foi designado justamente para isso (não lhe retornar nada se a senha estiver incorreta.). De fato, se a senha for Saulo mas você passar Paulo, não vai lhe retornar nada.

Acabe de saber que se eu fizer isso

//des é um objeto do tipo DESCryptoServiceProvider
des.Padding = PaddingMode.Zeros ;

antes do método decryptor() e encryptor() é possível
“decriptar” uma mensagem com uma chave diferente sem lançar exceção

isso procede?

Qual o algoritmo que eu posso usar que me permita decriptar uma mensagem com a senha errada?

Isso (DESCryptoServiceProvider) é .NET que você citou, não? Não sei exatamente como é que esse objeto do .NET trabalha, para que possa ser feita a interoperabilidade (ou seja, um arquivo criptografado em .NET possa ser lido com Java e vice-versa).

Mas sempre lembrando que senha é diferente de chave.
Algoritmos de PBE (password based encrypt) tem como entrada uma senha.
Algoritmos simétricos usam chave, que nem sempre dá para ser uma “coisa” digitável. Dá para tentar transformar uma String em uma chave (byte[]), mas você vai ter que ter uma lógica pois a chave tem que ter tamanho fixo. Uma idéia é usar o MD5 da senha digitada como chave.

Ok entendi,

porem eu mando como parametro no metodo de cripto e decripto duas coisas: a chave e o texto para ser encriptografado/decriptografado.

essa chave eu altero 1bit e mando decriptografar, e o algoritmo nao decriptografa pois a chave nao é a mesma…

o thingol falou aqui no forum que o algoritmo que estou utilizando (PBEWithMD5AndDES)
nao permite que decriptografe com a chave diferente da que foi encriptografada.

gostaria de saber qual algoritmo permite que eu decriptografe com a chave “ligeiramente” :slight_smile: diferente da utilizada para encriptografar.

Christiane

Utilizando um algoritmo de criptografia simétrico sozinho não se sabe qual a chave que criptografou a mensagem.

No link que eu tinha mandado anteriormente tem um exemplo usando DES. Pelas exception, dá para ver que ele trata 3 tipos de erro: Padding, BlockSize e Encoding. Para não dar BadPaddingException, é só usar um algoritmo sem padding. Para não dar IllegalBlockSizeException você tem que garantir que a mensagem vai ter tamanho multiplo do tamanho da chave (dependendo do algoritmo não é bem esta regra). Para não dar UnsupportedEncodingException é só fixar o encoding quando for manipular String.

[quote=chsolka]Ok entendi,

porem eu mando como parametro no metodo de cripto e decripto duas coisas: a chave e o texto para ser encriptografado/decriptografado.

essa chave eu altero 1bit e mando decriptografar, e o algoritmo nao decriptografa pois a chave nao é a mesma…

o thingol falou aqui no forum que o algoritmo que estou utilizando (PBEWithMD5AndDES)
nao permite que decriptografe com a chave diferente da que foi encriptografada.

gostaria de saber qual algoritmo permite que eu decriptografe com a chave “ligeiramente” :slight_smile: diferente da utilizada para encriptografar.
[/quote]

eu utilizei o algoritmo DES/ECB/NoPadding… e realmente ele descriptogafou o texto mesmo a chave sendo diferente!

obrigada!

na verdade estou fazendo um trabalho academico, aonde eu testo um algoritmo, faço um teste de perturbação…

altero 1 bit da chave e decriptografo o texto, o resultado teria que ser um texto com 50% de diferença do texto original.

mais o texto esta saindo completamente diferente, na verdade esta saindo um texto com caracteres estranhos, tipo : !@#$%%¨¨%

Para a maior parte dos algoritmos criptográficos “profissionais” conhecidos (DES, TripleDES, AES, RC4, Blowfish etc.), se você alterar um bit da chave, o resultado é um texto completamente diferente do texto original.
Se você comparar a saída bit por bit (não caracter por caracter, nem byte por byte) vai ver que em média 50% dos bits são alterados - como se a saída fosse completamente aleatória - o que seria de se esperar se o algoritmo fosse “perfeito”.
Eu estou sem tempo de preparar um programa de exemplo, mas é isso que ocorre.

Como eu disse, basta mexer um único bit da chave, para que o resultado seja totalmente diferente do resultado original.
Em média, 50% dos bits são alterados, como havia previsto.

import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.BitSet;
import java.util.Random;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;


public class Perturbacao {

    public void testar() {
        // estes são os algoritmos disponíveis para o Java 5.0
        String[] nomesAlgoritmos = {
            &quot;AES/ECB/NoPadding&quot;,
            &quot;DES/ECB/NoPadding&quot;,
            &quot;DESede/ECB/NoPadding&quot;,
            &quot;Blowfish/ECB/NoPadding&quot;,
            &quot;RC2/ECB/NoPadding&quot;,
            &quot;RC4/ECB/NoPadding&quot;
        };
        for (int i = 0; i &lt; nomesAlgoritmos.length; ++i) {
            testar (nomesAlgoritmos[i]);
        }
    }
    
    public void alteraUmBit (byte[] bytes) {
        // Vamos pegar o bit mais significativo, e alterá-lo 
        // (se for 0, alterá-lo para 1, e vice-versa.
        bytes[0] ^= 0x80;
    }
    
    private Random r = new Random ();
    
    public byte[] gerarDados (int n) {
        byte[] dados = new byte [n];
        r.nextBytes(dados);
        return dados;
    }
    // Esta função retorna um byte 00 se os dados originais baterem com os dados decifrados
    // nessa posição, e um byte diferente de 00 se os dados originais forem diferentes.
    // Por exemplo, se o original for 'P' (0x50) e o decifrado for 'S' (0x53), 
    // então a comparação irá retornar 0x03, que é o xor de 0x50 e 0x53.
    public byte[] comparar (byte[] dadosOriginais, byte[] dadosDecifrados) {
        byte[] resultado = new byte[dadosOriginais.length];
        for (int i = 0; i &lt; dadosOriginais.length; ++i) {
            resultado [i] = (byte) (dadosOriginais[i] ^ dadosDecifrados[i]);
        }
        return resultado;
    }
    
    // Se um bit houver sido alterado, ele vai ser 1, e se não foi alterado,
    // ele vai ser zero. 
    public double calcularProporcaoBitsAlterados (byte[] comparados) {
        int bitsUm = 0;
        for (int i = 0; i &lt; comparados.length; ++i) {
            byte valor = comparados[i];
            if ((valor & 0x01) == 0x01) bitsUm++;
            if ((valor & 0x02) == 0x02) bitsUm++;
            if ((valor & 0x04) == 0x04) bitsUm++;
            if ((valor & 0x08) == 0x08) bitsUm++;
            if ((valor & 0x10) == 0x10) bitsUm++;
            if ((valor & 0x20) == 0x20) bitsUm++;
            if ((valor & 0x40) == 0x40) bitsUm++;
            if ((valor & 0x80) == 0x80) bitsUm++;
        }
        return (double) bitsUm/ (comparados.length * 8);
    }
    public void printHex (String mensagem, byte[] bytes) {
        System.out.println (mensagem);
        for (int i = 0; i &lt; bytes.length; ++i) {
            System.out.printf (&quot;%02X &quot;, 0xFF & bytes[i]);
        }
        System.out.println ();
    }
    
    public void testar (String nomeAlgoritmo) {
        try {
            System.out.println (&quot;-----------------------&quot;);
            System.out.println (&quot;Nome do algoritmo: &quot; + nomeAlgoritmo);
            Cipher cipher = Cipher.getInstance (nomeAlgoritmo);
            String nomeAbreviado = nomeAlgoritmo.split(&quot;/&quot;)[0];
            KeyGenerator kg = KeyGenerator.getInstance(nomeAbreviado);
            SecretKey skOriginal = kg.generateKey();
            byte[] chave = skOriginal.getEncoded();
            printHex (&quot;Chave original: &quot;, chave);
            alteraUmBit (chave);
            printHex (&quot;Chave alterada: &quot;, chave);
            // Para simplificar, crie um dado cujo tamanho é múltiplo de 16.
            byte[] dadosOriginais = gerarDados (128);
            printHex (&quot;Dados originais: &quot;, dadosOriginais);
            SecretKey skAlterada = new SecretKeySpec (chave, nomeAbreviado);
            cipher.init (Cipher.ENCRYPT_MODE, skOriginal);
            byte[] dadosCifrados = cipher.doFinal(dadosOriginais);
            
            cipher.init (Cipher.DECRYPT_MODE, skOriginal);
            byte[] dadosDecifrados = cipher.doFinal (dadosCifrados);
            printHex (&quot;Dados decifrados com a chave original: &quot;, dadosDecifrados);
            byte[] dadosComparados = comparar (dadosOriginais, dadosDecifrados);
            printHex (&quot;Comparação: &quot;, dadosComparados);
            System.out.printf (&quot;A quantidade de bits que foi alterada é de %.2f %%.%n&quot;, 
                100.0 * calcularProporcaoBitsAlterados(dadosComparados));
            
            cipher.init (Cipher.DECRYPT_MODE, skAlterada);
            byte[] dadosDecifradosComChaveAlterada = cipher.doFinal (dadosCifrados);
            
            printHex (&quot;Dados decifrados com a chave alterada: &quot;, dadosDecifradosComChaveAlterada);
            dadosComparados = comparar (dadosOriginais, dadosDecifradosComChaveAlterada);
            printHex (&quot;Comparação: &quot;, dadosComparados);
            System.out.printf (&quot;A quantidade de bits que foi alterada é de %.2f %%.%n&quot;, 
                100.0 * calcularProporcaoBitsAlterados(dadosComparados));
            
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (IllegalStateException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        }
    }
    
    public static void main(String[] args) {
        Perturbacao p = new Perturbacao();
        p.testar();
    }
}

ok! muito Obrigada

Uma coisa interessante dos algoritmos de criptografia profissionais é que a saída é completamente indistinguível de dados aleatórios. Modificando o programa acima para comparar os dados decifrados com a chave certa e uma quantidade de dados aleatórios com o mesmo tamanho, o comparador também diz que cerca de 50% dos bits foram alterados.

bah tche!!

muito obrigada pelo exemplo! :slight_smile: