Criptografia rsa em java

35 respostas
S

dudes…parabens pelo site em primeiro lugar!
To fazendo um tcc na area de criptografia, e preciso implementar um software. O sistema que eu escolhi foi o rsa, mas nao manjo quase nada de programação. Alguem pode me indicar um site que eu ache um algoritmo pronto para o netbeans?? Obrigado!!

35 Respostas

I

Pesquise aqui mesmo no fórum que já tem exemplos…

T

Não use criptografia RSA para criptografar mais que 100 bytes.
Normalmente RSA é usado para criptografar chaves, não dados.
Eis um exemplo (grave este programa em um arquivo chamado "ExemploCriptografia.java", compile-o e o rode com:
java -cp . ExemploCriptografia
)

import java.io.*;
import java.util.*;
import javax.crypto.*;
import javax.crypto.spec.*;
import java.security.*;
import java.security.spec.*;
import java.security.cert.*;

class Cifrador {
    public byte[][] cifra (PublicKey pub, byte[] textoClaro) throws NoSuchAlgorithmException, 
    NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException,
    BadPaddingException, InvalidAlgorithmParameterException {
        byte[] textoCifrado = null;
        byte[] chaveCifrada = null;
        
        //-- A) Gerando uma chave simétrica de 128 bits
        KeyGenerator kg = KeyGenerator.getInstance ("AES");
        kg.init (128);
        SecretKey sk = kg.generateKey ();
        byte[] chave = sk.getEncoded();
        //-- B) Cifrando o texto com a chave simétrica gerada
        Cipher aescf = Cipher.getInstance ("AES/CBC/PKCS5Padding");
        IvParameterSpec ivspec = new IvParameterSpec (new byte[16]);
        aescf.init (Cipher.ENCRYPT_MODE, new SecretKeySpec (chave, "AES"), ivspec);
        textoCifrado = aescf.doFinal (textoClaro);
        //-- C) Cifrando a chave com a chave pública
        Cipher rsacf = Cipher.getInstance ("RSA");
        rsacf.init (Cipher.ENCRYPT_MODE, pub);
        chaveCifrada = rsacf.doFinal (chave);
        
        return new byte[][] { textoCifrado, chaveCifrada };
    }
}

class Decifrador {
    public byte[] decifra (PrivateKey pvk, byte[] textoCifrado, byte[] chaveCifrada) throws NoSuchAlgorithmException, 
    NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException,
    BadPaddingException, InvalidAlgorithmParameterException  {
        byte[] textoDecifrado = null;
        
        //-- A) Decifrando a chave simétrica com a chave privada
        Cipher rsacf = Cipher.getInstance ("RSA");
        rsacf.init (Cipher.DECRYPT_MODE, pvk);
        byte[] chaveDecifrada = rsacf.doFinal (chaveCifrada);
        //-- B) Decifrando o texto com a chave simétrica decifrada
        Cipher aescf = Cipher.getInstance ("AES/CBC/PKCS5Padding");
        IvParameterSpec ivspec = new IvParameterSpec (new byte[16]);
        aescf.init (Cipher.DECRYPT_MODE, new SecretKeySpec (chaveDecifrada, "AES"), ivspec);
        textoDecifrado = aescf.doFinal (textoCifrado);
        
        return textoDecifrado;
    }
}

class CarregadorChavePublica {
    public PublicKey carregaChavePublica (File fPub) throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream (new FileInputStream (fPub));
        PublicKey ret = (PublicKey) ois.readObject();
        ois.close();
        return ret;
    }
}

class CarregadorChavePrivada {
    public PrivateKey carregaChavePrivada (File fPvk) throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream (new FileInputStream (fPvk));
        PrivateKey ret = (PrivateKey) ois.readObject();
        ois.close();
        return ret;
    }
}


class GeradorParChaves {
    private static final int RSAKEYSIZE = 1024;
    
    public void geraParChaves(File fPub, File fPvk) 
        throws IOException, NoSuchAlgorithmException, 
        InvalidAlgorithmParameterException, 
        CertificateException, KeyStoreException {
            
        KeyPairGenerator kpg = KeyPairGenerator.getInstance ("RSA");
        kpg.initialize (new RSAKeyGenParameterSpec(RSAKEYSIZE, RSAKeyGenParameterSpec.F4));
        KeyPair kpr = kpg.generateKeyPair ();
        PrivateKey priv = kpr.getPrivate();        
        PublicKey pub = kpr.getPublic();
        
        //-- Gravando a chave pública em formato serializado
        ObjectOutputStream oos = new ObjectOutputStream (new FileOutputStream (fPub));
        oos.writeObject (pub);
        oos.close();
        
        //-- Gravando a chave privada em formato serializado
        //-- Não é a melhor forma (deveria ser guardada em um keystore, e protegida por senha), 
        //-- mas isto é só um exemplo
        oos = new ObjectOutputStream (new FileOutputStream (fPvk));
        oos.writeObject (priv);
        oos.close();
        
    }
}

