Assinatura digital em XML

A assinatura digital é um conjunto de operações criptográficas que permite comprovar a autenticidade e garantir a integridade de uma mensagem ou documento eletrônico.

E para exemplificar o processo vamos assinar a seguinte mensagem XML:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
 xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
 <soapenv:Body>
  <pedidoDeCompra xmlns="http://teste.com.br/">
    <infPedido Id="pedido12345">
      <nroPedido>12345</nroPedido>
      <vlrTotal>13.95</vlrTotal>
      <produtos>
       <item>
          <nomeProduto>Pão</nomeProduto>
          <quantidade>12</quantidade>
          <valorUnitario>0.98</valorUnitario>
       </item>
       <item>
          <nomeProduto>Leite</nomeProduto>
          <quantidade>1</quantidade>
          <valorUnitario>2.19</valorUnitario>
       </item>
      </produtos>
    </infPedido>
  </pedidoDeCompra>
 </soapenv:Body> 
</soapenv:Envelope>

E a seguir, a mesma mensagem assinada:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
 xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
 <soapenv:Body>
 <pedidoDeCompra xmlns="http://teste.com.br/">
  <infPedido Id="pedido12345">
    <nroPedido>12345</nroPedido>
    <vlrTotal>13.95</vlrTotal>
    <produtos>
     <item>
       <nomeProduto>Pão</nomeProduto>
       <quantidade>12</quantidade>
       <valorUnitario>0.98</valorUnitario>
     </item>
     <item>
       <nomeProduto>Leite</nomeProduto>
       <quantidade>1</quantidade>
       <valorUnitario>2.19</valorUnitario>
     </item>
    </produtos>
  </infPedido>
  <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
  <SignedInfo>
    <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
    <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/> 
    <Reference URI="#pedido12345">
    <Transforms>
      <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/> 
      <Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/> 
    </Transforms>
    <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
    <DigestValue>MeAffeccY54DFefdS=</DigestValue>
  </SignedInfo>
  <SignatureValue>ZSrLF8Uafjloo58asdf8ujnzleFa=</SignatureValue>
  <KeyInfo>
  <X509Data><X509Certificate>NBAsMAFEdsPJesiivApzclUPsEexVZfe
                   ...cortei os dados do certificado </X509Certificate>
  </X509Data>
  </KeyInfo> 
  </Signature>
 </pedidoDeCompra>
 </soapenv:Body> 
</soapenv:Envelope>

Agora falta mostrar como essa assinatura digital foi gerada.

Mas antes…

O que é assinatura digital ?
A assinatura digital é uma tecnologia que permite dar garantia de integridade e  autenticidade a arquivos eletrônicos.
É um conjunto de operações criptográficas que permite comprovar que a mensagem ou arquivo
não foi alterado e que foi assinado pela entidade ou pessoa que possui a chave privada utilizada na assinatura.

Como foi gerada a assinatura?
Primeiramente, é necessário que se tenha um certificado digital.

O certificado digital é um documento eletrônico assinado digitalmente, contendo a identificação de uma pessoa,
sua chave pública e assinado digitalmente por uma Autoridade Certificadora. O certificado digital comprova que
uma chave privada pertence a determinada pessoa.

Na assinatura digital utiliza-se o certificado digital e a chave privada correspondente.

O elemento ‘X509Certificate’, em nosso exemplo de assinatura, contém o conteúdo do certificado (chave pública).
O elemento ‘DigestValue’ contém o hash (função hash) do pedido de compra.
E por fim, o elemento ‘SignatureValue’ contém algum conteúdo cifrado com a chave privada. Como tudo que
é cifrado com a chave privada só pode ser interpretado com a chave pública se abrirmos o certificado empacotado
no elemento significa que a pessoa que assinou este XML realmente possui a chave privada.

E o código java para assinar?


public class Main {
	
