In this article, we will learn how symmetric-key encryption works from a practical perspective.
In the “Introduction to encryption for embedded Linux developers” article, we learned the basic concepts, including an introduction to security, confidentiality and encryption, the main motivations and how encryption works, types of encryption (symmetric-key and asymmetric-key encryption), the most commonly used ciphers and the trade-offs between them.
In this article, we will use OpenSSL to put into practice some concepts about symmetric-key encryption.
To follow along with this article and run the commands on your machine, you just need a terminal with a recent version of OpenSSL.
Have fun! :-)
Symmetric-key encryption
In a symmetric-key encryption algorithm, the same key is used for both encryption and decryption. This key is usually called a private key, and should stay private, or the security is broken!
There are several symmetric-key encryption algorithms available (DES, AES, IDEA, Blowfish, RC4, etc), and currently the most commonly used symmetric algorithm is AES (Advanced Encryption Standard).
AES is a standard set by the U.S. National Institute of Standards and Technology (NIST) in 2001 for the encryption of electronic data and became effective as a U.S. federal government standard in 2002. It is also the first (and only) publicly accessible cipher approved by the U.S. National Security Agency (NSA) for top-secret information. I will not judge if this is good or bad. :-)
AES is a block cipher and works with blocks of 128 bits. That means it will break the data to be encrypted (cleartext) in blocks/chunks of 16 bytes, encrypt them (block by block), and join the encrypted blocks together to form the ciphertext.
AES keys might have three different lengths (128, 192 or 256). Usually, longer keys improve security, especially against brute-force attacks (though sometimes that might not be true).
On the other hand, the execution might be slower with larger keys. AES for example will execute more rounds with larger keys. Currently, a 128 bits key in AES is considered to be a safe compromise between efficiency and security.
So let’s start by creating a 128 bits key for AES encryption.
Generating a symmetric key
An encryption key is just a random string of bits created explicitly for scrambling and unscrambling data. The more random, the better.
This is one of the reasons a good random number generator is very important in cryptography, and if you want to learn more about random numbers, have a look at the article What are random numbers and how they are managed on Linux?.
A key can be created manually by typing any combination of 128 bits (for the purpose of this article, we don’t care much about the randomness of the key). Anyway, it is easier to do this with a tool like OpenSSL:
$ openssl enc -pbkdf2 -aes-128-ecb -k my-secret-passphrase -P
salt=291F74776135CAF2
key=4A48195DFA143D17F44AB817C831FACF
This command is asking OpenSSL to create a 128-bit AES key (-aes-128-ecb) using a password-based key derivation function (-pbkdf2) and print the key in the terminal (-P).
The password-based key derivation function used is called PBKDF2. This algorithm will apply a hash function to the passphrase given (-k my-secret-passphrase) along with a salt value and repeats the process many times to produce a derived key.
The salt is just random data that is used as an additional input to the hash function. Without it, the same passphrase would always produce the same key!
Now save the derived key in a file:
$ echo 4A48195DFA143D17F44AB817C831FACF > key.priv
And we are ready for some encryption!
Encryption with AES-128
Let’s encrypt a snippet from The Hacker Manifesto, a small essay written in 1986 by a computer security hacker who went by the pseudonym of The Mentor:
$ cat cleartext.txt
This is our world now... the world of the electron and the switch, the
beauty of the baud. We make use of a service already existing without paying
for what could be dirt-cheap if it wasn't run by profiteering gluttons, and
you call us criminals. We explore... and you call us criminals. We seek
after knowledge... and you call us criminals. We exist without skin color,
without nationality, without religious bias... and you call us criminals.
You build atomic bombs, you wage wars, you murder, cheat, and lie to us
and try to make us believe it's for our own good, yet we're the criminals.
Yes, I am a criminal. My crime is that of curiosity. My crime is
that of judging people by what they say and think, not what they look like.
My crime is that of outsmarting you, something that you will never forgive me
for.
I am a hacker, and this is my manifesto. You may stop this individual,
but you can't stop us all... after all, we're all alike.
The command below will encrypt the file using AES-128 (enc -aes-128-ecb), taking the input file provided by the -in option, encrypting it with the key given in the -K option and creating an encrypted file called ciphertext.txt via the -out option. Easy, right?
$ openssl enc -aes-128-ecb -in cleartext.txt -K $(cat key.priv) -out ciphertext.txt
Now if you try to print the encrypted file (ciphertext.txt), you will just see garbage.
In the same manner, we can decrypt the file by passing the -d option:
$ openssl enc -d -aes-128-ecb -in ciphertext.txt -K $(cat key.priv)
This is our world now... the world of the electron and the switch, the
beauty of the baud. We make use of a service already existing without paying
for what could be dirt-cheap if it wasn't run by profiteering gluttons, and
...
There is just one problem with what we are doing here. We are using a block cipher mode called ECB (Electronic codebook). The ECB mode leaks information and it is very insecure!
So let’s learn now about block cipher modes and why ECB is so insecure…
Block cipher modes and ECB
Before explaining the problem, let me show how insecure the ECB mode is.
For the example, let’s take our lovely TUX image:
Download the image and convert it to PPM to make it easier to manipulate the header and the body of the image:
$ wget https://upload.wikimedia.org/wikipedia/commons/a/af/Tux.png
$ convert Tux.png tux.ppm
Now break down the file into two parts, the header and the body:
$ head -n 3 tux.ppm > header.txt
$ tail -n +4 tux.ppm > body.bin
Encrypt the body with AES-128 in ECB mode and add back the header to create a new image with the body encrypted:
$ openssl enc -aes-128-ecb -in body.bin -K $(cat key.priv) -out body.ecb.enc
$ cat header.txt body.ecb.enc > tux-ecb-enc.ppm
Open the encrypted image (tux-ecb-enc.ppm) and see the result for yourself!
Can you see that Tux is still there? But why?
As mentioned before, AES is a block cipher that works with blocks of 128 bits. In ECB mode, it will encrypt individually the blocks. Blocks with the same content will output the same value!
Although the image is encrypted and we don’t know its contents, we still can see data patterns. That means the ECB mode leaks information, it is very insecure and you should never use it!
If you look at this Wikipedia page, you can see that there are different modes of operation for block ciphers. One of the most commonly used modes is CBC (Cipher Block Chaining).
AES encryption in CBC mode
In CBC mode, one encrypted block (ciphertext) is used as input to encrypt the next block. For the first block, we need an Initialization Vector (IV), a random and unique number usually the same size as the block.
The Initialization Vector (IV) can be generated with the rand function of OpenSSL:
$ openssl rand -hex 16 > iv.txt
$ cat iv.txt
e9c43ea833e188d65ed225893af227f2
And now the image can be encrypted by passing the -aes-128-cbc mode and the Initialization Vector with the -iv option:
$ openssl enc -aes-128-cbc -in body.bin -K $(cat key.priv) -iv $(cat iv.txt) -out body.cbc.enc
Now add the header to the encrypted image:
$ cat header.txt body.cbc.enc > tux-cbc-enc.ppm
And open the encrypted image (tux-cbc-enc.ppm) to confirm that information is not leaking anymore (the image will look like garbage):
In this article, we learned some concepts about symmetric encryption, using AES in ECB and CBC modes to encrypt and decrypt data. In the next article, we will deep dive into asymmetric-key encryption and digital signatures.
See you there!
About the author: Sergio Prado has been working with embedded systems for more than 25 years. If you want to know more about his work, please visit the About Me page or Embedded Labworks website.
Please email your comments or questions to hello at sergioprado.blog, or sign up the newsletter to receive updates.