class ExemploCriptografia {
    static void printHex(byte[] b) {
        if (b == null) {
            System.out.println ("(null)");
        } else {
        for (int i = 0; i &lt b.length; ++i) {
            if (i % 16 == 0) {
                System.out.print (Integer.toHexString ((i & 0xFFFF) | 0x10000).substring(1,5) + " - ");
            }
            System.out.print (Integer.toHexString((b[i]&0xFF) | 0x100).substring(1,3) + " ");
            if (i % 16 == 15 || i == b.length - 1)
            {
                int j;
                for (j = 16 - i % 16; j &gt 1; --j)
                    System.out.print ("   ");
                System.out.print (" - ");
                int start = (i / 16) * 16;
                int end = (b.length &lt i + 1) ? b.length : (i + 1);
                for (j = start; j &lt end; ++j)
                    if (b[j] &gt= 32 && b[j] &lt= 126)
                        System.out.print ((char)b[j]);
                    else
                        System.out.print (".");
                System.out.println ();
            }
        }
        System.out.println();
        }
    }    
    
    public static void main(String[] args) throws Exception {
        //-- Gera o par de chaves, em dois arquivos (chave.publica e chave.privada)
        GeradorParChaves gpc = new GeradorParChaves();
        gpc.geraParChaves (new File ("chave.publica"), new File ("chave.privada"));

        //-- Cifrando a mensagem "Hello, world!"
        byte[] textoClaro = "Hello, world!".getBytes("ISO-8859-1");
        CarregadorChavePublica ccp = new CarregadorChavePublica();
        PublicKey pub = ccp.carregaChavePublica (new File ("chave.publica"));
        Cifrador cf = new Cifrador();
        byte[][] cifrado = cf.cifra (pub, textoClaro);
        printHex (cifrado[0]);
        printHex (cifrado[1]);
        
        //-- Decifrando a mensagem 
        CarregadorChavePrivada ccpv = new CarregadorChavePrivada();
        PrivateKey pvk = ccpv.carregaChavePrivada (new File ("chave.privada"));
        Decifrador dcf = new Decifrador();
        byte[] decifrado = dcf.decifra (pvk, cifrado[0], cifrado[1]);
        System.out.println (new String (textoClaro, "ISO-8859-1"));
    }
}
S

putz…valeu ai galera, mas acho que em breve vou precisar de mais ajuda. Abraços

L

thingol,

Estou estudando um pouco de Criptografia, pois terei de usá-lo para criptografar e descriptografar uma base de dados, e nos exemplos que encontrei na net, o seu foi o mais claro e eficiente q encontrei, parabéns…

Porém gostaria de saber se vc pode me ajudar… o código funciona perfeitamente, porém qdo eu separo as classes e vou utilizar o “Decifrador” separadamente do “Cifrador” para descriptografar um txt previamente criptografado com este código, este dá o seguinte erro:

Exception in thread "main" javax.crypto.IllegalBlockSizeException: Data must not be longer than 128 bytes
	at com.sun.crypto.provider.RSACipher.a(DashoA13*..)
	at com.sun.crypto.provider.RSACipher.engineDoFinal(DashoA13*..)
	at javax.crypto.Cipher.doFinal(DashoA13*..)
	at Decifrador.decifra(Decifrador.java:31)
	at Decifrador.main(Decifrador.java:85)

Para descriptografar este arquivo, eu mudei a linha 151 do seu código, ficando da seguinte forma:

byte[] decifrado = dcf.decifra(pvk, textoClaro, pub.getEncoded());

Visto que eu não quero chamar a criptografia novamente, antes de descriptografar…

Você pode me orientar para saber oq está ocorrendo?

Desde já agradeço.

T

Uai, não sei onde é que pode dar esse erro. Rodei meu programa novamente (mas com um conjunto de dados bem maior) e ele funciona corretamente. Qual foi a modificação que você fez no meu código?

T

Uai, como é que você vai decifrar algo decifrado? Vai dar pau mesmo.

byte[] decifrado = dcf.decifra(pvk, textoClaro, pub.getEncoded());
L

Bom, vou separar as variáveis pra ficar mais claro…

