anterior | índice | siguiente |
El resto del tutorial va a hacer un uso considerable de claves: la firma y verificación requieren de claves asimétricas, la parte de encriptación simétrica necesitará de claves simétricas y, en ocasiones, un vector de inicialización. Parece el momento ideal de enterarnos de qué va esto.
Probablemente no sea la mejor forma de nombrarlas. Por claves asimétricas entendemos las claves utilizadas por los algoritmos asimétricos (RSA, DSA, etc. ). Si bien cada uno de estos algortimos utiliza su propia estructura de datos para almacenar las claves (la estructura RSA y DSA respectivamente), EVP oculta estos detalles proporcionando una única estructura de datos en la que se puede almacenar la clave de cualquier algoritmo de clave pública implementado en OpenSSL. Se trata de la estructura EVP_PKEY.
Existen bastantes funciones que permiten manipular de forma directa una clave de este tipo que escapan al objetivo del tutorial. Nosotros vamos a utilizar las siguientes:
|
Su funcionalidad parece obvia. EVP_PKEY_new() y EVP_PKEY_free() permiten reservar/liberar memoria para las claves. Antes de poder utilizar una clave EVP va a ser necesario hacer una llamada a EVP_PKEY_new(). Esta función devuelve NULL en caso de producirse un error. Veamos un ejemplo.
|
Ejemplo 1. Reserva y liberación de memoria.
Pues bien, este ejemplo 1 se limita únicamente a reservar memoria para una clave EVP y posteriormente liberarla.
No es posible generar claves con evp. Para instanciar una clave debemos hacer uso de funciones de otras librerías (PEM, RSA, DH...) y posteriormente asignarla con la función EVP_PKEY_assign(), que devuelve 0 en caso de producirse un error. Veamos un ejemplo:
|
Ejemplo 2. Utilización de EVP_PKEY_assign().
El ejemplo 2 genera un par de claves (pública y privada) de 1024 bits con una función propia de la librería RSA y, posteriormente, se la asigna a la clave EVP que hemos reservado previamente. EVP_PKEY_assign() toma tres argumentos: la clave EVP, el tipo de clave que le vamos a asignar y un puntero a carácter con la clave generada. Para especificar el tipo, se proveen tres macros:
|
Existe una forma indirecta y más sencilla de hacer todo esto. Utilizando las macros siguientes:
|
Todas ellas toman como primer argumento la clave EVP que acabará con la clave y como segundo argumento la clave a asignar, que será del mismo tipo especificado en el nombre de la clave, es decir: RSA, DSA y DH respectivamente. Veamos como nos queda el ejemplo 2 utilizando la macro correspondiente.
|
Ejemplo 3. Utilizamos EVP_PKEY_assign_RSA() para asignar una clave.
Por último, en determinados casos puede sernos útil saber el tamaño de la clave que alberga una clave EVP (por ejemplo cuando queremos firmar un mensaje, la longitud de la firma va a ser como mucho la longitud de la clave en bytes). Para ello disponemos de la funcion EVP_PKEY_size().
|
Ejemplo 4. Utilización de la función EVP_size().
Este ejemplo lee un clave en formato PEM guardada en el fichero especificado por el primer argumento e imprime su tamaño en bytes. Como se puede apreciar en este caso no ha sido necesario reservar memoria para la clave. Y con esto creo que es suficiente para entender el resto del tutorial cuando nos manejemos con los algoritmos asimétricos.
En lo que a claves para algoritmos simétricos se refiere se nos presentan dos alternativas: utilizar como clave números aleatorios generados mediante la librería RAND ó bien derivar una clave a partir de una password introducida por el usuario. Esta última forma está basada en el PKCS#5 y hace uso de las PBE routines, que trataremos en un apartado propio. Aquí veremos algún ejemplo de generación de claves como números aleatorios.
Esta forma es interesante en lo que a generación de claves de sesión se refiere. Sin embargo, OpenSSL implementa una serie de funciones que automatizan todo el proceso de generación de claves de sesión y encriptación de las mismas en las envelope routines.
No vamos a explicar todo el proceso de alimentación del generador de números aleatorios. Para todo este tema puede consultar el tutorial sobre OpenSSL/RAND. Vamos a limitarnos a ver algún ejemplo y comentarlo.
|
Ejemplo 5. Generamos una clave para un algoritmo simétrico con longitud de clave fija.
En primer lugar cabe explicar algunas estructuras y funciones nuevas que han aparecido. La estructura de datos EVP_CIPHER se utiliza para identificar los algoritmos simétricos a utilizar. En la parte de cifrado simétrico utilizaremos ampliamente esta estructura y, además, mostraremos cómo obtener cualquier algoritmo que esté implementado (aunque ya hemos dado alguna pista :-P). En particular, la estructura nos es de interés para obtener la longitud de la clave del algoritmo así como la del vector de inicialización. Esto se hace a través de las macros (respectivamente):
|
Ambas toman como argumento un puntero a la estructura EVP_CIPHER y devuelven el valor en bytes.
Existen en OpenSSL algoritmos de longitud de clave variable (RC4 por ejemplo). A dichos algoritmos se les asigna una longitud de clave por defecto (128 bits para el caso del RC4) que es posible obtener mediante la macro descrita anteriormente. Sin embargo EVP_CIPHER_key_length() no es válida si establecemos la longitud de la clave distinta a la de por defecto. En la parte de cifrado simétrico aprenderemos a establecer la longitud de la clave y a cómo obtener la longitud de la misma una vez establecida.