Saltar al contenido
Nuevo

DeepSeek V4.1 Flash gratis por 7 días: 10M tokens al día tras cualquier recarga. Hasta el 30/11.

Cómo funciona

Claves pública y privada explicadas: firmas que puedes verificar

Claves pública y privada desde cero: qué prueba una firma, por qué la privada no sale de su dueño y un lab Ed25519 donde un archivo alterado falla.

Principiante10 min de lecturaPor NotHoly

La criptografía de clave pública resuelve un problema que los secretos compartidos no resuelven. Dos partes que nunca se han visto pueden acordar un secreto por una red que cualquiera puede leer. Alguien también puede demostrar que escribió un archivo, sin compartir ningún secreto con quienes lo comprueban. Las dos cosas funcionan porque un par de claves tiene dos mitades matemáticamente vinculadas. La mitad pública puede compartirse libremente. La mitad privada se queda con su dueño.

Si ya usaste TLS o SSH, ya dependiste de esta idea. El candado del navegador y el aviso de huella digital del cliente SSH dependen de claves públicas. Este artículo explica la idea que hay debajo de esas herramientas. Vas a generar un par de claves Ed25519 con OpenSSL, firmar un archivo, verificar la firma y, luego, cambiar una línea del archivo y ver cómo falla la verificación. Las versiones de software firmadas usan este mismo mecanismo, y es la base de las claves SSH que vemos en el siguiente artículo.

Qué es un par de claves

Un par de claves son dos valores generados juntos. La clave privada es secreta. La clave pública puede copiarse a un archivo, enviarse por correo o pegarse en la configuración de un servidor. Las dos están unidas por matemáticas que funcionan en un solo sentido. Derivar la clave pública a partir de la privada es fácil. Recuperar la clave privada a partir de la pública está diseñado para ser inviable.

Los criptógrafos llaman a esto criptografía asimétrica porque las dos partes usan claves distintas. La criptografía simétrica, como AES, usa un mismo secreto en ambas direcciones. Un esquema asimétrico reparte el trabajo: una clave realiza una operación y la otra la deshace o la comprueba.

Una imagen sencilla ayuda. Piensa en la clave pública como la ranura de un buzón. Cualquiera puede meter una carta por ahí, y solo el dueño tiene la llave que abre la caja. En las firmas, los papeles se invierten. El dueño sella un documento con un sello que solo él puede producir, y cualquiera con la referencia pública puede comprobar el sello. La imagen no es perfecta, porque las claves son números y no metal. Lo que conviene recordar es el sentido de cada operación.

Cifrar y firmar hacen trabajos opuestos

La gente mezcla estas dos cosas todo el tiempo, así que conviene separarlas.

Cifrar para una clave pública permite que cualquiera con tu clave pública cree un mensaje que solo tu clave privada puede abrir. El objetivo es la confidencialidad. Cualquiera puede escribirte, y solo tú puedes leer lo que escribieron.

Una firma es un valor que el titular de la clave privada calcula sobre algunos datos. Cualquiera con la clave pública puede comprobarlo. El objetivo es la autenticidad y la integridad: los datos vienen del titular de la clave, y nadie los cambió después de firmarlos. Una firma no esconde nada. Un archivo firmado sigue siendo totalmente legible para quien lo tenga.

Ed25519, el algoritmo de este laboratorio, es solo un esquema de firma. No puede cifrar un mensaje. El cifrado con clave pública usa otras construcciones, como RSA-OAEP, o un acuerdo de claves sobre curva elíptica seguido de un cifrado simétrico. Por eso "clave pública" nombra una forma de clave, no un único trabajo. Aprende primero el trabajo y después el algoritmo.

TLS usa los dos trabajos. En un handshake TLS 1.3, el servidor firma datos con la clave privada que corresponde a la clave pública de su certificado, lo que demuestra que controla esa clave. Un acuerdo de claves aparte deriva después claves simétricas que cifran la sesión. SSH sigue la misma división. Una clave de host firma parte del handshake, y una clave de usuario firma un desafío de autenticación. Una vez que separas los dos trabajos, los protocolos se leen con más claridad.

Por qué la clave privada nunca debe salir de su dueño

La clave privada es la prueba. Quien la tiene puede producir firmas que se verifican como esa identidad y puede descifrar mensajes cifrados para ella. El verificador no ve tu cara ni tu nombre. Comprueba una firma con la clave pública en la que confía. Si alguien copia tu clave privada, todo verificador que confía en tu clave pública acepta la copia como si fueras tú.