Mais na verdade o “textoClaro” é o que está criptografado no arquivo txt.

segue pra ficar amis claro:

File bdOne = new File(System.getProperty("user.dir").concat(
        				"\IF001.fdb"));
        	File bdTwo = new File(System.getProperty("user.dir").concat(
        				"\IF002.fdb"));
        
        	FileInputStream in = new FileInputStream(bdOne);
        
        	InputStreamReader conversor = new InputStreamReader(in);
        
        	BufferedReader bf = new BufferedReader(conversor);
        
        	RandomAccessFile random = new RandomAccessFile(bdTwo, "r");
        
        	int i = 0;
        	
        	while ((linha = bf.readLine()) != null) {
        	    i++;
        	
        		content = linha.split(" ");
        		Long convert = new Long(content[1]);
        
        		random.seek(convert.parseLong(content[1]));
        		random.readLine();
        
        		conteudo = random.readLine();
        		byte[] textoCifrado = conteudo.getBytes();
        
        		CarregadorChavePublica ccp = new CarregadorChavePublica();
        		PublicKey pub = ccp.carregaChavePublica(new File(System.getProperty("user.dir").concat("\chave.publica")));
        		
        		// -- Decifrando a mensagem
        		CarregadorChavePrivada ccpv = new CarregadorChavePrivada();
        		PrivateKey pvk = ccpv.carregaChavePrivada(new File(System.getProperty("user.dir").concat("\chave.privada")));
        		Decifrador dcf = new Decifrador();
        		
			byte[] decifrado = dcf.decifra(pvk, textoCifrado , pub.getEncoded());
        
        		System.out.println(new String(decifrado));
        
        	}
T

Ah, é que não ficou muito claro no programa que eu mostrei.

A rotina “cifra” retorna 2 arrays de bytes: um deles com os dados cifrados, e outro deles com a chave simétrica (AES) cifrada com a chave assimétrica (RSA).
Quando você vai guardar esses dados, você precisa guardar os 2 arrays, não só um deles. Se você não guardar a chave simétrica cifrada com a chave assimétrica, então você nunca conseguirá decifrar os dados cifrados. Não é perigoso guardar a chave simétrica cifrada, porque ela só poderá ser decifrada por alguém que tiver a chave privada disponível.

Quando você for decifrar os dados, você precisa passar a chave privada (primeiro parâmetro), os dados cifrados (segundo parâmetro), e a chave simétrica cifrada com a chave assimétrica (terceiro parâmetro).

Se você acha isso esquisito, é o jeito correto de fazer, que é usado no padrão PKCS#7 signedData, e no padrão S/MIME (usado para mandar e-mails criptografados pelo MS Outlook, MS Outlook Express, Eudora, Mozilla Thunderbird, etc. )

L

Obrigada pela paciência e grande ajuda thingol, mais assim, eu estou passando sim os três parâmetros... o estranho é q o programa funciona perfeitamente qdo rodo ele cifrando e decifrando logo em seguida, assim como está seu programa...

Agora se eu separo as classes, cifro um conteúdo e guardo em um arquivo, e depois só rodo o decifrar, ele emite esse erro... porém não entendo, pq eu estou guardando os arquivos com as chaves e lendo as duas, a pública e a privada e tbm leio no arquivo o conteúdo a ser decifrado, porém emite esse erro...

fiz algunst estes e o problema está justamente na linha

// pvk - chave privada, textoCifrado - conteúdo codificado obtido do arquivo txt, pub.getEncoded() - chave pública

byte[] decifrado = dcf.decifra(pvk, textoCifrado, pub.getEncoded());

Eu não mantive da forma original, pois este envocava antes a classe para cifrar, e não é oq eu quero, pois este já está no arquivo, eu gostaria apenas de decifrar o conteúdo deste arquivo.

Desde já agradeço novamente... :D

T

O primeiro parâmetro é a chave privada (ok)
O segundo é o texto cifrado (ok)
O terceiro não é a chave pública e sim a chave simétrica cifrada. (No programa acima era o elemento cifrado[1] do array de arrays retornado por “cifra”.)

L

Sim, exatamente isso, mais o “Decifra” não tem a função de tbm pegar essa chave pública criptografada, e descriptografar esta chave e com ela, tbm decifrar o texto?

Eu não queria ter de chamar o cifra, pois eu quero apenas decifrar…chamando o cifra para obter a chave, eu criptografo novamente um conteúdo q já está criptografado, e não é isso q eu quero…

