# Asymmetric Encryption

## How data gets securely transferred from point A to point B over a public internet connection.

When you think of the term “encryption”, you’re likely thinking of what is known as symmetric encryption. With symmetric encryption, you encrypt data with a password, and use the same exact password when you need to decrypt the data. This works fine when you’re encrypting a file, or maybe even an entire hard drive; however, symmetric encryption requires that both parties know the same password in order for the encryption and decryption to work properly. If the password is known, or can be known, by someone except for the sender and recipient, the encryption is pretty much pointless and if the recipient doesn’t know the password, they have no way of decrypting, and therefore reading, the data.

So, for symmetric encryption to work, both the sender and recipient need to know the same password. In order to securely transmit that password over something like the internet, which can’t be considered private, the password itself needs to be somehow encrypted. Which brings the question: what do you encrypt the password itself with? You could use another password, but then you’d need to figure out how to transmit that one securely, and how to transmit the password for the password securely, etc. Luckily, an answer exists: asymmetric encryption.

# What Is Asymmetric Encryption?

Asymmetric encryption uses two keys instead of one: a public key and a private key. Data can be encrypted with either, and that data can be decrypted with the other key in the pair. Data encrypted with the public key can be decrypted with the private key, and data encrypted with the private key can be decrypted with the public key. The public key is called public because it can be publicly available (i.e. on a server) without compromising the security of the encryption. Similarly, the private key must be kept private, or the security will be compromised.

## OpenSSL Example

Here’s an example of how asymmetric encryption works using OpenSSL (examples are from my post on end-to-end encryption). You can run this on a Linux system with the `openssl`

command installed, and I believe it also works in the Mac OS terminal. This example will use RSA, which is one of the more popular asymmetric encryption algorithms.

First, we need to generate a private and public key pair:

`openssl genrsa -out private.pem 2048`

openssl rsa -in private.pem -outform PEM -pubout -out public.pem

In this case, I’ve chosen to use a 2048-bit RSA key, which is still considered secure at the time of writing (up to 2030). However, in order to future proof your encryption beyond 2030, you’ll need to use a 3072-bit key or higher. Now that we have a public and private key, we can encrypt a message using the public key (“Hello” in this example):

`echo 'Hello' | openssl rsautl -encrypt -inkey public.pem -pubin`

Running the above command will result in output similar to the following:

`����G���t], �5�F�/nX���ݢ3����]�*a/��n�g�n�3u�Fh0�&%���������̍�LpD��|����v+[�Z��2���_Hm�@]�T;��STH#�f��8!��{�H���m� �X��7�ϊ�D`

�h{���4z�[")�V0�Fd��Upӹ>��&L���+�Kf'���^J�H*��+�$��~���&�˘��я7�

The mess you see above is because the encrypted message isn’t encoded in way which is readable to us. We can fix this a bit by using base64 encoding:

`echo 'Hello' | openssl rsautl -encrypt -inkey public.pem -pubin | openssl enc -a`

This gives us something much more readable:

`wnzFvxuQQDdSqKJMT00rApZ/hQLy1dyITIh45FS3eFrf7Tz1r5dB1Xjf1xCd4yCemjtB3MBJl6eyTJMHoNcJ7sfn3W0UDe+VWTO9LtiNScg2qts5HG316+3DNDDatIS0OgIaYCWFFii8nJQ/hdrUqHphfegNLiZUG3HjGAl6XVSe4hDp3d84tDBKx5wAXW4ZqRdKpzVSnDCvUMHx6SKgaMFFSWOY9zsPK6mHy3My4jM1JOU69QKnP3yl8vH0StpELbUdqtDF8WU0HkqjaUnUbdttlrrrzfXWD+6BieYs+kvYt0+mu1BJe3B9rVAF3XvA0WYKkmXp+sbTf6y1Hx68WQ==`

Ok, well, not exactly easy to read, but still much better than the mess we had before encoding. Since we encrypted the message using the public key, it can be decrypted with the private key:

`echo "wnzFvxuQQDdSqKJMT00rApZ/hQLy1dyITIh45FS3eFrf7Tz1r5dB1Xjf1xCd4yCemjtB3MBJl6eyTJMHoNcJ7sfn3W0UDe+VWTO9LtiNScg2qts5HG316+3DNDDatIS0OgIaYCWFFii8nJQ/hdrUqHphfegNLiZUG3HjGAl6XVSe4hDp3d84tDBKx5wAXW4ZqRdKpzVSnDCvUMHx6SKgaMFFSWOY9zsPK6mHy3My4jM1JOU69QKnP3yl8vH0StpELbUdqtDF8WU0HkqjaUnUbdttlrrrzfXWD+6BieYs+kvYt0+mu1BJe3B9rVAF3XvA0WYKkmXp+sbTf6y1Hx68WQ==" | openssl enc -d -a | openssl rsautl -decrypt -inkey private.pem`

*Note: when you run these commands yourself, you’ll end up with different output as the keys are different.*

## Digital Signatures

You’ll notice that in the above example, the public key was used to encrypt the message, while the private key was used to decrypt the message. While this is often how data is encrypted, the same process works in reverse. One of the most used cases for encrypting with the private key and decrypting with the public key is for digital signatures.

Digital signatures can be used to verify that a piece of data has been successfully received without any alterations. This is done by generating a hash of the data, and encrypting the hash with the private key. The encrypted data and hash are then sent over the internet, where they are received by the recipient, which has only access to the sender’s public key. The sender can then decrypt the sent data, and use the sender’s public key to decrypt the hash. They can then use the same hashing algorithm on the same data, and compare the hash to the received one. If the hashes match, then the data has not been tampered with, as any changes to the data would also alter the hash.

For example, the sha512 hash of “abc123” is:

`9760a80808894b09441d602b4fc779877756d98e976cdd33c64919b13b4f89dfb2d768562be616cbebf375f3f76598ca1dd5a90749e55899222a80ee3c7b15a5`

while the hash of “abc12” is:

`bcb008f47c2ada9563c0fe0e57afda3322f4c684bd74afbcc4aee0979132e26f40011a34a6cde8dfd57c2c21363167561f5f1e997574361148502ce96b6b9c7f`

Digital signatures also serve to verify the sender, as in order for the public key to successfully decrypt data, that data has to have been encrypted with the correct private key. Because the private key should never be shared, it is extremely difficult for a another party to forge a digital signature.

# Simple End-to-end Encryption

One of the easiest examples to show when asymmetric encryption is useful is for a simple end-to-end encryption implementation. For end-to-end encryption, you need to figure out how to send a message from the sender to the recipient without anyone else being able to read the message. As the sender and recipient likely won’t be on the same local network, the messages and keys must be on a publicly available server so the sender and recipeint can access them. But, because this is end-to-end encryption, even the party running the server shouldn’t be able to decrypt the messages. So, how would that work?

The answer is quite simple. The sender and recipient each generate a public and private key, and upload their respective public keys to the server. To send a message, the sender needs to first pull the recipient's public key from the server. They can then encrypt the message using the recipient’s public key, and upload the encrypted version of the message onto the server. The recipient can then download the encrypted version of the message, and decrypt it using their private key. This method ensures that no one except for the sender and recipient can decrypt the message. So, even if someone had complete and unauthorized access to the server storing everything, no useful data could be extracted.

Obviously, this example is not complete and is missing a few critical steps. For one, digital signatures could be used to verify the message has arrived correctly. Additionally, asymmetric ciphers like RSA aren’t optimized for encrypting large amounts of data. While that is not a problem for a messaging app with a character limit, it could be a problem for longer messages and attachments.

# TL;DR

Asymmetric encryption uses two keys: a public key and a private key. Each one can be used to encrypt data, and the other can be used to decrypt the data. Encryption of data is typically done using the recipient’s public key and decrypted with the recipient’s private key. Digital signatures are typically done by encrypting a hash of the data with the sender’s private key, which the recipient can verify by decrypting using the sender’s public key and hashing the data themselves to ensure the hashes are the same.

Sources: