PAF-ECF Assinatura Digital RSA [SOLUCIONADO]

Fala ae galera, blz?
Putz, muito tempo não passo por aqui…
Seguinte, tive um problema para geração da assinatura digita dos arquivos do PAF-ECF
encontrei umas dica em um forum de automação e consegui solucionar o problema, porém
achei importante compartilhar a solução com a comunidade Java para se alguém um dia precisar…

Post Envia no Forum de Autmoção Comercial
http://www.forumweb.com.br/foruns/index.php?/topic/76285-homologacao-paf-eecfcexe-cuidado-com-o-ead/page__view__findpost__p__323254


segue abaixo as dicas que segui para geração da assinatura:

Para a geração da chave utilizei o OpenSSL:
openssl dgst -md5 -sign private.key -out rsa.sign -hex arquivo-ex.txt

Pra a geração do modulo o seguinte comando:
openssl rsa -in chave.pem -modulus -out modulo.txt

Copiei o conteudo da primeira linha do arquivo modulo.txt, para o arquivo de configurações do validador eECFc.exe

Bem, como prometi, criei um programa em Java que cria uma assinatura válida, deve ser executado no console, necessário o instalar o Java (jvm).

[code]Como executar o programa:
java -jar mgsys-openpaf.jar

Funciona tanto no windows quanto no Linux[/code]

Segue link para download:

http://www.managersys.com.br/download/openpaf/

Ao fim da mensagem vou deixar o fonte do programa.
Ele pode ser usado tanto para assinar um arquivo existente, como para gerar um arquivo de exemplo e assiná-lo.
Também pode usar o programa para gerar o arquivo Software House.xml, depois basta alterar para no mome da sua empresa.

Observações importantes sobre o arquivo:
Com eu trabalho no Linux, estava gerando o arquivo usando apenas a quebra de linha #13, e esse foi o problema que tive quando mandei o post com o código.