O problema é que o Decifra recebe a chave pública como um array de bytes e não como um objeto PublicKey, com isso, eu não consigo transformar este objeto PublicKey em um array de bytes, caso conseguisse fazer isso, creio q resolveria meu problema.

como poderia fazer para utilizar somente o decifra, utilizando uma chave pública previamente criada e armazenada em um arquivo? Já repliquei o método cifra e tirei a parte de cifrar o texto e deixei a parte da chave para tentar utilizá-la separadamente, já tentei transformar a chave em um array de bytes, já tentei um pouco de tudo e obti diversos erros, não sei mais oq posso fazer… conto com a sua ajuda… :frowning:

Agradeço a disposição em ajudar… Obrigada :smiley:

L

Existem poucos tópicos aquí a respeito de criptografia, e este está off, mais será que ninguém mais pode me ajudar? :cry:

T

Calma, vou explicar tudo de novo. Pegue a sua cadeirinha e sente-se.

Normalmente, quando se quer cifrar uma grande quantidade de dados (ou seja, mais de 100 bytes), usa-se sempre criptografia normal (ou simétrica, onde a mesma chave que serve para cifrar um dado serve para decifrá-la. Ou seja, é uma chave “secreta” ou “simétrica”).
As vantagens da criptografia simétrica são:

  • Muito mais rápida
  • Segura para pequenas ou grandes quantidades de dados.
    O algoritmo recomendado hoje em dia é o AES ou Rijndael (com força de 128, 192 ou 256 bits); usei no exemplo o AES com chave de 128 bits.
    Entretanto, para você mandar um dado criptografado com criptografia simétrica, é necessário que ambas as partes (remetente e destinatário) conheçam a chave simétrica. Você deve saber muito bem que é difícil mandar essa chave a menos que você pessoalmente apareça com um envelope e o dê nas mãos da pessoa (é modo de dizer); você não pode mandá-la pelo telefone, e muito menos via sockets.
    A criptografia assimétrica veio para ajudar a resolver esse problema. Se você conhecer a chave PÚBLICA do destinatário, você pode mandar um dado (com menos de 100 bytes) para ele, criptografado com a chave PÚBLICA, de modo que o destinatário use a chave PRIVADA para decifrá-la.
    Dados com mais bytes não devem ser criptografados com criptografia assimétrica (por exemplo, RSA), porque isso expõe uma vulnerabilidade nesses algoritmos que só se manifesta quando a quantidade de dados é grande e os dados criptografados podem ser conhecidos. Por exemplo, se você criptografasse uma mensagem - como uma página HTML - integralmente com o algoritmo RSA, ela tem alguns valores conhecidos em vários pontos, como o começo, que normalmente é “”.
    E como o meu programa faz isso? Ele gera uma chave simétrica, que será usada para criptografar os dados a serem enviados. O remetente tem de mandar para o destinatário:
  • Os dados criptografados com a chave simétrica gerada pelo remetente (algoritmo AES)
  • A chave simétrica criptografada com a chave pública do destinatário (algoritmo RSA)
    O destinatário, para decifrar a mensagem, deve obter:
  • Os dados criptografados com a chave simétrica gerada pelo remetente (algoritmo AES)
  • A chave simétrica criptografada (algoritmo RSA)
    O que ele tem de fazer com os dados recebidos:
  • Tem de decifrar a chave simétrica criptografada com a chave privada do destinatário (usando o algoritmo RSA)
  • Uma vez decifrada essa chave simétrica, deve usá-la para decifrar os dados recebidos (usando o algoritmo AES)
    Note que nesse processo o destinatário NÃO PRECISA da própria chave pública. O destinatário só precisa da CHAVE PRIVADA.
L

Obrigada pela paciência thingol... muitas coisas eu já havia entendido, e algumas outras ficaram mais claras para mim...

Vamos lá:

O remetente tem de mandar para o destinatário: - Os dados criptografados com a chave simétrica gerada pelo remetente (algoritmo AES) - A chave simétrica criptografada com a chave pública do destinatário (algoritmo RSA)
Ok, isso eu entendi... que em código seria:
// -- B) Cifrando o texto com a chave simétrica gerada
		Cipher aescf = Cipher.getInstance("AES/CBC/PKCS5Padding");
		IvParameterSpec ivspec = new IvParameterSpec(new byte[16]);
		aescf.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(chave, "AES"), ivspec);
		textoCifrado = aescf.doFinal(textoClaro);

// -- C) Cifrando a chave com a chave pública
		Cipher rsacf = Cipher.getInstance("RSA");
		rsacf.init(Cipher.ENCRYPT_MODE, pub);
		chaveCifrada = rsacf.doFinal(chave);
