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.