Encriptación avanzada con GNU Privacy Guard

Publicado el 05 julio 2013 por Iyanmv @iyanmv

Hace unos días veíamos como encriptar y firmar archivos en KDE con la interfaz gráfica KGpg. En esta entrada quiero profundizar un poco más en el tema utilizando únicamente la terminal con GNU Privacy Guard, normalmente abreviado a simplemente GPG, la implementación libre del estándar OpenPGP.

Todas las distribuciones, o el 90% de ellas, incluyen gpg en su instalación base. Más que nada porque los gestores de paquetes (yum, pacman, synaptic…) utilizan estas herramientas para comprobar la integridad y origen de los paquetes y actualizaciones. Os recomiendo que echéis un vistazo al manual del programa antes de seguir leyendo, aunque solo sea una lectura rápida.

$ man gpg

Voy a suponer que ya tenemos nuestra pareja de claves creada y algunas claves públicas importadas y firmadas. Lo primero que nos puede interesar es encriptar un mensaje que tenemos guardado en un archivo de texto llamado mensaje.txt:

$ gpg --recipient destinatario --encrypt mensaje.txt

Esto nos generará un .gpg con el mismo nombre del archivo de texto y que estará encriptado con la clave pública que hayamos escogido en el parámetro –recipient. Podéis poner cualquier información que identifique la clave: la ID, el nombre (o incluso una parte) o el correo. Si se os olvida poner un recipiente el programa os preguntará por él, no os preocupéis. Este archivo de extensión .gpg no es un archivo de texto normal, si no que es un binario. Está bien si queremos adjuntarlo y compartirlo, pero si queremos copiar el contenido encriptado en el cuerpo de un correo necesitaremos caracteres “normales”. Para que me entendáis, probad a abrir el archivo .gpg con un editor de texto plano, como Kate o Gedit. Para conseguir una encriptación en texto plano podemos usar la opción –armor, que lo que hará será generar una salida ASCII. Para diferenciarlo del binario, el archivo se creará con la extensión .asc.

$ gpg --armor --recipient destinatario --encrypt mensaje.txt

Después de encriptar, lo más habitual es firmar archivos para que todo el mundo pueda verificar que efectivamente fuiste tú el que subió ese documento o escribió un mensaje determinado. La forma más sencilla sería escribiendo simplemente:

$ gpg --sign mensaje.txt

El problema es que nuevamente obtenemos un binario, y el mensaje original (si era texto)  ya no se podrá ver. Para conseguir un archivo firmado en el que el texto siga siendo legible podemos usar este otro comando:

$ gpg --clearsign mensaje.txt

El .asc que se genera tendrá una sección central en la que podremos leer el mensaje sin cifrar tal cual. En ambos casos, comprobar la firma es muy sencillo, siendo el único requisito disponer de las claves públicas apropiadas (la pareja de la clave con la que se ha firmado).

$ gpg --verify mensaje.txt.gpg

Aunque es más habitual usar la opción de desencriptar ya que, además de comprobar la firma, creará un archivo con el mensaje limpio (generalmente con la extensión .clear), tal cual lo escribió el firmante:

$ gpg --decrypt mensaje.txt.gpg

Y os estaréis preguntando, ¿si usamos la opción –armor con –sign no obtendremos lo mismo que con –clearsign? Pues no, aunque ambos son archivos de texto, en el primero no veremos el mensaje firmado mientras que en el segundo sí. Haced la prueba y lo veréis.

Se me olvidaba comentar, que si tenemos más de una clave privada tenemos que especificar que clave queremos usar para firmar. De no hacerlo se utilizará la clave por defecto que podéis modificar en el archivo de configuración (~/.gnupg/gpg.conf). Para elegir la clave se hace uso del parámetro –local-user, por ejemplo:

$ gpg --local-user 723F4C25 --sign mensaje.txt

Tenemos un tercer método para firmar. Los dos que hemos visto arriba son útiles para texto simple que podemos enviar en el cuerpo de un correo o insertar en una web, pero si por ejemplo, queremos firmar un comprimido zip y no queremos modificarlo, podemos generar una firma en un archivo separado. La única pega (si es que se puede considerar pega) es que tendremos que enviar los dos archivos en vez de uno solo. Para generar esta firma se hace uso del parámetro –detach-sign:

$ gpg --detach-sign datos.zip

Esto nos creará un binario .sig con la firma. Aquí también podéis hacer uso de –armor para obtener la firma en ASCII. Para verificar la firma ahora usaríamos el siguiente comando:

$ gpg --verify datos.zip.sig datos.zip

Tanto si la firma es incorrecta, como si el comprimido ha sido modificado, nos devolverá un error. Daros cuenta que aquí carece de sentido utilizar –decrypt ya que el comprimido no está encriptado.

Para acabar la entrada me gustaría hacer una aclaración y poner un ejemplo práctico. Todos los comandos que he escrito arriba tienen una versión abreviada pero para aprender es útil escribir el parámetro entero. Por ejemplo, esta es una versión reducida del comando de encriptar que puse arriba en formato texto:

$ gpg -ar destinatario -e mensaje.txt

Y el ejemplo práctico será generar un archivo CHECKSUM, muy parecido a los que usa Fedora para autentificar sus iso. Supongamos que tenemos una imagen que hemos creado nosotros y queremos compartirla. La gente confía en que tu imagen está libre de virus y funciona perfectamente. Pero, ¿cómo pueden estar seguros que la imagen que se han descargado es efectivamente la que tu has creado y no ha sido modificada? Hay muchas formas pero vamos a seguir el estilo de Fedora, generar un archivo con el hash SHA-256 de la imagen y firmando este archivo con nuestra clave privada:

$ sha256 imagen.iso | gpg --clearsign > imagen-CHECKSUM

Ahora podríamos compartir los dos archivos y cualquier usuario podría verificar la integridad de la imagen con el hash firmado de la siguiente manera:

$ gpg --decrypt datos-CHECKSUM | sha256sum -c