
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:
2. 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:
9. Contenido del archivo cifrado
10. Contenido del archivo descifrado.
Espero que la anterior implementación pueda servirle de ayuda. Cualquier duda con gusto pueden enviar un correo.