Imagine you are a software developer and you share your software or its updates on the Internet. How do you ensure that someone doesn’t tamper with your software and how do you distribute that tampered copy to your customers? The solution is a software signature. The way these signatures work is extremely clever and fascinating.
What is a software signature?
We use handwritten signatures for self-identification for two reasons: they are supposed to be verifiable and impossible to forge. The same principle applies when you’re trying to ensure that the copy of a piece of software on your computer is authentic and has not been modified in any way. The developer leaves a digital signature on the software package (which cannot be forged) and customers verify that signature in their copy before installing the software package.
This also applies to software updates. A malicious update (for example, malware disguised as a driver) can wreak havoc on your machine. Your operating system (whether Windows, macOS, or Linux) must verify that an update comes from the original source before installing it on the system.
Digital signatures are intended to perform the same two tasks as a handwritten signature, but the way they actually work couldn’t be more different. It takes some very clever cryptography tricks to create and verify digital signatures.
How to Hide a Secret Message in Plain Sight
Suppose you want to share a secret with a friend through handwritten notes. In this scenario, you will also have to leave them in a public area for your friend to pick up later. Anyone who walks by can pick up the note and read your secret. So that’s our problem: how do you ensure that only your friend can read the message, even if someone snooping gets the note?
A clever way would be to use a ‘key’ to lock and unlock this shared secret. Allow me to explain.
Both you and your friend agree on a key, and you use that key to convert your secret message into gibberish sound. The key can be anything. For example, you can agree to replace each letter of the message with the letter next to it in the alphabet.
Then you took your message and replaced each letter in it according to the key. So the message ‘SECRET’ becomes ‘TFDSFU’. You write ‘TFDSFU’ on a note and leave it in a public space. Your friend can decrypt it because he or she has the key that you both exchanged earlier. So all they have to do is move each letter to one spot in ‘TFDSFU’ and they get the original message ‘SECRET’. Any eavesdropper would see the nonsense, because they first need the key to understand the message. .
What we have just described here is a very simple cryptography technique and the key used is a simple Caesar cipher.
How computers send secret messages over the Internet
Now imagine doing the same thing over the Internet and your communications must be completely secure. In the real world you can meet beforehand and exchange keys. You cannot exchange the key on the internet because it is a public space. Anyone can pick up that key and use it to decrypt the rest of your communications. So, how do you exchange a key without sharing it with your friend?
To communicate securely you need a key, but you must first communicate the key securely. This way you ensure that two computers agree on the same key, without sending that key via the internet.
Without getting too technical, encryption works with mathematical equations that are easy to solve in one direction, but incredibly difficult (or even impossible) in the opposite direction. So if a computer had the equation with all the correct numbers, it could easily solve it. However, it would be impossible for the system to reverse engineer the equation itself if it were given the solution.
I’m making it way too simple here, otherwise I’ll be here all day. If you want to delve deeper into how this works, take a look at the Diffie-Hellman key exchange.
This is the scenario: there is a computer A, a computer B and a public space. It starts with a key sent to the public space (let’s call this the public key). Computer A creates another key and keeps it private (let’s call it private key A). Computer B does the same.
The public key is available to everyone, but the private key A and private B are kept securely on their respective computers.
Now computer A takes the public key and combines it with its own private key to create a combination. Computer B does the same with its own private key. Both combinations are different. Instead of sending their private keys to the public space, the computers send these combinations there.
Please note that it is impossible to reverse engineer these combinations to find the private key used to create them. And at no point do the two computers see each other’s private keys.
Now for the actual trick. Each computer takes the combination that the other sends to the public space. Then computer A adds its private key to that combination with its own private key to get the final key. The other computer does the same with its private key and gets the exact same final key that computer A created.
Now both computers have the same key that they can use to encrypt and decrypt all future communications. Here’s the way-too-simple answer: the two computers “make” their own copy of the key without actually sharing the key itself.
This entire process is called public key cryptography. This type of public key cryptography is the basis for digital signatures, such as software signatures.
How developers hide a secret signature in their code
Digitally signing software also involves public and private keys. However, the intention is different, so the inner workings are a little different too. The idea here is not to establish a secure line of communication. We just want one-way authentication. The software developer does not attempt to hide the contents of the software package. They are only interested in proving the origin of the package.
So the developer creates a pair of private and public keys. Remember that both keys are different, but they are mathematically linked, and it is impossible to reverse engineer one key from the other.
The developer uses his private key to encrypt the software package. That encrypted copy can only be decrypted with the public key they have already published on the Internet. So if you and I use a public key to decrypt that copy, we can be absolutely certain that it was sent by the developer, because they only have the private key that could have originally encrypted their software package.
Hashes make the job easy
Okay, so I lied a little. It is not practical to actually encrypt entire software packages because these files can become quite large. There is another clever way to solve that problem via hash functions. Hash functions are mathematical formulas that create a fixed length of numbers and letters from a file of any size.
For example, a SHA256 hash function takes any file and spits out a list of 256 numbers and letters. If that file changes even a little bit, it will produce a completely different result. So the developer will run the software package through a SHA256 function to generate a text file. And instead of encrypting the entire package, they just encrypt this text file with a private key (just as I explained above). They add the encrypted hash text to the software package and send it to us.
When you and I receive the software package, we will also run it through SHA256 to get our own hash list. And then we decrypt the encrypted message attached to the software package using the public key provided by the developer. If the decrypted hash list matches the list we generated on our end, we can be absolutely certain that this packet came from the developer and has not been tampered with. Any manipulation of the packet during transport will result in a completely different hash text. These text files are called checksums.
In a nutshell, that’s exactly what a software signature is: the encrypted hash and the public key. A digital signature works because it is unforgeable (the private key ensures that) and verifiable (the associated public key can decrypt the message).
Who keeps an eye on the watchmen?
If you’ve been paying attention, you may have noticed that there is still one flaw in this system that we haven’t addressed yet.
What happens if someone takes a copy of the software package, messes with it, creates a new checksum, and uses a new pair of keys to encrypt it? That threat actor could distribute the related public key or send it directly to us. We would decrypt the manipulated signature using the public key, assuming the hashes matched, so it must belong to the original author. But the public key we used belonged to an impostor.
That’s where certification authorities come into the picture. Such a trusted organization vets developers and awards them digital certificates linked to their public keys. It cryptographically signs the certificate, just like the developer does for us, and an even higher certification authority is responsible for the signature of this organization. They are certification organizations down to the last detail.
These certificates are legally binding and we can verify them ourselves to be absolutely sure we have the correct public keys.
All of these things happen automatically in the background as the computer takes care of the hashing, encryption, and verification. We only see a dialog asking our permission to install or update the app. If an app is not signed, the operating system warns us before installing it.