[RESOLVIDO] Vefirifando assinatura digital

Ola, a todos,

Estou tentando fazer um método que verifica se o texto que tem a assinatura gerada está certo, estou usando o seguinte código abaixo:


import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;

import org.bouncycastle.bcpg.ArmoredInputStream;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPObjectFactory;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPPublicKeyRing;
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
import org.bouncycastle.openpgp.PGPSignature;
import org.bouncycastle.openpgp.PGPSignatureList;
import org.bouncycastle.openpgp.PGPUtil;

public class FileVerify {
	public static void main(String[] args) throws Exception {

		
		new FileVerify ().verifyFile(new FileInputStream("C:\\Users\\helder\\Desktop\\assinado.txt"), readPublicKey(new FileInputStream("C:\\Users\\helder\\Desktop\\public.key")));

	}
	
	private static PGPPublicKey readPublicKey(InputStream in)
            throws IOException, PGPException {
        in = PGPUtil.getDecoderStream(in);

        PGPPublicKeyRingCollection pgpPub = new PGPPublicKeyRingCollection(in);

        Iterator rIt = pgpPub.getKeyRings();

        while (rIt.hasNext()) {
            PGPPublicKeyRing kRing = (PGPPublicKeyRing) rIt.next();
            Iterator kIt = kRing.getPublicKeys();

            while (kIt.hasNext()) {
                PGPPublicKey k = (PGPPublicKey) kIt.next();

                if (k.isEncryptionKey()) {
                    return k;
                }
            }
        }

        throw new IllegalArgumentException(
                "Can't find encryption key in key ring.");
    }

	public boolean verifyFile(InputStream fileStreamIn, PGPPublicKey keyIn)
			throws Exception {
		boolean verify = false;
		ArmoredInputStream aIn = new ArmoredInputStream(fileStreamIn, true);

		//
		// read the input, making sure we ingore the last newline.
		//
		int ch;
		boolean newLine = false;
		ByteArrayOutputStream bOut = new ByteArrayOutputStream();

		while ((ch = aIn.read()) >= 0 && aIn.isClearText()) {
			if (newLine) {
				bOut.write((byte) 'n');
				newLine = false;
			}
			if (ch == 'n') {
				newLine = true;
				continue;
			}

			bOut.write((byte) ch);
		}

		PGPObjectFactory pgpFact = new PGPObjectFactory(aIn);

		Object o = pgpFact.nextObject();
		if (o instanceof PGPSignatureList) {
			PGPSignatureList list = (PGPSignatureList) o;
			if (list.size() > 0) {
				PGPSignature sig = list.get(0);
				sig.initVerify(keyIn, "BC");
				sig.update(bOut.toByteArray());
				verify = sig.verify();
			}

		}

		return verify;
	}
}

O problema é que ao rodar o código abaixo dá o seguinte erro:

Exception in thread "main" java.security.NoSuchProviderException: provider BC not found.
	at org.bouncycastle.openpgp.PGPUtil.getProvider(Unknown Source)
	at org.bouncycastle.openpgp.PGPSignature.initVerify(Unknown Source)
	at test3.FileVerify .verifyFile(ClearSignedFileVerify.java:154)
	at test3.FileVerify .main(ClearSignedFileVerify.java:37)

Alguem tem idéia de como fazer isso???

Estou enviando os arquivos que tem a chave privada e a chave pública, para poder verificar se o arquivo assinado está correto.

Você precisa instalar o security provider BouncyCastle na sua JVM. Por exemplo, se a JVM estiver instalada em C:\Program Files\Java\jre6 , você precisa acertar o arquivo lib\security\java.security. Mais detalhes na documentação do BouncyCastle.

Segue o link abaixo de como acertar

http://www.itcsolutions.eu/2011/08/22/how-to-use-bouncy-castle-cryptographic-api-in-netbeans-or-eclipse-for-java-jse-projects/

Estou tentando, qualquer novidade, colocar mais detalhes.

Obrigado.

Corrigi o erro, mas estou com o seguinte erro abaixo:

Exception in thread "main" java.lang.NoClassDefFoundError: org/bouncycastle/util/encoders/Base64
	at org.bouncycastle.openpgp.PGPUtil.getDecoderStream(Unknown Source)
	at test3.ClearSignedFileVerify.readPublicKey(ClearSignedFileVerify.java:53)
	at test3.ClearSignedFileVerify.main(ClearSignedFileVerify.java:33)
