La JCA es un marco de trabajo para acceder y desarrollar funciones criptográficas en la plataforma Java. Se diseñó alrededor de dos principios básicos:
MessageDigest
, Signature
y
KeyFactory
.La separación entre el JCA y el JCE está motivada por las reglas de exportación de los EEUU para la encriptación. Las clases distribuidas con el JDK estándar sólo proporcionan herramientas para el resumen de mensajes y las firmas digitales, lo que permite tener un sistema de autentificación fiable sobre el que implementar un sistema de control de acceso más flexible que el modelo del cajón de arena. El problema es que estas herramientas no son suficientes para el envío seguro de datos, que necesitan algoritmos de encriptación.
La solución a este último problema es el JCE, que emplea la misma estructura que el JCA y proporciona clases motor para implementar criptografía de clave simétrica y para la generación y manipulación de las claves que estos emplean.
Antes de comenzar con la discusión del funcionamiento del JCA tenemos que definir algunos términos básicos:
En el contexto del JCA utilizamos el término motor (engine) para referirnos a una representación abstracta de un servicio criptográfico que no tiene una implementación concreta. Un servicio criptográfico siempre está asociado con un algoritmo o tipo de algoritmo y puede tener alguna de las siguientes funciones:
Un algoritmo es una implementación de un motor. P. ej. el algoritmo MD5 es una implementación del motor de algoritmos de resumen de mensajes. La implementación interna puede variar dependiendo del código que proporcione la clase MD5.
Un proveedor es el encargado de proporcionar la implementación de uno o varios algoritmos al programador (es decir, darle acceso a una implementación interna concreta de los algoritmos).
La JCA define el concepto de proveedor mediante la clase
Provider
del paquete java.security
. Se trata
de una clase abstracta que debe ser redefinida por clases
proveedor específicas.
El constructor de una clase proveedor ajusta los valores de varias propiedades que necesita el API de seguridad de Java para localizar los algoritmos u otras facilidades implementadas por el proveedor.
La clase Provider
tiene métodos para acceder al
nombre del proveedor, el número de versión y otras
informaciones sobre las implementaciones de los algorirmos
para la generación, conversión y gestión de claves y la
generación de firmas y resumenes.
Para entender como funcionan los proveedores daremos un ejemplo. Supongamos que un programa necesita una implementación del algoritmo MD5. Para obtenerla el programador necesita crear una instancia del mismo y lo hará escribiendo la siguiente línea de código:
MessageDigest m = MessageDigest.getInstance("MD5");
Internamente, el método getInstance()
solicita a la
clase java.security.Security
que le proporcione el
objeto solicitado. Como no se ha especificado proveedor la
clase Security
consulta a todos los proveedores
disponibles, solicitando una implementación del algoritmo
"MD5", hasta que encuentra una o se queda sin proveedores. La
consulta se realiza según la lista de proveedores del archivo
java.security
, que por defecto sólo contiene la
entrada:
Security.provider.1=sun.security.provider.Sun
Si se encuentra una implementación se retorna una instancia
de la clase retornada por el proveedor y si no se genera la
excepción NoSuchAlgorithmException
. En caso de que se
haya obtenido una implementación, para generar el resumen de
un vector de bytes (p. ej. buf
) con el MD5 bastará
invocar el método update()
del algoritmo. Para
obtener el vector resumen invocaremos el método
digest()
:
m.update(buf);
byte[] resumen = m.digest();
Por último sólo nos queda saber como se gestionan los proveedores, es decir, como se instalan o eliminan.
Existen dos modos de hacerlo:
java.security
addProvider()
o
insertProvider()
de la clase
java.security.Security
para añadirlos o al método
removeProvider()
Si un programador desea saber los proveedores disponibles
puede emplear los métodos getProvider("nombre")
(para saber si
un proveedor concreto está instalado) o
getProviders()
(que retorna un vector de cadenas con
los nombres de los proveedores).
En el JDK 1.2 el JCA define las clases motor presentadas en la tabla Clases motor de la JCA 1.2 y el JCE las de la tabla Clases motor de la JCE 1.2.
Para instanciar una clase motor se debe invocar el método
estático getInstance()
, si se le pasa un nombre de
algoritmo se intentará obtener una implementación de algún
proveedor (ver ejemplo en
El siguiente programa nos permite saber que proveedores y
algoritmos tenemos instalados en nuestro sistema. Además, si
lo invocamos con la opción -l
nos dirá que algoritmos
implementan (leyendo las propiedades del proveedor):
// InfoProveedores.java import java.security.*; import java.util.*; class InfoProveedores { public static void main(String[] args) { boolean listarProps = false; if ( args.length > 0 && args[0].equals("-l") ) listarProps=true; System.out.println("------------------------------------"); System.out.println("Proveedores instalados en su sistema"); System.out.println("------------------------------------"); Provider[] listaProv = Security.getProviders(); for (int i = 0; i < listaProv.length; i++) { System.out.println("Núm. proveedor : " + (i + 1)); System.out.println("Nombre : " + listaProv[i].getName()); System.out.println("Versión : " + listaProv[i].getVersion()); System.out.println("Información :\n " + listaProv[i].getInfo()); System.out.println("Propiedades :"); if (listarProps) { Enumeration propiedades = listaProv[i].propertyNames(); while (propiedades.hasMoreElements()) { String clave = (String) propiedades.nextElement(); String valor = listaProv[i].getProperty(clave); System.out.println(" " + clave + " = " + valor); } } System.out.println("------------------------------------"); } } }
Por defecto el JDK 1.2 incluye el proveedor de JCA SUN, para
saber que algoritmos implementa ejecutar el programa con la
opción -f
.