Prologue: When SSH Keys Felt Like Black Magic
I still remember the first time I tried to push code to GitHub. For a while, I'd been typing my password every single time. Then one day, boom: "Password authentication is removed." I panicked.
Stack Overflow told me to generate an SSH key. I ran ssh-keygen and got two files: id_rsa and id_rsa.pub. The instructions said to upload the public key to GitHub and keep the private key on my machine. My brain immediately asked: "Wait, if one key is public, how is this secure?"
I felt like I was missing something fundamental. If someone steals my public key, can't they decrypt my stuff? But the name literally says "public"... you're supposed to share it? That made no sense.
This confusion led me down a rabbit hole into public-key cryptography, and eventually, everything clicked. Here's how I made sense of it.
The Fundamental Problem with Symmetric Keys
When you first learn about encryption, you encounter symmetric keys. Same key for encryption and decryption. You lock something with password 1234, you unlock it with 1234.
# Symmetric encryption example (AES)
from cryptography.fernet import Fernet
# Generate key (used for both encrypt and decrypt)
key = Fernet.generate_key()
cipher = Fernet(key)
# Encrypt
message = b"This is secret"
encrypted = cipher.encrypt(message)
# Decrypt (same key)
decrypted = cipher.decrypt(encrypted)
print(decrypted) # b"This is secret"
The problem isn't the encryption itself. It works great. The problem is: How do you give the key to the other person?
If you send the key over the internet, someone can intercept it. If you have a secure way to send the key, why not just use that secure method to send the message itself? This is called the Key Distribution Problem, and it plagued cryptography for decades.
Then came asymmetric encryption.
The Core Insight: Lock and Key Are Separate Things
Asymmetric encryption uses two keys. One is the public key, one is the private key. I understood this through a physical metaphor: locks and keys.
- Public Key = Lock: Anyone can take it. Anyone can close it. But you can't open it without the key.
- Private Key = Key: Only I have it. Only this can open the lock.
Let's say I want my friend to send me a secret message:
- I send my public key (lock) to my friend. Even if someone intercepts it, who cares? It's just a lock.
- My friend encrypts the message using my public key (locks the box).
- If someone intercepts the encrypted message, they can't open it. They don't have my private key.
- I decrypt it with my private key (unlock the box).
The magic is this: What's locked with the public key can only be unlocked with the private key. And vice versa. This isn't magic, it's math. Algorithms like RSA make this possible.
How RSA Works: Multiplication Is Easy, Factorization Is Hard
RSA is based on a simple fact: multiplying two big prime numbers is easy. Factoring the result back into those primes is extremely hard.
For example: 61 × 53 = 3233 takes a calculator one second. But if I give you 3233 and ask "what two primes multiply to this?", it takes time to figure out (and if the number is hundreds of digits long, it would take supercomputers decades).
Simplified RSA key generation:
- Pick two large prime numbers (
pandq). - Multiply them:
n = p × q. (Thisnbecomes public.) - Use math to derive a public exponent
eand private exponentd. - Public key is
(n, e). Private key is(n, d). - Encrypting with the public key can only be decrypted with the private key.
I understood this as a trapdoor function. Easy to go one way, impossible to reverse without secret information.
How HTTPS Actually Works: The TLS Handshake
When I first learned about HTTPS, I thought: "Does this mean all communication is encrypted with asymmetric keys?" Nope. Asymmetric encryption is 100-1000x slower than symmetric. So the real-world solution is a hybrid approach.
Here's what happens in a TLS Handshake:
- Browser connects to server.
- Server sends its public key (inside a certificate).
- Browser generates a random session key (symmetric key).
- Browser encrypts this session key with the server's public key and sends it.
- Server decrypts the session key using its private key.
- From now on, all communication uses the symmetric session key.
So asymmetric encryption is only used to securely exchange the symmetric key. Once both sides have the session key, they switch to faster symmetric encryption. This blew my mind when I realized it. TLS Handshake isn't about encrypting everything asymmetrically—it's about solving the key distribution problem.
Digital Signatures: Using It Backwards for Authentication
Asymmetric encryption can be used in reverse. Instead of encrypting with public key and decrypting with private key, you can encrypt with private key and decrypt with public key. This doesn't provide secrecy—it provides authenticity.
At first, I thought: "Why would you encrypt something with your private key if everyone can decrypt it with the public key?" Then I realized: that's the point. If something can be decrypted with my public key, that proves it was encrypted with my private key. And only I have my private key.
This is called a digital signature. Here's how it works:
- I write a document.
- I hash the document and encrypt the hash with my private key. (This is the signature.)
- I send the document and the signature.
- You decrypt the signature with my public key to get the hash.
- You hash the document yourself and compare. If they match, you know: (a) I wrote this, and (b) it hasn't been tampered with.
This is how Git commit signing, software distribution, and blockchain transactions work.
SSH Authentication: Logging In Without Passwords
Let's revisit that moment when I generated my first SSH key. SSH authentication is one of the most practical uses of asymmetric cryptography.
# Generate SSH key pair
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
# Result:
# ~/.ssh/id_rsa (private key - never share)
# ~/.ssh/id_rsa.pub (public key - upload to GitHub)
Here's how SSH authentication works:
- You upload your public key to the server (e.g., GitHub).
- When you try to connect, the server sends you a random challenge.
- Your computer signs the challenge with your private key.
- The server verifies the signature using your public key.
- If verification succeeds, the server knows you have the private key and lets you in.
The beauty of this: your private key never leaves your machine. Unlike passwords, which travel over the network, SSH keys keep the secret local. Even if someone intercepts the signature, they can't reverse-engineer the private key from it.
Implementing It in Node.js: Encryption and Signatures
Theory is one thing, but I needed to see it in action. Here's how I implemented public-key cryptography in Node.js:
const crypto = require('crypto');
// 1. Generate RSA key pair
const { publicKey, privateKey } = crypto.generateKeyPairSync('rsa', {
modulusLength: 2048,
publicKeyEncoding: { type: 'spki', format: 'pem' },
privateKeyEncoding: { type: 'pkcs8', format: 'pem' }
});
console.log('Public Key:\n', publicKey);
console.log('Private Key:\n', privateKey);
// 2. Encryption (lock with public key)
const message = 'This is a secret message';
const encrypted = crypto.publicEncrypt(
publicKey,
Buffer.from(message)
);
console.log('Encrypted:', encrypted.toString('base64'));
// 3. Decryption (unlock with private key)
const decrypted = crypto.privateDecrypt(
privateKey,
encrypted
);
console.log('Decrypted:', decrypted.toString()); // "This is a secret message"
// 4. Signing (sign with private key)
const sign = crypto.createSign('SHA256');
sign.update(message);
const signature = sign.sign(privateKey, 'base64');
console.log('Signature:', signature);
// 5. Verification (verify with public key)
const verify = crypto.createVerify('SHA256');
verify.update(message);
const isValid = verify.verify(publicKey, signature, 'base64');
console.log('Signature valid:', isValid); // true
Running this code made it real. I could see that encrypting with the public key truly requires the private key to decrypt. And signing with the private key can only be verified with the public key. It's not theoretical—it's mathematical certainty.
Blockchain Wallets: Why Your Public Key Is Your Address
When you create a Bitcoin or Ethereum wallet, you get a stern warning: "DO NOT LOSE YOUR PRIVATE KEY." In blockchain systems, your public key is your account address, and your private key is your withdrawal authority.
- Public Key (Wallet Address): Anyone can send money here.
- Private Key: The only proof that you can spend the money.
When you make a transaction:
- You create a message: "Send 0.1 BTC from address A to address B."
- You sign this message with your private key.
- The network verifies the signature using your public key.
- If verification succeeds, the transaction is added to the blockchain.
Banks have a central authority that says "yes, this person is allowed to withdraw." Blockchain replaces that with mathematical proof (signatures). If you lose your private key, there's no customer support to call. The money is gone forever. That's why the warning is so serious.
Certificate Authorities: How Do You Trust a Public Key?
When you visit a website over HTTPS, the server sends you its public key. But how do you know it's the real public key and not a fake one from an attacker doing a man-in-the-middle attack?
This is where certificates and Certificate Authorities (CAs) come in. A CA is a trusted third party that says: "I verify that this public key really belongs to google.com."
The CA signs the public key with its own private key. Your browser has a built-in list of trusted CAs, so it can verify the CA's signature. If the signature checks out, you trust the public key.
Once I understood this, I finally got why Let's Encrypt was such a big deal. Before, you had to pay for certificates from CAs. Let's Encrypt automated the process and made it free, democratizing HTTPS for everyone.
PGP and Email Encryption: An Underused Tool
Email is inherently insecure. It travels through multiple servers, any of which could read it. PGP (Pretty Good Privacy) and GPG (GNU Privacy Guard) use public-key cryptography to encrypt emails.
Here's the workflow:
- I generate a PGP key pair.
- I publish my public key (often to a key server).
- If you want to send me an encrypted email, you encrypt it with my public key.
- Only I can decrypt it with my private key.
You can also sign emails with your private key to prove you wrote them. It's a beautiful system, but adoption is low because it's not user-friendly. Most people don't know how to use GPG, and email clients don't make it easy.
But in privacy-conscious circles (journalists, activists, security researchers), PGP is essential. If you're handling sensitive information, it's worth learning.
Code Signing: Trusting Software Downloads
When you download software, how do you know it hasn't been tampered with? Code signing uses digital signatures to verify the authenticity of software.
Here's how it works:
- Developer signs the software with their private key.
- You verify the signature with the developer's public key (often distributed via a certificate).
- If the signature is valid, you know: (a) the software came from the developer, and (b) it hasn't been modified.
Operating systems enforce this. macOS won't run unsigned apps without a warning. Windows SmartScreen flags unsigned executables. Mobile app stores require code signing.
This is why the recent supply-chain attacks (like the SolarWinds hack) are so serious. If attackers can compromise the signing process, they can distribute malicious code that looks legitimate.
The Metaphor That Made It Click: Mailboxes
After all this learning, I found one final metaphor that tied everything together: mailboxes.
A mailbox has a slot (public) and a key (private). Anyone can drop a letter through the slot, but only the owner can open the mailbox and read the letters. You can distribute as many mailbox slots as you want—it doesn't compromise security because only one key opens it.
This is public-key cryptography. The public key is the mail slot. The private key is the key to the mailbox. You can give out the slot to anyone, but you guard the key with your life.
Wrapping Up: Math-Based Trust
Public-key cryptography feels like magic: "How can I share a key publicly without compromising security?" But it's not magic. It's math. The difficulty of prime factorization. The properties of modular arithmetic. These mathematical truths underpin the security of the modern internet.
When I first generated that SSH key for GitHub, I didn't understand why it worked. Now I know: the public key is a lock. You can copy it, share it, plaster it on billboards—it doesn't matter. Without the private key, it's useless. And the private key stays with you, always.
This simple principle powers HTTPS, SSH, blockchain, email encryption, and software distribution. Next time you wonder "how does this service stay secure?", nine times out of ten, the answer is public-key cryptography.
And now, whenever I run ssh-keygen, I don't see random files. I see a mathematical guarantee of trust.