XML document with a digital signature

Five Stars

XML document with a digital signature

Hi, I need generate an XML document with a digital signature.
Example of XML document that I must sign and verify your signature: 
https://www.efactura.dgi.gub.uy/files/ejemplo-de-sobre?es

I am a programmer (PHP, C++, Python, NodeJs, etc..), but I do not work with the Java language.

How can I generate plugins for the designer of Talend Data Integration could sign my XMl document and the signature is verified. Any recommendation.


Guide translated from Spanish -
http://www.efactura.dgi.gub.uy/files/guias-en-el-uso-de-xmlencryption-11062014-pdf?es

Using the XMLEncryption standard (http://www.w3.org/2001/04/xmlenc).
It should be used as an asymmetric algorithm rsa-pkcs1 (http://www.w3.org/2001/04/xmlenc#rsa-1_5) and
as a symmetric algorithm: 3DES-CBC (http://www.w3.org/2001/04/xmlenc#tripledes-cbc).
Finally, as a key name (KeyName), CERT_DGI_EFACTURA must be used.


The public and private keys are generated in the following way:

1- As a first step, we create the private key pair (cakey.pem) and public key (cacert.pem) of our CA using the RSA algorithm (since DSA only serves to sign). A bit length (2048) is chosen according to the security that a CA needs.

openssl req -x509 -newkey rsa:4096 -days 3650 -keyout ca\private\cakey.pem -out ca\cacert.pem -config openssl.cfg


2- The pair of private keys (clientkey.pem) and CSR (client.cert.req) that will be sent to the CA are created for the Client (CSR stands for Certificate Signing Request or Certificate Signing Request).

openssl req -newkey rsa:1024 -keyout client\private\clientkey.pem -out client\csr\client.cert.req -config openssl.cfg


3- From the Client's CSR (client.cert.req), a signed X509 certificate (version 3) is created with the private key of the CA (clientcert.pem).

openssl ca -days 3650 -in client\csr\client.cert.req -out client\signed\clientcert.pem -config openssl.cfg


4- Finally, the client's private key (clientkey.pem) and its certificate issued by the CA (clientcert.pem) are exported to PKCS # 12 (client.p12).

openssl pkcs12 -export -out client\client.p12 -inkey client\private\clientkey.pem -in client\signed\clientcert.pem


Example implementation in Java.

import java.security.PrivateKey;
import java.security.PublicKey;

import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.apache.xml.security.encryption.EncryptedData;
import org.apache.xml.security.encryption.EncryptedKey;
import org.apache.xml.security.encryption.XMLCipher;
import org.apache.xml.security.keys.KeyInfo;
import org.apache.xml.security.utils.EncryptionConstants;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

public class XMLEncryptionSample {
 static {
  org.apache.xml.security.Init.init();
 }
 private static Document parseFile(String fileName) throws Exception {
  DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
  dbf.setNamespaceAware(true);
  DocumentBuilder db = dbf.newDocumentBuilder();
  return db.parse(fileName);
 }
 private static SecretKey generateSymmetricKey() throws Exception {
  String jceAlgorithmName = "DESede";
  KeyGenerator keyGenerator = KeyGenerator.getInstance(jceAlgorithmName);
  return keyGenerator.generateKey();
 }
 private static void writeDocToFile(Document doc, String fileName)
 throws Exception {
  FileOutputStream outStream = new FileOutputStream(new File(fileName));
  TransformerFactory factory = TransformerFactory.newInstance();
  Transformer transformer = factory.newTransformer();
  transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
  DOMSource source = new DOMSource(doc);
  transformer.transform(source, new StreamResult(outStream));
  outStream.close();
 }
 public static void encrypt(String source, String target, String ns, String element,
  Key publicKey, String keyName) throws Exception {
  // Read XML from file
  Document document = parseFile(source);
  // Generates symmetric key for 3Des
  Key symmetricKey = generateSymmetricKey();
  // Initialize cipher to encrypt the symmetric key
  XMLCipher keyCipher = XMLCipher.getInstance(XMLCipher.RSA_v1dot5);
  keyCipher.init(XMLCipher.WRAP_MODE, publicKey);
  // Encrypts the symmetric key
  EncryptedKey encryptedKey = keyCipher
   .encryptKey(document, symmetricKey);
  // Specifies the element of the XML document to be encrypted
  Element rootElement = document.getDocumentElement();
  Element elementToEncrypt = rootElement;
  if (element != null) {
   elementToEncrypt = (Element) rootElement.getElementsByTagNameNS(
    ns, element).item(0);
   if (elementToEncrypt == null) {
    System.err.println("The element is not found: " + element);
   }
  }
  // Initialize cipher to encrypt the XML Element
  XMLCipher xmlCipher = XMLCipher.getInstance(XMLCipher.TRIPLEDES);
  xmlCipher.init(XMLCipher.ENCRYPT_MODE, symmetricKey);
  // Add information from the encryption key
  EncryptedData encryptedDataElement = xmlCipher.getEncryptedData();
  KeyInfo innerKeyInfo = new KeyInfo(document);
  innerKeyInfo.addKeyName(keyName);
  encryptedKey.setKeyInfo(innerKeyInfo);
  KeyInfo keyInfo = new KeyInfo(document);
  keyInfo.add(encryptedKey);
  encryptedDataElement.setKeyInfo(keyInfo);
  // Cipher
  xmlCipher.doFinal(document, elementToEncrypt);
  // Write the result in the destination file
  writeDocToFile(document, target);
 }
 public static void decrypt(String source, String target, Key privateKey)
 throws Exception {
  // Read XML from file
  Document document = parseFile(source);
  // Get the XML Element with encrypted data
  String namespaceURI = EncryptionConstants.EncryptionSpecNS;
  String localName = EncryptionConstants._TAG_ENCRYPTEDDATA;
  Element encryptedDataElement = (Element) document
   .getElementsByTagNameNS(namespaceURI, localName).item(0);
  // The symmetric key is decrypted
  XMLCipher xmlCipher = XMLCipher.getInstance();
  xmlCipher.init(XMLCipher.DECRYPT_MODE, null);
  xmlCipher.setKEK(privateKey);
  // The encrypted node is replaced with the decrypted information
  xmlCipher.doFinal(document, encryptedDataElement);
  // Write the result in the destination file
  writeDocToFile(document, target);
 }
}


Loading the private and public key from a keystore (# PCKS12) named client.p12 whose alias is client, can be programmed as follows:

PrivateKey privateKey = null;
PublicKey publicKey = null;
....
....
KeyStore keystore = KeyStore.getInstance("PKCS12");
String p12Password = "secreto";
keystore.load(new FileInputStream("client.p12"), p12Password.toCharArray());
privateKey = (PrivateKey) keystore.getKey("client", p12Password.toCharArray());
publicKey = keystore.getCertificate("client").getPublicKey();


Finally, to perform a test, the encrypt / decrypt methods can be used as follows:

encrypt("Unencrypted.xml", "Encrypted.xml", "http://cfe.dgi.gub.uy", "Compl_Fiscal_Data",
publicKey, "CERT_DGI_EFACTURA");

decrypt("Encrypted.xml", "Decrypted.xml", privateKey);


Excuse me if my English is not understood correctly.

Thank you, I hope that I can integrate this into my project in Talend Data Integration with your help.

Regards.

 

Five Stars

Re: XML document with a digital signature

Could someone give me an example, how to implement it.?  Thank you very much.