Aunque Mirth Connect es una herramienta muy versátil por la cantidad de formatos y protocolos que maneja, es muy frecuente que nos encontremos una situación en la que necesitamos incluir componentes externos. Para ello veremos cómo utilizar una librería externa en Mirth Connect.
Como ejemplo de por qué podemos necesitar incluir componentes externos en Mirth puedo citar una experiencia profesional, desarrollando una integración para un Servicio de Salud. En aquella ocasión, se necesitaba encriptar las comunicaciones, y en lugar de definir un algoritmo, simplemente nos proporcionaron un fichero .jar con las clases necesarias. Caja negra.
Por tanto, añadí el jar en nuestro Mirth Connect. Posteriormente utilicé las funciones que incluía para encriptar las comunicaciones y generar los tokens en los mensajes.
Mirth Connect está desarrollado en Java, lo que proporciona bastante simplicidad para incluir librerías externas .jar. Siguiendo unos sencillos pasos veremos cómo usarla en nuestros canales con programa.
Caso práctico: Encriptar campos con información sensible
Siempre he considerado que es mas fácil ver las cosas siguiendo un ejemplo paso a paso, y eso es lo que vamos a hacer.
Suponemos un escenario hipotético en el que, en una integración de pacientes con un sistema, nos han pedido que encriptemos algunos campos con información sensible.
En el Hospital X se está instalando un nuevo analizador semántico para la codificación automática en CIE-10. El sistema recibirá los informes de alta de los pacientes, narrativa sin codificar, y tras analizarlos generará una codificación automática. Para ello se decide enviar estos informes como mensajes HL7 v2.5 de tipo MDM, donde el informe irá codificado en Base64 y encriptado en un segmento OBX.
En el segmento PID irán los datos del paciente.
El sistema analizador semántico está en una red externa del Hospital. Por cumplir un mínimo de seguridad se requiere que los datos del paciente sensibles a la LOPD estén encriptados.

Para ello, se utilizará el algoritmo AES con 128 bits para cada cadena, con una clave compartida y conocida, que permita desencriptar en el destino.
1. Crear nuestro jar externo
Vamos a empezar creándonos nuestro jar, con una clase Crypt que permita a través de dos métodos encriptar y desencriptar una cadena de texto. Para los propósitos ilustrativos lo haremos de la forma mas sencilla y directa.
AES (Advanced Encryption Standard) es un algoritmo de cifrado por bloques, cifrado de clave simétrica que opera sobre bloques de bits de tamaño fijo, con una transformación invariante. No vamos a profundizar mas en este algoritmo, porque no es el objeto del artículo. Solo decir que, para que funcione necesitamos pasarle un vector de inicialización, y una semilla.