  public static void main(String[] args) throws Exception {
   InputStream in = new FileInputStream(new File("C://xmlSemAssinatura.xml"));
   OutputStream os = new FileOutputStream(new File("C://xmlAssinado.xml"));

  //elemento que deve ser assinado
  String tagName="pedidoDeCompra";
  String elementoID = "pedido12345";

  //chave(certificado)
  String pathCertificado = "C://Certificado_digital.pfx";
  String senhaCertificado = "changeit";
  String alias = "???";
  DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
  dbf.setNamespaceAware(true);
  org.w3c.dom.Document doc = dbf.newDocumentBuilder().parse(in);

  InputStream entrada = new FileInputStream(pathCertificado);
  KeyStore ks = KeyStore.getInstance("pkcs12");
  try { 
    ks.load(entrada, senhaCertificado.toCharArray());
			
    if (ks.getEntry(alias, new KeyStore.PasswordProtection(senhaCertificado.toCharArray()))==null){
      throw new Exception("Alias existe?");
    }		
  } catch (IOException e) {
     throw new Exception("Senha do Certificado Digital incorreta ou Certificado inválido.");
  }
  KeyStore.PrivateKeyEntry keyEntry = (KeyStore.PrivateKeyEntry) 
     ks.getEntry(alias, new KeyStore.PasswordProtection(senhaCertificado.toCharArray()));

  DOMSignContext dsc = new DOMSignContext(keyEntry.getPrivateKey(), doc.getElementsByTagName(tagName).item(0));

  //Assembling the XML Signature
  XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");

  List transforms = new ArrayList();
  transforms.add(fac.newTransform(Transform.ENVELOPED, (TransformParameterSpec) null));
  transforms.add(fac.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE, (C14NMethodParameterSpec) null));

  Reference ref = fac.newReference("#" + elementoID, //
                       fac.newDigestMethod(DigestMethod.SHA1, null),//
                       transforms, null, null);

  SignedInfo si = fac.newSignedInfo(//
                      fac.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE, //
                     (C14NMethodParameterSpec) null), //
                      fac.newSignatureMethod(SignatureMethod.RSA_SHA1, null),//
                      Collections.singletonList(ref));

  KeyInfoFactory kif = fac.getKeyInfoFactory();

  List x509Content = new ArrayList();
  x509Content.add(keyEntry.getCertificate());

  X509Data kv = kif.newX509Data(x509Content);
  KeyInfo ki = kif.newKeyInfo(Collections.singletonList(kv));
  XMLSignature signature = fac.newXMLSignature(si, ki);

  signature.sign(dsc);

  TransformerFactory tf = TransformerFactory.newInstance();
  Transformer trans = tf.newTransformer();

   //salva resultado no arquivo de saída
   trans.transform(new DOMSource(doc), new StreamResult(os));

  }
}

E os imports

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.KeyStore;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.xml.crypto.dsig.CanonicalizationMethod;
import javax.xml.crypto.dsig.DigestMethod;
import javax.xml.crypto.dsig.Reference;
import javax.xml.crypto.dsig.SignatureMethod;
import javax.xml.crypto.dsig.SignedInfo;
import javax.xml.crypto.dsig.Transform;
import javax.xml.crypto.dsig.XMLSignature;
import javax.xml.crypto.dsig.XMLSignatureFactory;
import javax.xml.crypto.dsig.dom.DOMSignContext;
import javax.xml.crypto.dsig.keyinfo.KeyInfo;
import javax.xml.crypto.dsig.keyinfo.KeyInfoFactory;
import javax.xml.crypto.dsig.keyinfo.X509Data;
import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec;
import javax.xml.crypto.dsig.spec.TransformParameterSpec;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

Não é possível cobrir todos os conceitos sobre assinatura em um simples exemplo mas esse código java, além de outros disponíveis na Internet, atende o requisito de assinar a mensagem XML/SOAP usada no exemplo.

Links úteis:
http://www.infowester.com/criptografia.php
http://www.infowester.com/assincertdigital.php
http://www.receita.fazenda.gov.br/atendvirtual/orientacoes/conceitobasico.htm
http://www.jf.jus.br/cjf/tecnologia-da-informacao/identidade-digital/o-que-e-assinatura-digital

2 ideias sobre “Assinatura digital em XML

  1. Eduardo Henrique

    Bom dia, seu código ajudou muito mas gostaria de saber se conhece algum exemplo ou algo do tipo que ele assina no mesmo xml duas tags diferentes no caso criando duas tags signature

    Resposta
    1. Crestaniweb Autor do post

      Ola, usei isso e o código de assinatura é o mesmo (segue a mesma lógica) diferenciando a posição onde será inserida a assinatura.
      Na prática fica parecendo um XML grande com vários XMLs menores.

      Resposta

Deixe uma resposta

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s