Uma das especificações do PAF-ECF é criptografar um bloco de dados 128 bytes gerados por outros passos anteriormente…
O problema é…
Se eu criptografar com RSA, ele não aceita, me retorna que pode somente criptografar 117 bytes no máximo…
Alguém já fez essa assinatura do EAD…quais os passos que usou para assinar?
o que eu fiz foi…
Gerei um MD5 do texto contido no arquivo…
Gerei um array de 128 bytes, onde a primeira posição é o num 16 que é o tamanho do hash
depois adicionei nesse array o hash md5 nas próximas posições que chega até a posicao 16 do array…
até aí tudo bem, mas daí quando vou passar esse array de bytes para criptografar em RSA, dá o erro…
o que devo fazer…
a rotina para criptografar que eu faço é
Signature sig = Signature.getInstance( "NONEwithRSA");
sig.initSign(pk);//pk é private key que passo como argumento para o método
sig.update(b,0,b.length);
byte[] retorno = sig.sign();
e o engraçado se eu passar um array de bytes menor, ele aceita e criptografa certo
Já pensou em usar o openssl para fazer a criptografia? Homologamos o PAF sem problemas dessa forma
Obrigado pela atenção… no caso do openssl, como eu faria para gerar o rsa certinho, nunca mechi nele…
Em vez do signature , usei esse código e funcionou a geração do RSA
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
// -- A) Gerando uma chave simétrica de 128 bits
Cipher rsacf = Cipher.getInstance("RSA", "BC");
rsacf.init(Cipher.ENCRYPT_MODE, pk);//Chave privada
byte[] b1 = new byte[128];
int ret = rsacf.doFinal(b, 0, b.length, b1);
return b1;
Porém…não está validando lá no eECFc… só mostra a msg “Assinatura inválida”
Essa é classe que utilizamos pra fazer toda a operação de assinatura que o PAF exige
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.text.MessageFormat;
/**
* Classe para controle da assinatura digital que deve ser aplicada nos arquivos do PAF
*/
public class AssinaturaDigitalPAF {
private String openssl=null;
private String erro=null;
private static StringBuffer modeloXMLConfig;
static {
// Arquivo Padrão Para Validação da Assinatura
modeloXMLConfig = new StringBuffer();
modeloXMLConfig.append("<?xml version=\"1.0\"?>\r\n");
modeloXMLConfig.append("<empresa_desenvolvedora>\r\n");
modeloXMLConfig.append(" <nome>Software House</nome>\r\n");
modeloXMLConfig.append(" <chave>\r\n");
modeloXMLConfig.append(" <modulo>{0}</modulo>\r\n");
modeloXMLConfig.append(" <expoente_publico>10001</expoente_publico>\r\n");
modeloXMLConfig.append(" </chave>\r\n");
modeloXMLConfig.append("</empresa_desenvolvedora>\r\n");
}
/**
* É definido o caminho do programa OpenSSL ao instanciar a classe conforme
* o sistema operacional
*/
public AssinaturaDigitalPAF(){
openssl="openssl";
}
/**
* @param e Erro ocorrido
* @return Retorna sempre falso para facilitar a saida dos outros metodos
* na ocorrencia de erro
*/
private boolean setErro(String e){
erro=e;
return false;
}
/**
* @return Erro ocorrido
*/
public String getErro(){
return erro;
}
/**
* Gera uma chave privada com o openssl
* @param pathKey Endereco no sistema de arquivode onde a chave sera gravada
* @return verdadeiro em caso de sucesso.
*/
public boolean gerarChavePrivada(String pathKey){
//validacoes
if(pathKey.length()==0)
return setErro("Endereço informado está inválido.");
File fPriv = new File(pathKey);
if (fPriv.exists())
return setErro("Chave privada já existe, apagar para continuar");
//Executa comando OpenSSL
//exemplo: openssl -genrsa -out saida.txt 1024
// openssl -genrsa -out "/teste pasta/saida.txt" 1024
if(!execRuntime(openssl + " genrsa -out \"" + fPriv.getAbsolutePath() + "\" 1024"))
return false;
return true;
}
/**
* Gera o XML de configuracoes da empresa desenvolvedora comforme a chave privada
* o XML é utilizado para validacao das assinaturas utilizando o programa do governo
* cECFc
* @param pathKey Endereço da chave privada
* @param pathHouse Endereço onde será gravada o XML de configurações
* @return verdadeiro em caso de sucesso
*/
public boolean gerarConfiguracoes(String pathKey,String pathHouse) {
// validacoes
if(pathHouse.length()==0)
return setErro("Endereço informado está inválido.");
File fPriv=new File(pathKey);
if(!fPriv.exists())
return setErro("Chave privada não encontrada");
// Se encontrou o modulo deleta
File fMod = new File("modulo.txt");
if (fMod.exists())
fMod.delete();
// Se encontrou configuracao deleta
File fXml = new File(pathHouse);
if (fXml.exists())
fXml.delete();
// Cria o arquivo de modulo da chave privada
if(!execRuntime(openssl + " rsa -in \"" + fPriv.getAbsolutePath() + "\" -modulus -out "+fMod.getName()))
return false;
// Lendo o arquivo com o módulo
// Primeira linha do arquivo do módulo, contem o módulo
// Modulus=B4FCFDB3E...F1B85675F42646EDC5
try{
BufferedReader modIn = new BufferedReader(new FileReader(fMod));
String modulo = modIn.readLine();
modIn.close();
// Leitura do módulo após o sinal de igual
modulo = modulo.substring(modulo.indexOf('=') + 1);
// Inserindo módulo no Parâmetro
String xml = MessageFormat.format(modeloXMLConfig.toString(),new Object[]{modulo});
// Criando arquivo de configuracoes
FileOutputStream modOut = new FileOutputStream(fXml);
modOut.write(xml.getBytes());
modOut.flush();
modOut.close();
}
catch(IOException e){
return setErro("Erro ao gravar arquivo de configurações");
}
return true;
}
/**
* Assina um arquivo
* @param pathKey Endereço da chave privada
* @param pathFile Endereço do arquivo a ser assiado
* @return Verdadeiro em caso de sucesso
*/
public boolean assinaArquivo(String pathKey,String pathFile){
// validações
File fPriv = new File(pathKey);
if (!fPriv.exists())
return setErro("Chave privada nao encontrada");
File fArquivo = new File(pathFile);
if (!fArquivo.exists())
return setErro("Arquivo a ser assinado não encontrado");
// Verifica se é um arquivo ou diretório
if (fArquivo.isDirectory())
return setErro("Impossivel assinar um diretorio ["+fArquivo.getAbsolutePath()+"]");
// Verifica se tem permissao de escriuta
if (!fArquivo.canWrite())
return setErro("Sem permissao de escrita no arquivo ["+fArquivo.getAbsolutePath()+"]");
//arquivo temporario para receber a assinatura
File fSign = new File("sign.tmp");
//executa o comando openssl
String cmd=openssl + " dgst -md5 -sign \""
+ fPriv.getAbsolutePath() + "\" -out "
+ fSign.getName() + " -hex \""
+ fArquivo.getAbsolutePath()+"\"";
if(!execRuntime(cmd)) return false;
// Verifica se o arquivo foi gerado
if(!fSign.exists())
return setErro("Comando OpenSSL executado, porem arquivo temporario com a assinatura ["+fSign.getAbsolutePath()+"] não foi gerado");
// Leitura do conteúdo da assintatura
StringBuilder sbSign = new StringBuilder();
try{
FileInputStream inSign = new FileInputStream(fSign);
byte[] b = new byte[inSign.available()];
inSign.read(b);
sbSign.append(new String(b));
}
catch(IOException e){
return setErro("Erro ao abrir arquivo temporário.");
}
// Aplica a assinatura no arquivo
String assinatura = "EAD"+sbSign.substring(sbSign.indexOf("=")+1).trim()+"\r\n";
try{
FileOutputStream outArquivo = new FileOutputStream(fArquivo,true);
outArquivo.write(assinatura.getBytes());
outArquivo.flush();
outArquivo.close();
}
catch(IOException e){
return setErro("Erro ao gravar assinatura do arquivo.");
}
return true;
}
/**
* Executa um comando no sistema operacional
* @param cmd Comando a ser executado
* @return Verdadeiro em caso de sucesso
*/
private boolean execRuntime(String cmd){
try{
Process pr = Runtime.getRuntime().exec(cmd);
int status = pr.waitFor();
if (status != 0)
return setErro("Falha ao executar comando ["+cmd+"]");
}
catch(IOException e){
return setErro("Erro ao executar comando ["+cmd+"] (IOException)");
}
catch(InterruptedException e){
return setErro("Erro ao executar OpenSSL ["+cmd+"] (InterruptedException)");
}
return true;
}
}
Você vai precisar do executável do openssl para executar no Windows
Obrigado…vou estudar a sua classe e ver no que eu estou errando … vou baixar esse openssl …para ver aqui…
Muito obrigado…
o que não entendo é que criptografo usando chave publica e descriptografo e ele funciona, mas nao valida o eECFc…
Vou tentar implementar dessa forma aí que vc postou para ver se utilizando o ssl ele aceita
Gerei uma nova classe utilizando a sua idéia,de usar o openssl para gerar as assinaturas e funcionou…
Através desta classe que me passou, pude entender o funcionamento do openssl para gerar a assinatura… e como interagir com ele…
Muito obrigado…!!!
Só mais uma coisa… Seria confiável deixar um arquivo com a chave privada no sistema? Tipo, gerar um .PEM e deixar lá no meio dos arquivos de instalação? seria seguro?