La documentación de OpenSSL y por momentos uno no sabe qué funciones debe utilizar. Para compensar esto, aquí describo los pasos para encriptar, desencriptar un texto, generar un par de claves y la solicitud para el certificado.
Nota: Por razones legales, no puedo incluir en esta página el código fuente original que realiza cada una de las siguientes funciones. Por ese motivo, solo indico los pasos y las funciones de OpenSSL que utilice.
Encriptar un texto utilizando BlowFish (Devuelve el resultado en base 64)
- Creamos tres BIOs: s_mem, f_base64 y f_cipher.
- Al de base64 le seteamos el flag BIO_FLAGS_BASE64_NO_NL.
- Aplicamos BIO_set_cipher al f_cipher con el modo EVP_bf_cbc() y la contraseña.
- Obtenemos el contexto del cipher y con EVP_CIPHER_CTX_block_size recuperamos el tamaño del bloque del algoritmo de cifrado.
- Unimos los BIOs con BIO_push(cipher,b64) y BIO_push(b64, mem).
- En un ciclo for escribimos al BIO con el cipher, hasta que no queden más bytes.
- El tamaño del texto plaintext debe ser múltiplo de tamaño del bloque del algoritmo de cifrado. Por alguna razón, no pude hacer funcionar el padding. Asi que completamos los bytes faltantes con el caracter '\0'.
- Terminamos de procesar la entrada: BIO_flush(cipher), BIO_flush(b64) y BIO_flush(mem).
- Como no puedo terminar de antemano cuál es el tamaño del buffer que se necesita, si el buffer es NULL, devuelve la cantidad de bytes que se necesitan.
- Obtenemos el resultado utilizando la funcion BIO_get_mem_data.
- Devuelve la cantidad de bytes del texto en base64.
Desencriptar un texto utilizando BlowFish (La entrada está en base 64)
- Creamos tres BIOs: s_mem, f_base64 y f_cipher.
- Al de base64 le seteamos el flag BIO_FLAGS_BASE64_NO_NL.
- Aplicamos BIO_set_cipher al f_cipher con el modo EVP_bf_cbc() y la contraseña.
- Unimos los BIOs con BIO_push(cipher,b64) y BIO_push(b64, mem).
- En un ciclo for escribimos al BIO de memoria, hasta que no queden más bytes.
- Terminamos de procesar la entrada: BIO_flush(mem), BIO_flush(b64) y BIO_flush(cipher).
- Leemos del BIO cipher hasta que no queden datos.
En este caso, no tengo forma de determinar la longitud de los datos antes de leer el BIO Cipher. Pero siempre la longitud del texto en base64 va a ser mayor al texto original. Asi que con solo enviar un buffer del tamaño del texto en base64 solucionamos el problema.
Generación de una clave privada RSA
Genera un archivo con una clave privada RSA de 2048 bits. La misma es encriptada con TripleDES en CBC.
Recibe el path de la clave privada y una contraseña.
- Abrimos un BIO_new_file apuntando al archivo donde se guardara la clave privada.
- Utilizando RSA_generate_key generamos la clave privada.
- Con PEM_write_bio_RSAPrivateKey escribimos la salida en el archivo.
Generación de una solicitud de Certificado (request)
El request es generado con el formato PKCS #10.
Recibe el path del archivo con la clave privada (en formato DER) y la contraseña.
- Abrimos un BIO_new_file apuntando al archivo con la clave privada.
- Utilizando PEM_read_bio_PrivateKey, el BIO anterior y la contraseña de la clave privada recuperamos la clave privada.
- Abrimos un BIO_new_file apuntando al archivo donde se guardara el request.
- Creamos la estructura del request con X509_REQ_new().
- Con X509_REQ_set_pubkey le seteamos la clave privada y con X509_REQ_set_version(request,0L) la version.
- Obtenemos el campo DN con X509_REQ_get_subject_name.
- Agregamos cada elemento del DN utilizando X509_NAME_add_entry_by_txt e indicando el campo y el valor.
- Firmamos el request con X509_REQ_sign.
- Escribimos la salida en el archivo con PEM_write_bio_X509_REQ.
Leer el campo Subject (DN) de un certificado
Recibe el path del certificado en formato X509.3 (PEM) y un buffer con su tamaño.
- Abrimos un BIO_new_file apuntando al archivo con el certificado.
- Utilizando PEM_read_bio_X509 y el BIO anterior leemos el certificado.
- Creamos un BIO de memoria.
- Con X509_NAME_print_ex(mem, X509_get_subject_name (certificado), 0, XN_FLAG_ONELINE | XN_FLAG_DN_REV) guardamos el DN en la memoria.
- Cargamos el contenido del BIO en el buffer.
Firmar un texto utilizando un certificado y la clave privada
El formato de la clave privada debe ser DER y el del certificado asociado a la clave privada debe ser X509.3 (PEM)
- Abrimos un BIO_new_file apuntando al archivo con el certificado.
- Utilizando PEM_read_bio_X509 y el BIO anterior leemos el certificado.
- Abrimos un BIO_new_file apuntando al archivo con la clave privada.
- Utilizando PEM_read_bio_PrivateKey, el BIO anterior y la contraseña de la clave privada recuperamos la clave privada.
- Creamos un BIO de memoria a partir del texto que queremos firmar.
- Firmamos el texto utilizando PKCS7_sign(certificado, clavePrivada, NULL, BIO_mem, PKCS7_BINARY).
- Creamos un BIO de memoria para guardar la firma.
- Utilizando PEM_write_bio_PKCS7, pasamos el resultado al BIO anterior.
- Si el buffer recibido es NULL, devolvemos la cantidad de bytes necesarios.
- En otro caso, guardamos el resultado en el mismo.
- Debido a que a veces el buffer resulta insuficiente y el BIO me reporta un tamaño menor, al finalizar reviso si la salida contiene '-----END PKCS7-----'. De esta manera me aseguro que todo salio bien. El resultado se genera en formato PKCS #7 codificado en Base64 (PEM).