How do I Know It’s Really You? Verifying Authenticity of Public Keys
One of the most perplexing problems in cryptography is the process of verifying that a public key has not been replaced by an imposter…
One of the most perplexing problems in cryptography is the process of verifying that a public key has not been replaced by an imposter. The technical term for this is Man in the Middle Attack.
The industry has fumbled through a variety of poor user experiences trying to please a wide spectrum of people from those who just want to post selfies to the ultra paranoid crypto geek.
Before we go too far, let’s talk about some of the common cryptographic building blocks used in apps today.
The Secure Hash
Let’s start with the secure hash function. While there are lots of great hash functions to choose from, they all have similar properties. They reduce a variable length string of bits or data into a fixed length value in a deterministic way. Given the same input, it reproduces the same result over and over again.
So let’s say we take all the text that comprises your favorite movie script, or the bits from your last instagram selfie photo, and run it through one of these hash functions like SHA-256. It would give us back a 256 bit value. This value obviously doesn’t hold enough information to derive the input that created the hash, it’s a one way process. It’s not possible to work backwards from the hash to determine the original source of data. In fact, any slight change in the input, like a pixel in the photo or a word in the script will result in a radically large change in the hash value.
For example, let’s assume we had a secure hash of script from the original “Planet of the Apes”. This hash would be very different from hash of a slight revision of it the script, or a complete rewrite. The idea is that given enough bits these collisions become mathematically highly improbable.
What’s nice about this is that the result of the hash function can be used as an index to compare the source data with the hash of a duplicate of it without keeping the original data around.
The Public Key Algorithm
Another other major building block that holds the internet together is Public Key Cryptography. Public key algorithms use mathematically derived pairs of values that allow you encrypt data with one key and decrypt it with the other. Not surprisingly, one of these values is called the Public Key and the other the Private Key. What is important about these algorithms is that you cannot derive much about the original message from encrypted data nor can you reverse the process without the possession of the private key.
Many of the Public key algorithms out there can also serve as a way to digitally sign data, in that the Private key can be used to produce a result that the Public key can verify. So given the original text, you can attach a series of bits that only could be created by the person who possess the private key and verified by anyone who has a copy of the public portion of the key pair.
In practice, Public key algorithms only work with a fixed number of bits, so typically its the secure hash of a text that is fed into the public key algorithm along with the private key to produce the signature.
Binding identity to a key
To make public keys useful in the real world, we bind other information associated with the owner of that key; the owner’s email address, a user displayable name, the date a key was created or possibly an expiration date. All of this information can be fed into a hash algorithm in a predictable order along with the actual bits of the public key and the hash result signed by the private key. This is called the key self-signature or identity certificate.
That pesky middle-man
Assuming that all cool tech from public keys and secure hashes work and haven’t been hacked somehow, a question that presents itself is, “How do I know that the key that signed this message is not a fake?” To be more specific, how do I know that this message signature and the public key I am using to check it with are authentic and have not fallen victim to the Man in the Middle Attack.
Let’s look at how such a subterfuge can be orchestrated:
Alice creates a key pair and publishes her public key on a server that she considers trustworthy.
Alice then sends Bob a note that she signs with her public key.
Bob receives a message from Alice for the first time, and intending to authenticate the message, request a copy of Alice’s public key from the same server.
But somewhere along the line, a sneaky interloper hacks into the internet connection that Bob uses, intercepts Bob’s lookup for Alice’s public key and provides him with a counterfeit copy. Further this same scoundrel has modified Bob’s incoming message traffic to intercept and modify Alice’s messages and re-sign them with the counterfeit key.
Bob won’t be any wiser of this ruse and for all practical purposes will find Alice’s modified message signature to be authentic.
Traditionally defending against such an attack has employed one of two strategies or a hybrid of both: signing public key material with another public key you trust, or out of band key validation.
Since public keys are just a series of bits they can be fed into a hash algorithm and the hash results can be compared to check with a known copy.
This is how the earliest crypto applications verified key authenticity. Participants would manually compare the key hash results. Back then we were using the SHA-1 hash of 160 bits, which is 20 bytes or 40 hexadecimal characters. Sometimes we took a shortcut and only compared 8 or 16 of the hex characters.
We even tried some other innovative approaches such as mapping the hash values to know word lists or mnemonic encoding. As smart phones with integrated cameras became popular we even experimented with bar code methods.
All of this was pretty tedious, easy to get this wrong and not something that you could sell to mass market. This fact became evident while I was developing secure communications apps at Silent Circle and PGP. No matter how we simplified it, most people simply ignored the hash comparison process altogether.
Signing public key with a trusted key
For applications such as web browsers the canonical approach to verifying the authenticity of a public key is to sign it with another public key that you trust. These certificates are chained together with public key signatures signed by a trusted certificate authority in a hierarchal model. But how do we bootstrap the trust? The modern solution is to distribute the root public keys/certificates with the operating system or web browsers.
Of course none of this comes for free. With this model you pay rent for the signature on your public key from a certificate authority. (they have an expiration date). An entire billion dollar industry was pioneered by Verisign to perform this exact function. As a side note, somewhere in my garage I still have a floppy disks from the early nineties with my AOCE/PowerTalk developer RSA keys that Apple Computer signed.
Aside from the cost of signature, and the possibility that a certificate authority could misbehave and issue an unauthorized certificate, the hierarchal model isn’t always appropriate. As an alternative to the certificate authority the OpenPGP model allowed you to attach multiple signatures from other keys to your key creating a sort of Web of Trust model. You can even hybrid both hierarchal and web model to fabricate a trusted introducer model.
Either way, these modes require the signer to do some due diligence to verifying your key before signing, which brings us back to comparing hashes.
Enter the Blockchain
There is so much information about blockchain technology available today, and I won’t attempt to waste any bits rehashing the topic here but leave it to the reader to dive into that topic. I would though like to make clear a few key concepts:
A blockchain is a tamper proof ledger of records securely linked to previous entries using a cryptographic hash.
Since the current entries hash included the previous entries hash, tampering with a past entry would invalidate any of the subsequent hash values.
The blockchain is open to the public and widely replicated and distributed making tampering effectively impractical.
When I refer to the blockchain, I am specifically talking about the Ethereum distributed computing platform. What makes this platform so attractive is that the entries can consist of code or what is referred to as smart contracts. In addition to be executable on the blockchain platform, these smart contract functions can retain state between calls. Ethereum allows code that just reads state to be publicly executed, but using strong cryptography it ensures that code that modifies state only be called by the owner of the contract.
The other thing that I find fascinating about the Ethereum platform is there is a complete micropayment economy attached to paying for code that modified the blockchain that provides incentive for people to put additional blockchain nodes on the network.
What ZeroDark.cloud does
ZeroDark.cloud is a zero-trust Security as a Service, layered on top of AWS. This service includes an open-source (available for audit) developer framework that handles all the syncing, encryption, networking, messaging, notifications, and setup. The data your app syncs is automatically end to end encrypted on your device to your public key before being uploaded to the cloud. The server cannot read any of your data, filenames or meta-data.
When you share your data with other customers of ZeroDark.cloud it automatically encrypts it to the recipients public key. And thus the point of this blog post. “How do I know that I am encrypting my data to the recipients actual key and that there is no man in the middle attack taking place?.”
Lets start by looking at what happens when you create a ZeroDark.cloud user account for the first time:
An ECC Curve41417 private / public key pair is automatically generated on your device.
You bind your account to one or more social media accounts (or optionally create an account with no social media associations). The binding between your user identity (social ID) and your key is self-signed into your key and that public key is uploaded to the ZeroDark.cloud server.
The server then adds an entry to the Ethereum blockchain, binding the public key to that customer. Mitigating man-in-the-middle attacks.
Each object, any associated metadata, thumbnails, and attributes you upload to the cloud is protected with a separate, randomly generated, ThreeFish 512-bit key. Even the filename is encrypted and never exposed.
Similarly the objects names in the cloud are created by a cryptographic pseudo random number generator (PRNG)
The 512-bit file encryption symmetric keys are then encrypted to each user that you share the file with using the ECC Curve41417 public key algorithm in a form of ECC–DH Encryption. Similar, but not exactly compliant to ANSI X9.63, we produce a random key, hash it, and XOR the digest against the file encryption key.
All of this is done for the app developer automatically. They don’t need to have extensive cryptography knowledge. They don’t need to spend months obtaining AWS expertise or risk fumbling AWS credentials
Blockchain-based public key verification
The process of getting a public key binding on the Ethereum blockchain requires a bit of work. But the salient points are:
ZeroDark.cloud has a smart contract on the blockchain. This takes the 160 bit/20 byte customer id and a hash of the user’s public key (typically SHA-256) and stores them together as a transaction on the blockchain.
The smart contract code is open source. Anyone can examine it, and use it to verify a public key. But only the ZeroDark.cloud AWS serverless code has the ability to write data to the blockchain with it.
Once the transaction has been recorded to the blockchain, a transaction identifier is recorded and can be looked up by customers to verify the binding between customer ID and public key.
All transactions are publicly visible and can easily be verified by code and even manually, depending on your level of crypto-paranoia.
Once posted on the blockchain this binding is inherently resistant against modifications
What problem did we solve?
Well that was a lot of text. Pretty deep into TLDR territory. The bottom line is that you can leverage modern blockchain technology to address one of the public key trust issues and make sure that no funny business is occuring.
If you want to dive into more details about how ZeroDark.cloud talks to the Ethereum blockchain, There are a few posts that might want to read.
To find out more about ZeroDark.cloud:
Docs (high-level discussion of the framework, how it works, what it does, etc)
API Reference (low-level code documentation for the framework)