package gcom.util.validacao; import java.io.File; import java.math.BigInteger; import java.security.InvalidKeyException; import java.security.KeyFactory; import java.security.NoSuchAlgorithmException; import java.security.PublicKey; import java.security.Signature; import java.security.SignatureException; import java.security.spec.DSAPublicKeySpec; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.apache.commons.codec.binary.Base64; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; /** * * Classe respons�vel por validar assinaturas de algoritmo DSA a partir de uma chave p�blica * em formato XML. * * @author Hugo Azevedo * @date 02/05/2011 * */ public class AssinaturaDSA { //Arquivo XML da chave p�blica private String arquivoChavePublica; //Chave p�blica gerada ao se instanciar a classe private PublicKey chavePublica; public AssinaturaDSA(String arquivoChavePublica){ this.arquivoChavePublica = arquivoChavePublica; this.chavePublica = this.getChavePublica(); } public String getArquivoChavePublica() { return arquivoChavePublica; } public void setArquivoChavePublica(String arquivoChavePublica) { this.arquivoChavePublica = arquivoChavePublica; } /** * M�todo respons�vel por validar um par hash/assinatura a partir * da chave p�blica gerada pela classe * * @param hash - Hash que ser� validada * @param assinatura - Assinatura que ser� utilizada pelo algoritmo para validar a hash * @return Indicador se a hash � v�lida ou n�o * **/ public boolean validarHash(byte[] hash, byte[] assinatura) { boolean retorno = false; try { //Define a assinatura do cliente e o algoritmo utilizado para a descripta��o Signature assinaturaCliente = Signature.getInstance("SHA1withDSA"); //Define a chave p�blica assinaturaCliente.initVerify(this.chavePublica); //Define o dado a ser comparada assinaturaCliente.update(hash); //Convertendo para o formato DER, entendido por Java byte[] assinaturaDecodificada = Base64.decodeBase64(assinatura); // boolean retorno = verificador.validarHash(usur_nmlogin.getBytes(),verificador.ConvertToDsaSignatureToJavaEncoding(decoded)); //Compara a assinatura do cliente com a passada por par�metro pelo usu�rio, para valida��o //A assinatura gerada corretamente pelo C# cont�m exatos 40 bytes. if(assinaturaDecodificada.length == 40 && assinaturaCliente.verify(ConvertToDsaSignatureToJavaEncoding(assinaturaDecodificada))){ retorno = true; } else{ retorno = false; } } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (InvalidKeyException e) { e.printStackTrace(); } catch (SignatureException e) { e.printStackTrace(); } return retorno; } /** * M�todo respons�vel por gerar uma chave p�blica a partir do arquivo XML * * @return PublicKey - Classe de chave p�blica * **/ private PublicKey getChavePublica(){ PublicKey chave = null; try{ BigInteger Q = this.getParametroChave("Q"); BigInteger P = this.getParametroChave("P"); BigInteger G = this.getParametroChave("G"); BigInteger Y = this.getParametroChave("Y"); DSAPublicKeySpec dsaPublicKeySpec = new DSAPublicKeySpec(Y,P,Q,G); KeyFactory keyFactory = KeyFactory.getInstance("DSA"); chave = keyFactory.generatePublic(dsaPublicKeySpec); } catch(Exception ex){ } return chave; } /** * M�todo respons�vel retornar o valor de uma DOM do arquivo XML da chave p�blica * * @param paramDSA - DOM que ter� o valor retornado * @return BigInteger - Valor da DOM * **/ private BigInteger getParametroChave(String paramDSA){ BigInteger retorno = null; try{ //Leitura do Arquivo da chave p�blica File chavePublicaXML = new File(this.arquivoChavePublica); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document documentoXML = builder.parse(chavePublicaXML); //Recupera o valor da tag passada por par�metro NodeList listaNos = documentoXML.getElementsByTagName(paramDSA); Element no = (Element)listaNos.item(0); NodeList textFNList = no.getChildNodes(); String chave = ((Node)textFNList.item(0)).getNodeValue().trim(); byte[] chaveDecodificada = Base64.decodeBase64(chave.getBytes("UTF-8")); retorno = new BigInteger(1,chaveDecodificada); } catch(Exception ex){ //String msg = ex.getMessage(); } return retorno; } /** * * M�todo para transformar a assinatura de formato * IEEE P1363 (C#) em DER (Java) * * @param dsa - Array de bytes da assinatura original, em formato p1363 * @return Assinatura em formato der * **/ public byte[] ConvertToDsaSignatureToJavaEncoding(byte[] dsa){ if(dsa.length !=40) System.out.println("Exce��o"); byte[] r = new byte[20]; System.arraycopy(dsa, 0, r, 0, 20); byte[] s = new byte[20]; System.arraycopy(dsa, 20, s, 0, 20); // Convert to complement-2 byte[] complementTwoR = ToComplementTwo(r); byte[] complementTwoS = ToComplementTwo(s); // Build the result byte[] res = new byte[complementTwoR.length + complementTwoS.length + 6]; // Sequence{ res[0] = 0x30; res[1] = (byte) (complementTwoR.length + complementTwoS.length + 4); // Integer (R) res[2] = 0x02; res[3] = (byte) complementTwoR.length; System.arraycopy(complementTwoR, 0, res, 4, complementTwoR.length); // Integer (S) res[complementTwoR.length + 4] = 0x02; res[complementTwoR.length + 5] = (byte) complementTwoS.length; System.arraycopy(complementTwoS, 0, res, complementTwoR.length + 6, complementTwoS.length); return res; } public byte[] ToComplementTwo(byte[] d){ // Ensure the top-bit is zero, otherwise remove unneeded zeroes // - Find non-zero byte int i = 0; while (i < d.length && d[i] == 0) i++; //- Do we need an extra byte int extraByte = (d[i] & 0x80) == 1 ? 1 : 0; // - Build the result byte[] res = new byte[d.length-i+extraByte]; System.arraycopy(d, i, res, extraByte, d.length-i); return res; } public static void main(String[] arg0){ AssinaturaDSA verificador = new AssinaturaDSA("C:\\Encrypt\\DSA_PROGIS_Publica.xml"); /* * Caso de teste * */ String usur_nmlogin = "25187372947"; String sign = "1EmixF+4qXfVogAOwbyJrhLvN12vNFmCEij+7suJiJigh2V+M65wKg=="; boolean retorno = verificador.validarHash(usur_nmlogin.getBytes(),sign.getBytes()); if(retorno){ System.out.println("LOGIN V�LIDO"); } else{ System.out.println("LOGIN INV�LIDO"); } } }