Caused by: java.lang.ClassNotFoundException: org.bouncycastle.util.encoders.Base64
	at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
	at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:423)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
	... 3 more

Alguém tem ideia o que seria isso? Estou executando em uma máquina de 64 bits, será que é isso??

Consegui resolver o erro, mas a validação da assinatura está errada, alguem tem alguma ideia de como deverá ser essa validação da assinatura???

Obrigado

Consegui verificar se a assinatura foi gerada pela chave privada, com o seguinte código abaixo

package test14;

import java.io.*;
import java.security.*;

public class UtilizarAssinatura {
	public static void main(String[] args) {
		try {

				/* 1 passo gerar as chaves púbica e privada */
//				//Gerando as chaves
//				KeyPairGenerator pairgen = KeyPairGenerator.getInstance("DSA");
//				SecureRandom random = new SecureRandom();
//				pairgen.initialize(512, random);
//				
//				//Gera a chave publica
//				KeyPair keyPair = pairgen.generateKeyPair();
//				ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("C:\\Users\\helder\\Desktop\\public.key"));
//				out.writeObject(keyPair.getPublic());
//				out.close();
//				
//				//Gera a chave privada
//				out = new ObjectOutputStream(new FileOutputStream("C:\\Users\\helder\\Desktop\\privada.key"));
//				out.writeObject(keyPair.getPrivate());
//				out.close();				

//------------------------------------------------------------------------------------------------------------------------------------------------------------------//			
//------------------------------------------------------------------------------------------------------------------------------------------------------------------//
			
//				/* 2 passo assinar o documento  */
//				//Pega a chave privada para poder assinar o documento
//				ObjectInputStream keyIn = new ObjectInputStream(new FileInputStream("C:\\Users\\helder\\Desktop\\privada.key"));
//				PrivateKey privkey = (PrivateKey) keyIn.readObject();
//				keyIn.close();
//
//				Signature signalg = Signature.getInstance("DSA");
//				signalg.initSign(privkey);
//
//				//Pega o documento que irá ser feito a assinatura
//				File infile = new File("C:\\Users\\helder\\Desktop\\licenca.txt");
//				InputStream in = new FileInputStream(infile);
//				
//				int length = (int) infile.length();
//				byte[] message = new byte[length];
//				in.read(message, 0, length);
//				in.close();
//
//				signalg.update(message);
//				byte[] signature = signalg.sign();
//
//				//Escreve a assinatura gerada em outro documento
//				DataOutputStream out = new DataOutputStream(new FileOutputStream("C:\\Users\\helder\\Desktop\\licenca.sign.pgp"));
//				int signlength = signature.length;
//				out.writeInt(signlength);
//				out.write(signature, 0, signlength);
//				out.write(message, 0, length);
//				out.close();
			
//------------------------------------------------------------------------------------------------------------------------------------------------------------------//			
//------------------------------------------------------------------------------------------------------------------------------------------------------------------//
			
//				/* 3 passo verificar a assinatura do documento  */
//				//Pega a chave publica para validar a assinatura
//				ObjectInputStream keyIn = new ObjectInputStream(new FileInputStream("C:\\Users\\helder\\Desktop\\public.key"));
//				PublicKey pubkey = (PublicKey) keyIn.readObject();
//				keyIn.close();
//
//				Signature verifyalg = Signature.getInstance("DSA");
//				verifyalg.initVerify(pubkey);
//
//				//Pega a assinatura gerada
//				File infile = new File("C:\\Users\\helder\\Desktop\\licenca.sign.pgp");
//				DataInputStream in = new DataInputStream(new FileInputStream(infile));
//				int signlength = in.readInt();
//				byte[] signature = new byte[signlength];
//				in.read(signature, 0, signlength);
//
//				int length = (int) infile.length() - signlength - 4;
//				byte[] message = new byte[length];
//				in.read(message, 0, length);
//				in.close();
//
//				verifyalg.update(message);
//				
//				//Verifica se a assinatura é válida ou não
//				if (!verifyalg.verify(signature)){
//					System.out.print("Assinatura inválida ");
//				
//				} else {
//					System.out.println("Assinatura válida");
//				}

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}

Mas como eu faço para verificar se a assinatura pertence ao documento, e não só apenas se a assinatura é válida?

Tem como descriptografar a assinatura e voltar para o texto e validar o texto?

Alguem tem idéia de como fazer isso?

Obrigado

Resolvido segue o código abaixo

import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.SecureRandom;

public class GerarChaves {

	public static void main(String[] args) {

		try {
			// Gerando as chaves
			KeyPairGenerator pairgen = KeyPairGenerator.getInstance("DSA");
			SecureRandom random = new SecureRandom();
			pairgen.initialize(512, random);

			// Gera a chave publica
			KeyPair keyPair = pairgen.generateKeyPair();
			ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("public.key"));
			out.writeObject(keyPair.getPublic());
			out.close();

			// Gera a chave privada
			out = new ObjectOutputStream(new FileOutputStream("privada.key"));
			out.writeObject(keyPair.getPrivate());
			out.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.security.PrivateKey;
import java.security.Signature;

public class AssinarLicenca {

	public static void main(String[] args) {
		
		try {
			 //Pega a chave privada para poder assinar o documento
			 ObjectInputStream keyIn = new ObjectInputStream(new
			 FileInputStream("privada.key"));
			 PrivateKey privkey = (PrivateKey) keyIn.readObject();
			 keyIn.close();
			
			 Signature signalg = Signature.getInstance("DSA");
			 signalg.initSign(privkey);
			
			 //Pega o documento que irá ser feito a assinatura
			 File infile = new
			 File("licenca.txt");
			 InputStream in = new FileInputStream(infile);
			
			 int length = (int) infile.length();
			 byte[] message = new byte[length];
			 in.read(message, 0, length);
			 in.close();
			
			 signalg.update(message);
			 byte[] signature = signalg.sign();
			
			 String beginSignature = "\r\n-----BEGIN PGP SIGNATURE-----\r\n";
			 String endSignature = "\r\n-----END PGP SIGNATURE-----";
			
			 //Escreve a assinatura gerada em outro documento, para poder enviar para o cliente
			 FileOutputStream out = new
			 FileOutputStream("licencaSign.txt");
			 out.write(message, 0, length);
			 out.write(beginSignature.getBytes(), 0, beginSignature.length());
			 out.write(signature, 0, signature.length);
			 out.write(endSignature.getBytes(), 0, endSignature.length());
			 out.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.security.PublicKey;
import java.security.Signature;

public class ValidarAssinatura {

	public static void main(String[] args) {
		
		try {
			//Pega a chave publica para validar a assinatura
			 ObjectInputStream keyIn = new ObjectInputStream(new
			 FileInputStream("public.key"));
			 PublicKey pubkey = (PublicKey) keyIn.readObject();
			 keyIn.close();
			
			 Signature verifyalg = Signature.getInstance("DSA");
			 verifyalg.initVerify(pubkey);
			 
			 //Pega a licenca assinada
			 File infile = new File("licencaSign.txt");
			 FileInputStream in = new FileInputStream(infile);
			 
			 DataInputStream dataInput = new DataInputStream(in);
			 BufferedReader br = new BufferedReader(new InputStreamReader(dataInput));
			 
			 String strLine;
			 String licenca = "";
			 
			 //Procura a mensagem
			 while ((strLine = br.readLine()) != null) {
				 
				 if (strLine.equals("-----BEGIN PGP SIGNATURE-----")) {
					 break;
					 
				 } else {
					 
					 if (licenca.equals("")) {
						 licenca += strLine;
					 
					 } else {
						 licenca += "\r\n"+strLine;
					 }
				 }
			 }

			 strLine = "";
			 String assinatura = "";
			 
			//Procura a assinatura
			 while ((strLine = br.readLine()) != null) {
				
				 if (!strLine.equals("-----END PGP SIGNATURE-----")) {
					 
					 if (assinatura.equals("")) {
						 assinatura += strLine;
					 
					 } else {
						 assinatura += "\r\n"+strLine;
					 }
	 
				 }
			 }
			
			 verifyalg.update(licenca.getBytes());
			
			 //Verifica se a assinatura é válida ou não
			 if (!verifyalg.verify(assinatura.getBytes())){
				 System.out.print("Assinatura inválida ");
			
			 } else {
				 System.out.println("Assinatura válida");
			 }
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}

Resolvido, abs.

[quote=Helder8]Resolvido segue o código abaixo

import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.SecureRandom;

public class GerarChaves {

	public static void main(String[] args) {

		try {
			// Gerando as chaves
			KeyPairGenerator pairgen = KeyPairGenerator.getInstance("DSA");
			SecureRandom random = new SecureRandom();
			pairgen.initialize(512, random);

			// Gera a chave publica
			KeyPair keyPair = pairgen.generateKeyPair();
			ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("public.key"));
			out.writeObject(keyPair.getPublic());
			out.close();

			// Gera a chave privada
			out = new ObjectOutputStream(new FileOutputStream("privada.key"));
			out.writeObject(keyPair.getPrivate());
			out.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.security.PrivateKey;
import java.security.Signature;

public class AssinarLicenca {

	public static void main(String[] args) {
		
		try {
			 //Pega a chave privada para poder assinar o documento
			 ObjectInputStream keyIn = new ObjectInputStream(new
			 FileInputStream("privada.key"));
			 PrivateKey privkey = (PrivateKey) keyIn.readObject();
			 keyIn.close();
			
			 Signature signalg = Signature.getInstance("DSA");
			 signalg.initSign(privkey);
			
			 //Pega o documento que irá ser feito a assinatura
			 File infile = new
			 File("licenca.txt");
			 InputStream in = new FileInputStream(infile);
			
			 int length = (int) infile.length();
			 byte[] message = new byte[length];
			 in.read(message, 0, length);
			 in.close();
			
			 signalg.update(message);
			 byte[] signature = signalg.sign();
			
			 String beginSignature = "\r\n-----BEGIN PGP SIGNATURE-----\r\n";
			 String endSignature = "\r\n-----END PGP SIGNATURE-----";
			
			 //Escreve a assinatura gerada em outro documento, para poder enviar para o cliente
			 FileOutputStream out = new
			 FileOutputStream("licencaSign.txt");
			 out.write(message, 0, length);
			 out.write(beginSignature.getBytes(), 0, beginSignature.length());
			 out.write(signature, 0, signature.length);
			 out.write(endSignature.getBytes(), 0, endSignature.length());
			 out.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.security.PublicKey;
import java.security.Signature;

public class ValidarAssinatura {

	public static void main(String[] args) {
		
		try {
			//Pega a chave publica para validar a assinatura
			 ObjectInputStream keyIn = new ObjectInputStream(new
			 FileInputStream("public.key"));
			 PublicKey pubkey = (PublicKey) keyIn.readObject();
			 keyIn.close();
			
			 Signature verifyalg = Signature.getInstance("DSA");
			 verifyalg.initVerify(pubkey);
			 
			 //Pega a licenca assinada
			 File infile = new File("licencaSign.txt");
			 FileInputStream in = new FileInputStream(infile);
			 
			 DataInputStream dataInput = new DataInputStream(in);
			 BufferedReader br = new BufferedReader(new InputStreamReader(dataInput));
			 
			 String strLine;
			 String licenca = "";
			 
			 //Procura a mensagem
			 while ((strLine = br.readLine()) != null) {
				 
				 if (strLine.equals("-----BEGIN PGP SIGNATURE-----")) {
					 break;
					 
				 } else {
					 
					 if (licenca.equals("")) {
						 licenca += strLine;
					 
					 } else {
						 licenca += "\r\n"+strLine;
					 }
				 }
			 }

			 strLine = "";
			 String assinatura = "";
			 
			//Procura a assinatura
			 while ((strLine = br.readLine()) != null) {
				
				 if (!strLine.equals("-----END PGP SIGNATURE-----")) {
					 
					 if (assinatura.equals("")) {
						 assinatura += strLine;
					 
					 } else {
						 assinatura += "\r\n"+strLine;
					 }
	 
				 }
			 }
			
			 verifyalg.update(licenca.getBytes());
			
			 //Verifica se a assinatura é válida ou não
			 if (!verifyalg.verify(assinatura.getBytes())){
				 System.out.print("Assinatura inválida ");
			
			 } else {
				 System.out.println("Assinatura válida");
			 }
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}

Resolvido, abs.[/quote]

Olá, Helder.
Estou enfrentando uma dificuldade em um programa java desktop e, vendo seu tópico, resolvi tentar obter alguma ajuda sua, se possível.

Eu preciso validar a assinatura digital de um documento assinado.
Tenho a chave pública em uma string, ou seja, não preciso gerá-la. E também não preciso da chave privada. Estou certo?
Parece que terei que usar a classe Signature e também PublicKey.
Pesquisei bastante na internet, mas não estou conseguindo avançar no assunto.
A dificuldade inicial é conseguir transformar uma string em um objeto publicKey.
Vc pode me ajudar?

Ola Andre,

Isso mesmo, a chave privada serve somente para assinar o documento, essa chave ela é privada, deve ser guardada a 7 chaves, ninguém deve ter acesso, já a chave publica serve para ler o documento assinado pela chave privada, a chave publica poderá ficar com um cliente ou qualquer pessoa.

Por isso que quando eu gero as chaves eu crio uma publica e uma privada, sendo a privada para assinar um documento (somente essa chave pode assinar um documento), e a chave publica serve para verificar se o documento que foi assinado realmente encontra-se sem nenhuma modificação, entendeu? Só para você entender melhor, por exemplo: Eu assinei um documento com a chave privada, mas o cliente foi esperto o bastante e modificou o documento, mas assinatura ele não mecheu, pois, são codigos dificilmente de entender, ai ao pegar a chave publica e tentar validar o documento, você vai ver que o documento assinado pela chave privada não é validado pela chave publica, com isso você garante que um arquivo seja realmente real, sem nenhuma modificação, podendo ser ele um arquivo de licença por exemplo, como foi o meu caso.

Entendi seu problema, faz assim pega essa String e coloca em um arquivo .txt e salva como “public.key” dai você usa o codigo abaixo para ver se consegue transformar a String em um PublicKey, usando o código abaixo:

ObjectInputStream keyIn = new ObjectInputStream(new   
             FileInputStream("public.key"));   
             PublicKey pubkey = (PublicKey) keyIn.readObject();   
             keyIn.close(); 

Faz um teste e me fala se deu certo.

Usei esse site para poder me ajudar a entender e me basear, ela é um pouco melhor que usar as classes do Java mesmo (java.security.*)


http://cephas.net/blog/2004/04/01/pgp-encryption-using-bouncy-castle/

Abs,
Helder

[quote=Helder8]Ola Andre,

Isso mesmo, a chave privada serve somente para assinar o documento, essa chave ela é privada, deve ser guardada a 7 chaves, ninguém deve ter acesso, já a chave publica serve para ler o documento assinado pela chave privada, a chave publica poderá ficar com um cliente ou qualquer pessoa.

Por isso que quando eu gero as chaves eu crio uma publica e uma privada, sendo a privada para assinar um documento (somente essa chave pode assinar um documento), e a chave publica serve para verificar se o documento que foi assinado realmente encontra-se sem nenhuma modificação, entendeu? Só para você entender melhor, por exemplo: Eu assinei um documento com a chave privada, mas o cliente foi esperto o bastante e modificou o documento, mas assinatura ele não mecheu, pois, são codigos dificilmente de entender, ai ao pegar a chave publica e tentar validar o documento, você vai ver que o documento assinado pela chave privada não é validado pela chave publica, com isso você garante que um arquivo seja realmente real, sem nenhuma modificação, podendo ser ele um arquivo de licença por exemplo, como foi o meu caso.

Entendi seu problema, faz assim pega essa String e coloca em um arquivo .txt e salva como “public.key” dai você usa o codigo abaixo para ver se consegue transformar a String em um PublicKey, usando o código abaixo:

ObjectInputStream keyIn = new ObjectInputStream(new   
             FileInputStream("public.key"));   
             PublicKey pubkey = (PublicKey) keyIn.readObject();   
             keyIn.close(); 

Faz um teste e me fala se deu certo.

Usei esse site para poder me ajudar a entender e me basear, ela é um pouco melhor que usar as classes do Java mesmo (java.security.*)


http://cephas.net/blog/2004/04/01/pgp-encryption-using-bouncy-castle/

Abs,
Helder[/quote]

Olá, Helder.

Inicialmente, obrigado por todas as explicações.

Como sugerido, eu criei o arquivo public.key, porém ao executar o código, ocorreu o seguinte erro:

java.io.StreamCorruptedException: invalid stream header: 36463134
at java.io.ObjectInputStream.readStreamHeader(Unknown Source)
at java.io.ObjectInputStream.<init>(Unknown Source)
at ValidarAssinatura.main(ValidarAssinatura.java:16)

O que eu já pesquisei na internet nesses três últimos dias sobre essa minha necessidade não é brincadeira não é brincadeira não.
O que parecia ser algo simples de resolver, está se tornando quase um pesadelo.

Se você puder me ajudar sobre isso, ficarei muitíssimo grato.

Ola Andre,

Vc pode gerar novamente uma chave publica e uma privada? Se sim, use o meu exemplo acima.

Esse documento que esta assinado, esta em qual extensao?

Faz assim, me descreva com mais detalhes o que tem hoje e o que precisa ser feito, assim
eu posso analisar melhor o problema e ver uma melhor saida para solucionar ele.

O que eu poder te ajudar, estamos ai.

Abs,
Helder

[quote=Helder8]Ola Andre,

Vc pode gerar novamente uma chave publica e uma privada? Se sim, use o meu exemplo acima.

Esse documento que esta assinado, esta em qual extensao?

Faz assim, me descreva com mais detalhes o que tem hoje e o que precisa ser feito, assim
eu posso analisar melhor o problema e ver uma melhor saida para solucionar ele.

O que eu poder te ajudar, estamos ai.

Abs,
Helder[/quote]

Helder, é o seguinte:

Basicamente, eu preciso criar algo em java (talvez um método) que faça exatamente o que o aplicativo eECFc faz quando se clica no botão Validar Assinatura Digital (pelas suas mensagens anteriores, creio que você conheça esse aplicativo).

De posse de um arquivo MFD ou TDM no formato texto (gerado conforme o Ato-Cotepe ICMS 17/2004), eu preciso verificar se esse arquivo encontra-se íntegro, ou seja, verificar se o mesmo foi alterado ou não.

As chaves públicas geradas por cada fabricante de equipamentos ECF estão gravadas nos arquivos XML; e em cada arquivo MFD ou TDM consta o registro EAD (última linha do arquivo) com a assinatura digital do arquivo.

Caso eu não tenha sido muito claro, por favor, avise-me.

Forte abraço.

[quote=Helder8]Ola Andre,

Vc pode gerar novamente uma chave publica e uma privada? Se sim, use o meu exemplo acima.

Esse documento que esta assinado, esta em qual extensao?

Faz assim, me descreva com mais detalhes o que tem hoje e o que precisa ser feito, assim
eu posso analisar melhor o problema e ver uma melhor saida para solucionar ele.

O que eu poder te ajudar, estamos ai.

Abs,
Helder[/quote]

Olá, Helder.

Muito infelizmente não consegui avançar nada nessa questão.

Reforçando, o arquivo já está assinado. Eu preciso apenas verificar se o mesmo, após ter sido gerado e assinado pela DLL do fabricante, não foi alterado.

Estranho que a documentação do java diz que PublicKey é uma interface.

Ola Andre,

Eu entendi o seu problema, não conseugi responder antes porque estou meio corrido em um projeto no serviço. Então o grande problema é que esse arquivo foi assinado por um DLL do fabricante, vc tem a chave publica para ler, mas não consegue validar o documento pq precisa de alguma forma converter ela para uma PublicKey do Java.

Estava analisando o que eu fiz, mas eu gerei uma chave public e privada a partir do Java, dai eu assinava o arquivo e verifica ele depois com a chave publica, mas todas essas chaves foram geradas do java e não de uma DLL do fabricando, ai tá o problema. Estou achando que essa chave public gerada pelo fabricando não é compativel com a PublicKey do Java, por isso, você não consegue converter essa String…

Na minha sugestão, é tentar conversar com esse fabricando e falar com eles se tem algum exemplo de como validar esse documento utilizando o Java, dai fica mais facil, caso se eles não tiverem, logo, vão falar que essa chave public não é compativel com o PublicKey do Java.

Se tiver alguma idéia ou conseguir resolver de alguma forma, coloque no post, mas de imediato e como você está a bastante tempo com esse problema, não vejo outra solução a não ser tentar isso que eu falei.

Abs,
Helder

[quote=Helder8]Ola Andre,

Eu entendi o seu problema, não conseugi responder antes porque estou meio corrido em um projeto no serviço. Então o grande problema é que esse arquivo foi assinado por um DLL do fabricante, vc tem a chave publica para ler, mas não consegue validar o documento pq precisa de alguma forma converter ela para uma PublicKey do Java.

Estava analisando o que eu fiz, mas eu gerei uma chave public e privada a partir do Java, dai eu assinava o arquivo e verifica ele depois com a chave publica, mas todas essas chaves foram geradas do java e não de uma DLL do fabricando, ai tá o problema. Estou achando que essa chave public gerada pelo fabricando não é compativel com a PublicKey do Java, por isso, você não consegue converter essa String…

Na minha sugestão, é tentar conversar com esse fabricando e falar com eles se tem algum exemplo de como validar esse documento utilizando o Java, dai fica mais facil, caso se eles não tiverem, logo, vão falar que essa chave public não é compativel com o PublicKey do Java.

Se tiver alguma idéia ou conseguir resolver de alguma forma, coloque no post, mas de imediato e como você está a bastante tempo com esse problema, não vejo outra solução a não ser tentar isso que eu falei.

Abs,
Helder[/quote]

Ok, Helder.
Vou tentar esse contato com algum fabricante sim.
Muito obrigado pela disposição em ajudar.
Um forte abraço.

[quote=Helder8]Ola Andre,

Eu entendi o seu problema, não conseugi responder antes porque estou meio corrido em um projeto no serviço. Então o grande problema é que esse arquivo foi assinado por um DLL do fabricante, vc tem a chave publica para ler, mas não consegue validar o documento pq precisa de alguma forma converter ela para uma PublicKey do Java.

Estava analisando o que eu fiz, mas eu gerei uma chave public e privada a partir do Java, dai eu assinava o arquivo e verifica ele depois com a chave publica, mas todas essas chaves foram geradas do java e não de uma DLL do fabricando, ai tá o problema. Estou achando que essa chave public gerada pelo fabricando não é compativel com a PublicKey do Java, por isso, você não consegue converter essa String…

Na minha sugestão, é tentar conversar com esse fabricando e falar com eles se tem algum exemplo de como validar esse documento utilizando o Java, dai fica mais facil, caso se eles não tiverem, logo, vão falar que essa chave public não é compativel com o PublicKey do Java.

Se tiver alguma idéia ou conseguir resolver de alguma forma, coloque no post, mas de imediato e como você está a bastante tempo com esse problema, não vejo outra solução a não ser tentar isso que eu falei.

Abs,
Helder[/quote]

Parece que os passos a serem seguidos são os seguintes:

  1. Calcular o hash MD5 do arquivo MFD (sem o registro EAD).
  2. Extrair do XML do fabricante a chave pública.
  3. Extrair do registro EAD (última linha do arquivo) o buffer criptografado.
  4. Decriptografar o buffer obtendo a mensagem originalmente assinada.
  5. Extrair da mensagem o hash originalmente assinado.
  6. Comparar o hash assinado com o hash calculado no passo 1

Tem alguma idéia de como consigo fazer isso em java?

Abraço.

[quote=Helder8]Ola Andre,

Eu entendi o seu problema, não conseugi responder antes porque estou meio corrido em um projeto no serviço. Então o grande problema é que esse arquivo foi assinado por um DLL do fabricante, vc tem a chave publica para ler, mas não consegue validar o documento pq precisa de alguma forma converter ela para uma PublicKey do Java.

Estava analisando o que eu fiz, mas eu gerei uma chave public e privada a partir do Java, dai eu assinava o arquivo e verifica ele depois com a chave publica, mas todas essas chaves foram geradas do java e não de uma DLL do fabricando, ai tá o problema. Estou achando que essa chave public gerada pelo fabricando não é compativel com a PublicKey do Java, por isso, você não consegue converter essa String…

Na minha sugestão, é tentar conversar com esse fabricando e falar com eles se tem algum exemplo de como validar esse documento utilizando o Java, dai fica mais facil, caso se eles não tiverem, logo, vão falar que essa chave public não é compativel com o PublicKey do Java.

Se tiver alguma idéia ou conseguir resolver de alguma forma, coloque no post, mas de imediato e como você está a bastante tempo com esse problema, não vejo outra solução a não ser tentar isso que eu falei.

Abs,
Helder[/quote]

Olá, Helder.

Aproveitando que escrevi em outro post.

Depois de muito pesquisar na internet (e quase desistir), obtive ajuda de um excelente programador de c++ que me deu o passo-a-passo de como validar a assinatura digital de um arquivo e consegui enfim resolver a questão.

Resumidamente:
Passos executados para verificar a integridade do arquivo (os passos que o meu programa em java precisam executar):

  1. Submeter o arquivo recebido à função unidirecional MD5 e armazenar o resultado (um hash de 16 bytes).
  2. Descriptografar o hash recebido do remetente utilizando-se o algoritmo RSA e a chave pública do remetente.
  3. Comparar o hash do item 1 com o hash descriptogradado no item 2.
  4. Se forem diferentes significará que o arquivo foi alterado depois de sua geração.

Depois de conseguir entender todo o processo e saber os passos que meu programa precisava executar, você deve lembrar que fiquei emperrado em como transformar uma string com a chave pública do remetente em um objeto PublicKey do java. Foram vários dias de “google” até encontrar o seguinte código na internet:

public void saveToFile(String fileName, BigInteger mod, BigInteger exp) throws IOException { ObjectOutputStream oout = new ObjectOutputStream( new BufferedOutputStream(new FileOutputStream(fileName))); try { oout.writeObject(mod); oout.writeObject(exp); } catch (Exception e) { throw new IOException("Unexpected error", e); } finally { oout.close(); } }
Obs.: Para transformar uma string cujo conteúdo representa uma chave pública em hexadecimal, utilizei o new BigInteger(chave, 16), onde chave é a string com o conteúdo da chave.

Tendo a chave gravada em um arquivo “publickey.key”, por exemplo, os passos seguintes foram:

  1. Obter o hash do arquivo:

MessageDigest md = MessageDigest.getInstance("MD5"); md.update(conteudoArquivo); byte[] novoHash = md.digest();

Obs.: conteudoArquivo é um array de bytes com todo o conteúdo do arquivo.

  1. Obter a chave pública gravada em um arquivo.

InputStream in = new FileInputStream("publickey.key"); ObjectInputStream oin = new ObjectInputStream(new BufferedInputStream(in)); BigInteger m = (BigInteger) oin.readObject(); BigInteger e = (BigInteger) oin.readObject(); RSAPublicKeySpec keySpec = new RSAPublicKeySpec(m, e); KeyFactory fact = KeyFactory.getInstance("RSA"); PublicKey pubKey = fact.generatePublic(keySpec);

  1. Descritografar o hash recebido junto com o arquivo.

Cipher rsaCipher = null; rsaCipher = Cipher.getInstance("RSA/ECB/NoPadding"); rsaCipher.init(Cipher.DECRYPT_MODE, pubKey); byte[] hashOriginal = rsaCipher.doFinal(assinatura);
Obs.: assinatura é um array de bytes cujo conteúdo representa o hash criptografado.

  1. Comparar o hashOriginal com o novoHash.
    Se coincidir, significará “ASSINATURA VÁLIDA”.

Coloquei de forma resumida. Tem outros detalhes de, por exemplo, ter que transformar de string para byte, de hexa para binário, que não mencionei, pois ficaria muito extenso. Mas a base, no meu caso, é esse passo-a-passo acima.
Eu gastei muitas horas (alguns dias) de pesquisa na questão da chave pública e também em outros pontos, mas ao final deu certo.

Aproveito para agradecer a você pela disposição em ajudar.

Saudações.

Ola Andre,

Bacana que tenha conseguido resolver o problema!!! Valeu por colocar como conseguiu resolver esse problema, pois, assuntos relacionados a assinatura digital é muito pouco material que encontramos na internet infelizmente…

Que isso, se precisar de alguma coisa estamos ai.

Abs,
Helder