Gabriel Cachadiña

Firmas de documentos con RSA

· Gabriel Cachadiña

Una pregunta sencilla, ¿cómo puedo firmar documentos online? La respuesta parece sencilla, simplemente añado un garabato a un PDF y lo envías de forma directa por correo, ¿no?

Ciertamente, pero al enviar un PDF,TXT,… cualquier persona puede copiar la firma que ha sido utilizada en el documento y copiarla en cualquier otro lugar o modificar el contenido del mismo documento para hacer que diga otra cosa completamente distinta a lo que se ha firmado. En el caso de una firma presencial esto se solventa teniendo a múltiples partes que verifican que la persona física ha firmado el archivo en presencia de un tercero ajeno, pero hacer esto online es imposible.. Direct Communication En esta publicación veremos cómo firmar un documento usando la utilidad openssl, de forma que sea imposible modificar el contenido o crearlo en nombre de otra persona que no sea el autor original. Para esto generaremos un archivo de firma que junto al archivo original (PDF,TXT,…) de forma que cualquier persona pueda verificar usando la firma y el archivo la veracidad de la firma y de la integridad del archivo.

Teoría

Algoritmo RSA

Obtención de parámetros

El algoritmo RSA es usado a nivel global para encriptar cualquier datos usando $3$ números, un número usado para encriptar, que llamaremos $e$; un número para desencriptar, que llamaremos $d$; y un número común, que llamaremos $c$.

En primer lugar elegiremos $2$ números primos “grandes”, a los cuales llamaremos $p_1$ y $p_2$ y haremos su producto, obteniendo así $c$: $$ c = p_1 \cdot p_2 $$ Seguidamente obtendremos el número de coprimos de este número, que para un número generado mediante el producto de $2$ números primos debe seguir la función totiente de Euler: $$ \phi(c) = (p_1-1)(p_2-1) $$ Para conseguir $e$, también denominado exponente público, deberemos tomar un número que cumpla: $$ e = 1 < e <\phi(c)\ $$ $$ e = \text{Coprimo de }c,\phi(c) $$ Y para conseguir $d$, también denominado exponente privado, tenderemos elegir cualquier número que cumpla la siguiente expresión: $$ d\cdot e(mod(\phi(c)))= 1 $$

Para generar estos números podremos usar los siguientes comandos:

1# 4096‑bit RSA private key
2openssl genpkey -algorithm RSA -out Privatekey/private.pem -pkeyopt rsa_keygen_bits:4096
3
4# Public key
5openssl rsa -pubout -in Privatekey/private.pem -out Publickey/public.pem

Encriptación y Decriptación

Para encriptar un mensaje $m$, texto o documento usaremos la llave pública, que está formada por $e$ y $c$, siendo: $$ \text{pub}(e,c) \rightarrow m^e(mod(c)) = n $$ Dándonos así un número $n$ que solo podrá ser recuperado si se usa la llave privada, es decir, si se aplica: $$ \text{priv}(d,c) \rightarrow n^d(mod(c)) = m $$

SHA256

Para generar un archivo de firma se deberá primero entender el algoritmo SHA256, que toma cualquier input de bits y lo transforma en un string de 256 bits computacionalmente único para cualquier entrada. Este algoritmo permite verificar que el contenido de un archivo no ha sido modificado, ya que cualquier modificación en el original producirá un hash completamente distinto. La explicación teórica es muy compleja, pero recomiendo encarecidamente el vídeo de RedBlockBlue que lo explica en detalle sobre el white paper original.

Firmar documentos

Para firmar documentos entonces se deberá obtener el hash del documento y encriptarlo usando la llave privada. El documento junto al hash encriptado (llamado firma) serán enviados al receptor. El receptor calcula el hash del documento recibido y lo compara con el hash recuperado al descifrar la firma (usando la clave pública). Si ambos coinciden, el documento es íntegro y la firma es auténtica. Signature

Script

A continuación dejo un pequeño script para firmar documentos y validarlos, con ello espero que quede claro el proceso completo de validación de firmas digitales:

 1#!/bin/bash
 2
 3echo "Select an operation:"
 4options=("Sign a file" "Verify a signature" "Exit")
 5select opt in "${options[@]}"; do
 6    case $REPLY in
 7        1)  # Sign a file
 8            echo "Available files to sign:"
 9            FILES=(File/*)
10            select FILE in "${FILES[@]}"; do
11                [[ -n "$FILE" ]] && break
12                echo "Invalid selection, try again."
13            done
14
15            echo "Available private keys:"
16            KEYS=(Privatekey/*)
17            select PRIVATE_KEY in "${KEYS[@]}"; do
18                [[ -n "$PRIVATE_KEY" ]] && break
19                echo "Invalid selection, try again."
20            done
21
22            BASENAME=$(basename "$FILE")
23            HASH_FILE="Hash/$BASENAME.sha256"
24            SIGN_FILE="Hash/$BASENAME.sig"
25
26            # Hash and sign
27            openssl dgst -sha256 -out "$HASH_FILE" "$FILE"
28            openssl dgst -sha256 -sign "$PRIVATE_KEY" -out "$SIGN_FILE" "$FILE"
29            rm "$HASH_FILE"
30
31            echo "Done! Signature saved to: $SIGN_FILE"
32            break
33            ;;
34        2)  # Verify a signature
35            echo "Available files to verify:"
36            FILES=(File/*)
37            select FILE in "${FILES[@]}"; do
38                [[ -n "$FILE" ]] && break
39                echo "Invalid selection, try again."
40            done
41
42            echo "Available public keys:"
43            KEYS=(Publickey/*)
44            select PUBLIC_KEY in "${KEYS[@]}"; do
45                [[ -n "$PUBLIC_KEY" ]] && break
46                echo "Invalid selection, try again."
47            done
48
49            echo "Available signatures:"
50            SIGS=(Hash/*)
51            select SIGN_FILE in "${SIGS[@]}"; do
52                [[ -n "$SIGN_FILE" ]] && break
53                echo "Invalid selection, try again."
54            done
55
56            # Verify
57            if openssl dgst -sha256 -verify "$PUBLIC_KEY" -signature "$SIGN_FILE" "$FILE"; then
58                echo "Signature is VALID."
59            else
60                echo "Signature is INVALID."
61            fi
62            break
63            ;;
64        5)  # Exit
65            echo "Exiting."
66            exit 0
67            ;;
68        *)
69            echo "Invalid option, try again."
70            ;;
71    esac
72done

#gnu/linux #math

Reply to this post by email ↪