Sobre o arquivo:

  1. Utilizar para quebra de linha (#10 + #13)
  2. Ao gerar a assinatura o final do arquivo deve ser uma linha em branco

[code]ERRADO: Nao ha linha em branco no fim do arquivo
// ----- INICIO DO ARQUIVO (BOF)
TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO
TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO
TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO
TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO
// ----- FIM DO ARQUIVO (EOF)

CERTO: Ultima linha em branco
// ----- INICIO DO ARQUIVO (BOF)
TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO
TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO
TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO
TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO

// ----- FIM DO ARQUIVO (EOF)

ERRADO: Usou apenas o caracter 13 para pular linha
// ----- INICIO DO ARQUIVO (BOF)
TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO + (CHAR 13)
TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO + (CHAR 13)
TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO + (CHAR 13)
TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO + (CHAR 13)

// ----- FIM DO ARQUIVO (EOF)

CERTO: Usou caracter 10 e 13 para quebra de linha
// ----- INICIO DO ARQUIVO (BOF)
TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO + (CHAR 10) + (CHAR 13)
TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO + (CHAR 10) + (CHAR 13)
TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO + (CHAR 10) + (CHAR 13)
TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO + (CHAR 10) + (CHAR 13)

// ----- FIM DO ARQUIVO (EOF)

// DETALHE IMPORTANTE
// APOS A ASSINATURA SEMPRE DEVE HAVER UMA LINHA EM BRANCO

ERRADO: Não há uma linha em branco após a assinatura
// ----- INICIO DO ARQUIVO (BOF)
TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO + (CHAR 10) + (CHAR 13)
TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO + (CHAR 10) + (CHAR 13)
TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO + (CHAR 10) + (CHAR 13)
TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO + (CHAR 10) + (CHAR 13)
EADCDAB52C7E53E47D9B2A0325…A458B54EB2125039F8D76F4E270F
// ----- FIM DO ARQUIVO (EOF)

CERTO: Há uma linha em branco após a assinatura
// ----- INICIO DO ARQUIVO (BOF)
TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO + (CHAR 10) + (CHAR 13)
TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO + (CHAR 10) + (CHAR 13)
TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO + (CHAR 10) + (CHAR 13)
TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO + (CHAR 10) + (CHAR 13)
EADCDAB52C7E53E47D9B2A0325…A458B54EB2125039F8D76F4E270F + (CHAR 10) + (CHAR 13)

// ----- FIM DO ARQUIVO (EOF)
[/code]

Muito obrigado pela dicas enviada… me ajudou pra caramba a gerar essa %%$$#@#@#$%!!@# de assinatura… ehehhe
Abraço,
Rodrigo G. Tavares de Souza

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.text.MessageFormat;

/**
 * Geração da Assinatura EAD para os arquivos arquivos
 * 
 * @author Rodrigo G. Tavares de Souza
 * @author Managersys - Soluções em Sistemas
 */
public class AssinaturaDigitalPAF {

	/**
	 * Buffer para leitura do console
	 */
	private static BufferedReader	reader;
	
	/**
	 * Caminho para a geração da chave privada
	 */
	private static final String 	PATH_PRIV_KEY = "private.key";
	
	/**
	 * Caminho para geração do módulo
	 */
	private static final String 	PATH_MOD_KEY = "modulo.txt";
	
	/**
	 * Caminho para geração do arquivo de configuração do validor eECFc
	 */
	private static final String 	PATH_SHOUSE	 = "Software House.xml";
	
	/**
	 * Caminho padrão do OpenSSL no Linux
	 */
	private static final String		LNX_CAMINNHO_SSL	= "/usr/bin/";
	
	/**
	 * Caminho para geração do arquivo de teste
	 */
	private static final String			PATH_ARQUIVO_TESTE	= "arquivo-ex.txt";

	/**
	 * Caminho padrão do OpenSSL no Windows
	 */
	private static final String		WIN_CAMINNHO_SSL	= "/Arquivos de Programas/GnuWin32/bin/";


	/**
	 * Comando que será utilizado para a execução do OpenSSL
	 */
	private static String			openssl;
	
	/**
	 * Contem o modelo para geracao do XML de configuracao
	 */
	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");
	}

	public static void main(String[] args) throws Exception {
		System.out.println("*************************************");
		System.out.println("* Managersys - Solucoes em Sistemas *");
		System.out.println("* contato@managersys.com.br         *");
		System.out.println("* Fone: (19) 3388-1212              *");
		System.out.println("*************************************");
		System.out.println("* GERADOR ASSINATURA RSA - PAF-ECF  *");
		System.out.println("*  >> UTILIZACAO E COPIA LIVRE <<   *");
		System.out.println("*************************************");
		
		// Verifica o sistema operacional
		String os = System.getProperty("os.name");
		String path = null;
		String cmd = "";
		if (os.toUpperCase().equals("LINUX")) {
			path = LNX_CAMINNHO_SSL;
			cmd = "openssl";
		} else {
			path = WIN_CAMINNHO_SSL;
			cmd = "openssl.exe";
		}
		
		// Solicita informação do caminho do OpenSSL, vazio assume
		// o valor padrão
		File fOpenssl = new File(path);
		
		String vlr = lerConsole("Caminho OpenSSL ["
				+ fOpenssl.getAbsolutePath() + "] : ");
		
		// Atribuindo o caminho para o OpenSSL
		if (vlr.isEmpty())
			openssl = path + File.separator + cmd;
		else
			openssl = vlr + File.separator + cmd;
		
		// Verifica se o OpenSSL está encontra-se na máquina
		fOpenssl = new File(openssl);
		if (!fOpenssl.exists()) {
			System.out.println();
			System.err.println("OpenSSL nao encontrado em [" + fOpenssl.getAbsolutePath() + "]");
			System.err.println("  * Necessario instalar o OpenSSL para prosseguir");
			System.err.println("  * Linux: http://www.openssl.org/");
			System.err.println("  * Windows: http://gnuwin32.sourceforge.net/packages/openssl.htm");
			System.exit(-1);
		}
		
		openssl = fOpenssl.getAbsolutePath();
		
		// A primeira opçao efetua a geracao da assinatura
		// para o arquivo informado
		// A segunda opção efetua a geração dos arquivo
		// de para a assinatura. 
		System.out.println("\nSelecione uma Opcao");
		System.out.println("1. Gerar Assinatura");
		System.out.println("2. Gerar Configuracoes");
		vlr = lerConsole("Opcao: ");
		
		// Verifica a seleção das Opçoes
		if ("1".equals(vlr)) 
			gerarAssinatura();
		else if ("2".equals(vlr))
			gerarConfiguracoes();
		else {
			System.out.println();
			System.err.println("Opcao [" + vlr + "] invalida");
			System.exit(-1);
		}
			
	}

	private static void gerarAssinatura() throws Exception {
		File fPriv = new File(PATH_PRIV_KEY);
		// Verfica se a chave privada existe
		if (!fPriv.exists()) {
			System.out.println();
			System.err.println("Chave privada nao encontrada");
			System.exit(-1);
		}
		
		System.out.println("\nSelecione uma Opcao");
		System.out.println("1. Gerar Arquivo Exemplo");
		System.out.println("2. Informar Arquivo");
		String vlr = lerConsole("Opcao: ");
		
		File fArquivo = null;
		// Verifica se deve gerar um arquivo de exemplo
		// Ou o usuário irá gerar o arquivo
		
		// Verifica a seleção das Opçoes
		if ("1".equals(vlr)) {
			System.out.println();
			// Efetua a geração do arquivo de exemplo
			fArquivo = new File(PATH_ARQUIVO_TESTE);
			System.out.println("Gerando Arquivo de Exemplo ["
					+ fArquivo.getAbsolutePath() + "]...");
			criarArquivoExemplo(fArquivo);
			System.out.println("Criado Arquivo de Exemplo ["
					+ fArquivo.getName() + "]...");
		}else if ("2".equals(vlr)) {
			// Usuário vai informar o caminho do arquivo
			vlr = lerConsole("Caminho do Arquivo: ");
			if (vlr.isEmpty()) {
				System.out.println();
				System.out.println("Caminho do arquivo nao informado");
				System.exit(0);
			}
			
			// validação do arquivo informado
			fArquivo = new File(vlr);
			
			// Verifica se existe
			if (!fArquivo.exists()) {
				System.out.println();
				System.out.println("Arquivo informado nao existe ["
						+ fArquivo.getAbsolutePath() + "] ");
				System.exit(0);
			}
			
			// Verifica se é um arquivo ou diretório
			if (fArquivo.isDirectory()) {
				System.out.println();
				System.out.println("Impossivel assinar um diretorio ["
						+ fArquivo.getAbsolutePath() + "] ");
				System.exit(0);
			}
			
			// Verifica se tem permissao de escriuta
			if (!fArquivo.canWrite()) {
				System.out.println();
				System.out.println("Sem permissao de escrita no arquivo ["
						+ fArquivo.getAbsolutePath() + "] ");
				System.exit(0);
			}
		} else {
			System.out.println();
			System.err.println("Opcao [" + vlr + "] invalida");
			System.exit(-1);
		}
		
		System.out.println();
		// Iniciando assinatura do arquivo
		System.out.println("Iniciando assinatura do arquivo [" + fArquivo.getName() + "]");
		
		// Caminho do arquivo para geração do arquivo
		// com a assinatura
		final String PATH_TMP_SIGN = "sign.tmp";
		File fSign = new File(PATH_TMP_SIGN);
		
		Runtime rt = Runtime.getRuntime();
		
		// Executando comando OpenSSL
        Process pr = rt.exec(openssl + " dgst -md5 -sign "
				+ fPriv.getAbsolutePath() + " -out "
				+ fSign.getAbsolutePath() + " -hex "
				+ fArquivo.getAbsolutePath());
        
        // Aguarda até que o processo tenha terminado
        int status = pr.waitFor();
        // Valor diferente de Zero, indica
        // que houve falha ao executar o comando
        if (status != 0) {
			System.out.println();
			System.err.println("Falha ao executar OpenSSL");
			System.exit(status);
        } 
        
        // Verifica se o arquivo foi gerado
        if (!fSign.exists()) {
			System.out.println();
			System.err.println("Comando OpenSSL executado, "
					+ "porem arquivo temporario  com a " + "assinatura ["
					+ fSign.getAbsolutePath() + "] não foi gerado");
			System.exit(status);	
        }
        
        System.out.println("Verificando dados da assinatura gerada...");
		// Leitura do conteúdo da assintatura
		StringBuffer sbSign = new StringBuffer();
		
		// Abrindo arquivo com a assinatura
		FileInputStream inSign = new FileInputStream(fSign);
		byte[] b = new byte[inSign.available()];
		inSign.read(B);
		sbSign.append(new String(B));
		
		System.out.println("Icluindo linha EAD no " + "arquivo ["
				+ fArquivo.getName() + "] com assinatura gerada");
		// Arquivo gerado com 
		String assinatura = "EAD"
				+ sbSign.substring(sbSign.indexOf("=")+1).trim() + "\r\n";
		
		// Abre arquivo para inclusão da assinatura
		System.out.println("Assinatura: " + assinatura);
		FileOutputStream outArquivo = new FileOutputStream(fArquivo, true);
		outArquivo.write(assinatura.getBytes());
		outArquivo.flush();
		outArquivo.close();
		
		// Concluído o processo de geração da assinatura
		System.out.println();
		System.out.println("Assinatura digital gerada com sucesso");
		System.out.println("  + Arquivo Assinado: " + fArquivo.getAbsolutePath());
	}
	
	/**
	 * Geração dos arquivos necessários para a configuração 
	 */
	private static void gerarConfiguracoes() throws Exception {
		File fPriv = new File(PATH_PRIV_KEY);
		// Verfica se a chave privada já foi gerada
		if (fPriv.exists()) {
			System.out.println();
			System.out.println("Chave privada ja existe, apagar para continuar");
			System.exit(0);
		}
		
		// Se encontrou o modulo deleta
		File fMod = new File(PATH_MOD_KEY);
		if (fMod.exists())
			fMod.delete();
		
		// Se encontrou configuracao deleta
		File fXml = new File(PATH_SHOUSE);
		if (fXml.exists())
			fXml.delete();
		
		// Executa comando para geração do arquivo
		System.out.println("Gerando chave privada [" + fPriv.getAbsolutePath()
				+ "]...");
		Runtime rt = Runtime.getRuntime();
		
		// Executando comando OpenSSL
        Process pr = rt.exec(openssl + " genrsa -out " + fPriv.getAbsolutePath() + " 1024 ");
        int status = pr.waitFor();
        
        // Valor diferente de Zero, indica
        // que houve falha ao executar o comando
        if (status != 0) {
			System.out.println();
			System.err.println("Falha ao executar OpenSSL");
			System.exit(status);
        }
        
        System.out.println("Chave privada gerada [" + fPriv.getName() + "]");
        
        // Iniciando a geração do módulo
        System.out.println("Gerando módulo [" + fMod.getAbsolutePath() + "]...");
        pr = rt.exec(openssl + " rsa -in " + fPriv.getAbsolutePath()
				+ " -modulus -out " + fMod.getAbsolutePath() + " ");
        status = pr.waitFor();
        
        // Valor diferente de Zero, indica
        // que houve falha ao executar o comando
        if (status != 0) {
			System.out.println();
			System.err.println("Falha ao executar OpenSSL");
			System.exit(status);
        } 
        
        System.out.println("Modulo gerado [" + fMod.getName() + "]");
        
        // Criando arquivo de configurações
		System.out.println("Criando arquivo de configuracao ["
				+ fXml.getAbsolutePath() + "]...");
		
		// Lendo o arquivo com o módulo
		// Primeira linha do arquivo do módulo, contem o módulo
		// Modulus=B4FCFDB3E...F1B85675F42646EDC5
		BufferedReader modIn = new BufferedReader(new FileReader(fMod));
		String modulo = modIn.readLine();
		System.out.println(modulo);
		
		// Fechando stream de leitura
		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();
		
		// Arquivo de cofingurações criado
		System.out.println("Arquivo de configuracao criado ["
				+ fXml.getName() + "]");
		
		System.out.println();
		
		System.out.println("Geracao das configuracoes concluido...");
		System.out.println("  + Chave : " + fPriv.getAbsolutePath() );
		System.out.println("  + Modulo: " + fMod.getAbsolutePath() );
		System.out.println("  + Config: " + fXml.getAbsolutePath() );
		
	}
	
	/**
	 * Efetua a leitura de dados do console
	 * 
	 * @param msg
	 *            Uma {@link String} com a mensagem para exibição
	 * @return Uma {@link String} com a entrada do usuário
	 */
	private static String lerConsole(String msg) throws Exception {
		System.out.print(msg);
		if (reader == null)
			reader = new BufferedReader(new InputStreamReader(System.in));
		
		String entrada = reader.readLine();
		if (entrada == null)
			entrada = "";

		return entrada;
	}
	
	/**
	 * Efetua a criação de um arquivo de exemplo para teste de geração da assinatura digital
	 */
	private static void criarArquivoExemplo(File f) throws Exception {
		StringBuffer sb = new StringBuffer();
		sb.append("E00BE0104SC56001203764  01ECF-IF BEMATECH            MP-25 FI            000000  000000000000000000000000000000000000000000\r\n");
		sb.append("E01BE0104SC56001203764  ECF-IF BEMATECH            MP-25 FI            010102                  00105831026000103RFD001326001326200902112009021101.00.00PC5207 01.00.00\r\n");
		sb.append("E02BE0104SC56001203764  MP-25 FI            05831026000103387155811110       ELISABETH STRAZZIERI DE CARVALHO -          \"V E R O  R I S T O R A N T E\"        ROD. CASTELO BRANCO KM 72,5 S/N LJ 56/57 ITU-SP                                        00000000000000007093532601\r\n");
		sb.append("E14BE0104SC56001203764  MP-25 FI            0100000101967120081222000000000019000000000000000V0000000000190V00000000002090N0000000000000A                                        00000553960890\r\n");
		sb.append("E14BE0104SC56001203764  MP-25 FI            0100000201967220081222000000000019000000000000000V0000000000190V00000000002090N0000000000000A                                        00004032410810\r\n");
		sb.append("E14BE0104SC56001203764  MP-25 FI            0100000301967320081222000000000089800000000000000V0000000000898V00000000009878N0000000000000A                                        64614449000122\r\n");
		sb.append("E15BE0104SC56001203764  MP-25 FI            010196710000010010000000000156 #AGUA MIN 310 C/ GAS                                                                                0001000UN 00000220000000000000000000000000000220I1     N000000000000000000000000000000000T32\r\n");
		sb.append("E15BE0104SC56001203764  MP-25 FI            010196710000010020000000000754 #VIRADO A PAULISTA                                                                                  0001000UN 0000168000000000000000000000000000168001T0700N000000000000000000000000000000000T32\r\n");
		sb.append("E15BE0104SC56001203764  MP-25 FI            010196720000020010000000000155 #AGUA MIN 310 ML S/G                                                                                0001000UN 00000220000000000000000000000000000220I1     N000000000000000000000000000000000T32\r\n");
		sb.append("E21BE0104SC56001203764  MP-25 FI            01019671000001000000Dinheiro       0000000002090N0000000000000\r\n");
		sb.append("E21BE0104SC56001203764  MP-25 FI            01019672000002000000Dinheiro       0000000002090N0000000000000\r\n");
		
		if (f.exists())
			f.delete();

		FileOutputStream out = new FileOutputStream(f);
		out.write(sb.toString().getBytes());
		out.flush();
		out.close();
	}

}

