Aplicaciones Criptográficas Java http://jcef.sourceforge.net Proyecto Fin de Carrera Facultad de Informática Universidad de Las Palmas de Gran Canaria Bienvenidos a la presentación del proyecto fin de carrera titulado “Aplicaciones Criptográficas Java”. Un proyecto realizado y presentado por Jesús María Ramos Saky (un servidor) y tutorizado por Miguel Ángel Pérez Aguiar aquí presente. Autor: Jesús María Ramos Saky Tutor: Miguel Ángel Pérez Aguiar 24/05/06
Breve descripción (1/4) A grandes rasgos, el uso de la criptografía ayuda a: · Evitar el uso fraudulento de sistemas. · Proteger información confidencial o importante. · Permitir comunicaciones seguras. · Posibilitar el comercio electrónico. Siendo más precisos y tal y como se puede ver en la imagen, la criptografía permite asegurar objetos convirtiéndolos en seguros y volver a recuperar los objetos asegurados a partir de sus versiones seguras.
Breve descripción (2/4) El objetivo es “Aprender a utilizar mecanismos criptográficos para asegurar objetos y volver a recuperarlos: Protección y Autentificación”. El resultado del proyecto: Conjunto librerías Java sobre algoritmos criptográficos. Destacando JCEF (Java Cryptographic Extension Framework). El objetivo primordial de este proyecto es aprender a utilizar los principales mecanismos criptográficos: la protección y autentificación. Estos mecanismos son los utilizados para asegurar objetos y volver a recuperar dichos objetos asegurados. El resultado del proyecto ha sido un conjunto de librerías Java sobre algoritmos criptográficos, destacando entre ellas JCEF (Java Cryptographic Extension Framework).
Breve descripción (3/4) JCEF (Java Cryptographic Extension Framework): Es útil y sobre todo de muy fácil uso. Ideal para usuarios inexpertos. Suplanta a las librerías criptográficas Java estándar llamadas JCA y JCE. Esta librería, JCEF, es útil y sobre todo de muy fácil uso, ideal para usuarios inexpertos y que suplanta a las librerías criptográficas Java ya existentes JCA y JCE proporcionadas por Sun Microsystems, las cuales son muy complicadas de utilizar. JCEF realiza un mayor nivel de sencillez que las librerías estándar.
Breve descripción (4/4) Como un EJEMPLO del valor añadido de este proyecto observen cómo se asegura un objeto y se vuelve a recuperar con suma facilidad: /* 1. */ Object object = new String(“my object”); /* 2. */ CryptoAlgorithm secureAlgorithm = new AES_BlockSymmetricProtectionRREXKY(); /* 3. */ SecureObject secureObject = new SecureObject(object, secureAlgorithm); /* 4. */ Object = (String)secureObject.getObject(secureAlgorithm); Como un EJEMPLO del valor añadido de este proyecto, observe el código que se muestra en pantalla. En él se muestra cómo se asegura un objeto e inmediatamente después se recupera el mismo; y todo ello de una forma super sencilla: Primero. Basta con definir el objeto que se desea asegurar. (Señalar al punto 1) Segundo. Seleccionar el algoritmo criptográfico de seguridad deseado e inicializarlo si fuera necesario. Tercero. Construir el objeto seguro. Cuarto. Volver a recuperar el objeto asegurado a partir de su versión segura a través del algoritmo correctamente inicializado.
Introducción a la seguridad Bien, comencemos por una breve introducción al tema de la seguridad.
Introducción a la seguridad (1/9) La seguridad es muy importante hoy día Hoy día, es necesario proporcionar sistemas seguros que eviten o prevengan ataques de diversa índole que pongan en peligro la seguridad de los sistemas
Introducción a la seguridad (2/9) Evitar que se obtengan documentos de forma ilegal. Un sistema debe proporcionar seguridad para por ejemplo: “Evitar que se obtengan documentos de forma ilegal”.
Introducción a la seguridad (3/9) Evitar que se obtenga información sobre los comunicantes. ... o “Evitar que se obtenga información importante sobre los comunicantes”
Introducción a la seguridad (4/9) Evitar que se pueda suplantar una identidad También se podría garantizar la identidad de sus usuarios, evitando que pudiera suplantarse tales identidades
Introducción a la seguridad (5/9) Evitar que se puedan repetir mensajes sin ser detectada tal repetición También podría: “Evitar que se puedan repetir mensajes sin ser detectado”. Para por ejemplo evitar cosas acciones tales como el ingreso de dinero en una cuenta de forma repetida.
Introducción a la seguridad (6/9) Evitar la modificación de mensajes antes de llegar a su destinatario Un sistema seguro también podría: “Evitar que se puedan modificar los mensajes antes de llegar a su destinatario”. Una posible consecuencia de estos ataques sería transformar un mensaje como “Ingresar un millón de euros en la cuenta A” por otro mensaje como “Ingresar un millón de euros en la cuenta B”.
Introducción a la seguridad (7/9) Evitar la interrupción de sus servicios Un sistema seguro también debe: “Evitar la interrupción de sus servicios”.
Introducción a la seguridad (8/9) Los servicios de seguridad solucionan o previenen los ataques Para prevenir o solucionar estos ataques, se utilizan servicios de seguridad. ENTRE OTROS, los más importantes son la autentificación, el control de acceso, la confidencialidad, la integridad, no repudio y la disponibilidad.
Introducción a la seguridad (9/9) Y para implementar estos servicios, se utiliza principalmente la Criptografía. Y para implementar estos servicios, se utiliza principalmente la Criptografía.
Criptografía Orientada a Objetos Introducción Criptografía Orientada a Objetos Continuando con la introducción, en esta sección se hará una breve descripción de la criptografía desde un enfoque sencillo y orientado a objetos.
Criptografía OO (1/8) La Criptografía es una herramienta que permite: Asegurar objetos. Y recuperar objetos asegurados. La Criptografía es una herramienta que permite tratar objetos que no son seguros por algún motivo o para alguna finalidad a través de dos operaciones: · Asegurar objetos construyendo objetos seguros. · Y recuperar objetos asegurados a partir de su versión segura. Un objeto puede ser cualquier cosa: información, recursos, datos, mensajes, ficheros, incluso un objeto seguro, etc...
Criptografía OO (2/8) La Criptografía gestiona objetos seguros: Protegidos y/o Autentificables La Criptografía gestiona objetos seguros. Un objeto seguro es aquel que está protegido y/o es autentificable. Si está protegido significa que sus propiedades son incomprensibles. Si es autentificable quiere decir que su origen y/o sus propiedades se pueden verificar para comprobar su autenticidad.
Criptografía OO (3/8) Para gestionar objetos seguros se utilizan algoritmos de seguridad u operaciones criptográficas. Para crear objetos protegidos se utiliza la protección. La desprotección se emplea para obtener el objeto asegurado a partir de un objeto protegido. Para construir objetos autentificables se utiliza la autentificación. Y para comprobar la autenticidad y/o integridad de estos objetos, se usa la verificación de autenticidad.
Criptografía OO (4/8) En la imagen se muestra el proceso de proteger un objeto mediante protección simétrica, la cual se caracteriza por usar las mismas claves y parámetros tanto en la protección como la desprotección.
Criptografía OO (5/8) En esta otra imagen, se muestra la protección y desprotección asimétrica. En ella se observa cómo se utilizan claves distintas para la protección y desprotección.
Criptografía OO (6/8) Es auténtico sólo si la huella de éste objeto es la misma que la adjunta La imagen de ahora muestra el proceso de generar un objeto autentificable mediante una huella digital. Para ello se emplean algoritmos de autentificación mediante huellas digitales. Aunque aquí no aparece, verificar si el objeto es auténtico y/o íntegro se reduce a comprobar si la huella digital adjunta es la que le corresponde al objeto.
Criptografía OO (7/8) De la misma manera, el proceso de generar un objeto autentificable mediante un sello digital es muy similar al anterior proceso, pero esta vez se utilizan claves, la misma tanto para la generación como la verificación del sello. A diferencia de la huella digital, los sellos digitales proporcionan un mayor nivel de seguridad al utilizar una clave simétrica tanto para la generación como para la verificación
Criptografía OO (8/8) Finalmente, se pueden firmar objetos. Se utilizan algoritmos de autentificación mediante firmas digitales que emplean claves asimétricas, una clave privada para firmar y otra pública para comprobar la autenticidad y/o integridad del objeto. Finalmente, las firmas digitales proporcionan el mayor nivel de seguridad de todos los tipos de autentificación al utilizar claves asimétricas, evitándose así distribuir la clave de firmado.
Introducción Análisis de JCA y JCE Tras una breve introducción a la seguridad y la criptografía en las secciones anteriores; en esta sección se mostrarán las deficiencias más importantes que mejora este proyecto.
Análisis de JCA y JCE (1/40) El uso más habitual de la criptografía: Crear objetos seguros Obtener objetos asegurados Con parámetros generados recientemente O reutilizando parámetros El uso más habitual de la criptografía es crear objetos seguros y obtener los objetos asegurados a partir de sus versiones seguras utilizando parámetros nuevos o reutilizando unos ya existentes generados con anteriodad.
Análisis de JCA y JCE (2/40) Asegurar un objeto con nuevos parámetros criptográficos Almacenar parámetros criptográficos para un uso posterior Obtener el objeto asegurado utilizando los nuevos parámetros criptográficos Asegurar otro objeto reutilizando parámetros criptográficos ya existentes Obtener el objeto asegurado reutilizando parámetros criptográficos ya existentes El proceso habitual de gestión de objetos seguros es el siguiente: 1. Asegurar un objeto con nuevos parámetros. 2. Almacenar parámetros criptográficos para un uso posterior. 3. Obtener el objeto asegurado utilizando los nuevos parámetros criptográficos. 4. Asegurar otro objeto reutilizando parámetros criptográficos ya existentes. 5. Obtener el objeto asegurado reutilizando parámetros criptográficos ya existentes. A continuación se mostrará cómo se realiza este proceso habitual con JCA y JCE pero sin entrar en detalles. Se realizará mostrando un ejemplo general pero INCOMPLETO ya que sólo funciona para un mismo tipo de algoritmo criptográfico concreto (los algoritmos de protección simétrica de bloques o de flujo). Además puede incluso que no sirva para algunos algoritmos concretos del tipo mencionado.
Análisis de JCA y JCE (3/40) 1. Asegurar un objeto con nuevos parámetros criptográficos 1.1. Definición del objeto a asegurar y carga del proveedor 1.2. Definición del generador de claves simétricas 1.3. Inicialización del generador de claves simétricas y generación de la clave 1.4. Definición del generador de parámetros 1.5. Inicialización del generador de parámetros 1.6. Generación del parámetro 1.7. Definición del algoritmo de seguridad 1.8. Inicialización del algoritmo de seguridad 1.9. Obtención del parámetro que se haya podido generar automáticamente 1.10. Creación del objeto seguro Aquí se muestra el primer paso del proceso habitual desglosado, en donde se observa que para asegurar un objeto es necesario realizar muchas tareas previas tales como: · La carga de un proveedor criptográfico. · Definición e inicialización de algoritmos de generación de claves. · Definición e inicialización de algoritmos de generación de parámetros. · Generación de la clave. · Generación del parámetro. · Definición e inicialización del algoritmo de seguridad.
Análisis de JCA y JCE (4/40) 2. Almacenar parámetros criptográficos para un uso posterior 2.1. Traducción de la clave 2.2. Traducción del parámetro 2.3. Otra traducción del parámetro 2.4. Almacenamiento de los parámetros Con el objetivo de reutilizar los parámetros y claves para un uso posterior, es necesario almacenarlos pero antes se necesita traducirlos desde su forma transparente y de funcionalidad a su forma persistente.
Análisis de JCA y JCE (5/40) 3. Obtener el objeto asegurado utilizando los nuevos parámetros criptográficos 3.1. Carga de los parámetros 3.2. Definición del algoritmo de seguridad 3.3. Traducción de los parámetros a la forma adecuada 3.4. Inicialización del algoritmo de seguridad para desprotección 3.5. Obtención del objeto asegurado Para obtener el objeto asegurado es necesario: · Cargar los parámetros. · Traducirlos desde su forma persistente a su forma adecuada (la transparente y de funcionalidad). Y para ello es necesario definir e inicializar dos algoritmos de traducción uno para la clave y otro para el parámetro. · Finalmente se define e inicializa el algoritmo de seguridad para poder obtener el objeto asegurado.
Análisis de JCA y JCE (6/40) 4. Asegurar otro objeto reutilizando parámetros criptográficos ya existentes 4.1. Definición del objeto y carga de los parámetros 4.2. Traducción de la clave a su forma adecuada 4.3. Traducción del parámetro a su forma adecuada 4.4. Definición del algoritmo de seguridad 4.5. Inicialización del algoritmo de seguridad para protección 4.6. Obtención del parámetro si fuera generado automáticamente 4.7. Creación del objeto seguro Para asegurar otro objeto con parámetros ya utilizados, es necesario cargarlos y traducirlos a su forma adecuada, definir e inicializar el algoritmo de seguridad con estos parámetros y finalmente crear el objeto seguro.
Análisis de JCA y JCE (7/40) 5. Obtener el objeto asegurado reutilizando parámetros criptográficos ya existentes 5.1. Carga de los parámetros 5.2. Definición del algoritmo de seguridad 5.3. Traducción de la clave a su forma adecuada 5.4. Traducción del parámetro a su forma adecuada 5.5. Inicialización del algoritmo de seguridad para desprotección 5.6. Obtención del objeto asegurado Y finalmente, para recuperar el objeto inicializado es necesario cargar y traducir los parámetros a su forma adecuada, definir e inicializar el algoritmo de seguridad con estos parámetros y emplear para recuperar el objeto asegurado.
Análisis de JCA y JCE (8/40) 1. Asegurar un objeto con nuevos parámetros criptográficos 1.1. Definición del objeto a asegurar y carga del proveedor String object = "my object"; Provider provider = new BouncyCastleProvider(); Security.addProvider(provider); String providerName = provider.getName(); A partir de aquí ya se muestran los subpasos junto con el código Java asociado. Un total de 32 subpasos. Demasiados para poder detenernos en cada uno de ellos. Antes de empezar hay que decir que este ejemplo no es más que un ejemplo particular con un tipo de algoritmo de seguridad concreto y puede volverse más complicado utilizando otros tipos de algoritmos de seguridad como firmas digitales, sellos digitales, protección asimétrica, etc... Incluso puede volverse más complicado entre algoritmos del mismo tipo. Todo esto y más ya está solucionado con este proyecto. Para asegurar un objeto, primero es necesario definirlo y posteriormente cargar el proveedor criptográfico.
Análisis de JCA y JCE (9/40) 1. Asegurar un objeto con nuevos parámetros criptográficos 1.2. Definición del generador de claves simétricas SecureRandom random = null; Key key = null; javax.crypto.KeyGenerator keyGenerator = null; try { keyGenerator = javax.crypto.KeyGenerator.getInstance("AES", providerName); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); return; } catch (NoSuchProviderException e) { e.printStackTrace(); return; } Se define el generador de claves simétricas que se encargará de generar la clave que se necesita para asegurar el objeto.
Análisis de JCA y JCE (10/40) 1. Asegurar un objeto con nuevos parámetros criptográficos 1.3. Inicialización del generador de claves simétricas y generación de la clave int keySize = 256; AlgorithmParameterSpec genParameter = null; if (genParameter != null && random == null) { try { keyGenerator.init(genParameter); } catch (InvalidAlgorithmParameterException e) { e.printStackTrace(); return; } } else if (genParameter != null && random != null) { try { keyGenerator.init(genParameter, random); } } else if (genParameter == null && keySize > 0 && random == null) { keyGenerator.init(keySize); } else if (genParameter == null && keySize > 0 && random != null) { keyGenerator.init(keySize, random); } else if (genParameter == null && keySize <= 0 && random != null) { keyGenerator.init(random); key = keyGenerator.generateKey(); Se inicializa este generador de claves para generar la clave que se utilizará para asegurar el objeto.
Análisis de JCA y JCE (11/40) 1. Asegurar un objeto con nuevos parámetros criptográficos 1.4. Definición del generador de parámetros AlgorithmParameterSpec parameter = null; Class parameterType = IvParameterSpec.class; AlgorithmParameterGenerator parameterGenerator = null; try { parameterGenerator = AlgorithmParameterGenerator.getInstance("AES", providerName); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); return; } catch (NoSuchProviderException e) { e.printStackTrace(); return; } También se necesita otro parámetro criptográfico para asegurar el objeto y por ello se define un generador de parámetros. Para ello es necesario conocer el nombre del algoritmo generador asociado al algoritmo de seguridad que se empleará.
Análisis de JCA y JCE (12/40) 1. Asegurar un objeto con nuevos parámetros criptográficos 1.5. Inicialización del generador de parámetros genParameter = null; int parameterSize = 16; if (genParameter != null && random == null) { try { parameterGenerator.init(genParameter); } catch (InvalidAlgorithmParameterException e) { e.printStackTrace(); return; } } else if (genParameter != null && random != null) { try { parameterGenerator.init(genParameter, random); } } else if (genParameter == null && random == null) { parameterGenerator.init(parameterSize); } else if (genParameter == null && random != null) { parameterGenerator.init(parameterSize, random); } Se inicializa este generador de parámetros y para ello hay que conocer los datos de inicialización.
Análisis de JCA y JCE (13/40) 1. Asegurar un objeto con nuevos parámetros criptográficos 1.6. Generación del parámetro AlgorithmParameters algorithmParameters = parameterGenerator.generateParameters(); try { parameter = algorithmParameters.getParameterSpec(parameterType); } catch (InvalidParameterSpecException e) { e.printStackTrace(); return; } Tras su definición e inicialización, ya se puede utilizar este generador para obtener un nuevo parámetro.
Análisis de JCA y JCE (14/40) 1. Asegurar un objeto con nuevos parámetros criptográficos 1.7. Definición del algoritmo de seguridad Cipher secureAlgorithm = null; try { secureAlgorithm = Cipher.getInstance("AES/CBC/PKCS7Padding", providerName); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); return; } catch (NoSuchProviderException e) { e.printStackTrace(); return; } catch (NoSuchPaddingException e) { e.printStackTrace(); return; } Se define el algoritmo de seguridad que se utilizará para asegurar el objeto.
Análisis de JCA y JCE (15/40) 1. Asegurar un objeto con nuevos parámetros criptográficos 1.8. Inicialización del algoritmo de seguridad int mode = Cipher.ENCRYPT_MODE; if (parameter != null && random == null) { try { secureAlgorithm.init(mode, key, parameter); } catch (InvalidKeyException e) { e.printStackTrace(); return; } catch (InvalidAlgorithmParameterException e) { e.printStackTrace(); return; } } else if (parameter != null && random != null) { try { secureAlgorithm.init(mode, key, parameter, random); } } else if (parameter == null && random == null) { try { secureAlgorithm.init(mode, key); } } else if (parameter == null && random != null) { try { secureAlgorithm.init(mode, key, random); } } Se requiere inicializar este algoritmo de seguridad
Análisis de JCA y JCE (16/40) 1. Asegurar un objeto con nuevos parámetros criptográficos 1.9. Obtención del parámetro que se haya podido generar automáticamente try { algorithmParameters = secureAlgorithm.getParameters(); } catch (Throwable throwable) {} if (parameter == null && algorithmParameters != null) { if (parameterType == null) { parameterType = AlgorithmParameterSpec.class; } try { parameter = algorithmParameters.getParameterSpec(parameterType); } catch (InvalidParameterSpecException e) { e.printStackTrace(); return; } En ocasiones es necesario obtener un parámetro si éste fuera generado automáticamente. Es más, independientemente del parámetro adicional indicado de forma manual, siempre hay que quedarse con el devuelto es este punto. Por lo general, serán el mismo pero no siempre es así; ya que por ejemplo, la implementación del algoritmo de seguridad puede utilizar un parámetro adicional por defecto y siempre utilizar éste aunque el usuario le indique otro bien distinto. Y es por ello la necesidad de este punto.
Análisis de JCA y JCE (17/40) 1. Asegurar un objeto con nuevos parámetros criptográficos 1.10. Creación del objeto seguro SealedObject secureObject = null; try { secureObject = new SealedObject(object, secureAlgorithm); } catch (IllegalBlockSizeException e) { e.printStackTrace(); return; } catch (IOException e) { e.printStackTrace(); return; } saveObject(secureObject); Finalmente se puede asegurar el objeto construyendo un objeto sellado.
Análisis de JCA y JCE (18/40) 2. Almacenar parámetros criptográficos para un uso posterior 2.1. Traducción de la clave encodedKey = key.getEncoded(); Traducir una clave a su forma persistente es sencillo
Análisis de JCA y JCE (19/40) 2. Almacenar parámetros criptográficos para un uso posterior 2.2. Traducción del parámetro if (parameter instanceof IvParameterSpec) { IvParameterSpec iv = (IvParameterSpec)parameter; encodedParameter = iv.getIV(); } y traducir un parámetro particular también lo es, pero ...
Análisis de JCA y JCE (20/40) 2. Almacenar parámetros criptográficos para un uso posterior 2.3. Otra traducción del parámetro AlgorithmParameters parameterTranslator = null; try { parameterTranslator = AlgorithmParameters.getInstance("RIJNDAEL", providerName); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); return; } catch (NoSuchProviderException e) { e.printStackTrace(); return; } try { parameterTranslator.init(parameter); } catch (InvalidParameterSpecException e) { e.printStackTrace(); return; } try { encodedParameter = parameterTranslator.getEncoded(); } catch (IOException e) { e.printStackTrace(); return; } ... traducir cualquier parámetro ya deja de ser tan sencillo.
Análisis de JCA y JCE (21/40) 2. Almacenar parámetros criptográficos para un uso posterior 2.4. Almacenamiento de los parámetros saveKey(encodedKey); saveParameter(encodedParameter); Una vez traducidos los parámetros a su forma persistente ya es posible almacenarlos.
Análisis de JCA y JCE (22/40) 3. Obtener el objeto asegurado utilizando los nuevos parámetros criptográficos 3.1. Carga de los parámetros encodedKey = loadKey(); encodedParameter = loadParameter(); Para recuperar el objeto asegurado, se puede empezar por cargar los parámetros que anteriormente se utilizaron para asegurar el objeto.
Análisis de JCA y JCE (23/40) 3. Obtener el objeto asegurado utilizando los nuevos parámetros criptográficos 3.2. Definición del algoritmo de seguridad try { secureAlgorithm = Cipher.getInstance("AES/CBC/PKCS7Padding", providerName); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); return; } catch (NoSuchProviderException e) { e.printStackTrace(); return; } catch (NoSuchPaddingException e) { e.printStackTrace(); return; } Se puede continuar por definir el algoritmo de seguridad que se empleará para recuperar el objeto asegurado.
Análisis de JCA y JCE (24/40) 3. Obtener el objeto asegurado utilizando los nuevos parámetros criptográficos 3.3. Traducción de los parámetros a la forma adecuada key = new SecretKeySpec(encodedKey, "AES"); parameterType = IvParameterSpec.class; parameterTranslator = null; try { parameterTranslator = AlgorithmParameters.getInstance("RIJNDAEL", providerName); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); return; } catch (NoSuchProviderException e) { e.printStackTrace(); return; } try { parameterTranslator.init(encodedParameter); } catch (IOException e) { e.printStackTrace(); return; } try { parameter = parameterTranslator.getParameterSpec(parameterType); } catch (InvalidParameterSpecException e) { e.printStackTrace(); return; } Continuando por la traducción de los parámetros, tanto de la clave como del parámetro adicional, a su forma transparente, no persistente pero útil para el algoritmo de seguridad.
Análisis de JCA y JCE (25/40) 3. Obtener el objeto asegurado utilizando los nuevos parámetros criptográficos 3.4. Inicialización del algoritmo de seguridad para desprotección mode = Cipher.DECRYPT_MODE; if (parameter != null && random == null) { try { secureAlgorithm.init(mode, key, parameter); } catch (InvalidKeyException e) { e.printStackTrace(); return; } catch (InvalidAlgorithmParameterException e) { e.printStackTrace(); return; } } else if (parameter != null && random != null) { try { secureAlgorithm.init(mode, key, parameter, random); } } else if (parameter == null && random == null) { try { secureAlgorithm.init(mode, key); } } else if (parameter == null && random != null) { try { secureAlgorithm.init(mode, key, random); } } Se inicializa el algoritmo de seguridad con los parámetros ya traducidos a su forma adecuada.
Análisis de JCA y JCE (26/40) 3. Obtener el objeto asegurado utilizando los nuevos parámetros criptográficos 3.5. Obtención del objeto asegurado try { secureObject = (SealedObject)loadObject(); object = (String)secureObject.getObject(secureAlgorithm); } catch (IllegalBlockSizeException e) { e.printStackTrace(); return; } catch (BadPaddingException e) { e.printStackTrace(); return; } catch (IOException e) { e.printStackTrace(); return; } catch (ClassNotFoundException e) { e.printStackTrace(); return; } Se obtiene finalmente el objeto asegurado a través del algoritmo de seguridad de seguridad definido e inicializado.
Análisis de JCA y JCE (27/40) 4. Asegurar otro objeto reutilizando parámetros criptográficos ya existentes 4.1. Definición del objeto y carga de los parámetros String otherObject = "other object"; encodedKey = loadKey(); encodedParameter = loadParameter(); Para asegurar otro objeto con parámetros ya generados, hay que definir el objeto y cargar dichos parámetros
Análisis de JCA y JCE (28/40) 4. Asegurar otro objeto reutilizando parámetros criptográficos ya existentes 4.2. Traducción de la clave a su forma adecuada key = new SecretKeySpec(encodedKey, "AES"); Traducir la clave a su forma adecuada
Análisis de JCA y JCE (29/40) 4. Asegurar otro objeto reutilizando parámetros criptográficos ya existentes 4.3. Traducción del parámetro a su forma adecuada parameterType = IvParameterSpec.class; parameterTranslator = null; try { parameterTranslator = AlgorithmParameters.getInstance("RIJNDAEL", providerName); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); return; } catch (NoSuchProviderException e) { e.printStackTrace(); return; } try { parameterTranslator.init(encodedParameter); } catch (IOException e) { e.printStackTrace(); return; } try { parameter = parameterTranslator.getParameterSpec(parameterType); } catch (InvalidParameterSpecException e) { e.printStackTrace(); return; } Y también traducir el parámetro adicional a su forma adecuada.
Análisis de JCA y JCE (30/40) 4. Asegurar otro objeto reutilizando parámetros criptográficos ya existentes 4.4. Definición del algoritmo de seguridad secureAlgorithm = null; try { secureAlgorithm = Cipher.getInstance("AES/CBC/PKCS7Padding", providerName); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); return; } catch (NoSuchProviderException e) { e.printStackTrace(); return; } catch (NoSuchPaddingException e) { e.printStackTrace(); return; } Definir el algoritmo de seguridad
Análisis de JCA y JCE (31/40) 4. Asegurar otro objeto reutilizando parámetros criptográficos ya existentes 4.5. Inicialización del algoritmo de seguridad para protección mode = Cipher.ENCRYPT_MODE; if (parameter != null && random == null) { try { secureAlgorithm.init(mode, key, parameter); } catch (InvalidKeyException e) { e.printStackTrace(); return; } catch (InvalidAlgorithmParameterException e) { e.printStackTrace(); return; } } else if (parameter != null && random != null) { try { secureAlgorithm.init(mode, key, parameter, random); } } else if (parameter == null && random == null) { try { secureAlgorithm.init(mode, key); } } else if (parameter == null && random != null) { try { secureAlgorithm.init(mode, key, random); } } Inicializarlo
Análisis de JCA y JCE (32/40) 4. Asegurar otro objeto reutilizando parámetros criptográficos ya existentes 4.6. Obtención del parámetro si fuera generado automáticamente try { algorithmParameters = secureAlgorithm.getParameters(); } catch (Throwable throwable) {} if (parameter == null && algorithmParameters != null) { if (parameterType == null) { parameterType = AlgorithmParameterSpec.class; } try { parameter = algorithmParameters.getParameterSpec(parameterType); } catch (InvalidParameterSpecException e) { e.printStackTrace(); return; } } Obtener el parámetro adicional si ha sido generado automáticamente
Análisis de JCA y JCE (33/40) 4. Asegurar otro objeto reutilizando parámetros criptográficos ya existentes 4.7. Creación del objeto seguro SealedObject otherSecureObject = null; try { otherSecureObject = new SealedObject(otherObject, secureAlgorithm); } catch (IllegalBlockSizeException e) { e.printStackTrace(); return; } catch (IOException e) { e.printStackTrace(); return; } saveObject(otherSecureObject); Finalmente se crea el objeto seguro
Análisis de JCA y JCE (34/40) 5. Obtener el objeto asegurado reutilizando parámetros criptográficos ya existentes 5.1. Carga de los parámetros encodedKey = loadKey(); encodedParameter = loadParameter(); Para recuperar el objeto asegurado, se puede empezar por cargar los parámetros
Análisis de JCA y JCE (35/40) 5. Obtener el objeto asegurado reutilizando parámetros criptográficos ya existentes 5.2. Definición del algoritmo de seguridad try { secureAlgorithm = Cipher.getInstance("AES/CBC/PKCS7Padding", providerName); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); return; } catch (NoSuchProviderException e) { e.printStackTrace(); return; } catch (NoSuchPaddingException e) { e.printStackTrace(); return; } Continuar por definir el algoritmo de seguridad
Análisis de JCA y JCE (36/40) 5. Obtener el objeto asegurado reutilizando parámetros criptográficos ya existentes 5.3. Traducción de la clave a su forma adecuada key = new SecretKeySpec(encodedKey, "AES"); Traducir la clave a su forma adecuada
Análisis de JCA y JCE (37/40) 5. Obtener el objeto asegurado reutilizando parámetros criptográficos ya existentes 5.4. Traducción del parámetro a su forma adecuada parameterType = IvParameterSpec.class; parameterTranslator = null; try { parameterTranslator = AlgorithmParameters.getInstance("RIJNDAEL", providerName); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); return; } catch (NoSuchProviderException e) { e.printStackTrace(); return; } try { parameterTranslator.init(encodedParameter); } catch (IOException e) { e.printStackTrace(); return; } try { parameter = parameterTranslator.getParameterSpec(parameterType); } catch (InvalidParameterSpecException e) { e.printStackTrace(); return; } Traducir también el parámetro a su forma transparente y útil para el algoritmo de seguridad
Análisis de JCA y JCE (38/40) 5. Obtener el objeto asegurado reutilizando parámetros criptográficos ya existentes 5.5. Inicialización del algoritmo de seguridad para desprotección mode = Cipher.DECRYPT_MODE; if (parameter != null && random == null) { try { secureAlgorithm.init(mode, key, parameter); } catch (InvalidKeyException e) { e.printStackTrace(); return; } catch (InvalidAlgorithmParameterException e) { e.printStackTrace(); return; } } else if (parameter != null && random != null) { try { secureAlgorithm.init(mode, key, parameter, random); } } else if (parameter == null && random == null) { try { secureAlgorithm.init(mode, key); } } else if (parameter == null && random != null) { try { secureAlgorithm.init(mode, key, random); } } Inicializar correctamente el algoritmo de seguridad que se encargará de recuperar el objeto asegurado.
Análisis de JCA y JCE (39/40) 5. Obtener el objeto asegurado reutilizando parámetros criptográficos ya existentes 5.6. Obtención del objeto asegurado try { otherSecureObject = (SealedObject)loadObject(); object = (String)otherSecureObject.getObject(secureAlgorithm); } catch (IllegalBlockSizeException e) { e.printStackTrace(); return; } catch (BadPaddingException e) {e.printStackTrace(); return; } catch (IOException e) { e.printStackTrace(); return; } catch (ClassNotFoundException e) { e.printStackTrace(); return; } } Y finalmente recuperar el objeto asegurado.
Análisis de JCA y JCE (40/40) Deficiencias JCA y JCE Difícil uso y aprendizaje. Mucho conocimiento técnico exigido. Más líneas de código de las necesarias. Gran esfuerzo en tiempo exigido. Gran dedicación por usuario. Muy compleja para usuarios inexpertos. Tras observar el proceso anterior, se ve claramente que JCA y JCE resulta totalmente inadecuado para usuarios inexpertos. Vuelvo a recordar que el ejemplo anterior no es más que un ejemplo. En resumen, las PRINCIPALES deficiencias de JCA y JCE son: Primero. Son muy difíciles de utilizar y aprender. Segundo. Exigen mucho conocimiento técnico. Tercero. Muchas líneas de código, más de las necesarias. Cuarto. Exigen un gran esfuerzo en tiempo y dedicación al usuario Quinto y más importante. Son totalmente inadecuadas para usuarios inexpertos. Decíamos que las deficiencias aquí presentadas son las más generales pero no son las únicas. Otras deficiencias son: · Utilizan términos muy poco comprensibles. · Los distintos tipos de algoritmo criptográficos no tienen una base común, impidiendo de esta forma poder gestionarlos de manera homogénea. El uso de estas librerías, en general, es demasiado heterogéneo. · Conocer los parámetros de configuración y de inicialización de los algoritmos requiere tiempo al no estar éstos documentados ni disponibles de una manera adecuada. · Los algoritmos se definen de forma distinta a cómo se utilizan. Para obtener más información sobre estas y otras deficiencias se necesita consultar la documentación del proyecto.
El proyecto Valor añadido de JCEF Tras la introducción a este proyecto, ya es hora de entrar de lleno en el mismo. Comencemos por lo más importante e interesante de su valor añadido.
Valor añadido de JCEF (1/7) Asegurar un objeto con nuevos parámetros criptográficos Almacenar parámetros criptográficos para un uso posterior Obtener el objeto asegurado utilizando los nuevos parámetros criptográficos Asegurar otro objeto reutilizando parámetros criptográficos ya existentes Obtener el objeto asegurado reutilizando parámetros criptográficos ya existentes Recordemos el proceso habitual de gestión de objetos seguros. Se trata de asegurar objetos y recuperar los objetos asegurados con nuevos parámetros criptográficos o reutilizando otros ya existentes. JCEF es sencillo. Basta con seleccionar un algoritmo, inicializarlo si fuera necesario, y asegurar objetos u obtener los objetos asegurados a partir de sus versiones seguras utilizando dicho algoritmo. A diferencia del ejemplo anterior con JCA y JCE, mediante JCEF se realiza lo mismo de forma más sencilla y con una mayor independencia del tipo de algoritmo de seguridad seleccionado En ejemplo que veremos a continuación, a diferencia del ejemplo mostrado para las librerías criptográficas estándar, es general y completo, ya que funciona con todos los tipos de algoritmos criptográficos, es decir, para cualquier algoritmo de protección y de autentificación sin necesidad de cambiar gran parte del código.
Valor añadido de JCEF (2/7) 1. Asegurar un objeto con nuevos parámetros criptográficos try { // 1. Se desea asegurar un objeto // 1.1. Definimos un objeto que se desea asegurar String object = "my object"; // 1.2. Se selecciona un algoritmo de seguridad SymmetricProtection secureAlgorithm = new AES_BlockSymmetricProtectionRREXKY(); // 1.3. Se inicializa el algoritmo con parámetros concretos si fuera necesario (esta inicialización es opcional) // Esta inicialización es inexistente ya que se desea utilizar unos parámetros nuevos (clave y parámetro generado automáticamente por el algoritmo) // 1.4. Se asegura el objeto y se guarda en algún lugar SecureObject secureObject = new SecureObject(object, secureAlgorithm); saveObject(secureObject); // ... Asegurar un objeto con nuevos parámetros criptográficos es así de sencillo. · Se define el objeto a asegurar · Se define el algoritmo de seguridad que se desea utilizar. No es necesario inicializarlo ya que si no se especifican, los parámetros requeridos se generan automáticamente. · Se asegura el objeto creando un objeto seguro.
Valor añadido de JCEF (3/7) 2. Almacenar parámetros criptográficos para un uso posterior // 2. Se guardan los parámetros para su posterior uso, ya sea para generar nuevos objetos seguros u obtener objetos asegurados (objetos inseguros) que es lo más habitual byte[] encodedKey = secureAlgorithm.getSymmetricKey().getEncoded(); byte[] encodedParameter = secureAlgorithm.getEncodedParameter(); saveKey(encodedKey); saveParameter(encodedParameter); // ... Para poder recuperar el objeto asegurado en un momento posterior, es necesario almacenar los parámetros criptográficos utilizados para asegurar el objeto.
Valor añadido de JCEF (4/7) 3. Obtener el objeto asegurado utilizando los nuevos parámetros criptográficos // ... tiempo más tarde en algún otro lugar del código ... // 3. Se desea recuperar el objeto de forma segura // 3.1. Cargamos los datos que se necesitan encodedKey = loadKey(); encodedParameter = loadParameter(); // 3.2. Inicializamos el algoritmo con los parámetros apropiados para poder obtener el objeto asegurado secureAlgorithm = new AES_BlockSymmetricProtectionRREXKY(); secureAlgorithm.setSymmetricKey(encodedKey); secureAlgorithm.setParameter(encodedParameter); // 3.3. Se obtiene el objeto asegurado a partir de su versión en forma de objeto seguro secureObject = (SecureObject)loadObject(); object = (String)secureObject.getObject(secureAlgorithm); // ... Recuperar el objeto asegurado es muy sencillo, basta con cargar los parámetros, definir el algoritmo de seguridad e indicarle los parámetros que han sido cargados, sin necesidad de traducirlos (esto es automático). Y ahora ya se puede recuperar el objeto asegurado.
Valor añadido de JCEF (5/7) 4. Asegurar otro objeto reutilizando parámetros criptográficos ya existentes // ... tiempo más tarde en algún otro lugar del código ... // 4. Se desea asegurar un nuevo objeto con la misma clave y parámetro en un instante de tiempo posterior // 4.1. Se define el nuevo objeto String otherObject = "other object"; // 4.2. Se cargan los parámetros que se necesitan encodedKey = loadKey(); encodedParameter = loadParameter(); // 4.3. Se inicializa el algoritmo secureAlgorithm = new AES_BlockSymmetricProtectionRREXKY(); secureAlgorithm.setSymmetricKey(encodedKey); secureAlgorithm.setParameter(encodedParameter); // 4.4. Se asegura el nuevo objeto SecureObject otherSecureObject = new SecureObject(otherObject, secureAlgorithm); saveObject(otherSecureObject); // ... Asegurar otro objeto reutilizando parámetros criptográficos ya existentes es muy similar a recuperar un objeto asegurado. Se define el objeto a asegurar, se cargan los parámetros, se define e inicializa el algoritmo de seguridad, y se asegura el objeto.
Valor añadido de JCEF (6/7) 5. Obtener el objeto asegurado reutilizando parámetros criptográficos ya existentes // ... tiempo más tarde en algún otro lugar del código ... // 5. Se desea recuperar el nuevo objeto asegurado // 5.1. Cargamos los datos que se necesitan encodedKey = loadKey(); encodedParameter = loadParameter(); // 5.2. Inicializamos el algoritmo con los parámetros apropiados para poder obtener el objeto asegurado secureAlgorithm = new AES_BlockSymmetricProtectionRREXKY(); secureAlgorithm.setSymmetricKey(encodedKey); secureAlgorithm.setParameter(encodedParameter); // 5.3. Se obtiene el objeto asegurado a partir de su versión en forma de objeto seguro otherSecureObject = (SecureObject)loadObject(); object = (String)otherSecureObject.getObject(secureAlgorithm); } catch (Throwable throwable) { throwable.printStackTrace(); return; } Para recuperar el objeto asegurado, nuevamente basta con cargar los parámetros, definir e inicializar el algoritmo de seguridad y usarlo para recuperar el objeto asegurado a partir de su versión segura.
Valor añadido de JCEF (7/7) Mejoras de JCEF Fácil de utilizar. Sencillo y rápido aprendizaje. Posibilidad de mejora. Fácil definición de nuevos algoritmos criptográficos 64 algoritmos de todo tipo. Sencillo para usuarios inexpertos y expertos. Objetos seguros para cualquier algoritmo criptográfico Tras observar el proceso habitual tanto con JCA-JCE y JCEF, se ve claramente que JCEF resulta, al menos, mucho más adecuado para usuarios inexpertos y por supuesto para usuarios expertos. En resumen, las principales mejoras, aunque no las únicas, o valores añadidos de este proyecto y de JCEF respecto a JCA y JCE son: Primera. Es mucho más fácil de utilizar ya que simplifica, elimina y automatiza muchas operaciones de bajo nivel. Segunda. Exige conocimiento técnico casi inexistente, posibilitando un sencillo y rápido aprendizaje. Tercera. Posee grandes posibilidades de extensión o mejora para el futuro. Cuarta. Permite además definir algoritmos criptográficos muy fácilmente. Quinta. Trae consigo un paquete inicial de 64 algoritmos criptográficos de todo tipo. Sexta. Permite gestionar objetos seguros con cualquier algoritmo criptográfico. Estas mejoras generales no son las únicas. Existen otras no tan generales tales como: · Evita el uso de conceptos técnicos. · Elimina, simplifica o hace transparente para el usuario, múltiples operaciones de bajo nivel. · El uso de este proyecto es bastante homogéneo. · De forma sencilla, los algoritmos se pueden definir, configurar, inicializar, usar y ser nuevamente reutilizados. · Se potencia la creación de proveedores criptográficos personalizados. Para obtener más información sobre estas mejoras y otras tantas es preciso consultar la memoria del proyecto.
Detalles y curiosidades El proyecto Detalles y curiosidades En esta sección se mencionarán algunos detalles y curiosidades del proyecto.
Detalles y curiosidades (1/7) Estructura y composición del proyecto Este proyecto se compone de un total de 38 librerías, entre las que destacan “JCEF” y “RREXKY JCEF Provider”. Todas estas librerías dependen de otras como J2SE, JUnit, Apache Jakarta Commons Lang y las librerías de los proveedores criptográficos adaptados sean de especificación estándar JCA-JCE u otra especificación. Estas 38 librerías se dividen en 19 librerías de usuario y otras 19 que verifican el correcto funcionamiento de las anteriores 19. 17 de las 19 librerías son proveedores de algoritmos criptográficos que cumplen con la especificación JCEF.
Detalles y curiosidades (2/7) Pruebas realizadas Todos los métodos de todas las clases. Pruebas de lectura y escritura de propiedades. Pruebas de funcionalidad sobre los algoritmos. Las librerías de pruebas se encargan de someter al proyecto a una serie de tests con el objetivo de comprobar el correcto funcionamiento del mismo Se han realizado pruebas para comprobar el correcto funcionamiento de todos los métodos de todas las clases que componen el proyecto. La mayoría de las pruebas se basan en comprobar que las propiedades de los objetos de una clase se leen y escriben correctamente. Existen otras pruebas que verifican la funcionalidad de los algoritmos. Esta prueba genera parámetros y claves, realiza traducciones de parámetros y claves y especialmente trata de generar objetos seguros para posteriormente obtener el objeto asegurado con varios tipos de parámetros y claves. Si el objeto asegurado es el mismo que el original o si es auténtico, entonces el algoritmo supera la prueba de funcionalidad. Un algoritmo no supera esta prueba de funcionalidad en caso contrario o cuando se produce alguna excepción provocada principalmente por una mala configuración del algoritmo.
Detalles y curiosidades (3/7) Metodología La metodología seguida ha sido la clásica, es decir, la basada en el ciclo de vida clásico del software: Análisis, Diseño, Implementación y Pruebas con retroalimentaciones.
Detalles y curiosidades (4/7) Coste del proyecto Coste económico: CERO EUROS Coste de tiempo: entre 2000 y 3000 horas. Complejidad: El coste de este proyecto, desde un punto de vista económico ha sido nulo al haber utilizado recursos totalmente gratuitos. Sin embargo, el coste de tiempo ha sido muy superior a 300 horas, el máximo deseado por el reglamento. Se sabe con seguridad que no se ha dedicado al proyecto menos de 2000 horas y tampoco más de 3000. Un largo camino de más de un año, concretamente 14 meses de trabajo. Además, este proyecto contiene 3142 clases, 315 campos, 2914 métodos, 73959 líneas de código y 22941 líneas de comentarios de documentación.
Detalles y curiosidades (5/7) Además, este proyecto tiene la posibilidad de gestionar, tanto para uso como para definición, un conjunto completo de algoritmos, tanto criptográficos como de apoyo. Entre los que destacan algoritmos criptográficos y los de apoyo, ya sean de generación o traducción de parámetros.
Detalles y curiosidades (6/7) Disponibilidad http://jcef.sourceforge.net Para que este proyecto pueda seguir creciendo, sea conocido y pueda ser utilizado por quien lo desee, se encuentra alojado, por entero y accesible a todo el mundo, en el mayor repositorio de proyectos software de código abierto existente llamado SourceForge.net. Para mayor información puede consultar la dirección web que aparece en pantalla (http://jcef.sourceforge.net) Este proyecto está totalmente disponible para todos los públicos bajo licencia LGPL en la dirección web que se observa en pantalla (http://jcef.sourceforge.net). Se distribuye tanto: · El código fuente de todas las librerías de este proyecto, incluyendo las pruebas. · Las librerías compiladas listas para ser usadas. · También incluye las librerías que reutiliza este proyecto, exceptuando la librería estándar “API J2SE”. · La documentación en formato HTML de todas las librerías incluyendo acceso al código fuente. Aunque de forma online sólo se puede acceder a la documentación de la librería principal “JCEF” debido a falta de espacio en el alojamiento; desde la cual también se puede acceder a la guía del usuario de JCEF. · La mismísima página web. · La memoria del proyecto, incluyendo imágenes.
Detalles y curiosidades (7/7) Recursos utilizados ArgoUML FileZilla WinSCP Para la realización del proyecto se han utilizado numerosos recursos totalmente gratuitos de licencia Open Source o Freeware, tales como bibliografía, recursos web, programas, etc... Entre todos estos recursos se destacarán los siguientes: · Multitud de bibliografía y recursos webs. · Eclipse como entorno de desarrollo Java. · Herramientas de documentación como OpenOffice, Javadoc y ArgoUML. · Utilidades de diseño web como Nvu. · Herramientas para publicar el proyecto: WinSCP, FileZilla y SourceForge.net Y otros muchos tantos recursos como Mozilla Firefox o JUnit. Mozilla Firefox
El proyecto Futuros proyectos Por desgracia, JCEF no es perfecto y todavía puede y debe seguir creciendo. Algunas de las posibles mejoras que se le puede hacer a este proyecto en un futuro se muestran a continuación. Estas propuestas han sido redactadas como si fueran propuestas de proyectos fin de carrera para la Facultad de Informática de la Universidad de Las Palmas de Gran Canaria.
Futuros proyectos (1/7) Ampliaciones de JCEF Este proyecto consiste en ampliar JCEF con mejoras tales como flujos de entrada/salida seguros, protocolos de intercambio de claves y gestión completa de modos de operación y esquemas de relleno.
Futuros proyectos (2/7) Pruebas sobre algoritmos JCEF Este otro proyecto consiste en realizar pruebas de implementación y corregir algoritmos que no pasen las pruebas de funcionalidad.
Futuros proyectos (3/7) Certificados digitales con JCEF Este otro en añadir soporte a JCEF para gestión de certificados digitales.
Futuros proyectos (4/7) Archivos seguros con JCEF Éste trata de desarrollar un programa con interfaz gráfica de usuario para gestionar archivos seguros.
Futuros proyectos (5/7) Proveedor Criptográfico JCEF Este proyecto consiste en implementar algoritmos nuevos no implementados hasta ahora en Java pero utilizando JCEF.
Futuros proyectos (6/7) Almacén de objetos seguros con JCEF Este proyecto trata de añadir a JCEF soporte de almacenes seguros para cualquier tipo de objetos.
Futuros proyectos (7/7) Metaimplementación de “Aplicaciones Criptográficas Java” Y éste último pero no menos interesante, consiste en volver a implementar el proyecto utilizando un metalenguaje sobre Java con el objetivo de mejorar su futuro mantenimiento, principalmente en lo que se refiere a las adaptaciones de proveedores criptográficos.
El proyecto Conclusiones Para terminar con esta presentación, vamos a concluir indicando los aspectos valorables positivamente de este proyecto, y también los puntos negativos.
Conclusiones (1/3) Puntos débiles: Tiempo empleado superior a 300 horas. No haber desarrollado exactamente lo que estaba previsto desde un principio. Comencemos por los puntos débiles. Éstos son: · El tiempo empleado en el proyecto podría considerarse excesivo al superar las 300 horas, entre 2000 y 3000 horas. · No haber desarrollado exactamente lo que estaba previsto desde un principio también podría considerarse como un punto negativo.
Conclusiones (2/3) Puntos fuertes: Haber desarrollado un trabajo novedoso Aguantar un año de trabajo. Diseño de imágenes Sección “Preguntas frecuentes”. Sección “Futuros proyectos”. Publicación del proyecto en una página web. El uso 100% de herramientas Open Source, Freeware y gratuitas. Conocimiento aplicado: Ingeniería del software, gráficos, programación, ofimática, diseño web,... Sin embargo, en mi opinión, los aspectos que son valorables positivamente superan con creces a los negativos. Éstos son: · Haber desarrollado un trabajo novedoso en lugar de lo que se tenía previsto. Mejor hacer algo nuevo que no algo que ya está hecho. · Haber sido capaz de trabajar en el proyecto durante algo más de un año. · El diseño de imágenes propias y originales. · La sección de preguntas frecuentes como ayuda adicional al lector del proyecto. · Las propuestas realizadas sobre posibles futuros proyectos fin de carrera. · Publicación del proyecto en una página web (http://jcef.sourceforge.net) para que sea accesible a todo el mundo · El uso 100% de herramientas Open Source, Freeware y gratuitas. · Haber aplicado el conocimiento de varias áreas: Ingeniería del software, gráficos, programación, ofimática, diseño web ...
http://jcef.sourceforge.net Si se desea mayor información, consultar la web del proyecto (http://jcef.sourceforge.net).
Aplicaciones Criptográficas Java http://jcef.sourceforge.net Proyecto Fin de Carrera Facultad de Informática Universidad de Las Palmas de Gran Canaria Ahora me quedo a disposición del tribunal para posibles dudas. Esto es todo, gracias. Autor: Jesús María Ramos Saky Tutor: Miguel Ángel Pérez Aguiar 24/05/06