Cifrar archivo con OpenSSL

Cifrado

Mi objetivo principal para los cypherpunks, es hacer que las personas defiendan su propia privacidad, en lugar de confiar en alguien más para proporcionarla»

Eric Hughes – Cypherpunk Mailing – List 23 de Marzo de 1993

En muchas ocaciones necesitaremos enviar algún archivo por un medio inseguro, almacenar en un repositorio que no es nuestro, transportar en un dispositivo físico, que se puede extraviar o ser robado. Todas son instancias donde «alguien», no autorizado, pudiera tener acceso a el y a nuestra información.

Existen varios métodos de cifrado, pero que pasa si queremos compartir o enviar ese archivo a otra persona, tendremos que compartir también la contraseña y como la enviamos, que canal es más seguro y de vuelta a lo mismo.. – Bueno esto es tema antiguo, fue solucionado hace mucho y se llama cifrado asimétrica, donde sólo compartes tu llave pública y cualquier archivo cifrado con esta llave, sólo puede ser decifrado por su par privado, con esto también nos aseguramos, en gran medida, que sólo el destinatario pueda ver lo que enviamos.

Una forma de hacer lo anteriormente señalado es utilizando OpenSSL.
Primero debemos descargar e instalar OpenSSL en nuestro equipo.

 

I. Generando llaves privada y pública

Lo siguiente es generar nuestras llaves públicas y privadas:

$ openssl genrsa -out eh337.pem 4096

Primero generamos las claves, en un archivo que llamaremos eh337.pem, ahí ahora se encuentran, tanto la clave privada como la pública.

$ openssl rsa -in eh337.pem -out eh337.pub.pem -outform PEM -pubout

Entonces extraemos la llave pública a un archivo aparte.

El método de claves publica y privada No permite! cifrar archivos de gran tamaño, entonces para despreocuparnos si nuestro archivo es el tamaño correcto, realizaremos un truco, usaremos un cifrado simétrico con una clave generada en forma aleatoria y esta la cifraremos de forma asimétrica con nuestra llave pública previamente generada y almacenada en el archivo eh337.pub.pem.

 

II. Cifrando archivo

$ openssl rand -base64 -out KeyFileEH.txt 337

Primero, el comando rand nos permite generar números aleatorios, a continuación especificamos el formato, para este caso usamos -base64, la salida queda almacenada en KeyFileEH.txt y por último especificamos el largo, que en esta oportunidad lo definimos en 337 ;). Finalmente el archivo queda de la siguiente forma:

ScDS5haVcBSwx81lpzM4yrIXjgmUtQEeDKpg3lFCFJsi3M9diibgguB5ZUtjhxAg
st6w9EY7jONEovB7MX97G0VyViP3iZioCqoUzmipCLSgqYrExgSrvu4HdrrcDMKN
U8zseppiVO1WLzmEU7DhDEFwVPzSgmVklibE65yClnpBLGUCKv8cKnv6VCrht313
W9McLz+/MfF3fm6GkSDO3F2YddKMqoY5M0qX8uDyEhMqPjHOFa320WjzfHWIqohp
TcLLxj+u88RwzWA9KeSSQhd1LzHs2dJ6SLPHX4EA1pD/ErpYyqDejIXCm9YLWEAR
LFMqso4nTcpVzKJrtyA+82xup30anuDrc3aCHOhJu66YwpBiPJqvfLjUgOkvXnTw
No/lhSi18Vfz+mNHzvKkHG8HER4wogLKIXS/dtFl6qoFhgm33rZT0YJQt/3gKAQh
HQ==

Ahora cifraremos el archivo utilizando el base64 generado previamente como clave.

$ openssl enc -aes-256-cbc -a -salt -in DatosTopSecret.txt -out DatosTopSecret.enc.txt -pass file:KeyFileEH.txt -iter 337

En la línea anterior podemos identificar como primer parámetro a enc el que nos indica que la acción de openssl es realizar un cifrado, aes-256-cbc es el tipo de cifrado simétrico utilizado, -a nos dice que la codificación será en Base64 la cual convierte la información binaria de 8 bits en un conjunto de caracteres ASCII, esto se realiza para mejorar la transferencia por la red y por defecto el cifrado quedará en formato binario, -salt especifica que robusteceremos el cifrado con una contraseña, -in es el fichero de entrada, -out representa el fichero de salida, tanto el nombre como la extensión no necesitan ser igual al de entrada, pero para mantener una lógica y saber cual es la extensión original ocupamos la nomenclatura: «.enc.txt«, -pass file representa al archivo que contiene la clave con la cual se cifrará el fichero de entrada y finalmente -iter que especifica el número de iteraciones y el uso forzado de PBKDF2 (el cual reduce la posibilidad de ataques de fuerza bruta).

$ openssl rsautl -encrypt -in KeyFileEH.txt -out KeyFileEH.enc.txt -inkey eh337.pub.pem -pubin

Ahora cifraremos el archivo que contiene la clave simétrica, el cual utilizamos para cifrar nuestro archivo secreto, esto lo realizaremos usando la llave pública generada previamente. Ahora detallemos la línea anterior: el parámetro rsautl indica que vamos a usar RSA para firmar, verificar, cifrar o decifrar, -encrypt para especificar que vamos a cifrar el fichero de entrada con una llave RSA pública, -inkey es donde definimos la llave pública con la cual cifraremos el archivo, -in y -out, vamos!! que ya los conocemos! #^.^#.

Resumen

Capitulemos, hasta ahora llevamos:

  • Generar llave pública/privada
  • Generar contraseña aleatoria en base64
  • Cifrar archivo con la contraseña anterior
  • Cifrar contraseña aleatoria con llave pública

 

III. Decifrando archivo

Ahora para hacer el proceso inverso deberíamos recibir los siguientes archivos:

  • KeyFileEH.enc.txt: El archivo con la contraseña, cifrado con la llave pública.
  • DatosTopSecret.enc.txt: El arhivo cifrado con la contraseña del archivo anterior.

Primero deciframos el archivo KeyFileEH.enc.txt con nuestra llave privada:

$ openssl rsautl -decrypt -inkey eh337.pem -in KeyFileEH.enc.txt -out KeyFileEH.txt

Ahora ya tenemos la contraseña y vamos a decifrar finalmente el archivo.

$ openssl enc -aes-256-cbc -d -pass file:KeyFileEH.txt -in DatosTopSecret.enc.txt -out DatosTopSecret.txt

Del comando previo sólo no habiamos visto, previamente, el parámetro -d con este le indicamos a OpenSsl que vamos a decifrar el archivo de entrada y ahora ya tenemos nuestro mensaje con el texto original.

 

Es probable que muchos no conocian este método, pero es una funcionalidad de OpenSSL que lleva varios años operando. Publique esta guía con la idea de actualizar el procedimiento ya que varios de los parámetros utilizados originalmente ya estan obsoletos y siempre se agradece encontrar información actualizada, además creo que es muy útil. Dentro de las pruebas que realice cifre un archivo pdf de 100MB apróx. y el proceso de cifrado y decifrado no tomo mas de un par de segundos, como mucho.

Realizaré un script en python para automatizar este proceso, pero por ahora se los quedo debiendo… #^.^#

Por último si quieren enviarme algún archivo, les comparto mi llave pública, ahora, ya saben como hacerlo.