Olá amigo muito bom seu programa!!

Não tenho conhecimento em java, mas usei as suas dicas para fazer a assinatura digital mas não consegui.

Gostaria de saber se é possivel vc me enviar o código fonte ou um aplicativo pronto como esse que vc fez porém que não tivesse aquelas perguntas sobre o caminho, arquivo de exemplo e etc. somente um arquivo .jar que é executado e ele não ter opções,somente assina o arquivo e pronto!

Mto bom, parabéns…nossa empresa estamos tentando fazer em C# com base nesse seu ai!
:roll:

[quote=black_fire]Fala ae galera, blz?
Putz, muito tempo não passo por aqui…
Seguinte, tive um problema para geração da assinatura digita dos arquivos do PAF-ECF
encontrei umas dica em um forum de automação e consegui solucionar o problema, porém
achei importante compartilhar a solução com a comunidade Java para se alguém um dia precisar…

Post Envia no Forum de Autmoção Comercial
http://www.forumweb.com.br/foruns/index.php?/topic/76285-homologacao-paf-eecfcexe-cuidado-com-o-ead/page__view__findpost__p__323254


segue abaixo as dicas que segui para geração da assinatura:

Para a geração da chave utilizei o OpenSSL:
openssl dgst -md5 -sign private.key -out rsa.sign -hex arquivo-ex.txt