De esto salen cuatro reglas prácticas:

  • Genera la clave privada en la máquina que la va a usar, o en un token de hardware diseñado para eso. No descargues una clave privada de una web ni la recibas en un chat.
  • Restringe los permisos del archivo. Protege la clave con una frase de contraseña cuando la herramienta lo permita, o guárdala en un almacén respaldado por hardware.
  • Mantenla fuera de Git, de tickets, de capturas de pantalla y de las solicitudes de soporte. Los escáneres de secretos buscan cabeceras PEM. Cuando una clave llega al historial de un repositorio, trátala como expuesta, aunque después borres el archivo.
  • Si sospechas que se expuso, retira esa clave. Crea un par nuevo, publica la nueva clave pública por un canal en el que confíen tus verificadores y revoca la anterior. Borrar el archivo local no elimina las copias que ya salieron de tu máquina.

Compartir la clave pública es seguro por diseño. El problema difícil va en la otra dirección. Un verificador debe saber que una clave pública pertenece de verdad a la persona o al proyecto que dice representar. Las autoridades de certificación, las claves de release fijadas y las huellas de host SSH existen para resolver exactamente ese problema. Una firma válida demuestra que el titular de la clave firmó esos bytes. No demuestra que el titular sea quien esperabas.

Cómo firmar y verificar, paso a paso

La secuencia de una versión firmada es esta:

  1. El publicador genera un par de claves una vez y mantiene la clave privada en secreto.
  2. El publicador comparte la clave pública por un canal en el que confía el verificador, como una página que el verificador ya conoce, una huella publicada en un segundo lugar o una clave verificada antes.
  3. En cada versión, el publicador firma los bytes exactos del archivo con la clave privada. Una firma Ed25519 mide 64 bytes.
  4. El publicador distribuye el archivo y su firma juntos.
  5. El verificador ejecuta la comprobación con los bytes del archivo, la firma y la clave pública de confianza. El resultado es válido o no válido.

Dos detalles importan más de lo que parecen. Primero, una firma cubre bytes exactos. Un espacio de más, un fin de línea distinto o un paquete reempaquetado es otro mensaje, y la verificación falla. Segundo, la firma Ed25519 de la RFC 8032 es determinista. La misma clave y el mismo mensaje producen siempre la misma firma, así que firmar no necesita un número aleatorio nuevo cada vez. Eso elimina una fuente común de fallos. La FIPS 186-5 incluye EdDSA junto con ECDSA y RSA como algoritmos de firma digital aprobados.

Laboratorio práctico: firma un archivo y mira fallar la verificación

Necesitas OpenSSL 3.x. La salida de este laboratorio viene de Windows 11 con Git Bash y OpenSSL 3.2.4. Revisa tu versión con openssl version antes de empezar. Las versiones antiguas pueden no aceptar las mismas opciones.

Usa Git Bash, una shell de Linux o Terminal en macOS. Windows PowerShell 5.1 escribe UTF-16 cuando rediriges con >, y eso cambia los bytes que firmas. Ejecuta el laboratorio en una carpeta vacía de tu propia máquina. No contacta ningún servidor.

Genera el par de claves

bash
openssl genpkey -algorithm ed25519 -out priv.pem
openssl pkey -in priv.pem -pubout -out pub.pem

Los dos comandos no imprimen nada cuando funcionan. Revisa el resultado:

bash
ls -l priv.pem pub.pem

En nuestra máquina, priv.pem tenía 122 bytes y pub.pem tenía 116 bytes. Abre pub.pem y verás el bloque -----BEGIN PUBLIC KEY-----. No imprimas ni pegues priv.pem. En este laboratorio es la mitad secreta de la identidad, y acostumbrarte a no mostrarla es un hábito que también necesitarás con las claves SSH.

Firma el archivo

bash
echo 'release v1.0' > msg.txt
openssl pkeyutl -sign -inkey priv.pem -rawin -in msg.txt -out msg.sig
ls -l msg.sig

La opción -rawin indica a OpenSSL que firme el contenido del archivo directamente. Ed25519 calcula el hash de su entrada dentro del propio algoritmo, así que no calculas el hash del archivo antes. El comando de firma no imprime nada. Nuestro msg.sig tenía 64 bytes.

Verifica con la clave pública

bash
openssl pkeyutl -verify -pubin -inkey pub.pem -rawin -in msg.txt -sigfile msg.sig

Salida:

text
Signature Verified Successfully

La opción -pubin dice que el archivo de clave contiene solo la mitad pública. El verificador no necesita nada más, así que esta comprobación puede correr en otra máquina que nunca vio el priv.pem.

Cambia una línea y verifica de nuevo

bash
echo 'release v1.1' > msg.txt
openssl pkeyutl -verify -pubin -inkey pub.pem -rawin -in msg.txt -sigfile msg.sig

Salida:

text
Signature Verification Failure

