Práctica 2007-2008 La práctica a realizar consiste en implementar un servicio Web simple que permita realizar operaciones de encriptación/desencriptación/resumen sobre ficheros locales. Para ello se propone un modelo de desarrollo desacoplado en tres capas, tal y como se muestra en la Figura 1.
Cliente Servicio Web
SERVICIO WEB Encapsula Encapsula las l as operaciones
SERVIDOR RMI OPERACIONES CRIPTOGRÁFICAS Figura 1. Modelo de componentes desacoplado en tres capas.
Se puede apreciar en la Figura 1 que se emplean tres tecnologías diferentes combinadas que forman un sistema distribuido completo. Con este modelo es posible independizar el servicio de la implementación puesto que el empleo de servicios web pone a disposición de cualquier cliente (por ejemplo una interfaz web AJAX o un cliente Java puro) las funciones exportadas en formato XML y disponible en el directorio de servicios (UDDI). Por lo tanto, la práctica se puede dividir en tres partes completamente diferentes: 1) Implementación de un servicio RMI de proveedor de funciones criptográfico genérico 2) Desarrollo de un servicio Web que encripte/desencripte/resuma ficheros representados como datos binarios. 3) Implementación de un cliente simple que use el servicio Web anterior. Para cada parte se proporciona una especificación completa del componente, así como los entregables y documentación a aportar.
PARTE 1: IMPLEMENTACIÓN DEL SERVIDOR CRIPTOGRÁFICO La primera parte consiste en realizar un sistema distribuido capaz de realizar operaciones criptográficas usando la tecnología RMI. La interfaz remota del servidor RMI definirá las siguientes operaciones: RMICryptographicServiceProvider extends Remote { public interface RMICryptographicServiceProvider Information doOperation(Information inf) throws RemoteException; String[] algsAvailable( algsAvailable(boolean Cipher_or_Digest) throws RemoteException; } de tal manera que se podrá realizar las operaciones de cifrado/resumen usando un objeto de tipo Information y se devolverá un objeto genérico de tipo Object (recuerde el modelo de herencia de Java) con el resultado de la operación que se desea. Además cualquier cliente Java RMI debe
ser capaz de obtener los algoritmos soportados por el servidor criptográfico para cada una de las operaciones soportadas (Véase el apartado de Introducción a la criptografía en Java ). Según se observa en la definición de la interfaz, se devolverán los algoritmos soportados para cifrado cuando el parámetro Cipher_or_Digest tenga el valor true y los de resumen cuando se use el valor false. El nombre de la clase que define la interfaz remota debe ser RMICryptographicServiceProvider . La clase Information, que se deberá usar, debe almacenar las siguientes propiedades: int cryptographic_mode; // Modo criptográfico String algorithm; // Algoritmo seleccionado dentro de los disponibles en el modo String mode; // Modo asociado al algoritmo, siempre se empleará “ECB” String padding; // Relleno, siempre se empleará “WithCTS” keySize; // Tamaño de la clave, siempre se usará 128 byte[] data; // Datos: Puede ser la información de entrada para la operación seleccionada y la información resultante (por ejemplo, cifrada) de la operación. boolean ok = false; // Resultado de la operación String pass = null; // Contraseña para la operación, también llamada key String msg = null; // Mensaje significativo resultado de la operación, por ejemplo Todo ha ido bien boolean encrypt = true; //Define si es una operación de encriptación o desencriptación long operationTime = 0; // Se usa para almacenar el número de milisegundos necesarios para realizar la operación criptográfica en el servidor. Por lo tanto, para realizar una operación criptográfica hay que crear un objeto de tipo Information y modificar sus atributos convenientemente (operación, algoritmo, clave y datos fuente de la operación) y realizar la llamada a la interface remota con este objeto. La llamada producirá un nuevo objeto de tipo Information que almacenará el resultado de la operación (datos resultantes, el valor ok y el mensaje indicando si todo ha ido bien o ha habido un error). Las dos clases (RMICryptographicServiceProvider.java e Information.java) se pueden descargar del área de documentos de la plataforma aLF. Se deben usar estas dos clases, y no se admitirá ninguna otra desarrollada por el alumno (salvo las que se deseen usar de prueba). Como se ha dicho antes el servidor debe proporcionar servicios de cifrado/descifrado simétrico (por bloques) y resúmenes (Digest) para las siguientes opciones: Algoritmos de Cifrado/Descifrado Simétrico por Bloques: AES, Blowfish , DESede, IDEA y Rijndael . Se debe tener en cuenta que hay distintos modos que se pueden usar para cada algoritmo de cifrado (cifrado por bloques), distintos tamaños de las claves para cada algoritmo y el tamaño de bloque (sobre todo con algoritmos donde no se defina la especificación de relleno). Los modos soportados por el JCE (véase la sección sobre criptografía) para los algoritmos son ECB, CBC , OFB8 y CFB8 y los esquemas de relleno: No padding (Sin relleno), PKCS5/7, ISO10126/ISO10126-2, X9.23/X923, CTS. Para evitar complejidades sobre las distintas combinaciones, todos los algoritmos usan ECB en el modo, con claves de 128 bits y padding CTS. Resumen (Digest): MD2, MD4, MD5, RipeMD128, RipeMD160, SHA1, SHA-256, SHA-384, Tiger
Instrucciones sobre el código Las clases desarrolladas deben estar TODAS en el paquete es.uned.dia.sd.practica.rmi , y el nombre de las clases que ejecuta el proceso servidor debe llamarse ServidorRMI. El nombre del servicio RMI (el nombre usado para buscar la ubicación del objeto remoto) debe ser ServicioCriptografia. Si se sigue estas definiciones la fase de prueba de las aplicaciones se simplifica.
NO SE CORREGIRÁ NINGUNA PRÁCTICA QUE NO SIGA ESTAS DIRECTRICES. En el área de documentos de la plataforma aLF se dispondrá un fichero RMICrypt.jar con el servidor RMI desarrollado que muestra el funcionamiento esperada de la misma: Se puede usar como ejemplo para ver que se pide y para probar el funcionamiento de la aplicación RMI que se desarrolle. En esa misma dirección se han puesto dos scripts para ejecutar una aplicación cliente de prueba (que no hay que desarrollar) y el servidor RMI. A continuación se hace una introducción a las dos tecnologías Java que se deben usar en la práctica: RMI y soporte criptográfico de Java.
Introducción a RMI RMI se estudia con detalle en el apartado 5.5 del libro recomendado (Colouris), por lo que no se va a comentar más. Para más información se puede acudir a las direcciones: http://www.programacion.com/java/tutorial/rmi/, que contiene un ejemplo muy completo paso a paso del desarrollo de una aplicación RMI (Motor de tareas de computación). Es muy recomendable su lectura. http://java.sun.com/products/jdk/rmi/index.html, página web oficial de RMI, proporciona una documentación muy amplia (eso sí, en inglés) sobre la utilización de RMI. Es interesente ejecutar y comprender el ejemplo Hola Mundo distribuido con RMI, que se puede obtener de http://java.sun.com/j2se/1.4.2/docs/guide/rmi/archives/getStart.zip. De esta manera, se obtienen los conocimientos mínimos necesarios para ejecutar una aplicación distribuida RMI. A continuación se hace una breve introducción a la seguridad en Java, en concreto, a las técnicas criptográficas para que sean usadas en esta parte de la práctica.
Introducción a la criptografía en JAVA Antes de profundizar en el modelo de seguridad y de criptografía de java, es altamente recomendable leerse el capítulo 7.2 (VISIÓN GENERAL DE LAS TÉCNICAS DE SEGURIDAD) del libro recomendado de la asignatura (Colouris). El concepto de criptografía en JAVA viene ligado al modelo de seguridad del JDK 1.2 (mostrado en la siguiente figura).
La primera versión del API de seguridad del JDK en JDK 1.1 presento la Java Cryptography Architecture (JCA), refiriéndose al marco de trabajo para acceder y desarrollar funcionalidades de criptografía para la plataforma Java. El JCA incluye un proveedor de arquitectura que permite múltiples implementaciones criptográficas. El término Cryptographic Service Provider (CSP) , o simplemente proveedor, se refiere a un paquete (o conjunto de paquetes) que suministran una implementación concreta de un subconjunto de aspectos de criptografía del API de Seguridad del JDK. Por ejemplo, un proveedor podría contener una implementación de uno o más algoritmos de firmas digitales , o de message digest , y algoritmos de generación de claves El API denominado Java Cryptography Extension (JCE) amplía el JDK para que se incluya en el API encriptación , intercambio de claves, y código de autentificación de mensajes (MAC). Junto con el JCE y los aspectos de criptografía del JDK mencionados antes, se dispone de un completo API de criptografía independiente de la plataforma. El JCE es una extensión separada del JDK, en concordancia con las regulaciones de control de la exportación del gobierno de los U.S. respecto a los algoritmos criptográficos. La siguiente figura ilustra varios módulos del JCA. La capa SPI (Service Provider Interface), está representada por los métodos que deben ser implementados para proveedores de servicios de criptografía.
Los interfaces de aplicación suministrados por una clase motor base son implementados en términos de una interfaz para el proveedor de servicios (en inglés, Service Provider Interface). Es decir, cada clase motor tiene una correspondiente clase abstracta SPI que define los métodos de la interface del proveedor del servicio, que el proveedor del servicio criptográfico debe implementar. De esta manera para usar un SPI cada objeto de una clase motor encapsula un ejemplar de su correspondiente clase SPI implementada por un proveedor de servicio criptográfico. Cada método API de una clase motor invoca al correspondiente método SPI del objeto SPI encapsulado. Queda, por tanto, decidir que proveedor de servicios criptográficos usaremos para nuestro servidor RMI. En la dirección: http://www.rediris.es/pki/iris-pca/gti-pca/tras-JT01/Librerias_Criptografica.ppt se hace un resumen y revisión de la disponibilidad de ciertas suites criptográficas, tanto de libre uso como de pago. En este caso, para la práctica usaremos el proveedor de servicios Bouncy Castle, que es una asociación dedicada a la implementación de servicios criptográficos de libre distribución en JAVA.
¿Cómo usar el proveedor criptográfico? Es necesario descargarse de la página Web http://www.bouncycastle.org/ la librería (en formato jar) que nos permite usar la JCE (Java Cryptography Extension) para ofrecer servicios de criptografía a las aplicaciones java. Puesto que la práctica debe ser usada usando la versión del JDK 1.5 se debe seleccionar el f ichero jar adecuado en la dirección http://www.bouncycastle.org/latest_releases.html (http://www.bouncycastle.org/download/bcprov jdk16-137.jar ) Es importante, revisar la documentación de la suite para ver que opciones y especificaciones ofrece, así como los ejemplos que vienen con la distribución (http://www.bouncycastle.org/specifications.html ). Una vez que hemos descargado la librería debemos probar el funcionamiento de la misma. Para ello se puede usar el siguiente código. package
es. uned. di a. sd. pr acti ca. r mi . bouncycast l e;
import j import j import j
ava. i o. * ; ava. s ecur i t y. * ; avax. c r ypt o. * ;
import
or g. bouncycast l e. j ce. pr ovi der . *;
public class Test Pr ovi der public Test Pr ovi der ( ) {
{
} public static void
mai n( St r i ng ar gs[ ] ) {
/* * Est a demost r aci ón gener a una cl ave al eat or i a, y encr i pt a con DES * un t ext o */ Key key = null;
KeyGener at or keyGen = null; Ci pher encr ypt = null; / / Lo / / cri / / obj Secur i
pr i mer o es i ndi car l e a l a J VM que el pr oveedor de ser vi ci os pt ogr áf i cos es l a l i br er í a BouncyCast l e, r egi st r ando un et o de t i po BouncyCast l ePr ovi der . t y. addPr ovi der ( new BouncyCast l ePr ovi der ( ) ) ;
try
{ / / Necesi t amos usar un gener ador de cl aves par a el t i po de / / al gor i t mo sel ecci onado DES- BC e i ni ci al i zar l o con una semi l l a / / al eat or i a keyGen = KeyGener at or . get I nst ance( " DES" , " BC" ) ; keyGen. i ni t ( new Secur eRandom( ) ) ; / / Gener amos l a cl ave que usar emos en el ci f r ado key = keyGen. gener at eKey( ) ; / / y obt enemos el al gor i t mmo de ci f r ado a t r avés de un obj et o de / / t i po Ci pher que usar emos despúes encr ypt = Ci pher. get I nst ance( " DES/ CBC/ PKCS5Paddi ng", " BC" ) ; encr ypt . i ni t ( Ci pher . ENCRYPT_MODE, key) ; / / Sol o queda def i ni r el dest i no de l a oper aci ón de ci f r ado / / que en est e caso se har á sobr e un obj et o de t i po / / Byt eAr r ayOut put St r eam usando de f or ma i nt ermedi a el st r eam de / / ci f r ado cOut Byt eAr r ayOut put St r eam bOut = new Byt eAr r ayOut put St r eam( ) ; Ci pher Out put St r eam cOut = new Ci pher Out put St r eam( bOut , encr ypt ) ; / / Ci f r amos el t ext o sobr e bOut escr i bi endo sobr e el / / s t r eam de ci f r ado cOut . wr i t e( " Est o es un t ext o de pr ueba DES" . get Byt es ( ) ) ; c Out . c l os e( ) ; / / EN bOut t enemos ahora el t ext o ci f r ado Sys t e m. out . pr i nt l n( bOut . t oSt r i ng( ) ) ; } catch
( Except i on e)
{ Sys t e m. er r . pr i nt l n( e) ; Syst em. exi t ( 1) ; } } }
Si no se obtiene ningún tipo de excepción, todo indicará que el servidor de servicios criptográficos funciona bien.
Software Necesario Es necesario usar el JDK 1.6 de Sun Microsystems, podéis descargarlo de http://java.com/es/download/index.jsp y las librerías java de criptografía descritas en el apartado de Intr oducción a la criptografía en Java: http://www.bouncycastle.org/download/bcprov-jdk16137.jar
Pruebas Una vez que se ha desarrollado el servidor RMI es posible comprobar la validez del funcionamiento usando una aplicación cliente que realice llamadas remotas con la información necesaria. Por ejemplo, usando como texto “Hola mundo soy un texto plano” se deberían obtener los siguientes resultados (en codificación BASE 64) para la prueba de los algoritmos de resumen (DIGEST): Algoritmo de resumen
MD2 MD4 MD5 RIPEMD128 RIPEMD160 SHA SHA-256 SHA-384 TIGER
Resultado
R7dDGfTLD5z25F/HUELjdQ== YDCsnJ+CHgbBeKF0hoeFnQ== llr5wLVo/W6PbSorRWhf9Q== G7SGpHlFy6DTA3zM1AyVuw== ToxfXVNCbLAPVQvWCsofGO4AjzY= zdrBLDTU2h2Ad8xhSyQ3+Mx0YoU= iqN43hjGP/DmqKpzeXSQpkha6y/i80IVEzO/9fsxvGg= 6xD8rSnAQMjrxIZI4qFTiAS5NMI2OSXFZn0v5RVw2e/DGGSs AR4cGIkGdSflOY9e hEODf3iWvwgcZkYQ2u+LFIlNYQrRsVc/
Y así realizar una tabla con todos los algoritmos correspondientes a los algoritmos simétricos por bloques. Analizando la forma de realizar estas pruebas, se puede observar que son bastante laboriosas, por lo que se debería usar algún método automático. Existe un framework (entorno de trabajo) para Java que permite realizar pruebas unitarias sobre clases Java. Este framework se denomina JUnit (http://www.junit.org/index.htm) y consta de una serie de clases que permite la ejecución de casos de prueba y presentación de resultados en formato texto y gráfico. En la dirección anterior está toda la documentación necesaria (eso sí, en Inglés) para definir casos de prueba para testear vuestras clases. En las direcciones: http://www.dc.fi.udc.es/ai/tp/practica/junit/ppasos.html http://adictosaltrabajo.com/tutoriales/tutoriales.php?pagina=junit están disponibles dos tutoriales en español presentando el framework y dando ejemplos de su uso. En este caso, las pruebas se realizarán usando JUnit, en concreto usando un clase denominada TestResults , que se apoya en dos casos de prueba para cada una de las operaciones criptográficas: ClientTestDigestCase y ClientTestBLOCKCase. Estas clases (empaquetadas en un fichero llamado TestRMI.jar ) se pueden descargar del área de documentos de aLF y se pueden usar para probar la aplicación desarrollada (para la corrección se usarán estas clases). Estas clases utilizan un conjunto de ficheros originales (en formato texto) que producen unos resultados y que se utilizan para compararlos con los resultados generados por la aplicación que se ha sido desarrollada por el equipo docente y que se almacenan en un directorio de objetivos (targets). Los ficheros fuentes y objetivos se pueden también del área de almacenamiento de aLF.
Al ejecutar la clase es.uned.dia.sd.practica.rmi.test.TestResults pedirá información sobre la práctica a probar mostrando una pantalla que pregunta si se desea generar y analizar el conjunto de ficheros resultados o sólo generar:
Se debe seleccionar GENERAR Y VERIFICAR RESULTADOS. Una vez hecho esto, se realizaran los test de TODOS los algoritmos presentándose una barra de progreso en verde una vez que haya terminado. Si la barra es roja, la práctica no ha pasado la prueba.
Informe Cómo informe de la primera parte de la práctica se debe entregar un fichero zip en la pestaña de Evaluación del curso virtual en aLF. En este fichero deben aparecer los siguientes ficheros: -
Las clases compiladas y empaquetadas en un fichero jar llamado RmiCrypt.jar . Debe estar en el directorio lib del fichero zip. Los ficheros fuentes de las clases generadas situados en el directorio sources . Documento en formato texto (puede ser word, txt o pdf) con la arquitectura del sistema y comentarios sobre los problemas encontrados durante el desarrollo y prueba de la aplicación RMI. Este documento debe estar situado en el directorio doc del fichero zip. Guiones de trabajo (scripts) para poder ejecutar las aplicaciones cliente y servidor (usando el fichero RmiCrypt.jar del directorio lib ), así como un script que construya el fichero RmiCrypt.jar a partir de los ficheros fuentes situados en el directorio sources . Estos scripts deben estar situados en el directorio raíz del fichero zip.
PARTE 2: DESARROLLO DEL SERVICIO WEB Disponible próximamente