Pra a geração do modulo o seguinte comando:
openssl rsa -in chave.pem -modulus -out modulo.txt

Copiei o conteudo da primeira linha do arquivo modulo.txt, para o arquivo de configurações do validador eECFc.exe

Bem, como prometi, criei um programa em Java que cria uma assinatura válida, deve ser executado no console, necessário o instalar o Java (jvm).

[code]Como executar o programa:
java -jar mgsys-openpaf.jar

Funciona tanto no windows quanto no Linux[/code]

Segue link para download:

http://www.managersys.com.br/download/openpaf/

Ao fim da mensagem vou deixar o fonte do programa.
Ele pode ser usado tanto para assinar um arquivo existente, como para gerar um arquivo de exemplo e assiná-lo.
Também pode usar o programa para gerar o arquivo Software House.xml, depois basta alterar para no mome da sua empresa.

Observações importantes sobre o arquivo:
Com eu trabalho no Linux, estava gerando o arquivo usando apenas a quebra de linha #13, e esse foi o problema que tive quando mandei o post com o código.

Sobre o arquivo:

  1. Utilizar para quebra de linha (#10 + #13)
  2. Ao gerar a assinatura o final do arquivo deve ser uma linha em branco

[code]ERRADO: Nao ha linha em branco no fim do arquivo
// ----- INICIO DO ARQUIVO (BOF)
TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO
TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO
TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO
TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO
// ----- FIM DO ARQUIVO (EOF)

CERTO: Ultima linha em branco
// ----- INICIO DO ARQUIVO (BOF)
TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO
TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO
TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO
TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO

// ----- FIM DO ARQUIVO (EOF)

ERRADO: Usou apenas o caracter 13 para pular linha
// ----- INICIO DO ARQUIVO (BOF)
TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO + (CHAR 13)
TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO + (CHAR 13)
TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO + (CHAR 13)
TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO + (CHAR 13)

// ----- FIM DO ARQUIVO (EOF)

CERTO: Usou caracter 10 e 13 para quebra de linha
// ----- INICIO DO ARQUIVO (BOF)
TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO + (CHAR 10) + (CHAR 13)
TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO + (CHAR 10) + (CHAR 13)
TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO + (CHAR 10) + (CHAR 13)
TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO + (CHAR 10) + (CHAR 13)

// ----- FIM DO ARQUIVO (EOF)

// DETALHE IMPORTANTE
// APOS A ASSINATURA SEMPRE DEVE HAVER UMA LINHA EM BRANCO

ERRADO: Não há uma linha em branco após a assinatura
// ----- INICIO DO ARQUIVO (BOF)
TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO + (CHAR 10) + (CHAR 13)
TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO + (CHAR 10) + (CHAR 13)
TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO + (CHAR 10) + (CHAR 13)
TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO + (CHAR 10) + (CHAR 13)
EADCDAB52C7E53E47D9B2A0325…A458B54EB2125039F8D76F4E270F
// ----- FIM DO ARQUIVO (EOF)

CERTO: Há uma linha em branco após a assinatura
// ----- INICIO DO ARQUIVO (BOF)
TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO + (CHAR 10) + (CHAR 13)
TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO + (CHAR 10) + (CHAR 13)
TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO + (CHAR 10) + (CHAR 13)
TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO TEXTO + (CHAR 10) + (CHAR 13)
EADCDAB52C7E53E47D9B2A0325…A458B54EB2125039F8D76F4E270F + (CHAR 10) + (CHAR 13)

// ----- FIM DO ARQUIVO (EOF)
[/code]

Muito obrigado pela dicas enviada… me ajudou pra caramba a gerar essa %%$$#@#@#$%!!@# de assinatura… ehehhe
Abraço,
Rodrigo G. Tavares de Souza

[code]
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.text.MessageFormat;

/**

  • Geração da Assinatura EAD para os arquivos arquivos

  • @author Rodrigo G. Tavares de Souza

  • @author Managersys - Soluções em Sistemas
    */
    public class AssinaturaDigitalPAF {

    /**

    • Buffer para leitura do console
      */
      private static BufferedReader reader;

    /**

    • Caminho para a geração da chave privada
      */
      private static final String PATH_PRIV_KEY = "private.key";

    /**

    • Caminho para geração do módulo
      */
      private static final String PATH_MOD_KEY = "modulo.txt";

    /**

    • Caminho para geração do arquivo de configuração do validor eECFc
      */
      private static final String PATH_SHOUSE = "Software House.xml";

    /**

    • Caminho padrão do OpenSSL no Linux
      */
      private static final String LNX_CAMINNHO_SSL = "/usr/bin/";

    /**

    • Caminho para geração do arquivo de teste
      */
      private static final String PATH_ARQUIVO_TESTE = "arquivo-ex.txt";

    /**

    • Caminho padrão do OpenSSL no Windows
      */
      private static final String WIN_CAMINNHO_SSL = "/Arquivos de Programas/GnuWin32/bin/";

    /**

    • Comando que será utilizado para a execução do OpenSSL
      */
      private static String openssl;

    /**

    • Contem o modelo para geracao do XML de configuracao
      */
      private static StringBuffer modeloXMLConfig;

    static {
    // Arquivo Padrão Para Validação da Assinatura
    modeloXMLConfig = new StringBuffer();
    modeloXMLConfig.append("<?xml version=&quot;1.0&quot;?>\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");
    }

    public static void main(String[] args) throws Exception {
    System.out.println("");
    System.out.println("
    Managersys - Solucoes em Sistemas ");
    System.out.println("
    contato@managersys.com.br ");
    System.out.println("
    Fone: (19) 3388-1212 ");
    System.out.println("
    ");
    System.out.println("* GERADOR ASSINATURA RSA - PAF-ECF ");
    System.out.println("
    >> UTILIZACAO E COPIA LIVRE << ");
    System.out.println("
    ************************************");

     // Verifica o sistema operacional
     String os = System.getProperty(&quot;os.name&quot;);
     String path = null;
     String cmd = &quot;&quot;;
     if (os.toUpperCase().equals(&quot;LINUX&quot;)) {
     	path = LNX_CAMINNHO_SSL;
     	cmd = &quot;openssl&quot;;
     } else {
     	path = WIN_CAMINNHO_SSL;
     	cmd = &quot;openssl.exe&quot;;
     }
     
     // Solicita informação do caminho do OpenSSL, vazio assume
     // o valor padrão
     File fOpenssl = new File(path);
     
     String vlr = lerConsole(&quot;Caminho OpenSSL [&quot;
     		+ fOpenssl.getAbsolutePath() + &quot;] : &quot;);
     
     // Atribuindo o caminho para o OpenSSL
     if (vlr.isEmpty())
     	openssl = path + File.separator + cmd;
     else
     	openssl = vlr + File.separator + cmd;
     
     // Verifica se o OpenSSL está encontra-se na máquina
     fOpenssl = new File(openssl);
     if (!fOpenssl.exists()) {
     	System.out.println();
     	System.err.println(&quot;OpenSSL nao encontrado em [&quot; + fOpenssl.getAbsolutePath() + &quot;]&quot;);
     	System.err.println(&quot;  * Necessario instalar o OpenSSL para prosseguir&quot;);
     	System.err.println(&quot;  * Linux: http://www.openssl.org/&quot;);
     	System.err.println(&quot;  * Windows: http://gnuwin32.sourceforge.net/packages/openssl.htm&quot;);
     	System.exit(-1);
     }
     
     openssl = fOpenssl.getAbsolutePath();
     
     // A primeira opçao efetua a geracao da assinatura
     // para o arquivo informado
     // A segunda opção efetua a geração dos arquivo
     // de para a assinatura. 
     System.out.println(&quot;\nSelecione uma Opcao&quot;);
     System.out.println(&quot;1. Gerar Assinatura&quot;);
     System.out.println(&quot;2. Gerar Configuracoes&quot;);
     vlr = lerConsole(&quot;Opcao: &quot;);
     
     // Verifica a seleção das Opçoes
     if (&quot;1&quot;.equals(vlr)) 
     	gerarAssinatura();
     else if (&quot;2&quot;.equals(vlr))
     	gerarConfiguracoes();
     else {
     	System.out.println();
     	System.err.println(&quot;Opcao [&quot; + vlr + &quot;] invalida&quot;);
     	System.exit(-1);
     }
    

    }

    private static void gerarAssinatura() throws Exception {
    File fPriv = new File(PATH_PRIV_KEY);
    // Verfica se a chave privada existe
    if (!fPriv.exists()) {
    System.out.println();
    System.err.println("Chave privada nao encontrada");
    System.exit(-1);
    }

     System.out.println(&quot;\nSelecione uma Opcao&quot;);
     System.out.println(&quot;1. Gerar Arquivo Exemplo&quot;);
     System.out.println(&quot;2. Informar Arquivo&quot;);
     String vlr = lerConsole(&quot;Opcao: &quot;);
     
     File fArquivo = null;
     // Verifica se deve gerar um arquivo de exemplo
     // Ou o usuário irá gerar o arquivo
     
     // Verifica a seleção das Opçoes
     if (&quot;1&quot;.equals(vlr)) {
     	System.out.println();
     	// Efetua a geração do arquivo de exemplo
     	fArquivo = new File(PATH_ARQUIVO_TESTE);
     	System.out.println(&quot;Gerando Arquivo de Exemplo [&quot;
     			+ fArquivo.getAbsolutePath() + &quot;]...&quot;);
     	criarArquivoExemplo(fArquivo);
     	System.out.println(&quot;Criado Arquivo de Exemplo [&quot;
     			+ fArquivo.getName() + &quot;]...&quot;);
     }else if (&quot;2&quot;.equals(vlr)) {
     	// Usuário vai informar o caminho do arquivo
     	vlr = lerConsole(&quot;Caminho do Arquivo: &quot;);
     	if (vlr.isEmpty()) {
     		System.out.println();
     		System.out.println(&quot;Caminho do arquivo nao informado&quot;);
     		System.exit(0);
     	}
     	
     	// validação do arquivo informado
     	fArquivo = new File(vlr);
     	
     	// Verifica se existe
     	if (!fArquivo.exists()) {
     		System.out.println();
     		System.out.println(&quot;Arquivo informado nao existe [&quot;
     				+ fArquivo.getAbsolutePath() + &quot;] &quot;);
     		System.exit(0);
     	}
     	
     	// Verifica se é um arquivo ou diretório
     	if (fArquivo.isDirectory()) {
     		System.out.println();
     		System.out.println(&quot;Impossivel assinar um diretorio [&quot;
     				+ fArquivo.getAbsolutePath() + &quot;] &quot;);
     		System.exit(0);
     	}
     	
     	// Verifica se tem permissao de escriuta
     	if (!fArquivo.canWrite()) {
     		System.out.println();
     		System.out.println(&quot;Sem permissao de escrita no arquivo [&quot;
     				+ fArquivo.getAbsolutePath() + &quot;] &quot;);
     		System.exit(0);
     	}
     } else {
     	System.out.println();
     	System.err.println(&quot;Opcao [&quot; + vlr + &quot;] invalida&quot;);
     	System.exit(-1);
     }
     
     System.out.println();
     // Iniciando assinatura do arquivo
     System.out.println(&quot;Iniciando assinatura do arquivo [&quot; + fArquivo.getName() + &quot;]&quot;);
     
     // Caminho do arquivo para geração do arquivo
     // com a assinatura
     final String PATH_TMP_SIGN = &quot;sign.tmp&quot;;
     File fSign = new File(PATH_TMP_SIGN);
     
     Runtime rt = Runtime.getRuntime();
     
     // Executando comando OpenSSL
     Process pr = rt.exec(openssl + &quot; dgst -md5 -sign &quot;
     		+ fPriv.getAbsolutePath() + &quot; -out &quot;
     		+ fSign.getAbsolutePath() + &quot; -hex &quot;
     		+ fArquivo.getAbsolutePath());
     
     // Aguarda até que o processo tenha terminado
     int status = pr.waitFor();
     // Valor diferente de Zero, indica
     // que houve falha ao executar o comando
     if (status != 0) {
     	System.out.println();
     	System.err.println(&quot;Falha ao executar OpenSSL&quot;);
     	System.exit(status);
     } 
     
     // Verifica se o arquivo foi gerado
     if (!fSign.exists()) {
     	System.out.println();
     	System.err.println(&quot;Comando OpenSSL executado, &quot;
     			+ &quot;porem arquivo temporario  com a &quot; + &quot;assinatura [&quot;
     			+ fSign.getAbsolutePath() + &quot;] não foi gerado&quot;);
     	System.exit(status);	
     }
     
     System.out.println(&quot;Verificando dados da assinatura gerada...&quot;);
     // Leitura do conteúdo da assintatura
     StringBuffer sbSign = new StringBuffer();
     
     // Abrindo arquivo com a assinatura
     FileInputStream inSign = new FileInputStream(fSign);
     byte[] b = new byte[inSign.available()];
     inSign.read(B);
     sbSign.append(new String(B));
     
     System.out.println(&quot;Icluindo linha EAD no &quot; + &quot;arquivo [&quot;
     		+ fArquivo.getName() + &quot;] com assinatura gerada&quot;);
     // Arquivo gerado com 
     String assinatura = &quot;EAD&quot;
     		+ sbSign.substring(sbSign.indexOf(&quot;=&quot;)+1).trim() + &quot;\r\n&quot;;
     
     // Abre arquivo para inclusão da assinatura
     System.out.println(&quot;Assinatura: &quot; + assinatura);
     FileOutputStream outArquivo = new FileOutputStream(fArquivo, true);
     outArquivo.write(assinatura.getBytes());
     outArquivo.flush();
     outArquivo.close();
     
     // Concluído o processo de geração da assinatura
     System.out.println();
     System.out.println(&quot;Assinatura digital gerada com sucesso&quot;);
     System.out.println(&quot;  + Arquivo Assinado: &quot; + fArquivo.getAbsolutePath());
    

    }

    /**

    • Geração dos arquivos necessários para a configuração
      */
      private static void gerarConfiguracoes() throws Exception {
      File fPriv = new File(PATH_PRIV_KEY);
      // Verfica se a chave privada já foi gerada
      if (fPriv.exists()) {
      System.out.println();
      System.out.println("Chave privada ja existe, apagar para continuar");
      System.exit(0);
      }

      // Se encontrou o modulo deleta
      File fMod = new File(PATH_MOD_KEY);
      if (fMod.exists())
      fMod.delete();

      // Se encontrou configuracao deleta
      File fXml = new File(PATH_SHOUSE);
      if (fXml.exists())
      fXml.delete();

      // Executa comando para geração do arquivo
      System.out.println("Gerando chave privada [" + fPriv.getAbsolutePath()
      + "]…");
      Runtime rt = Runtime.getRuntime();

      // Executando comando OpenSSL
      Process pr = rt.exec(openssl + " genrsa -out " + fPriv.getAbsolutePath() + " 1024 ");
      int status = pr.waitFor();

      // Valor diferente de Zero, indica
      // que houve falha ao executar o comando
      if (status != 0) {
      System.out.println();
      System.err.println("Falha ao executar OpenSSL");
      System.exit(status);
      }

      System.out.println("Chave privada gerada [" + fPriv.getName() + "]");

      // Iniciando a geração do módulo
      System.out.println("Gerando módulo [" + fMod.getAbsolutePath() + "]…");
      pr = rt.exec(openssl + " rsa -in " + fPriv.getAbsolutePath()
      + " -modulus -out " + fMod.getAbsolutePath() + " ");
      status = pr.waitFor();

      // Valor diferente de Zero, indica
      // que houve falha ao executar o comando
      if (status != 0) {
      System.out.println();
      System.err.println("Falha ao executar OpenSSL");
      System.exit(status);
      }

      System.out.println("Modulo gerado [" + fMod.getName() + "]");

      // Criando arquivo de configurações
      System.out.println("Criando arquivo de configuracao ["
      + fXml.getAbsolutePath() + "]…");

      // Lendo o arquivo com o módulo
      // Primeira linha do arquivo do módulo, contem o módulo
      // Modulus=B4FCFDB3E…F1B85675F42646EDC5
      BufferedReader modIn = new BufferedReader(new FileReader(fMod));
      String modulo = modIn.readLine();
      System.out.println(modulo);

      // Fechando stream de leitura
      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();

      // Arquivo de cofingurações criado
      System.out.println("Arquivo de configuracao criado ["
      + fXml.getName() + "]");

      System.out.println();

      System.out.println("Geracao das configuracoes concluido…");
      System.out.println(" + Chave : " + fPriv.getAbsolutePath() );
      System.out.println(" + Modulo: " + fMod.getAbsolutePath() );
      System.out.println(" + Config: " + fXml.getAbsolutePath() );

    }

    /**

    • Efetua a leitura de dados do console

    • @param msg

    •        Uma {@link String} com a mensagem para exibição
      
    • @return Uma {@link String} com a entrada do usuário
      */
      private static String lerConsole(String msg) throws Exception {
      System.out.print(msg);
      if (reader == null)
      reader = new BufferedReader(new InputStreamReader(System.in));

      String entrada = reader.readLine();
      if (entrada == null)
      entrada = "";

      return entrada;
      }

    /**

    • Efetua a criação de um arquivo de exemplo para teste de geração da assinatura digital
      */
      private static void criarArquivoExemplo(File f) throws Exception {
      StringBuffer sb = new StringBuffer();
      sb.append("E00BE0104SC56001203764 01ECF-IF BEMATECH MP-25 FI 000000 000000000000000000000000000000000000000000\r\n");
      sb.append("E01BE0104SC56001203764 ECF-IF BEMATECH MP-25 FI 010102 00105831026000103RFD001326001326200902112009021101.00.00PC5207 01.00.00\r\n");
      sb.append("E02BE0104SC56001203764 MP-25 FI 05831026000103387155811110 ELISABETH STRAZZIERI DE CARVALHO - &quot;V E R O R I S T O R A N T E&quot; ROD. CASTELO BRANCO KM 72,5 S/N LJ 56/57 ITU-SP 00000000000000007093532601\r\n");
      sb.append("E14BE0104SC56001203764 MP-25 FI 0100000101967120081222000000000019000000000000000V0000000000190V00000000002090N0000000000000A 00000553960890\r\n");
      sb.append("E14BE0104SC56001203764 MP-25 FI 0100000201967220081222000000000019000000000000000V0000000000190V00000000002090N0000000000000A 00004032410810\r\n");
      sb.append("E14BE0104SC56001203764 MP-25 FI 0100000301967320081222000000000089800000000000000V0000000000898V00000000009878N0000000000000A 64614449000122\r\n");
      sb.append("E15BE0104SC56001203764 MP-25 FI 010196710000010010000000000156 #AGUA MIN 310 C/ GAS 0001000UN 00000220000000000000000000000000000220I1 N000000000000000000000000000000000T32\r\n");
      sb.append("E15BE0104SC56001203764 MP-25 FI 010196710000010020000000000754 #VIRADO A PAULISTA 0001000UN 0000168000000000000000000000000000168001T0700N000000000000000000000000000000000T32\r\n");
      sb.append("E15BE0104SC56001203764 MP-25 FI 010196720000020010000000000155 #AGUA MIN 310 ML S/G 0001000UN 00000220000000000000000000000000000220I1 N000000000000000000000000000000000T32\r\n");
      sb.append("E21BE0104SC56001203764 MP-25 FI 01019671000001000000Dinheiro 0000000002090N0000000000000\r\n");
      sb.append("E21BE0104SC56001203764 MP-25 FI 01019672000002000000Dinheiro 0000000002090N0000000000000\r\n");

      if (f.exists())
      f.delete();

      FileOutputStream out = new FileOutputStream(f);
      out.write(sb.toString().getBytes());
      out.flush();
      out.close();
      }

}
[/code][/quote]

Olá, amigo.
Estou enfrentando uma dificuldade com um programa java desktop.
É um pouco semelhante ao que vc passou.
É relacionado a validação da assinatura digital de arquivos do Ato-Cotepe ICMS 17/2004 que são gerados pelo programa eECFc em conjunto com a DLL de cada fabricante de equipamento.

Cada fabricante disponibiliza em um arquivo XML a chave pública.

O que preciso é, de posse de um arquivo em formato texto (por exemplo, arquivo TDM ou MFD) e, tendo a chave pública, como posso verificar a validade da assinatura do arquivo?
Cada arquivo tem um registro EAD (a última linha do arquivo).
Eu não sei como gerar um objeto publicKey a ser passado como parâmetro para o objeto Signature, tendo a chave pública armazenada em uma String, por exemplo.