Asymmetric cryptography (also known as public-key cryptography) is widely misunderstood.
Most non-cryptographers don't understand asymmetric cryptography at all due to the lack of a relatable, real world analogy they can reference.
Conversely, most cryptographers don't seem to understand how and why developers use asymmetric cryptography in their own software.
I believe solving both problems (first, assisting developers understand what asymmetric cryptography is and how it works; but also, ensuring cryptographers understand the business needs that lead to the inclusion of asymmetric cryptography in software) will lead to all-around better cryptography designs and non-catastrophic asymmetric cryptography deployments.
Asymmetric "Public-Key" Cryptography for Neophytes
Recommended reading: You wouldn't base64 a password!
This section is written for developers who have never heard of asymmetric cryptography before. If you're already familiar with the concepts, please feel free to skip this.
Asymmetric cryptography can get complicated quickly, as you increase the number of participants and/or design intricate forward secrecy schemes. If you've never heard of it before, however, an oversimplified explanation is warranted.
In cryptography, keys are strings of random-looking characters.
Each participant in a protocol that uses asymmetric cryptography has at least one keypair, which consists of two keys:
- Their secret key, which MUST NOT ever shared with anyone
- Their public key, which is derived from the secret key, and can shared with everyone
Unfortunately, there isn't a good real-world analogy we can point to, without muddying the waters. All you need to know is that:
- Secret keys are usually meant to be randomly generated from a CSPRNG
- You get your public key by feeding the secret key into an asymmetric cryptography function that you can treat like a black box
- The asymmetric cryptography functions designed by cryptographers are supposed to be very difficult (read: nearly impossible) to allow anyone else to take your public key and recover your secret key from it
To illustrate by example:
<?php
$secret = sodium_hex2bin("da93b1db433cfb2efe490a1bb263e440b586b6167c20b86f14cd058515806940");
$public = sodium_crypto_scalarmult_base($secret);
var_dump(sodium_bin2hex($public));
// string(64) "bfade946ef746beef397fbec6c1801d0337201c7a14f108f98c2d68a8232f027"
(You can see more examples here.)
Given only the public key ("bfade946ef746beef397fbec6c1801d0337201c7a14f108f98c2d68a8232f027"
), it's not feasible to recover the secret key ("da93b1db433cfb2efe490a1bb263e440b586b6167c20b86f14cd058515806940"
).
However, these two keys are related in a way that is useful.
Common Uses for Asymmetric Cryptography
Digital Signatures
Digital signatures allow developers to verify that a message was provided from a trusted identity.
For example: digital signatures would enable the development of secure automatic updates into WordPress (whereas, currently, if an attacker gained access to their update server, they'd be able to immediately install malware on over 30% of the websites on the Internet).
Digital signatures are extremely common. They underpin every public key infrastructure (PKI), especially the Certificate Authority system upon which Transport-Layer Security (TLS) depends.
Transport-Layer Security
TLS is the most common use-case for asymmetric cryptography, and the ones that developers and end users should be least involved with. (Thanks, LetsEncrypt, for making this almost a no-brainer.)
TLS is an online protocol that authenticates the server (and optionally the client), negotiates a shared encryption key, then encrypts normal traffic.
When HTTP is communicated over TLS, it's called HTTPS.
TLS is widely regarded as the most important cryptography protocol on the Internet, and if your website doesn't support it: You're insecure! Get TLS today; it's free.
Recently the IETF finalized RFC 8446 (TLS version 1.3), which is a considerable improvement over the previous versions of the protocol. It is my hope that every website on the Internet will one day speak a minimum of TLS 1.3. It really is that good.
However, and this may come as a surprise to some cryptography experts, TLS is NOT the end-all be-all of software developers' experience with asymmetric cryptography. Read on to learn more.
Sealing APIs: Offline Public-Key Encryption
A sealing API is one that satisfies this use case:
- Encrypt some data with a public key, in an online application; then
- Decrypt the data with the appropriate secret key, hopefully in an offline (airgapped) computer
The actual message encryption itself can (and usually does) employ symmetric cryptography, so long as the symmetric key can only be obtained by the recipient in possession of the correct secret key.
In libsodium, crypto_box_seal
generates a random ECDH keypair, performs a handshake with the long-term public key, encrypts the message using the shared secret (using an AEAD construction), then prepends the ephemeral public key to the authenticated ciphertext.
You can see this function in action here.
Why Sealing APIs Matter
The use-case of "encrypt online, decrypt offline" rears its head a lot situations. The most common you're likely to encounter are eCommerce-related.
Let's say you're storing sensitive information (e.g. credit card numbers) in a database, but don't want this information easily stolen by an attacker capable of dumping database tables. A sealing API will allow you to encrypt this information with your public key and store the ciphertext in the database. When the time comes to decrypt this data, you can load the ciphertext onto an airgapped computer, decrypt it with the secret key, then manually key in the transactions.
Unfortunately, none of NIST's Post-Quantum Cryptography Round 1 Candidates appear to be designed with this use-case in mind. The main use-case of these new cryptography designs seem to be simply: TLS.
The narrowness of use-case is particularly egregious in Learning With Errors (LWE) protocols, which have a nontrivial chance of failure built in, which in most cases would require the handshake be restarted.
You can't restart a handshake against a static public key when the corresponding secret key is offline. You won't even know if it failed.
Post-Quantum Readiness: Where to Go From Here?
There are a lot of other use cases (Authenticated Key Exchanges, cryptocurrency, the Double Ratchet from the Signal Protocol, etc.) that weren't covered here, but they're all in the long tail of uncommon requirements.
If a practical quantum computer were developed today, we have proposed designs for digital signature protocols that will likely allow software security to survive (most notably, the SPHINCS family of digital signature algorithms). We also have designs undergoing review right now that could lead to a post-quantum secure TLS in the near future.
But for software that relies on a sealing API to operate securely, there is no immediate post-quantum secure alternative to migrate to. Unless we can convince NIST and the cryptography community to consider sealing APIs a priority, those applications may be left holding the bag long after a post-quantum secure TLS is in the works.
What worries me most is, in the absence of guidance from experts, developers have a tendency to just roll their own cryptography.