Public-key cryptography
Understand public and private keys
Use a shareable public key and protected private key while keeping encryption, agreement, and signing purposes distinct.
Public-key cryptography splits a key into two parts: a public one and a private one. They are mathematically linked. What one does, only the other can undo or verify. The private key never becomes public.
This solves the problem symmetric keys cannot solve: working with someone you have never shared a secret with. You publish the public key to anyone. You guard the private key like the secret it is.
Let’s generate a pair in Node:
import { generateKeyPairSync } from 'node:crypto'
const { publicKey, privateKey } = generateKeyPairSync('ed25519')
publicKey.export({ type: 'spki', format: 'pem' })
// -----BEGIN PUBLIC KEY----- <- share this freely
privateKey.export({ type: 'pkcs8', format: 'pem' })
// -----BEGIN PRIVATE KEY----- <- never leaves your control
One pair, one purpose
A key pair can do key agreement, encryption, or signatures, depending on the construction. With signatures, the private key signs and anyone verifies with the public key. With encryption, anyone encrypts to the public key and only the private key decrypts.
Some algorithms only do one job. Ed25519 keys sign. X25519 keys do key agreement. They are not interchangeable, even though they are built on the same curve.
Even when the math allows one pair to do several jobs, don’t. Keep signing keys, encryption keys, and key-agreement keys separate. If one leaks or gets misused, the damage stays inside one purpose. A leaked TLS key should never also be your release-signing key.
You already use these pairs every day. Your SSH key is one (~/.ssh/id_ed25519 and id_ed25519.pub). TLS server keys are another. So are package and commit signing keys.
Public does not mean trusted
A public key still needs an authenticated way to bind it to the identity you expect. This is the part that trips people up.
Say an application downloads a public key from the same unauthenticated response as the signed update. An attacker replaces the update, the signature, and the public key together. Every mathematical check passes. The attacker signed their malware with their own key and handed you the matching verifier.
Public means shareable. It does not mean trusted. The link between a key and an identity has to come from somewhere the attacker does not control: a certificate chain, a key pinned at install time, or a fingerprint you checked over a different channel.
The SSH host key prompt on a first connection is exactly this question. SSH can verify the key, but it cannot tell you whose it is. Only you can. That binding problem is what the rest of this module is about.
Try this on your own: for an SSH login, a TLS site, and a package-signing workflow, list which material is public and which is private, and write down how each public key earns its trust. Verify one signed test message with the expected public key. Then generate a second, attacker-controlled key pair and show why the math alone cannot tell the two apart.
Lesson completed