El comando termina con estado 1. La firma de msg.sig se hizo sobre release v1.0, así que no puede respaldar release v1.1. OpenSSL no dice qué cambió. Solo informa de que los bytes y la firma no coinciden. Un verificador debe tratar ese resultado como un alto obligatorio, no como una advertencia que se puede ignorar.

Prueba los bordes

Estas comprobaciones muestran exactamente qué cubre la firma. Ejecutamos cada una en la misma máquina, en la misma carpeta.

Firmar el mismo archivo dos veces da los mismos bytes:

bash
echo 'release v1.0' > msg.txt
openssl pkeyutl -sign -inkey priv.pem -rawin -in msg.txt -out a.sig
openssl pkeyutl -sign -inkey priv.pem -rawin -in msg.txt -out b.sig
cmp a.sig b.sig && echo "identical"

Salida:

text
identical

Un archivo sin el salto de línea final falla. echo agrega un salto de línea, así que este archivo queda un byte más corto:

bash
printf 'release v1.0' > nonl.txt
openssl pkeyutl -verify -pubin -inkey pub.pem -rawin -in nonl.txt -sigfile a.sig

Salida:

text
Signature Verification Failure

msg.txt tiene 13 bytes y nonl.txt tiene 12. La firma se hizo sobre la versión de 13 bytes, así que el archivo más corto falla.

Un par de claves distinto también falla, incluso con el archivo original:

bash
openssl genpkey -algorithm ed25519 -out other.pem
openssl pkey -in other.pem -pubout -out other.pub
openssl pkeyutl -verify -pubin -inkey other.pub -rawin -in msg.txt -sigfile a.sig

Salida:

text
Signature Verification Failure

El archivo y la firma son correctos. La clave pública pertenece a otro par, así que la comprobación falla.

Errores comunes

  • Tratar una firma como cifrado. Un archivo firmado sigue siendo legible para cualquiera. Si necesitas secreto, necesitas cifrado, que es otra construcción.
  • Confiar en cualquier clave pública que encuentres. Una firma válida demuestra que el titular de la clave firmó los bytes. No demuestra quién es ese titular. Compara huellas por un segundo canal.
  • Verificar bytes distintos de los firmados. Un pipeline que recodifica, recomprime o cambia los fines de línea rompe la verificación. Firma el artefacto final y verifica ese mismo artefacto.
  • Firmar en una shell que reescribe bytes. La redirección de Windows PowerShell 5.1 es un ejemplo. Los editores que guardan con otra codificación o con otro fin de línea son otro.
  • Reutilizar una clave para todo. Claves separadas para firmar versiones, entrar por SSH y cifrar limitan el daño cuando una se filtra.
  • Suponer que una clave borrada ya no existe. Las copias en backups, carpetas sincronizadas, historial de la shell o registros de chat sobreviven a un borrado local.
  • Elegir primitivas por el nombre. "RSA" o "ECC" no dicen qué relleno, curva o modo se usa. Lee los parámetros en la norma, no solo la etiqueta.

Cómo seguir

El próximo artículo, ¿Qué es SSH y cómo funcionan las claves SSH?, usa esta misma idea de firma para los inicios de sesión. Si tienes archivos id_ed25519, son un par exactamente de este tipo. Lee también el artículo sobre hash de contraseñas, porque las contraseñas y las claves resuelven partes distintas de la autenticación, y conviene no mezclarlas.

Para profundizar, lee la RFC 8032 para ver cómo Ed25519 estructura sus firmas y por qué es determinista. Lee la FIPS 186-5 para ver dónde encaja EdDSA entre los algoritmos de firma aprobados. Lee las páginas de manual de genpkey y pkeyutl de OpenSSL para conocer las demás opciones, como la selección de digest en los algoritmos que la necesitan. Después, verifica una versión de un proyecto que ya uses, con la clave que el propio proyecto publica en su sitio. Ejecuta solo archivos descargados de la fuente oficial y solo después de comprobarlos.

Fuentes

Las normas y las páginas de manual de arriba son las referencias primarias de este artículo:

  • RFC 8032, Edwards-Curve Digital Signature Algorithm (EdDSA)
  • FIPS 186-5, Digital Signature Standard (DSS)
  • Documentación de OpenSSL, openssl-genpkey
  • Documentación de OpenSSL, openssl-pkeyutl

Fuentes

  1. RFC 8032: Edwards-Curve Digital Signature Algorithm (EdDSA)
  2. FIPS 186-5: Digital Signature Standard (DSS)
  3. OpenSSL documentation: openssl-genpkey
  4. OpenSSL documentation: openssl-pkeyutl

Más en Criptografía

Criptografía

Contraseñas y hash con Argon2id

Por qué los hashes rápidos fallan con contraseñas, qué hacen la sal y el factor de trabajo, y cómo hashear y verificar con Argon2id en Python.

Intermedio11 min de lectura