O destinatário, para decifrar a mensagem, deve obter: - Os dados criptografados com a chave simétrica gerada pelo remetente (algoritmo AES) - A chave simétrica criptografada (algoritmo RSA)

que em código:

return new byte[][] { textoCifrado, chaveCifrada };
O que ele tem de fazer com os dados recebidos: - Tem de decifrar a chave simétrica criptografada com a chave privada do destinatário (usando o algoritmo RSA) - Uma vez decifrada essa chave simétrica, deve usá-la para decifrar os dados recebidos (usando o algoritmo AES)

Certo, que isto seria o papel do Decifrar

// -- A) Decifrando a chave simétrica com a chave privada
		Cipher rsacf = Cipher.getInstance("RSA");
		rsacf.init(Cipher.DECRYPT_MODE, pvk);
		byte[] chaveDecifrada = rsacf.doFinal(pub);
		
// -- B) Decifrando o texto com a chave simétrica decifrada
		Cipher aescf = Cipher.getInstance("AES/CBC/PKCS5Padding");
		IvParameterSpec ivspec = new IvParameterSpec(new byte[16]);
		aescf.init(Cipher.DECRYPT_MODE, new SecretKeySpec(chaveDecifrada, "AES"), ivspec);
		textoDecifrado = aescf.doFinal(textoCifrado);
Note que nesse processo o destinatário NÃO PRECISA da própria chave pública. O destinatário só precisa da CHAVE PRIVADA.
Se ele não precisa da chave pública, o que seria o pub na linha 4
byte[] chaveDecifrada = rsacf.doFinal(pub);
do código acima... ?

Pois, para decifrar, vc passa os seguintes parâmetros:

byte[] textoCifrado = conteudo.getBytes();
        
        		CarregadorChavePublica ccp = new CarregadorChavePublica();
			PublicKey pub = ccp.carregaChavePublica(new File(System.getProperty("user.dir").concat("\chave.publica")));
			Cifrador cf = new Cifrador();
//////////////////////////////////////////////////////////////////////////
			byte[][] cifrado = cf.cifra(pub, textoCifrado);
//////////////////////////////////////////////////////////////////////////
        		
        		// -- Decifrando a mensagem
        		CarregadorChavePrivada ccpv = new CarregadorChavePrivada();
        		PrivateKey pvk = ccpv.carregaChavePrivada(new File(System.getProperty("user.dir").concat("\chave.privada")));
        		
        		Decifrador dcf = new Decifrador();
        
//////////////////////////////////////////////////////////////////////////////////////
        		byte[] decifrado = dcf.decifra(pvk, cifrado[0], cifrado[1]);
///////////////////////////////////////////////////////////////////////////////////////

Onde nas linhas destacadas pvk = chave privada, cifra[0] = textoCifrado e cifrado[1] = pub, que seria a chave Pública que é obtida seu eu chamo o cifra, sendo q eu quero apenas decifrar a mensagem e não cifrá-la novamente para depois decifrá-la.

Porém, partindo do princício, se eu modificar a linha destacada do código acima, da seguinte forma:

byte[] decifrado = dcf.decifra(pvk, textoCifrado, pub);

Não é possível fazer de tal forma pq o pub é um objeto tipo PublicKey e o decifra espera um parâmetro array de bytes...

Este está sendo o meu problema... eu não sei se estou sendo clara...

Peço desculpas caso eu tenha feito muita confusão, mas o conceito de criptografar e descriptografar creio que entendi, porém não sei ao certo então o que seria a variável pub no meio de tudo isso senão a chave pública. :roll:

Obrigada pela ótima e detalhada explicação thingol, porém ainda estou um pouco confusa, como tentei explicar acima.... :oops:

Abraços... :)

T
byte[][] cifrado = cf.cifra (pub, textoClaro);  
...
byte[] decifrado = dcf.decifra (pvk, cifrado[0], cifrado[1]);

Tá bom. Em cf.cifra, que deve ser chamada pelo remetente, eu pego o texto claro, a chave pública do destinatário, e:

  • Gero uma chave simétrica AES e a uso para criptografar o “textoClaro”
  • Criptografo a chave simétrica AES com a chave pública RSA
  • Retorno um array com 2 arrays de bytes. O primeiro array de bytes contém o textoClaro criptografado com a chave simétrica AES. O segundo array de bytes contém a chave simétrica AES criptografada com a chave pública RSA.

