Esta entrada se hace con 3 en 1. Esto quiere decir: Crear llave para cifrar, Cifrar Mensaje, descifrar mensaje; gracias a las librerías de Apache Santuario. A continuación veremos gráficamente la implementación.

1. Estructura del proyecto y librerías utilizadas:

clases-blog-y-librerias2.  Las clases que manejaremos son en orden de utilización son:

  • RutaArchivosBlog : Clase donde se encuentran las rutas y nombre de los archivos necesarios para la implementación.
  • GenerarArchivoLlaveBlog : Clase encargada de generar la llave que llamaremos, “kekFileBlog
  • MensajeBlogDto: Clase encargada de transformarse en XML, con el mensaje a cifrar.
  • EncriptarXMLBlog: Clase que crea el archivo XML cifrado.
  • DesencriptarXMLBlog: Clase encargada de cargar el archivo cifrado y descifrarlo.

3. Contenido de la clase MensajeBlogDto.

import java.io.Serializable;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class MensajeBlogDto implements Serializable {
    private static final long serialVersionUID = -9034773544663261282L;
    private String mensaje;
    private Boolean isValido;

    public String getMensaje() {
        return mensaje;
    }   
    public void setMensaje(String mensaje) {
        this.mensaje = mensaje;
    }
    public Boolean getIsValido() {
        return isValido;
    }
    public void setIsValido(Boolean isValido) {
        this.isValido = isValido;
    }
}

4. Contenido de la clase RutaArchivosBlog.

/**
 * Clase de ruta de archivos.
 */
public class RutaArchivosBlog {

    /**
     * Ruta del archivo que contiene la llave.
     */
    public static final String RUTA_ARCHIVO_KEK = "build/kekFileBlog";
    /**
     * Ruta del archivo encriptado.
     */
    public static final String RUTA_ARCHIVO_XML_ENCRYPTED = "build/encryptedMensajeBlog.xml";

    /**
     * Ruta del archivo desencriptado.
     */
    public static final String RUTA_ARCHIVO_XML_DENCRYPTED = "build/decryptedMensajeBlog.xml";
}

5. Contenido GenerarArchivoLlaveBlog.

import java.io.File;
import java.io.FileOutputStream;
import java.security.Key;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
import org.apache.xml.security.utils.JavaUtils;

public class GenerarArchivoLlaveBlog {

