Uso de OpenSSL Crear Primitivas Criptográficas desde Línea de Comandos
Uso de OpenSSL Crear Primitivas Criptográficas desde Línea de Comandos

Uso de OpenSSL: Cómo Crear Primitivas Criptográficas desde Línea de Comandos

El entorno OpenSSL, particularmente rico y complejo, permite crear diversas primitivas criptográficas también desde la línea de comandos. Entre ellas se encuentran el cifrado simétrico y la firma digital RSA. Aquí tienes una guía introductoria para familiarizarte con esta poderosa herramienta.

El software de código abierto OpenSSL, junto con algunas de sus bifurcaciones, es una herramienta bien conocida por muchos especialistas para la creación de diversas primitivas criptográficas, aprovechando principalmente las Interfaces de Programación de Aplicaciones (API, Application Programming Interface) que pone a disposición.

Pocos conocen el entorno que permite la ejecución de estas primitivas desde la línea de comandos. El objetivo de este artículo es introducirte al uso de este entorno, que es rico y complejo. Su dominio va más allá de nuestros propósitos aquí; nos limitaremos a presentarlo, proporcionar referencias para su estudio y examinar algunas primitivas criptográficas simples, como el cifrado simétrico, la firma digital y su verificación, las funciones hash, y algunos otros detalles. Proporcionaremos ejemplos de uso, haciendo referencia a OpenSSL versión 3.x.x.

En este artículo asumiremos que el lector está familiarizado con los principales conceptos de criptografía básica. En caso de que falte este requisito, será necesario comprender varios conceptos preliminares.

A través de la terminal o el símbolo del sistema, después de asegurarte de haber instalado OpenSSL e incluirlo en el PATH, puedes obtener la versión en uso con el comando openssl version. A continuación, para mayor claridad, se usará texto en cursiva para los comandos ingresados y texto en negrita para la salida de la computadora.

En este caso:

openssl version
OpenSSL 3.2.0 23 Nov 2023 (Library: OpenSSL 3.2.0 23 Nov 2023)
Comando man openssl
Salida del comando man openssl

En la terminal de Linux/macOS, utilizada para invocar OpenSSL, el comando man openssl proporciona una amplia descripción de cómo usar el comando, mostrando su complejidad y riqueza.

Cifrado Simétrico

El primer caso de uso considerado es el cifrado simétrico de un archivo. Para este propósito, será apropiado crear un archivo para cifrar. Decidimos comenzar con una imagen del logo de esgeeks. El archivo se llama logo.jpg.

Si queremos cifrar el archivo, la primera pregunta que surge es: ¿con qué algoritmo de cifrado simétrico? Es interesante notar que podemos obtener información sobre los algoritmos compatibles con el simple comando openssl.

openssl
Comandos disponibles de openssl
Comandos disponibles de openssl

Este comando mostrará una lista de comandos disponibles, incluyendo algoritmos de resumen de mensajes (digest), comandos de cifrado y otros. Puedes usar estos algoritmos según tus necesidades específicas para la cifra simétrica de archivos.

