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!!
Criptografia rsa em java
35 Respostas
Pesquise aqui mesmo no fórum que já tem exemplos…
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 < 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 > 1; --j)
System.out.print (" ");
System.out.print (" - ");
int start = (i / 16) * 16;
int end = (b.length < i + 1) ? b.length : (i + 1);
for (j = start; j < end; ++j)
if (b[j] >= 32 && b[j] <= 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"));
}
}
putz…valeu ai galera, mas acho que em breve vou precisar de mais ajuda. Abraços
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.
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?
Uai, como é que você vai decifrar algo decifrado? Vai dar pau mesmo.
byte[] decifrado = dcf.decifra(pvk, textoClaro, pub.getEncoded());
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));
}
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. )
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
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”.)
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… 
Agradeço a disposição em ajudar… Obrigada 
Existem poucos tópicos aquí a respeito de criptografia, e este está off, mais será que ninguém mais pode me ajudar? 
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.
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);
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... :)
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.
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?
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:
É 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.
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:
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).
thingol, agora deu certo… Obrigada pelas explicações e grande paciência… :thumbup:
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.
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.
Valeu pela dica, já peguei o livro.
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?
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.
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
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.
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.
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.
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!
no lugar de BC troque por new BouncyCastleProvider()
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).
exato…
security.provider.7=org.bouncycastle.jce.provider.BouncyCastleProvider
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…