    public static void main(String[] args) {
        try {
            org.apache.xml.security.Init.init();
            Key symmetricKey = GenerateAndStoreKeyEncryptionKey();
            //prueba de carga del archivo y existe
            Key kek = loadKeyEncryptionKey();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    private static SecretKey GenerateAndStoreKeyEncryptionKey() throws Exception {
        String jceAlgorithmName = "DESede";
        KeyGenerator keyGenerator = KeyGenerator.getInstance(jceAlgorithmName);
        SecretKey kek = keyGenerator.generateKey();
        byte[] keyBytes = kek.getEncoded();
        File kekFile = new File(RutaArchivosBlog.RUTA_ARCHIVO_KEK);
        FileOutputStream f = new FileOutputStream(kekFile);
        f.write(keyBytes);
        f.close();
        System.out.println("Key encryption key stored in " + kekFile.toURI().toURL().toString());
        return kek;
    }
    private static SecretKey loadKeyEncryptionKey() throws Exception {
        String fileName = RutaArchivosBlog.RUTA_ARCHIVO_KEK;
        String jceAlgorithmName = "DESede";
        File kekFile = new File(fileName);
        DESedeKeySpec keySpec = new DESedeKeySpec(JavaUtils.getBytesFromFile(fileName));
        SecretKeyFactory skf = SecretKeyFactory.getInstance(jceAlgorithmName);
        SecretKey key = skf.generateSecret(keySpec);
        return key;
    }
}

6. Contenido EncriptarXMLBlog.

import java.io.File;
import java.io.FileOutputStream;
import java.io.StringWriter;
import java.security.Key;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
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.JavaUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

public class EncriptarXMLBlog {
    public static void main(String[] args) throws Exception {
        JAXBContext context;
        try {
            MensajeBlogDto respuesta = new MensajeBlogDto();
            respuesta.setIsValido(Boolean.TRUE);
            respuesta.setMensaje("Este es el mensaje a cifrar para el blog");
            context = JAXBContext.newInstance(MensajeBlogDto.class);
            Marshaller marshaller = context.createMarshaller();
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
            final StringWriter w = new StringWriter();
            marshaller.marshal(respuesta, w);
            String retornoXml = w.toString();
            System.out.println("" + retornoXml);
            // Create the Document
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            DocumentBuilder db = dbf.newDocumentBuilder();
            Document document = db.newDocument();
            marshaller.marshal(respuesta, document);

            org.apache.xml.security.Init.init();
            Key symmetricKey = GenerateDataEncryptionKey();
            Key kek = EncriptarXMLBlog.loadKeyEncryptionKey();

            String algorithmURI = XMLCipher.TRIPLEDES_KeyWrap;
            XMLCipher keyCipher = XMLCipher.getInstance(algorithmURI);
            keyCipher.init(XMLCipher.WRAP_MODE, kek);
            EncryptedKey encryptedKey = keyCipher.encryptKey(document, symmetricKey);

            Element rootElement = document.getDocumentElement();
            algorithmURI = XMLCipher.AES_128;
            XMLCipher xmlCipher = XMLCipher.getInstance(algorithmURI);
            xmlCipher.init(XMLCipher.ENCRYPT_MODE, symmetricKey);

            EncryptedData encryptedData = xmlCipher.getEncryptedData();
            KeyInfo keyInfo = new KeyInfo(document);
            keyInfo.add(encryptedKey);
            encryptedData.setKeyInfo(keyInfo);
            xmlCipher.doFinal(document, rootElement, true);
            EncriptarXMLBlog.outputDocToFile(document, RutaArchivosBlog.RUTA_ARCHIVO_XML_ENCRYPTED);
        } catch (JAXBException ex) {
            Logger.getLogger(EncriptarXMLBlog.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    private static SecretKey GenerateDataEncryptionKey() throws Exception {
        String jceAlgorithmName = "AES";
        KeyGenerator keyGenerator = KeyGenerator.getInstance(jceAlgorithmName);
        keyGenerator.init(128);
        return keyGenerator.generateKey();
    }
    private static SecretKey loadKeyEncryptionKey() throws Exception {
        String fileName = RutaArchivosBlog.RUTA_ARCHIVO_KEK;
        String jceAlgorithmName = "DESede";
        File kekFile = new File(fileName);
        DESedeKeySpec keySpec = new DESedeKeySpec(JavaUtils.getBytesFromFile(fileName));
        SecretKeyFactory skf = SecretKeyFactory.getInstance(jceAlgorithmName);
        SecretKey key = skf.generateSecret(keySpec);
        System.out.println("Key encryption key loaded from " + kekFile.toURI().toURL().toString());
        return key;
    }
    private static void outputDocToFile(Document doc, String fileName) throws Exception {
        File encryptionFile = new File(fileName);
        FileOutputStream f = new FileOutputStream(encryptionFile);
        TransformerFactory factory = TransformerFactory.newInstance();
        Transformer transformer = factory.newTransformer();
        transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
        DOMSource source = new DOMSource(doc);
        StreamResult result = new StreamResult(f);
        transformer.transform(source, result);
        f.close();
        System.out.println("Wrote document containing encrypted data to " + encryptionFile.toURI().toURL().toString());
    }
}

7. Contenido DesencriptarXMLBlog.

import java.io.File;
import java.io.FileOutputStream;
import java.security.Key;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
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.XMLCipher;
import org.apache.xml.security.utils.EncryptionConstants;
import org.apache.xml.security.utils.JavaUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

public class DesencriptarXMLBlog {
    public static void main(String[] args) throws Exception {
        Document document = DesencriptarXMLBlog.loadEncryptionDocument();
        Element encryptedDataElement = (Element) document.getElementsByTagNameNS(
                EncryptionConstants.EncryptionSpecNS,
                EncryptionConstants._TAG_ENCRYPTEDDATA).item(0);
        
        Key kek = DesencriptarXMLBlog.loadKeyEncryptionKey();
        org.apache.xml.security.Init.init();
        XMLCipher xmlCipher = XMLCipher.getInstance();

        xmlCipher.init(XMLCipher.DECRYPT_MODE, null);
        xmlCipher.setKEK(kek);
        xmlCipher.doFinal(document, encryptedDataElement);
        DesencriptarXMLBlog.outputDocToFile(document, RutaArchivosBlog.RUTA_ARCHIVO_XML_DENCRYPTED);
    }
    private static Document loadEncryptionDocument() throws Exception {
        String fileName = RutaArchivosBlog.RUTA_ARCHIVO_XML_ENCRYPTED;
        File encryptionFile = new File(fileName);
        javax.xml.parsers.DocumentBuilderFactory dbf = javax.xml.parsers.DocumentBuilderFactory.newInstance();
        dbf.setNamespaceAware(true);
        javax.xml.parsers.DocumentBuilder db = dbf.newDocumentBuilder();
        Document document = db.parse(encryptionFile);
        System.out.println("Encryption document loaded from " + encryptionFile.toURI().toURL().toString());
        return document;
    }
    private static void outputDocToFile(Document doc, String fileName) throws Exception {
        File encryptionFile = new File(fileName);
        FileOutputStream f = new FileOutputStream(encryptionFile);
        TransformerFactory factory = TransformerFactory.newInstance();
        Transformer transformer = factory.newTransformer();
        transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
        DOMSource source = new DOMSource(doc);
        StreamResult result = new StreamResult(f);
        transformer.transform(source, result);
        f.close();
        System.out.println("Wrote document containing encrypted data to " + encryptionFile.toURI().toURL().toString());
    }
    public static SecretKey loadKeyEncryptionKey() throws Exception {
        String fileName = RutaArchivosBlog.RUTA_ARCHIVO_KEK;
        String jceAlgorithmName = "DESede";
        File kekFile = new File(fileName);
        DESedeKeySpec keySpec = new DESedeKeySpec(JavaUtils.getBytesFromFile(fileName));
        SecretKeyFactory skf = SecretKeyFactory.getInstance(jceAlgorithmName);
        SecretKey key = skf.generateSecret(keySpec);
        System.out.println("Key encryption key loaded from " + kekFile.toURI().toURL().toString());
        return key;
    }
}

8. Salida de los archivos al ejecutar cada una de las clases:

salida-archivos-cifrar9. Contenido del archivo cifradomensaje-cifrado

10. Contenido del archivo descifrado. mensaje-descifrado

 

Espero que la anterior implementación pueda servirle de ayuda. Cualquier duda con gusto pueden enviar un correo.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *