When we founded Epicode in 2020, we decided it would be a middleware company that caters to application developers who require telephony features. Any application development these days is a multidisciplinary effort. No matter which business domain an application is targeting, the end customer will expect it to be secure, reliable, scalable, highly available, performant, etc., as foundational features. However, it is very difficult to achieve everything under one roof, and such efforts usually lead to the Pentathlon Trap.
Last month, Zoho’s Arattai instant messenger was in the news everywhere. Every social media channel was abuzz with applause and critique, in equal measure. Most of the criticism was centered around lack of end-to-end or E2E encryption, and fear of government surveillance. I took part in some of these discussions, mainly to address some misinformation and confusion. Eventually I decided to summarise those ideas into an article, where I can give a friendly explanation to E2E encryption, authentication, et al. So this is going to be the first of the Middleware musings, where I talk about how different foundational technologies work. Hopefully, more will follow if and when I find time.
Prior to the 1990s, individuals didn’t really have the luxury of encryption. Take the telephone system, every government in the world could tap calls according to the laws of the country. There were no technical challenges to it. The very first electronic exchanges (like 1ESS) came with options to tap calls. Other communications like email, fax, telegraph, postal mail or courier system had no encryption either. Even if you did encrypt by hand, the governments always had better cryptographers than individuals. The companies that could afford large computers had access to cryptography, but they were subject to US government restriction too. It was illegal to export encryption software that could use keys bigger than 40bits. If you were downloading an Internet browser in the mid 90s from India, you could only download a 40 bit encryption browser.
In 1991, PGP software finally enabled individuals to use 128bit encryption. That means the US government couldn’t break it. The author of PGP got into a lot of legal trouble with the US government.
In other words, individuals have had the ability to communicate privately only since 1991. But most people started benefiting from it in the last 10-15 years. Phones are still not E2E encrypted. Most emails are not E2E encrypted. Until instant messengers enabled E2E encryption, there was no way to avoid government surveillance on voice or video calls. In fact, many countries still don’t allow instant messengers or softphones to make voice/video calls unless they allow surveillance. Most countries, including India have laws that allow them to surveil phone calls and messages. Fortunately, the Indian government has not chosen to enforce this law when it comes to instant messengers. Therefore, Indian residents are able to enjoy E2E encryption on their calls and messages on Whatsapp, Signal, etc.
The foundational technology underlying E2E encryption is Public Key Infrastructure or PKI cryptography. It is built using very advanced mathematical concepts like Number theory, Discrete maths, Abstract and Linear Algebra, Statistics, etc. We don’t have to learn how it is done. We will focus on what they achieve for us. The PKI system basically uses a pair of digital keys, namely private key and public key. As the name suggests, private keys are never shared, while the public keys are freely shared.
5 goals of cryptography
- Encryption: Encrypt the data so that no one can read it during transmission. This is achieved by obfuscating the original message using a digital key (string of characters). If the data can be decrypted using the same digital key, such a key is called symmetric key and the process is called symmetric key encryption. If the encryption and decryption is achieved using different keys, they are called asymmetric keys and the process is called asymmetric key encryption.
- Key-Exchange: This refers to the process of exchanging the symmetric key used for encryption.
- Authentication: Authentication means ensuring that the data is being sent from the correct sender. This is achieved by making the sender sign the message using the private key, and the recipient verifying the signature using the sender’s public key. This can be used for signing/verifying messages as well as public keys. Digital X.509 certificates are also created using this process.
- Veracity/Integrity: Veracity or Integrity means ensuring that the data was not modified in transmission. Again, the sign and verify process takes care of checking the integrity.
- Non-repudiation: This is the byproduct of authentication and integrity, the sender cannot deny sending the message.
Basically, we deal with 3 types of keys. The public key, the private key and the symmetric key.
Symmetric Key: The most common symmetric keys are AES or Advanced Encryption Standard. As the name suggests, it is used for symmetric encryption. These are very fast, impossible to break and can encrypt large amounts of data. The bit size can vary between 128-bit, 192-bit or 256-bit, the last being the most standard these days. There are older standards like DES and 3DES, which are too insecure by current standards.
Public/Private Key: These are created together and have a close relationship. There are many types of PKI keys, serving different purposes.
The order of key types indicate the popularity of these cryptographic algorithms.
- RSA remains dominant due to its legacy and compatibility.
- Elliptic curve-based algorithms (ECC, EdDSA, X25519, ECDSA, ECDH) are rapidly winning market share thanks to better efficiency and security.
- DSA, ElGamal, and ECIES are rarely encountered in new deployments but are still supported in cryptographic libraries.
Encryption
Older algorithms like RSA and EIGamal were capable of encryption, key-exchange and sign/verify functions. However, with modern computing power, it is not as unbreakable as before. If you notice, all the modern algorithms do just one function, either key-exchange or sign/verify. None of them bother to have an encrypt function. In fact, even the existing RSA implementations that use asymmetric encryption, use it only for encrypting the AES key before sending it over. It uses the encryption feature only for achieving key exchange, and not for encrypting the data. All modern systems use AES-256 symmetric keys for encryption.
Key-Exchange
In order to use symmetric key encryption, we need to ensure that the sender and receiver have the same AES-256 key. We already discussed how it can be sent over using asymmetric encryption, which would work only with older and thus unsafe algorithms. Modern systems use Diffie-Hellman (DH/ECDH/X25519) for key-exchange even with RSA, which provides better security. These days RSA is simply used for Sign/Verify in most cases.
For key-exchange, both ends generate a DH/ECDH/X25519 public/private key pair; they should use the same algorithm though. Then both sides will exchange their public keys openly. And then using their local private key with the public key of the other end, they both generate a secret, which will be the same on both sides. How? Magic of mathematics. They never have to exchange that common secret. That shared secret can be used to generate a common AES key on both sides. Now they can encrypt any amount of data and exchange it, and nobody in the middle can decrypt it. If they want to use a new AES key every time, then they have to exchange new public keys every time, and generate a new AES key every time for encryption. Or they can pass a new AES key along with each data transmission, and use that AES key for the next transmission. That will ensure a new AES key for each transmission.
Do note that all the above can be done without the internet at all. Both sides could have exchanged their public keys by saving it to an USB drive and sending it over courier to each other. After that, every time they have data to send, they could save the AES symmetric key encrypted data into one more USB drive and courier it to the other. But if they want to change the AES key every time, that courier company will get lots of business exchanging public keys on the USB drive every time. Or the both sides can generate 100 key pairs and exchange them in bulk, and then use them in the same order for the next 100 transmissions.
Authentication
If the two parties, let’s call them A and B, know each other, they can exchange each other’s public keys. If they had safely exchanged their public keys, then the data is really safe. But if the courier company, whom we can conveniently call C, was swapping the public keys? If C was generating its own key pair, and gave its own public key to both A and B, it can decrypt and read every message before re-encrypting and sending it to the final destination. C can even change the data before final delivery, and no one would know. Then C is known as the man in the middle. If you are working in a company that uses a firewall with DPI (deep packet inspection) feature, it will act like C for standard protocols like web or email. Actual implementation can differ, this example gives you a general pattern of man in the middle attack.
There are a couple of ways to solve it. A could personally visit B and give the USB drive, and collect B’s USB drive. This will work as long as A and B know each well. But it will be tedious to exchange public keys repeatedly by visiting each other in person. What if you could exchange once reliably, and not require any more visits? That is where we can use digital signing and verification. The PKI key pair we use for key-exchange won’t be useful for this purpose. Instead, both sides should generate a ECDSA or Ed25519 key pair, which are capable of sign/verify functions. And they should exchange the public keys, say by visiting the other, just once. Let’s call them self-issued verification public keys. After this, whenever each side generates a key-exchange key pair, they must sign the key-exchange public key with the self-issued signing private key, which results in a X.509 certificate or self-certified public key. Then the certificate can be couriered to the other side.
That brings us to verification. If a data is signed using a private key by an entity, anyone can verify that signature using the corresponding public key. Successful verification will confirm that the data was signed by the entity to whom the public key belongs. Thus the recipient will use the self-issued verification public key of the sender to verify that the certificate is valid, which authenticates that the key-exchange public key came from the right sender. The authenticated public key can be extracted from the certificate, and used for generating the shared secret like before. As long as they trust each other, they can keep exchanging certificates containing new key-exchange public keys. This is called a trust chain, in that a key-exchange public key is trusted because it can be verified using the self-issued verification public key of yet another trusted entity.
This way courier C can’t inject its uncertified public keys in between to read the data. Whatsapp can be that key issuer, who will digitally certify the key-exchange public key generated by the Whatsapp clients. When two Whatsapp clients exchange their digitally certified public certificates, each can verify that the public key is authentic.
What if A and B don’t know each other? Then they will need a common friend who will vouch A to B, and B to A. That common friend can be called a Certificate Authority (CA), who will issue the sign/verify keypair to each side. The public key of the keypair will be signed by CA, making it a certificate. Any data signed by the private key of this keypair, can be verified by the certified public key, whose certifier (CA) is trusted by both sides. Generally there are two types of CAs, private CAs maintained by companies and institutions for certifying their internal public keys, and public CAs who are trusted across the Internet. The public CAs are usually accredited by governments and root CA programs. If you go to your web browser settings and search for certificates, you can view all the public CAs trusted by your OS. In a corporate environment, the list would also contain the company CA, to ensure company certificates are trusted. Without this, the company firewall cannot do deep packet inspection of data passing through the firewall.
Using a public CA doesn’t always ensure your trust chain is accepted everywhere. For example, Windows 11 certificate store would list India’s eMudhra CA, while MacOS doesn’t. This results in a document signed by eMudhra certificate that shows up as verified on Windows, but unverified on MacOS. Unlike regional CAs like eMudhra, the global CAs like Entrust or DigiCert are trusted globally. So pick your public CA carefully.
Signing and verification functions can be used on any kind of data, even when no encryption is involved. Authentication may be required for public documents, to ensure it was issued by the right authorities.
Signing
What exactly does signing entail? It is a process where the data is hashed into a small string. The data could be a public key or a message or a document. Even a huge file can be hashed into a 32/64 bytes string depending on the hash function. Then the hash is encoded using the private key. The resulting output is called a signed digest. The signed digest is slightly bigger than the hash, or it could be the same size as in case of Ed25519. In the absence of a CA, one can sign the data using a self-issued key pair, and send the signed digest along with the data to the other side. If the CA issued key pair is available, then the public key can also be signed by CA issued private key and sent along as a certificate. Messages that are signed with a private key issued by a public CA, will always include the corresponding certified public key. So the signed message contains the signed digest, the message content and optionally the certified public key.
Verifying
If the signed message doesn’t contain the certified public key, the recipient must already have the corresponding self-issued public key to verify the signature. The public key is used to decode the signed digest and obtain the original hash. The successful decoding ensures that the digest was signed by the corresponding private key. Now the hash is recomputed and then compared with the decoded hash. If the hashes match, it means the message content is unmodified since it was sent. If the signed message contains the certified public key, it is verified similarly using the CA certificate corresponding to the certified public key, by going up the certificate trust chain.
Veracity/Integrity
Symmetric encryption ensures confidentiality, but does not guarantee integrity. This is because someone in the middle can modify the data in transit in a way that it cannot be detected. They can’t read the data, but they can make a mess of it. AES has different modes like CBC, ECB, GCM or CCM. The CBC and ECB modes are vulnerable to attacks, since they don’t create any hash that can be recomputed at the destination. In order to achieve integrity, AES should be used with GCM or CCM modes, which generates authentication tags, which can be sent along with the encrypted data. The authentication tags will be recomputed during decryption and if the tags don’t match, it indicates modification. Alternatively, you can separately compute a tag using MAC (Message Authentication Code) and pass it along with the message for recomputing on the other side. There are many types of MAC, namely HMAC, CMAC, GMAC, etc. In this case, we are not relying on the AES modes to create/recompute tags.
In case of digitally signed unencrypted data, signature verification also ensures that the data is unmodified since it was signed. That is because the signature contains the cryptographic hash of the document, which is recomputed upon receipt. If the original hash and recomputed hash doesn’t match, the verification will fail.
Non-repudiation
Non-repudiation is achieved by using digital signatures that can be verified using a certified public key and by ensuring the integrity of the signed data. This way, the signer cannot credibly deny their intent or the content of the signed message. For example, a digitally signed purchase order cannot be disowned by the issuer.
Applications
Instant messengers: Instant messengers like Whatsapp and Signal use key-exchange PKI keys for exchanging public keys, to generate AES keys. Then use the AES keys to encrypt the communication. Since the AES key is only known to the sender/recipient whatsapp clients, no one in the middle can read the messages, thus achieving E2E encryption. The same holds good for voice/video calls. Different apps may use different algorithms, but the concept is the same.
VOIP Phones: Voice-Over-IP phones use SIP protocol over TLS, which uses DH/ECDHE for key exchange, and then encrypt the voice packets (RTP) using the common AES key. However, telephony switches and session-border-controllers in between can play man-in-the-middle during the multi-layer call setup. However, by using ZRTP, the key-exchange can be pushed to the media layer bypassing any actors in the middle, thus achieving E2E encryption.
Document signing: You can digitally sign a NDA, or a legal agreement using the keypair issued by a public CA (eMudhra, etc); it won’t encrypt the document at all. I am sure plenty of readers here have DSC USB keys that you use for signing documents, purchase orders and invoices. The DSC issuer (CA) would have done KYC before issuing you the DSC USB. When you sign a PDF, your certified public key will be embedded into the document, along with the cryptographic hash. When someone opens the document in PDF reader, it will verify the trust chain of the public key, that it was issued by a trusted CA like eMudhra, and only then verify the signature with the public key. If the verification was successful, it means it was signed by the right person and it has not been unmodified since then. Even blockchains primarily use authentication and integrity, and not encryption.
Conclusion
I have tried to explain all the above without using networking, so that we don’t get bogged down with techie stuff like sockets or internet protocols. Cryptography works even if you print the public keys or encrypted data into an A4 page and hand deliver it to the destination. The recipient has to type all that back into the PC to decrypt it. However, all these details are well hidden in the middleware layer. All of us use all the above functions in our daily lives (UPI payments, Web browsing, Whatsapp messaging), without realising all the hard work being done underneath. I hope this musing was helpful. If there are any questions, do ask in the comments section. I’ll answer to the best of my knowledge.