Authors: João Paulo Barraca, Vitor Cunha, Paulo C. Bartolomeu, Alfredo Matos, Catarina Silva
Slides
Download here
Support File Required: symmetric_cryptography_c.zip
Symmetric Cryptography
Cipher Modes
Your task is to implement two modes of operation for the AES128
block cipher: the Electronic Codebook (ECB
) mode and the Cipher Block Chaining (CBC
) mode.
-
AES128 Implementation: You should use an implementation of
AES128
block cipher. Remember that AES128 operates on 16-byte blocks and uses a key of 16 bytes. -
ECB Mode: In ECB mode, each block of plaintext is encrypted separately. This means that if two identical blocks of plaintext are encrypted with the same key, they will produce identical blocks of ciphertext.
-
CBC Mode: In CBC mode, each block of plaintext is XORed with the previous ciphertext block before being encrypted. This means that each ciphertext block depends on all plaintext blocks processed up to that point. To make each message unique, an initialization vector must be used in the first block.
-
Validation: After implementing
ECB
, andCBC
, validate your implementation against the test vectors provided in fileaes128-test-vectors.txt
. Your implementation should produce the same output as the test vectors for the same input. Start by encrypting thePLAINTEXT
and compare the result with theCIPHERTEXT
, then decrypt the result and compare it withPLAINTEXT
. Note that the values in the file are in hexadecimal.
You can either use as a starting point the aes128-test-modes.c
or produce your own code.
Along with aes128-test-modes.c
there is an implementation of AES128
built on top of Intel AES instruction set (in aes.h
) and another one built on top of openssl (in aes-sw.h
).
Inspect both files.
NOTE : If your cpu do not support the Intel AES
instruction set, you need to do 2 things: 1) change the include on aes128-test-modes.c
; 2) remove -msse2 -msse -maes
from file cflags.txt
.
You can check the availability of Intel AES
instruction set with the command:
$ grep -c aes /proc/cpuinfo # if it prints some number greater than 0 the AES instruction set is available
If you want to use python
you need to install
Python3 Cryptography module.
The module can be installed using:
$ sudo apt update
$ sudo apt install python3-cryptography
Or
$ pip install cryptography
If you want to use c
you need to install some tools to compile the code:
$ sudo apt update
$ sudo apt install build-essential libssl-dev libbsd-dev
Then you can execute:
$ gcc aes128-test-modes.c -o ase128-test-modes $(cat cflags.txt) # remember you need to run this every time you change the code.
Additional resources:
Padding
A block cipher requires input blocks of a fixed size that equals the algorithm block size. However, its improbable that a file to encrypt as a number of bytes that is multiple of the block size of the algorithm to be used, i.e., frequently, the number of bytes that remain for the last block do not equals the block size. To solve this problem, extra bytes are added to have a block with the correct size. These extra bytes are then removed when in the decryption operation.
There are several standards for padding. PKCS#7
is one of them. The objective for this exercise is that you demonstrate the existence of padding in a encryption operation, and that it is according the PKCS#7
standard.
Your task is to implement two functions: one for adding padding to a given plaintext according to the PKCS#7
standard, and another for removing the padding from a given ciphertext.
-
Add Padding: Write a function that adds padding to an arbitrary
plaintext
in order to make it a valid input for the encrypt operation. -
Remove Padding: Write a function that removes the padding of the result of a decrypt operation. The function should verify that the padding is correct.
-
Validation: Validate your implementation against the tests provided in file
aes128-test-padding.txt
.
Note: Take special care when the size of the input data is a multiple of the block size. In such cases, PKCS#7
padding requires that a full block of padding be added. This is to ensure that the padding can always be unambiguously removed.
You can either use as a starting point the aes128-test-padding.c
or produce your own code.
Symmetric key generation
Before a cipher is used, it is required the generation of proper arguments. These arguments are the key, the cipher mode, and potentially the IV. The cipher mode is chosen at design time, and the IV should always be a large random number (size similar to the block size or key) that is never repeated. In the previous examples we have been using known keys and IVs in order to validate the implementations. This lab will discuss the creation of random keys and IVs.
The key can be obtained from good sources of random numbers,
or generated from other primitive material such as a password.
When choosing the a password, it is imperative to transform the
user text into a key of the correct complexity.
While there are many methods, we will consider the Password Based Key Derivation Function 2
(PBKDF2),
which takes a key, a random value named salt, a digest algorithm,
and a number of iterations (you should use several thousands).
The algorithm will iterate the digest algorithm in a chain starting in the concatenation of the salt
and key, for the specified number of iterations.
Using SHA2
, the result is at least 256 bit, which can be used as key and IV, two values of 128 bit.
Your task is to enable the user to provide a password that will be used to generate random values for keys and IVs.
- Construct a function that generates 256bits according to
PBKDF2-HMAC-SHA256
, i.e. withSHA256
as digest function used in the derivation (done inpbkdf2-kickoff.c
). - Use these 256bit as two values of 128bit, the key and IV, and integrate this change with the previous cipher modes.
You can either use as a starting point the pbkdf2-kickoff.c
or produce your own code.
If you prefer to use Python3
, to provide the password check the getpass
module.
To compile pbkdf2-kickoff.c
use:
gcc pbkdf2-kickoff.c -o pbkdf2-kickoff $(cat cflags.txt)
Note Try different number of iterations and measure this impact.
File encryption
Create a function to encrypt the contents of a file, whose name should be provided by the user. The key should be generated according to the previous task. The user must provide (as program parameters or by request or any other suitable method): (i) the name of the file to encrypt, (ii) the name of the file to store the cryptogram, (iii) the mode of the encryption algorithm, according to the previous tasks.
If you need to save multiple fields to the same file (e.g, salt, cryptogram), save these as fixed length fields to the beginning of the file (see pbkdf2-kickoff.c
).
An alternative is to use Base64 to convert the objects to text (base64
), and then use a delimited such as \n
.
Take in consideration that data may need to be encrypted in blocks, and the last block may require padding, according to the previous tasks.
Questions:
- Can you determine the structure of the text from the cryptogram?
- Compare the lengths of the text and the cryptogram?
File decryption
Alter your program by adding a function that decrypts a user file. For this functionality, the user must provide the following (as program parameters or by request or any other suitable method): (i) the name of the file to decrypt, (ii) the name of the file to store the decryption result. The key must be requested.
Take care of removing the padding (if present!)
Questions:
- Is padding visible in the decrypted text?
- What happens if the cryptogram is truncated?
- What happens if the cryptogram lacks some bytes in the beginning?
Patterns
In this exercise we will analyze the impact of ECB
and CBC
cipher modes in the reproduction of
patterns in the original document into the encrypted document.
For this, we are going to encrypt an image in the bit map (BMP
) file format,
after which we are going to visualize the contents of the obtained encrypted
file and compare it with the original image.
In order we can visualize the contents of the encrypted file we must replace the first
54 bytes with the first 54 bytes from the original file (these bytes
constitute the header of BMP
formatted files, which is necessary so
the file can be recognized as a BMP
formatted file).
Use the program you developed in the previous sections to encrypt the
file Tux.bmp
using the ECB
cipher mode.
Using the dd
application copy the copy the first 54 bytes from the original
image file into the first 54 bytes of the encrypted file:
dd if=Tux.bmp of=Tux_enc.bmp ibs=1 count=54 conv=notrunc
Using a program to visualize images, open the original image and the encrypted image and compare them. What do you observe?
Repeat all the above operations, now using the CBC
cipher mode instead of
ECB
cipher mode.
Then, compare the original image with the obtained encrypted image.
An image and the typical result result of ECB and CBC cipher mode.
(Images by Larry Ewing)
(OPTIONAL) Human Readable Symmetric Encryption
Modern ciphers lies in their indistinguishability from random data by a computationally limited adversary. In the previous exercises we used symmetric cryptography to produce indistinguishable results. In this exercise, we want to use ciphers to produce a human “readable” text.
Write a program using AES
encryption, for example with CTR
mode, and replace encrypted bytes with words from a dictionary ensuring that your code encrypts and decrypts the input text while maintaining the human “readable” format of the cipher text.
NOTE: you can use markov-word-generator Python library to generate random credible words.
Experiment with different dictionaries and input strings to observe the effects on the cipher text.