Para el desarrollo de esta clase Crypt necesitaremos descargarnos las librerías la librería Apache Commons Codec.
Utilizaremos la class Cipher para encriptar/desencriptar en Java, con el AES/CBC/PKCS5Padding.
Nuestra clase será muy simple, expondrá dos métodos que encapsulan el cifrado:
encrypt
Utilizaremos este método para encriptar un texto. Recibirá tres parámetros:
- String llave: La semilla o llave.
- String iv: El vector de inicialización.
- String texto: El texto que queremos encriptar.
Y devolverá un valor String con el texto encriptado. Este método puede devolver las siguientes excepciones: NoSuchAlgorithmException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, NoSuchPaddingException.
decrypt
Este otro método servirá para desencriptar un texto previamente encriptado con AES 128. Aunque en este ejemplo no lo vamos a usar, porque la integración será en un sentido, ya lo tenemos para posteriores usos. No cuesta nada.
Igualmente recibirá tres parámetros:
- String llave: La semilla o llave.
- String iv: El vector de inicialización.
- String encrypted: El texto que queremos desencriptar.
Y devolverá un valor String con el texto desencriptado. Este método también puede devolver las siguientes excepciones: NoSuchAlgorithmException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, NoSuchPaddingException.
Ya lo tenemos, y el código queda así de simple:
/** Clase de ejemplo ilustrativo para otros propósitos con: Función para encriptación de un String mediante algoritmo AES por bloques Autor: José Ramón Pascual **/ package crypt; import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import static org.apache.commons.codec.binary.Base64.decodeBase64; import static org.apache.commons.codec.binary.Base64.encodeBase64; public class Crypt { // Algoritmo (AES, DES, RSA) private final static String algoritmo = "AES"; // Tipo de cifrado, por bloques, padding etc. private final static String tipoCifrado = "AES/CBC/PKCS5Padding"; /** Función para encriptación de un String mediante algoritmo AES por bloques con los siguientes parámetros: @param llave tipo String a utilizar @param iv el vector de inicialización @param texto el texto a encriptar @return el texto cifrado en modo String codificado en base64 @throws Exception excepciones que puede devolver: NoSuchAlgorithmException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, NoSuchPaddingException */ public static String encrypt(String llave, String iv, String texto) throws Exception { Cipher cipher = Cipher.getInstance(tipoCifrado); SecretKeySpec secretKeySpec = new SecretKeySpec(llave.getBytes(), algoritmo); IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes()); cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec); byte[] encrypted = cipher.doFinal(texto.getBytes()); return new String(encodeBase64(encrypted)); } /** Función para desencriptar un String mediante algoritmo AES por bloques con los siguientes parámetros: @param llave tipo String a utilizar @param iv el vector de inicialización @param encrypted el texto a desencriptar previamente encriptado con la misma llave y codificado en base64 @return el texto descrifrado en modo String codificado en base64 @throws Exception excepciones que puede devolver: NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException */ public static String decrypt(String llave, String iv, String encrypted) throws Exception { Cipher cipher = Cipher.getInstance(tipoCifrado); SecretKeySpec secretKeySpec = new SecretKeySpec(llave.getBytes(), algoritmo); IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes()); byte[] enc = decodeBase64(encrypted); cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec); byte[] decrypted = cipher.doFinal(enc); return new String(decrypted); } }
Para mas información, consultar la documentación de javax.cryptor.Cipher
Empaquetamos la clase en el paquete crypt y exportamos a un jar que podamos utilizar en Mirth Connect.
2. Cargar el recurso externo
Una vez tenemos nuestro jar empaquetado, únicamente necesitamos cargar el nuevo recurso externo en Mirth. Para ello, copiamos el jar en la ruta custom-lib de donde hayamos desplegado Mirth Connect, por ejemplo:
C:\Program Files\Mirth Connect\custom-lib

También tenemos la opción de crear nuevas subcarpetas en dicha ruta para organizar nuestros recursos externos, o especificar otra, pero por simplicidad suelo utilizar la misma.
Nos vamos al menú Settings, y a la pestaña Resources. Aquí veremos los recursos externos cargados en Mirth Connect. Pulsaremos el botón Reload Resource en el submenú Resources Tasks de la izquierda. Esto volverá a cargar los recursos externos que se encuentren en las rutas especificadas, y aparecerá nuestra librería crypt.

3. Utilizar la librería externa en Mirth Connect
Para comenzar a utilizar la librería externa en Mirth Connect hay que saber que podemos hacer referencia a ella en cualquier Transformer.
Mediante un paso de un Transformer con Javascript, por ejemplo, podremos instanciar la clase Crypt y utilizar los métodos para encriptar/desencriptar.
En este caso, en el Source haremos una lectura programada sobre la base de datos del HIS. En esta lectura obtendremos tanto el reporte como los datos del paciente que luego utilizaremos para mapear en el Transformer.

En el Source Transformer de este canal, realizaremos un mapeo de todos los datos obtenidos al mensaje destino HL7 MDM, campo por campo.
En el último paso creado, de tipo Javascript, es donde voy a colocar el código que me permita instanciar mi clase Crypt y acceder a los métodos para encriptar.

Marco en amarillo donde usamos la clase Crypt para encriptar.
He aprovechado código que utilicé para mi Trabajo de Fin de Grado, donde se encriptaban las comunicaciones con un sistema de tickets y claves compartidas dinámicas. La llave se calculaba en función de la fecha y otros datos compartidos,. El ticket tenía un tiempo de vida de 60 segundos desde su creación, posterior a ese tiempo se descartaba el mensaje.
Aquí dejo el código de este paso del transformer:
var version = globalMap.get('version'); var instalacion = globalMap.get('instalacion'); var did = globalMap.get('did'); // Calculamos la llave (Aqui algoritmo simple de llave dinamica conocido por ambas partes): // concatenar fecha con version e instalacion // -> Un mensaje/ticket/cadena de ayer no esta autorizada para hoy var llave = DateUtil.getCurrentDate("yyyyMMdd") + version + instalacion + did; // Vector de inicializacion constante y conocido por ambas partes var iv = globalMap.get('iv'); try{ // Cifrar campos sensibles // A modo ilustrativo solo consideraremos nombres y apellidos tmp['PID']['PID.5']['PID.5.2'] = new Packages.crypt.Crypt.encrypt(llave,iv,msg['PacNombre'].toString()); tmp['PID']['PID.5']['PID.5.1'] = new Packages.crypt.Crypt.encrypt(llave,iv,msg['PacApell1'].toString()); tmp['PID']['PID.6']['PID.6.1'] = new Packages.crypt.Crypt.encrypt(llave,iv,msg['PacApell2'].toString()); }catch(e){ //Aqui haremos algo con la excepcion que ocurra logger.error("Error descifrando ticket: " + e); channelMap.put('responseStatusCode', '401'); return -1; }
Mensajes generados
A modo de prueba, si generamos dos mensajes, uno sin encriptación, y otro con encriptación, estos serán los resultados.
Nota: Prestar atención a los componentes del campo PID-5, donde se incluyen nombre y apellido, y PID-6, donde se incluye el apellido2.
Mensaje sin encriptación
MSH|^~\&|HIS|HOSPITAL|ANALIZADOR|SEMANTICO|20190820183002||MDM^T02^MDM_T02|E59DD457-874F-4044-8239-86AB68B3BB58|P|2.5 EVN|T10|20190820183002 PID|1||20237313||APE1INVENTADO^PEDRO|APE2NINGUNO|20150605|M||||||||||| PV1|1|E|^^|||^^||||HOS|||||||||11112545|||||||||||||||||0 ||||||||20170614220819|20170615000100||||||| TXA|1|Informe de Alta|TX|||20170614235600||||||GUID12398755a5a555a51|||||AU||||| OBX|1|ED|INF_HOL^GUID12398755a5a555a51.pdf^INTR^^|1|^^TX^Base64^e1xydGYxXGFuc2lcYW5zaWNwZzEyNTJcZGVmZjBcZGVmbGFuZzMwODJ7XG...|^^^^|||||U||||^^^^|^^^|^^^^|||
Mensaje con encriptación de los datos sensibles
MSH|^~\&|HIS|HOSPITAL|ANALIZADOR|SEMANTICO|20190820190331||MDM^T02^MDM_T02|7394D297-E186-476A-B811-85822C3894F2|P|2.5 EVN|T10|20190820190331 PID|1||20237313||zDHVlGwlajTWVIXkeEuMcg==^zDHVlGwlajTWVIXkeEuMcg==|zDHVlGwlajTWVIXkeEuMcg==|20150605|M||||||||||| PV1|1|E|^^|||^^||||HOS|||||||||11112545|||||||||||||||||0 ||||||||20170614220819|20170615000100||||||| TXA|1|Informe de Alta|TX|||20170614235600||||||GUID12398755a5a555a51|||||AU||||| OBX|1|ED|INF_HOL^GUID12398755a5a555a51.pdf^INTR^^|1|^^TX^Base64^e1xydGYxXGFuc2lcYW5zaWNwZzEyNTJcZGVmZjBcZGVmbGFuZzMwODJ7XG...|^^^^|||||U||||^^^^|^^^|^^^^|||
3 ideas sobre “Cómo utilizar una librería externa en Mirth Connect”
Muy interesante, muchas gracias por compartí este conocimiento tan util, poder incluir clases java externas da mucha potencia a Mirth Connect. Estupendo.
Interesante articulo, ejemplo muy ilustrativo y útil.
¿Es posible utilizar librerias externas que no sean Java en Mirth Connect?
Creo que no es posible, parece que como Mirth Connect está hecho en Java prermite esas jar.
Muy interesante blog, me ha sido útil, estoy aprendiendo Mirth y este articulo me ha ayudado bastante.
Gracias!