Criptografía
Cifrado, codificación y hash: diferencias explicadas
Separa codificación, cifrado y hash con laboratorios de Base64, SHA-256 y OpenSSL. Entiende por qué Base64 no protege y el hash es de un solo sentido.
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.
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.
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.
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.
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:
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.
La secuencia de una versión firmada es esta:
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.
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.
openssl genpkey -algorithm ed25519 -out priv.pem
openssl pkey -in priv.pem -pubout -out pub.pemLos dos comandos no imprimen nada cuando funcionan. Revisa el resultado:
ls -l priv.pem pub.pemEn 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.
echo 'release v1.0' > msg.txt
openssl pkeyutl -sign -inkey priv.pem -rawin -in msg.txt -out msg.sig
ls -l msg.sigLa 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.
openssl pkeyutl -verify -pubin -inkey pub.pem -rawin -in msg.txt -sigfile msg.sigSalida:
Signature Verified SuccessfullyLa 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.
echo 'release v1.1' > msg.txt
openssl pkeyutl -verify -pubin -inkey pub.pem -rawin -in msg.txt -sigfile msg.sigSalida:
Signature Verification FailureEl 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.
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:
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:
identicalUn 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:
printf 'release v1.0' > nonl.txt
openssl pkeyutl -verify -pubin -inkey pub.pem -rawin -in nonl.txt -sigfile a.sigSalida:
Signature Verification Failuremsg.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:
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.sigSalida:
Signature Verification FailureEl archivo y la firma son correctos. La clave pública pertenece a otro par, así que la comprobación falla.
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.
Las normas y las páginas de manual de arriba son las referencias primarias de este artículo:
openssl-genpkeyopenssl-pkeyutlCriptografía
Separa codificación, cifrado y hash con laboratorios de Base64, SHA-256 y OpenSSL. Entiende por qué Base64 no protege y el hash es de un solo sentido.
Criptografía
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.
Criptografía
Criptografía desde cero: cifrado, claves, hashes, firmas digitales y por qué el cifrado César enseña ideas pero no protege nada.