help:
Standard commands
asn1parse         ca                ciphers           cmp               
cms               crl               crl2pkcs7         dgst              
dhparam           dsa               dsaparam          ec                
ecparam           enc               engine            errstr            
fipsinstall       gendsa            genpkey           genrsa            
help              info              kdf               list              
mac               nseq              ocsp              passwd            
pkcs12            pkcs7             pkcs8             pkey              
pkeyparam         pkeyutl           prime             rand              
rehash            req               rsa               rsautl            
s_client          s_server          s_time            sess_id           
smime             speed             spkac             srp               
storeutl          ts                verify            version           
x509              
Message Digest commands (see the `dgst' command for more details)
blake2b512        blake2s256        md4               md5               
mdc2              rmd160            sha1              sha224            
sha256            sha3-224          sha3-256          sha3-384          
sha3-512          sha384            sha512            sha512-224        
sha512-256        shake128          shake256          sm3               
Cipher commands (see the `enc' command for more details)
aes-128-cbc       aes-128-ecb       aes-192-cbc       aes-192-ecb       
aes-256-cbc       aes-256-ecb       aria-128-cbc      aria-128-cfb      
aria-128-cfb1     aria-128-cfb8     aria-128-ctr      aria-128-ecb      
aria-128-ofb      aria-192-cbc      aria-192-cfb      aria-192-cfb1     
aria-192-cfb8     aria-192-ctr      aria-192-ecb      aria-192-ofb      
aria-256-cbc      aria-256-cfb      aria-256-cfb1     aria-256-cfb8     
aria-256-ctr      aria-256-ecb      aria-256-ofb      base64            
bf                bf-cbc            bf-cfb            bf-ecb            
bf-ofb            camellia-128-cbc  camellia-128-ecb  camellia-192-cbc  
camellia-192-ecb  camellia-256-cbc  camellia-256-ecb  cast              
cast-cbc          cast5-cbc         cast5-cfb         cast5-ecb         
cast5-ofb         des               des-cbc           des-cfb           
des-ecb           des-ede           des-ede-cbc       des-ede-cfb       
des-ede-ofb       des-ede3          des-ede3-cbc      des-ede3-cfb      
des-ede3-ofb      des-ofb           des3              desx              
idea              idea-cbc          idea-cfb          idea-ecb          
idea-ofb          rc2               rc2-40-cbc        rc2-64-cbc        
rc2-cbc           rc2-cfb           rc2-ecb           rc2-ofb           
rc4               rc4-40            seed              seed-cbc          
seed-cfb          seed-ecb          seed-ofb          sm4-cbc           
sm4-cfb           sm4-ctr           sm4-ecb           sm4-ofb   

La parte más interesante en este momento es la introducida por los comandos de cifrado (Cipher commands). Tenemos una serie de cadenas generalmente compuestas por tres partes, según el esquema xxx-yyy-zzz, donde el carácter “-” se usa para separar las tres partes. La primera parte es un nombre o acrónimo que identifica el algoritmo utilizado, la segunda describe la longitud (en bits) de la clave y la tercera es el modo operativo seleccionado.

Por ejemplo, AES-128-cbc denota el algoritmo AES con clave de 128 bits y modo operativo CBC. A veces, no todas las cadenas están presentes y se omiten aquellas que son predeterminadas u obligatorias. Elijamos usar, por ejemplo, precisamente el mencionado aes-128-cbc (estándar del Instituto Nacional de Estándares y Tecnología de los Estados Unidos, NIST).

Para cifrar, por lo tanto, el archivo logo.jpg y construir su cifrado logo.enc, podemos usar (existen más formas en OpenSSL de obtener el mismo resultado):

openssl enc -aes-128-cbc -in logo.jpg -out col.enc
enter AES-128-CBC encryption password:
Verifying - enter AES-128-CBC encryption password:
*** WARNING : deprecated key derivation used.
Using -iter or -pbkdf2 would be better.
Uso del cifrado AES-128-cbc
Uso del cifrado AES-128-cbc

La entrada y salida se han copiado y pegado, por lo que se muestra la reproducción fiel de la interacción. Primero, la biblioteca solicita una contraseña para generar internamente una clave de cifrado (a través de una función de derivación de clave, o KDF), luego pide su confirmación; después, advierte que la KDF utilizada, que es la predeterminada, no se recomienda (porque es poco segura) y sugiere alternativas. De hecho, la opción -pbkdf2 permite usar una KDF mejor y más moderna.

Repetimos, entonces, la operación de cifrado usando la palabra “es33^%*” como contraseña, obteniendo:

openssl enc -aes-128-cbc -pbkdf2 -in logo.jpg -out logo.enc

Ahora el resultado está en el archivo logo.enc.

Podemos repetir todo agregando la opción -p, que proporciona una mayor visibilidad de los parámetros utilizados:

openssl enc -aes-128-cbc -pbkdf2 -p -in logo.jpg -out logo2.enc
Uso de cifrado AES con pbkdf2
Uso de cifrado AES con pbkdf2
enter AES-128-CBC encryption password:
Verifying - enter AES-128-CBC encryption password:
salt=D19BCF06E40A8C51
key=D702AE76F45BF69690397FA80FCEB7BB
iv =C7C9909A151952544943064C0F8EEA84

En particular, hemos obtenido la visualización de la sal generada (salt), de la clave construida (key) y del IV creado (iv, necesario para CBC); todos los valores se expresan en hexadecimal. Podemos ver los primeros dieciséis bytes del archivo creado logo2.enc de la siguiente manera:

hexdump -C logo2.enc | head -1
00000000  53 61 6c 74 65 64 5f 5f  d1 9b cf 06 e4 0a 8c 51  |Salted__.......Q|
Ver bytes de archivo enc
Ver bytes de archivo enc

Desde la visualización, podemos verificar que los primeros ocho bytes del resultado codifican la cadena “Salted__” y los segundos ocho describen la sal (se usan minúsculas en lugar de mayúsculas, pero no hay diferencia real). Estos detalles son necesarios para generar el mismo IV durante la descifración. Sin embargo, se debe mencionar que la decisión de colocar estos dieciséis bytes al principio del archivo cifrado es una característica de OpenSSL, no de AES. Esto significa que otra biblioteca que use AES con claves de 128 bits y CBC podría generar un archivo diferente porque podría insertar esta información auxiliar al final del archivo o en otro archivo.

Ahora tomemos el archivo logo2.enc y descifrémoslo, colocando el contenido en logo2.jpg. Lo que esperamos es que logo.jpg y logo2.jpg sean idénticos. Puedes verificar esto con el comando cmp. La línea para descifrar es similar a la de cifrar, con algunas pequeñas variaciones: se ha agregado la opción -d para la descifración (el valor predeterminado es cifrar), el archivo de entrada se convierte en logo2.enc y el de salida en logo2.jpg.

openssl enc -aes-128-cbc -pbkdf2 -d -p -in logo2.enc -out logo2.jpg

La comparación con cmp confirma la total coincidencia.

cmp logo.jpg logo2.jpg

Si los archivos son idénticos, no habrá ninguna salida del comando. Si hay alguna diferencia, el comando mostrará la ubicación y el valor del primer byte diferente encontrado.

En la página del manual (man) es posible ver cómo cifrar/descifrar proporcionando sal, IV y/o contraseña arbitrarios directamente desde la línea de comandos.

Firma Digital RSA

Ahora nos ocuparemos del cifrado asimétrico, examinando el uso de RSA con fines de firma digital. Para aplicar una firma mediante RSA, es necesario:

  1. Tener un par de claves, que posiblemente se deban generar.
  2. Realizar la operación de firma en sí.
  3. Saber cómo realizar la verificación.

OpenSSL permite generar fácilmente una clave privada RSA con el siguiente comando:

openssl genpkey -algorithm RSA -out key.pem
...+...........+.+.................+.+......+...+...+...+.....+.+......+..+.............+++++++++++++++++++++++++++++++++++++++*..........+..+.+.....+............+...+............+.+.....+.+...+++++++++++++++++++++++++++++++++++++++*..................+......+.........+......+......++++++
.+.....................+++++++++++++++++++++++++++++++++++++++*....+.........+.+...+......+......+...+..+............+......+......+.+...+..+........................+...+...+...+....+.....+...+....+...+...+........+......+...+...+.......+.....+.......+...+..+++++++++++++++++++++++++++++++++++++++*...+...........+...+.++++++

Este comando crea una clave privada RSA y la guarda en el archivo key.pem. Si intentamos observar el inicio del archivo, podemos usar el siguiente comando:

head key.pem
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC42m/dU+PUlNAI
mImiMDtXpLGVZ+TpqNVFbKyMRr+LCWo17TIxyDU8gQs7HMTKxnH1KYTEMZQlLyeB
lgjDsK6Snw417+nLS5OhrKr+g4ZKsC6jUQ6dk3qhVLVXKBufgVy9u8poZlOop/CK
YjDwtEqBGo1nPHC8AzYdSC5JD49nlBPuxMuTFSxW9/x71HKP4DoYkGwf3v5MDGXT
6ZiXFitcSLEaj+o8r5egJf6ggQK3SjZ9dCQsZUP0nlsx7thb52SaO9CiYxHTG6AE
Comando para crear clave privada RSA
Comando para crear clave privada RSA

A pesar de la indicación inicial “BEGIN PRIVATE KEY“, el archivo contiene toda la información relacionada con ambas claves. Notamos que está uuencoded y de lectura inmediata (plaintext). Esto no es adecuado para una clave privada. Se debe generar su representación cifrada, por ejemplo, usando AES. Además, el tamaño de la clave es el predeterminado (2048 bits); si queremos una clave de 4096 bits, debemos usar la opción -pkeyopt rsa_keygen_bits:4096.

openssl genpkey -algorithm RSA -out key.pem -aes-128-cbc -pkeyopt rsa_keygen_bits:4096
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:

Se generará una contraseña PEM, y al verificarla, podrás observar el inicio del archivo generado key.pem:

head -6 key.pem
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIJtTBfBgkqhkiG9w0BBQ0wUjAxBgkqhkiG9w0BBQwwJAQQkjQveqMuhf3anPQk
c+H4ygICCAAwDAYIKoZIhvcNAgkFADAdBglghkgBZQMEAQIEEEnfeobx2p2wESh8
DCyfRbAEgglQNah8FRgO6yjcoc7wlE3CqXl72/dULgXoy8L2uhMEd3slQGRa5Vz2
V0sGejEMNcA+XYXG59kdTXT9UT6FmJCPGBGhuOJ4kUc08uhRK7ImIaFjyFtu4fNg
iQWtwsZAenrVRQHniHI6XOzY79p1TenexlObrFR6QUzate97EpsMF3Ck0DDXoW8f

Para obtener detalles de la clave, puedes usar la opción -text:

openssl pkey -in key.pem -text
Detalles de clave con opción text
Detalles de clave con opción text

Como podemos observar, hay cinco campos presentes: modulus (el valor N = p·q, producto de los primos p y q), publicExponent, que se establece por defecto en 65537, privateExponent d, el inverso multiplicativo de e mod (p – 1)(q – 1), y algunos detalles que facilitan los cálculos de RSA.

Es posible extraer la clave pública de la privada de la siguiente manera:

openssl rsa -in key.pem -out pub.pem -pubout
Enter pass phrase for key.pem:
writing RSA key

Verifiquemos las primeras dos líneas de pub.pem:

head -2 pub.pem
-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAyyLghKTCaIrg9HZ/zrnv

Hemos extraído efectivamente la clave pública.

Para firmar digitalmente el archivo logo.jpg, usemos la función hash SHA-256 (muy utilizada). Ahora surge una pregunta: hay tres estándares para RSA, descritos por PKCS#1 durante sus evoluciones, y podemos referirnos a ellos como PKCS#1 v1.5, PKCS#1 OAEP y PKCS#1 PSS, que describen cómo se debe preprocesar el resumen del archivo antes de realizar la exponenciación RSA.

Las técnicas de uso de RSA admitidas por OpenSSL se refieren a los tres estándares mencionados, con los nombres de pkcs1, oaep y pss. Según la documentación de OpenSSL, solo pkcs1 y pss admiten la firma, mientras que oaep solo admite cifrado y descifrado. Construyamos el hash (binario) del archivo.

openssl dgst -sha256 -binary -out hash logo.jpg
hexdump hash
Hash del archivo binario
Hash del archivo binario

Centrémonos primero en PKCS#1 v1.5, el más antiguo y único recomendado para casos de retrocompatibilidad. Podemos firmar con:

openssl pkeyutl -sign -in hash -inkey key.pem -out sign1.5 -pkeyopt rsa_padding_mode:pkcs1
Enter pass phrase for key.pem:

El archivo sign1.5 contiene la firma y es binario.

0000000 5eb2 19ff 7363 3f75 5889 5ea2 c451 39fa
0000010 27c0 a2d6 5ca2 a1b7 b3b7 2e27 4fd3 7a2a
0000020 2734 9fe8 4ea2 2e4d aa38 a3fc a95c 642c

La verificación es casi igual, hay que reemplazar ‘sign’ con ‘verify’ y hacer algunas intervenciones simples.

openssl pkeyutl -verify -sigfile sign1.5 -in hash -inkey key.pem -pkeyopt rsa_padding_mode:pkcs1
Signature Verified Successfully

En el caso de PSS, el comando de firma también requiere la especificación de la longitud del salt: el valor especial -1 indica la misma longitud que el digest.

openssl pkeyutl -sign -in hash -inkey key.pem -out signpss -pkeyopt digest:sha256 -pkeyopt rsa_padding_mode:pss -pkeyopt rsa_pss_saltlen:-1

Las primeras líneas de la firma obtenida:

hexdump signpss | head -3
0000000 cb4b 7c2d d5bc 51bc ec93 574e 21d3 8b6d
0000010 2aa9 c550 f661 7be1 96fc a353 48c9 7c0d
0000020 bb01 421e 9f14 2b8d fcde ac81 e419 e364

En este sentido, observamos que al realizar la misma firma en el archivo ‘signpssbis’:

openssl pkeyutl -sign -in hash -inkey key.pem -out signpssbis -pkeyopt digest:sha256 -pkeyopt rsa_padding_mode:pss -pkeyopt rsa_pss_saltlen:-1
Enter pass phrase for key.pem:

se obtiene un archivo diferente.

hexdump signpssbis | head -3
0000000 bd8c 6ff4 383e 65e7 9ed1 957b 3f8d d2e9
0000010 4158 f4e9 a50e 940c f9f1 a702 feee 85dd
0000020 a32e b63b 9588 319c 7b3b 2a7f 47b4 040c

Esto es lo que esperábamos porque la firma PSS no es determinista. Repitiendo la firma PKCS#1 y creando un archivo ‘sign1.5bis’ será idéntico a ‘sign1.5’ (firma determinista).

En el caso de PSS, la verificación es análoga al caso de PKCS#1.

openssl pkeyutl -verify -sigfile signpss -in hash -inkey key.pem -pkeyopt digest:sha256 -pkeyopt rsa_padding_mode:pss -pkeyopt rsa_pss_saltlen:-1
Signature Verified Successfully

Notamos que en ambas verificaciones tuvimos que ingresar la contraseña para acceder a la clave privada; esto se debe a que contiene la información necesaria para la verificación (que encontraríamos en la clave pública).

openssl pkeyutl -verify -sigfile signpss -in hash -pubin -inkey pub.pem -pkeyopt digest:sha256 -pkeyopt rsa_padding_mode:pss -pkeyopt rsa_pss_saltlen:-1
Signature Verified Successfully

De hecho, no se solicitó una contraseña.

Te podrías preguntar cuál es la relación entre la firma generada por OpenSSL y las firmas tradicionales utilizadas por muchas personas, como PAdES o CAdES. Desde un punto de vista técnico, las firmas PAdES y CAdES pueden basarse en RSA. Veamos las distinciones más significativas:

  • Las firmas PAdES y CAdES son compatibles con certificados X509, que confirman la validez y corrección de las claves y otorgan valor legal a las firmas.
  • En la firma PAdES, la firma se inserta en el propio PDF, por lo que no es un archivo separado; en CAdES, la firma (además de otra información) se inserta en un sobre criptográfico llamado P7M, una especie de contenedor que agrupa toda la información de interés para la firma y desde el cual se pueden extraer las componentes con software especializado.

Es relevante señalar que tanto la sección ‘dgst’ como ‘pkeyutl’ permiten aplicar firmas. La primera es a un nivel más alto, mientras que la segunda es a un nivel más bajo y requiere el hash del archivo a firmar. Hay otras diferencias, pero son más técnicas.

El software OpenSSL contiene muchas secciones, llamadas “comandos” en la documentación. En la siguiente tabla, se puede examinar un resumen, directamente obtenido de la documentación oficial; se destaca el alcance masivo de la biblioteca, útil no solo para realizar operaciones criptográficas simples, sino también para trabajar con certificados, asegurar el correo electrónico, trabajar con números aleatorios, generar contraseñas, elegir una KDF, etc.

NombreDescripción Original del Comando
asn1parseAnaliza una secuencia ASN.1
caGestión de Autoridad de Certificación (CA)
ciphersDeterminación de Descripción de Conjunto de Cifrado
cmsComando de Sintaxis de Criptografía (Cryptographic Syntax)
crlGestión de Lista de Revocación de Certificados (CRL)
crl2pkcs7Conversión de CRL a PKCS#7
dgstCálculo de Resumen de Mensaje. Los cálculos de MAC son reemplazados por openssl-mac(1)
dhparamGeneración y Gestión de Parámetros de Diffie-Hellman. Sustituido por openssl-genpkey(1) y openssl-pkeyparam(1)
dsaGestión de Datos de DSA (Algoritmo de Firma Digital)
dsaparamGeneración y Gestión de Parámetros de DSA. Sustituido por openssl-genpkey(1) y openssl-pkeyparam(1)
ecProcesamiento de Clave EC (Curva Elíptica)
ecparamManipulación y Generación de Parámetros EC
encEncriptación, desencriptación y codificación
engineInformación y manipulación de Módulos Cargables (Engine)
errstrConversión de Número de Error a Cadena de Error
fipsinstallInstalación de Configuración FIPS
gendsaGeneración de Clave Privada DSA a partir de Parámetros. Sustituido por openssl-genpkey(1) y openssl-pkey(1)
helpMuestra información sobre las opciones de un comando
infoMuestra información diversa incorporada en las bibliotecas OpenSSL
kdfFunciones de Derivación de Clave
listLista algoritmos y características
macCálculo de Código de Autenticación de Mensaje (MAC)
nseqCrea o examina una secuencia de certificados Netscape
ocspComando del Protocolo de Estado de Certificado en Línea (OCSP)
passwdGeneración de contraseñas con hash
pkcs12Gestión de Datos PKCS#12
pkcs7Gestión de Datos PKCS#7
pkcs8Conversión de formato de clave privada en formato 8
pkeyGestión de claves pública y privada
pkeyparamGestión de parámetros de algoritmo de clave pública
pkeyutlComando criptográfico de algoritmo de clave pública
primeCalcula números primos
randGenera bytes pseudoaleatorios
rehashCrea enlaces simbólicos a archivos de certificados y CRL nombrados por los valores de hash
reqGestión de Solicitud de Firma de Certificado (CSR) PKCS#10 X.509
rsaGestión de claves RSA
rsautlComando RSA para firmar, verificar, encriptar y desencriptar. Sustituido por openssl-pkeyutl(1)
s_clientImplementa un cliente SSL/TLS genérico que puede establecer una conexión transparente a un servidor remoto que habla SSL/TLS. Destinado solo para pruebas y proporciona funcionalidad de interfaz rudimentaria, pero internamente utiliza principalmente toda la funcionalidad de la biblioteca SSL de OpenSSL
s_serverImplementa un servidor SSL/TLS genérico que acepta conexiones de clientes remotos que hablan SSL/TLS. Destinado solo para pruebas y proporciona funcionalidad de interfaz rudimentaria, pero internamente utiliza principalmente toda la funcionalidad de la biblioteca SSL de OpenSSL. Proporciona tanto un protocolo de línea de comandos propio para probar funciones SSL como una sencilla instalación de respuesta HTTP para emular un servidor web consciente de SSL/TLS
s_timeTemporizador de Conexión SSL
sess_idGestión de Datos de Sesión SSL
smimeProcesamiento de Correo S/MIME
speedMedición de Velocidad de Algoritmo
spkacImpresión y generación de comandos SPKAC
srpMantener archivo de contraseñas SRP. Este comando está obsoleto
storeutlComando para listar y mostrar certificados, claves, CRL, etc.
tsComando de Autoridad de Estampado de Tiempo
verifyVerificación de Certificado X.509. Consulta también la página del manual openssl-verification-options(1)
versionInformación de Versión de OpenSSL
x509Gestión de Datos de Certificado X.509

Todos los comandos mencionados pueden ser explorados escribiendo “man openssl-” seguido del nombre del comando. Por ejemplo, “man openssl-smime“. A veces, la documentación no refleja con precisión el comportamiento real y es necesario realizar experimentos.

Conclusión

Hemos examinado algunas operaciones que se pueden realizar con OpenSSL, comprendiendo la potencia y versatilidad de la biblioteca.

De entre las muchas funciones compatibles, hemos seleccionado algunas que están más cercanas a las necesidades de un usuario final, como el cifrado y la firma digital.

Hay otras, como ahora es evidente, que son extremadamente más especializadas. En un próximo artículo, se abordará el uso de OpenSSL para probar conexiones TLS y gestionar certificados.

Mi Carro Close (×)

Tu carrito está vacío
Ver tienda