Em dcf.decifra, que deve ser chamada pelo destinatário, eu pego a chave privada do destinatário, o textoClaro criptografado com a chave simétrica AES, e a chave simétrica AES criptografada com a chave pública RSA. Aí eu faço o tal do processo inverso.

T

Perguntinha - pegue o programa original, e separe direito dessa vez em pedaços. Eu vi que você fez isto aqui:

byte[] chaveDecifrada = rsacf.doFinal(pub);

Mas eu não fiz isso aí de jeito nenhum. De onde você tirou isso?

L

thingol realmente esta linha estava diferente do seu código… nas diversas mudanças, devo ter mudado isso sem querer… :oops: sorry… por isso a minha confusão…

Mais de qualquer forma, como eu mesmo havia falado, o conceito e o funcionamento do seu código eu entendi… a minha dúvida é como vou passar a chave simétrica criptografada para o Decifra sem chamar o Cifra, pois eu quero somente descriptografar… sendo que se eu duplico o método cifra e retiro apenas a parte do texto e retorno apenas a chave, ocorre uma mensagem de erro…

:shock:

T

É que é o seguinte: experimente rodar o tal código diversas vezes com os mesmos dados de entrada.

Você vai ver que a tal chave criptografada MUDA SEMPRE, e isso faz com que os dados criptografados MUDEM SEMPRE.

Portanto é necessário mandar do remetente para o destinatário os dados criptografados e a chave criptografada.

Não dá para mandar só os dados ou só a chave - os dados e a chave são “casados”.

No PKCS#7 envelopedData, que é o formato-padrão para mandar dados criptografados usando-se, por exemplo, RSA + AES, tanto os dados quanto a chave são sempre enviados.

L

Certo, as chaves são criadas de forma randômica, mais então não teria como eu utilizar a mesma chave criada anteriormente, com o mesmo texto criptografado só para descriptografar?

Seria então “obrigatório” eu chamar o cifra para decifrar? isso acaba criptografando algo q já foi criptografado anteriormente e jogado no banco…

Portanto eu só consigo utilizar o Decifra, caso eu esteja criptografando o conteúdo q eu quero descriptografar simultaneamente, é isso? :shock:

T

Não, não, não; você usa o cifra para cifrar, e ele lhe volta 2 arrays de bytes, que você envia para o destinatário de forma separada (por exemplo, como 2 arquivos, ou então como 2 blobs no banco de dados).

No outro lado, você usa o decifra para decifrar, e ele precisa desses 2 arrays de bytes, que você precisa pegar de algum lugar.

Se quiser pôr tudo em um array só, não tem problema, mas você tem de saber qual é o tamanho ocupado pela chave criptografada (que nesse caso é 128 bytes) e o tamanho ocupado pelos dados criptografados (que é igual ao tamanho dos dados originais, mais 1 a 16 bytes necessários para completar um múltiplo de 16).

L

thingol, agora deu certo… Obrigada pelas explicações e grande paciência… :thumbup:

B

Olá a todos,

Estou tentando criptografar alguns dados com RSA, mas gostaria de carregar a chave publica a partir de uma string. Mas não estou tendo sucesso em carregar uma String em um PublicKey, alguém tem alguma idéia de como fazer ?

Também gostaria de saber como eu configuro o valor do expoente.

T

Dica: arranje o livro “Beginning Cryptography with Java”, de David Hook, que lhe dará um monte de informações sobre o que você precisa. Ele tem todas as receitas de bolo.

B

Valeu pela dica, já peguei o livro.

B

thingol,

O Livro foi muito útil mesmo, esclareceu todas as dúvidas e funcionou como eu precisava.Obrigado!

Agora estou com o seguinte problema, a criptografia vai funcionar dentro de um applet e o uso do Bouncy Castle como provider me obriga a ter o jar dele instalado no diretório do JRE, teria como incorporar ele ao meu código para que o usuário não tivesse que colocar o arquivo no JRE dele?

T

Você pode usar algumas rotinas do BouncyCastle sem que ele seja provider, mas é questão de testar. Não sei o que você está usando em seu programa; de qualquer maneira, veja (talvez no livro) como é que se adiciona dinamicamente um provider em tempo de execução, sem que seja necessário modificar o arquivo java.security.

L

thingol,

Parabéns pelo belo exemplo, realmente foi de muita valia para o meu entendimento sobre criptografia utilizando RSA e Java. Funcionou 100%.

Percebo por suas explicações claras e coesas sobre este assunto que talvez possa me orientar na resolução de um problema que estou enfrentando.

Recebi de um cliente atendido por nossa empresa o seguinte cenário:

[list]Um arquivo chamado “chave_publica.pem”[/list]
[list]Um arquivo chamado “chave_privada.der”[/list]
[list] A especificação para construir um cliente java que criptografa um número de cartão de crédito utilizando a chave pública (chave_publica.pem) fornecida por eles e um servidor java que receberá a String criptografada e decriptografe utilizando a chave privada (chave_privada.der).
[/list]

Este sistema já existia anteriormente, porém era desenvolvido em ASP, utilizava uma DLL do OpenSSL para realizar criptografia e decriptografia. A necessidade de portar este sistema para Java tem sido um grande desafio pra mim, estou a três dias tentando encontrar uma orientação concreta mas estou perdendo o fio da meada em algum momento.

É realmente possível fazer o que me foi solicitado? Se sim pode me orientar? Qualquer ajuda será de enorme valia.

Agradeço desde já pela atenção,


Conteúdo da chave_publica.pem

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv4Lvd+7YZxMDTw5cKCLe
uLebDQcPNVRukzh4R4gh+fArX2CiU79Sv2XtCXBFEI4YdVe3OKRki4bXFgcZ/vFK
AMf4ly9+maHlA/4NggRj/ZpI8wYY6Plc5JZkPaLqiwiYehFLKqRG490xyxO7T194
hKJb0pGvCVNuB3akIOP9fOwc/SRnFpQG3YiflqBaj2G0oclxkUHt2co3+JA6wEgv
0fcxBc7B45+VwXjx06oJlzxpAIchtJL5xE8d3sOoA/d9EvuVsr+ffFddgyqkemyi
kUE2CGt4dOxGh4a/0zX9Mrsul2V1Nt3K0uibptAhuouxMj3IuSdUCQBeaUrq4Nrw
YwIDAQAB
-----END PUBLIC KEY-----

Obs.: Por questões legais não posso publicar a chave privada, mas entenda como sendo um par desta chave pública em formato .DER

T

Se não me engano, o BouncyCastle tem algumas rotinas que permitem entender o formato PEM tanto para chaves privadas quanto públicas.
O formato PEM do OpenSSL é mais antigo que os padrões PKCS#9 (chave pública) e PKCS#12 (chave privada), se não me engano, portanto é necessário ter código especial para usá-lo.
Dê uma procuradinha na documentação do BouncyCastle. Ele deve ter até umas classes “OpenSSL” ou coisa parecida.
De qualquer maneira, se esse cliente Java puder chamar um programa externo (como o OpenSSL.exe) e não tiver problemas de desempenho (do tipo “eu preciso decifrar 1000 números de cartões por segundo”) você pode chamar o openssl.exe com um monte de parâmetros adequados, e obter um arquivo com os dados decifrados.

T

Olá Pessoal!!
Implementei um Web Service que faz encriptação e assinatura digital, separadamente.
Porém, eu preciso assinar uma mensagem e depois encriptar essa mesma mensagem que foi assinada digitalmente, garanntindo assim a confidencialidade, autenticidade e não-repúdio.
Está dando o seguinte erro, quando analiso o log do servidor e não estou sabendo como resolver.

12/02/2009 17:00:08 com.sun.xml.ws.server.sei.EndpointMethodHandler invoke

INFO: Data must not be longer than 53 bytes

javax.crypto.IllegalBlockSizeException: Data must not be longer than 53 bytes

at com.sun.crypto.provider.RSACipher.a(DashoA13*)

at com.sun.crypto.provider.RSACipher.engineDoFinal(DashoA13*)

at javax.crypto.Cipher.doFinal(DashoA13*)

at SecurityServices.INCA.codifica(INCA.java:33)

at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)

at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)

at java.lang.reflect.Method.invoke(Method.java:597)

at com.sun.xml.ws.api.server.InstanceResolver$1.invoke(InstanceResolver.java:246)

at com.sun.xml.ws.server.InvokerTube$2.invoke(InvokerTube.java:146)

at com.sun.xml.ws.server.sei.EndpointMethodHandler.invoke(EndpointMethodHandler.java:257)

at com.sun.xml.ws.server.sei.SEIInvokerTube.processRequest(SEIInvokerTube.java:93)

at com.sun.xml.ws.api.pipe.Fiber.__doRun(Fiber.java:598)

at com.sun.xml.ws.api.pipe.Fiber._doRun(Fiber.java:557)

at com.sun.xml.ws.api.pipe.Fiber.doRun(Fiber.java:542)

at com.sun.xml.ws.api.pipe.Fiber.runSync(Fiber.java:439)

at com.sun.xml.ws.server.WSEndpointImpl$2.process(WSEndpointImpl.java:243)

at com.sun.xml.ws.transport.http.HttpAdapter$HttpToolkit.handle(HttpAdapter.java:444)

at com.sun.xml.ws.transport.http.HttpAdapter.handle(HttpAdapter.java:244)

at com.sun.xml.ws.transport.http.servlet.ServletAdapter.handle(ServletAdapter.java:135)

at com.sun.xml.ws.transport.http.servlet.WSServletDelegate.doGet(WSServletDelegate.java:129)

at com.sun.xml.ws.transport.http.servlet.WSServletDelegate.doPost(WSServletDelegate.java:160)

at com.sun.xml.ws.transport.http.servlet.WSServlet.doPost(WSServlet.java:75)

at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)

at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)

at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)

at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)

at org.netbeans.modules.web.monitor.server.MonitorFilter.doFilter(MonitorFilter.java:390)

at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)

at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)

at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)

at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)

at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)

at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)

at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)

at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:286)

at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:845)

at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)

at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)

at java.lang.Thread.run(Thread.java:619)

Alguém podería me ajudar?
Desde já agradeço pela ajuda.

T

Dá a impressão que você está tentando chamar o RSA diretamente sobre os dados, em vez de fazê-lo sobre um hash dos dados.

T

Obrigado pela dica thingol…
Uma outra dúvida pessoal…
Estou executando alguns código do livro Beginning Cryptography, mas tem dado o seguinte problema:

Exception in thread “main” java.security.NoSuchProviderException: no such provider: BC

at sun.security.jca.GetInstance.getService(GetInstance.java:66)

at sun.security.jca.GetInstance.getInstance(GetInstance.java:190)

at java.security.KeyPairGenerator.getInstance(KeyPairGenerator.java:237)

at chapter6.Utils.generateRSAKeyPair(Utils.java:15)

at chapter6.X509V1CreateExample.main(X509V1CreateExample.java:34)

Estou começando a trabalhar agora com a Bouncy Castle e não estou conseguindo resolver o problema.
Vlw!

W

no lugar de BC troque por new BouncyCastleProvider()

T

Você não seguiu adequadamente as instruções do livro. Para que haja um provider “BC”, você precisa copiar alguns dos JARs do BouncyCastle para o diretório jre/lib/ext e alterar um arquivo java.security (resumidamente).

W

exato…

security.provider.7=org.bouncycastle.jce.provider.BouncyCastleProvider
T

Olá pessoal!
Estou fazendo uma assinatura em um arquivo pdf, mas na hora de verificar a mesma está dando os seguintes erros…

java.security.cert.CertificateException: java.io.IOException: DerInputStream.getLength(): lengthTag=109, too big.

at sun.security.provider.X509Factory.engineGenerateCertificates(X509Factory.java:419)

at java.security.cert.CertificateFactory.generateCertificates(CertificateFactory.java:427)

at chapter16.SignedPdfMODIFICADO.main(SignedPdfMODIFICADO.java:148)

Caused by: java.io.IOException: DerInputStream.getLength(): lengthTag=109, too big.

at sun.security.util.DerInputStream.getLength(DerInputStream.java:544)

at sun.security.util.DerValue.init(DerValue.java:346)

at sun.security.util.DerValue.(DerValue.java:302)

at sun.security.provider.X509Factory.parseX509orPKCS7Cert(X509Factory.java:532)

at sun.security.provider.X509Factory.engineGenerateCertificates(X509Factory.java:417)

… 2 more

o meu trecho do código é o seguinte:
System.out.println("-----> Começa o processo de verificação da assinatura."); CertificateFactory cf = CertificateFactory.getInstance("X509"); //Collection col = cf.generateCertificates(new FileInputStream("/home/thiago/iText/exemplos/chapter16/foobar.cer")); Collection col = cf.generateCertificates(new FileInputStream("/home/thiago/certificados/guj.jks")); KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); ks.load(null, null); for (Iterator it = col.iterator(); it.hasNext();) { X509Certificate cert = (X509Certificate) it.next(); System.out.println(cert.getIssuerDN().getName()); ks.setCertificateEntry(cert.getSerialNumber().toString(Character.MAX_RADIX), cert); } reader = new PdfReader("/home/thiago/iText/exemplos/chapter16/signed_messageTESTE.pdf"); AcroFields af = reader.getAcroFields(); ArrayList names = af.getSignatureNames(); String name;

Obrigado!
Abraço a todos…

Criado 4 de abril de 2007
Ultima resposta 28 de jul. de 2009
Respostas 35
Participantes 8