In cryptography, we often encrypt and sign messages that contain characters. However, asymmetric key cryptosystems (where Alice and Bob use different keys), such as RSA and ElGamal, are based on arithmetic operations on integers. Symmetric key cryptosystems (where Alice and Bob use the same key), such as DES and AES, are based on bitwise operations on bits (a bit is either 0 or 1 and is an abbreviation for binary digit). Therefore, we must convert characters into integers or bits before applying the cryptosystem to the message.
Because a computer can only handle bits, there already exists a method for converting characters into integers or bits, which uses the ASCII (American Standard Code for Information Interchange) table. A part of the ASCII table from Wikipedia is shown in the following table (note that the binary representation on the Wikipedia site uses only seven bits, but we use eight bits by prepending an extra 0):
Character | Decimal | Hexadecimal | Binary |
---|---|---|---|
(space) | 32 | 20 | 00100000 |
! | 33 | 21 | 00100001 |
\( \vdots \) | \( \vdots \) | \( \vdots \) | \( \vdots \) |
A | 65 | 41 | 01000001 |
B | 66 | 42 | 01000010 |
\( \vdots \) | \( \vdots \) | \( \vdots \) | \( \vdots \) |
a | 97 | 61 | 01100001 |
b | 98 | 62 | 01100010 |
\( \vdots \) | \( \vdots \) | \( \vdots \) | \( \vdots \) |
For example, if Alice wants to send the message "Hey Bob!" encrypted to Bob using a symmetric key cryptosystem, she first converts it into its integer representation and then into its binary representation:
\( \eqalign{ H &\rightarrow 72 &&\rightarrow 01001000 \\ e &\rightarrow 101 &&\rightarrow 01100101 \\ y &\rightarrow 121 &&\rightarrow 01111001 \\ &\rightarrow 32 &&\rightarrow 00100000 \\ B &\rightarrow 66 &&\rightarrow 01000010 \\ o &\rightarrow 111 &&\rightarrow 01101111 \\ b &\rightarrow 98 &&\rightarrow 01100010 \\ ! &\rightarrow 33 &&\rightarrow 00100001 } \)
That is, the message "Hey Bob!" is represented with integers as "72 101 121 32 66 111 98 33" and in binary as "01001000 01100101 01111001 00100000 01000010 01101111 01100010 00100001".
In mathematics, we are all familiar with arithmetic operations such as addition, subtraction, multiplication, and division. However, computers work with bit strings — that is, sequences of 0s and 1s — and therefore require similar operations that act on two bit strings. The most important bitwise operations are NOT, AND, OR, and XOR. Below, we show the results of these operations with one or two bits as input.
The NOT operation is often represented as !:
The AND operation is represented as \( \wedge \):
The OR operation is represented as \( \vee \):
The XOR (exclusive OR) operation is represented as \( \oplus \):
Alice and Bob's adversary, Eve, can attempt the following types of attacks on a symmetric key cryptosystem such as DES or AES:
Symmetric key cryptosystems can be divided into two groups: deterministic and probabilistic cryptosystems. A deterministic cryptosystem, such as DES or AES, uses no randomness during encryption; that is, encrypting the same plaintext twice with the same key always produces the same ciphertext (which can be observed by Eve). This issue can be addressed with a probabilistic cryptosystem, such as the various modes of operation for DES and AES, which use randomness in the form of an initialization vector.
In a good deterministic cryptosystem, there should be no discernible relationship between the plaintext and ciphertext when the key is unknown. In other words, encryption in a deterministic cryptosystem should behave like a truly random function. If this is the case, we say that the encryption function is a pseudo-random function (PRF), and the cryptosystem is PRF-secure if Eve's advantage in correctly guessing in the following game is negligible:
Eve sends a message \( m \) to an oracle, which returns a ciphertext \( c \). Here, \( c \) is either an encryption of \( m \) using the cryptosystem's encryption function or an encryption of \( m \) using a truly random function. Eve then tries to guess which encryption function the oracle used.
With a probabilistic cryptosystem, we can achieve higher security compared to a deterministic cryptosystem. Therefore, we require that Eve cannot distinguish between a real encryption of her message \( m \) and an encryption of a random message unrelated to \( m \). We say that a probabilistic cryptosystem is CPA-secure if Eve's advantage in correctly guessing in the following game is negligible:
Eve sends a message \( m \) to an oracle, which returns a ciphertext \( c \). Here, \( c \) is either an encryption of \( m \) or a random message of the same length as \( m \). Eve then tries to guess what \( c \) is an encryption of.
Hence, if a probabilistic cryptosystem is CPA-secure, the only information that a ciphertext reveals is the length of the encrypted message.
A block cipher such as DES or AES only encrypts a single block of fixed size (56 bits for DES and 128 bits for AES). However, the data we want to encrypt (the plaintext) is often larger than 56 or 128 bits. This problem is solved by using a mode of operation, which describes how to repeatedly apply DES or AES (for both encryption and decryption) to plaintexts (and ciphertexts) larger than one block.
Most modes of operation require an initialization vector, denoted \( IV \) (or \( ctr \) in one of the modes), which is a random bit string with the same length as a block—either 56 bits or 128 bits. The initialization vector adds randomness to the encryption. For example, if we encrypt the same plaintext twice with the same key but use different initialization vectors, the resulting ciphertexts will be completely unrelated. It is therefore important that the initialization vector is unique for every encryption, but it does not need to be secret. As you will see below, the initialization vector is typically included with the ciphertext after encryption.
In 1980, the first four modes of operation were developed for DES (and can also be used with AES):
Later, in 2001, NIST (the US National Institute of Standards and Technology) added the following mode of operation for AES:
The size of the key \( K \) used in a mode of operation depends on the block cipher being used, i.e., whether it is DES or AES. For DES, the key is 56 bits, and for AES, the key can be 128, 192, or 256 bits. In the following, we assume that the plaintext \( m \) can be evenly divided into \( t \) blocks \( m_{1}, m_{2}, \dots, m_{t} \).
But what if the last block of the plaintext \( m_{t} \) is shorter than the size of one block, i.e., shorter than 56 bits or 128 bits? Because DES and AES only work on blocks of 56 bits and 128 bits, respectively, we have to pad \( m_{t} \) so that it has the correct length. There are various ways of padding the blocks, but as you can see in the demo, we add the missing \( p \) bytes \( p \) times, all with the value \( p \), at the end of \( m_{t} \). For example, if we want to encrypt the message "Hello Alice" with AES and the length of this message is 368 bits, we can divide it into three blocks \( m_{1}, m_{2}, m_{3} \). Now, \( m_{1} \) and \( m_{2} \) are each 128 bits, as they should be, but \( m_{3} \) is only 112 bits, so we need 16 more bits. Because 16 bits is the same as 2 bytes (8 bits is 1 byte), we pad \( m_{3} \) with "22", i.e., we actually encrypt the message "Hello Alice22".
Of the modes of operation we present, only the ECB and CBC modes require the last block to be padded before encryption if it is too short. The stream cipher modes — CFB, OFB, and CTR — do not require padding because the plaintext is XORed with a keystream.
The electronic codebook (ECB) mode corresponds to the naive use of a block cipher. Given the plaintext blocks \( m_{1}, m_{2}, \dots, m_{t} \), each block is encrypted with the same key \( K \), producing ciphertexts \( c_{1}, c_{2}, \dots, c_{t} \). The same method is used for decryption, i.e., \( c_{i} = E_{K}(m_{i}) \) and \( m_{i} = D_{K}(c_{i}) \), where \( E_{K} \) is the encryption algorithm and \( D_{K} \) is the decryption algorithm. Therefore, in ECB mode, encrypting the same plaintext block will always result in the same ciphertext, which is a serious weakness if the plaintext space is small or contains repeated patterns.
In the cipher block chaining (CBC) mode, the first ciphertext block (for encryption) is equal to the initialization vector \( IV \), and the remaining \( t \) ciphertext blocks are the encryption of the \( i \)-th plaintext block XORed with the previous ciphertext block, i.e., \( c_{0} = IV \) and \( c_{i} = E_{K}(c_{i-1} \oplus m_{i}) \). During decryption, the \( i \)-th plaintext block is computed by first decrypting the \( i \)-th ciphertext block and then XORing it with the previous ciphertext block, i.e., \( m_{i} = D_{K}(c_{i}) \oplus c_{i-1} \). Notice that if the plaintext block \( m_{i} \) is altered during encryption, then \( c_{i} \) and all subsequent ciphertext blocks will be affected. This property makes CBC mode very useful for authentication and is used in the CBC-MAC.
The output feedback (OFB) mode uses a keystream \( z_{1}, z_{2}, \dots, z_{t} \), where the first block in the keystream, \( z_{0} \), is equal to the initialization vector \( IV \), and the remaining \( t \) blocks are generated by encrypting the previous block, i.e., \( z_{0} = IV \) and \( z_{i} = E_{K}(z_{i-1}) \). The keystream is used during both encryption and decryption: the \( i \)-th ciphertext is the XOR of the \( i \)-th plaintext and the \( i \)-th keystream block, i.e., \( c_{i} = m_{i} \oplus z_{i} \), and the \( i \)-th plaintext is the XOR of the \( i \)-th ciphertext and the \( i \)-th keystream block, i.e., \( m_{i} = c_{i} \oplus z_{i} \). Notice that only the encryption algorithm is used, which makes OFB suitable for small devices with limited computing power, such as smart cards.
The cipher feedback (CFB) mode also uses a keystream, where the \( i \)-th keystream block is the encryption of the previous ciphertext block, i.e., \( z_{i} = E_{K}(c_{i-1}) \). During encryption, the first ciphertext block is equal to the initialization vector \( IV \), and the remaining \( t \) ciphertext blocks are the XOR of the \( i \)-th plaintext block and the \( i \)-th keystream block, i.e., \( c_{0} = IV \) and \( c_{i} = m_{i} \oplus z_{i} \). Decryption is almost the same, with \( m_{i} = c_{i} \oplus z_{i} \). Again, only the encryption algorithm is used.
The counter (CTR) mode is similar to OFB mode, but the keystream is generated slightly differently. In CTR mode, the initialization vector is called a counter vector and is denoted \( ctr \). The keystream is then the XOR of \( ctr \) and the counter \( i \), i.e., \( T_{i} = ctr \oplus i \; mod \; 2^{n} \), where \( n \) is the block size in bytes. During encryption, the \( i \)-th ciphertext block is the XOR of the \( i \)-th plaintext block and the encryption of the \( i \)-th keystream block, i.e., \( c_{i} = m_{i} \oplus E_{K}(T_{i}) \). During decryption, the \( i \)-th plaintext is the XOR of the \( i \)-th ciphertext block and the encryption of the \( i \)-th keystream block, i.e., \( m_{i} = c_{i} \oplus E_{K}(T_{i}) \). Notice that the encryption algorithm is used for both encryption and decryption, and the keystream depends only on \( ctr \) and the counter \( i \), so CTR mode can be run in parallel because the keystream does not depend on previous blocks.
It is recommended to use either CBC or CTR mode. CTR mode has the advantage of being faster, as it can run in parallel and uses only the encryption algorithm.
Key exchange | |
Alice and Bob agree on the key \( K \). | |
Encryption | |
Alice: Uses the key \( K \) with the encryption algorithm \( E \) to encrypt each plaintext block \( m_{i} \) as \( c_{i} = E_{K}(m_{i}) \). |
|
Alice sends the ciphertext blocks \( c \) to Bob. | |
Decryption | |
Bob: Uses the key \( K \) with the decryption algorithm \( D \) to recover each plaintext block \( m_{i} \) from the ciphertext blocks \( c_{i} \) as \( m_{i} = D_{K}(c_{i}) \). |
Key exchange | |
Alice and Bob agree on the key \( K \). | |
Encryption | |
Alice: Generates a random initialization vector \( IV \) with the same length as the block size. Uses the key \( K \) with the encryption algorithm \( E \) to encrypt the plaintext blocks \( m_{i} \) by setting \( c_{0} = IV \) and \( c_{i} = E_{K}(c_{i-1} \oplus m_{i}) \). |
|
Alice sends the ciphertext blocks \( c \) to Bob. | |
Decryption | |
Bob: Uses the key \( K \) with the decryption algorithm \( D \) to recover the plaintext blocks \( m_{i} \) from the ciphertext blocks \( c_{i} \) by setting \( c_{0} = IV \) and \( m_{i} = D_{K}(c_{i}) \oplus c_{i-1} \). |
Key exchange | |
Alice and Bob agree on the key \( K \). | |
Encryption | |
Alice: Generates a random initialization vector \( IV \) with the same length as the block size. Uses the key \( K \) with the encryption algorithm \( E \) to encrypt the plaintext blocks \( m_{i} \) by setting \( z_{0} = IV \), then for each block, computes \( z_{i} = E_{K}(z_{i-1}) \) and \( c_{i} = m_{i} \oplus z_{i} \). |
|
Alice sends the ciphertext blocks \( c \) to Bob. | |
Decryption | |
Bob: Uses the key \( K \) with the encryption algorithm \( E \) to decrypt the ciphertext blocks \( c_{i} \) by setting \( z_{0} = IV \), then for each block, computes \( z_{i} = E_{K}(z_{i-1}) \) and \( m_{i} = c_{i} \oplus z_{i} \). |
Key exchange | |
Alice and Bob agree on the key \( K \). | |
Encryption | |
Alice: Generates a random initialization vector \( IV \) with the same length as the block size. Uses the key \( K \) with the encryption algorithm \( E \) to encrypt the plaintext blocks \( m_{i} \) by setting \( c_{0} = IV \), then for each block, computes \( z_{i} = E_{K}(c_{i-1}) \) and \( c_{i} = m_{i} \oplus z_{i} \). |
|
Alice sends the ciphertext blocks \( c \) to Bob. | |
Decryption | |
Bob: Uses the key \( K \) with the encryption algorithm \( E \) to decrypt the ciphertext blocks \( c_{i} \) by setting \( c_{0} = IV \), then for each block, computes \( z_{i} = E_{K}(c_{i-1}) \) and \( m_{i} = c_{i} \oplus z_{i} \). |
Key exchange | |
Alice and Bob agree on the key \( K \). | |
Encryption | |
Alice: Generates a random initialization vector \( ctr \) with the same length as the block size. Uses the key \( K \) with the encryption algorithm \( E \) to encrypt the plaintext blocks \( m_{i} \) by computing \( T_{i} = ctr \oplus i \; mod \; 2^{n} \) and \( c_{i} = m_{i} \oplus E_{K}(T_{i}) \), where \( i \geq 0 \) and \( n \) is the block size in bytes. |
|
Alice sends the ciphertext blocks \( c \) to Bob. | |
Decryption | |
Bob: Uses the key \( K \) with the encryption algorithm \( E \) to decrypt the ciphertext blocks \( c_{i} \) by computing \( T_{i} = ctr \oplus i \; mod \; 2^{n} \) and \( m_{i} = c_{i} \oplus E_{K}(T_{i}) \), where \( i \geq 0 \) and \( n \) is the block size in bytes. |
Try a demo of the encryption scheme using one of the mode of operation here.
Alice needs to send an email \( m \) to Bob that contains sensitive information, so she encrypts the email before sending it. They first agree to use AES in CTR mode with a 128-bit key \( K = 01001000 \dots \).
Alice then divides the email \( m \) into 128-bit blocks. Assume that the email fits into three blocks, \( m_{1}, m_{2}, m_{3} \), and the 128-bit counter vector is \( ctr = 00000110 \dots \). She encrypts the plaintext blocks by first computing the keystream \( T_{i} = ctr \oplus i mod 2^{16} \) (where \( n = 16 \) because 128 bits is equal to 16 bytes), and then encrypting the \( i \)-th plaintext block as \( c_{i} = m_{i} \oplus E_{K}(T_{i}) \):
\( \eqalign{ T_{1} &= ctr \oplus 1 \; mod \; 2^{128} = 00000110 \dots \\ c_{1} &= m_{1} \oplus E_{K}(T_{1}) = 11010101 \dots \\ T_{2} &= ctr \oplus 2 \; mod \; 2^{128} = 10000110 \dots \\ c_{2} &= m_{2} \oplus E_{K}(T_{2}) = 10100101 \dots \\ T_{3} &= ctr \oplus 3 \; mod \; 2^{128} = 10000110 \dots \\ c_{3} &= m_{3} \oplus E_{K}(T_{3}) = 10111001 \dots } \)
She then sends the ciphertext blocks \( c_{1}, c_{2}, c_{3} \) to Bob.
Bob decrypts the received ciphertext blocks by first computing the keystream just as Alice did, i.e., \( T_{i} = ctr \oplus i mod 2^{16} \), and then decrypting the \( i \)-th ciphertext block as \( m_{i} = c_{i} \oplus E_{K}(T_{i}) \):
\( \eqalign{ T_{1} &= ctr \oplus 1 \; mod \; 2^{128} = 00000110 \dots \\ m_{1} &= c_{1} \oplus E_{K}(T_{1}) = 01010100 \dots \\ T_{2} &= ctr \oplus 2 \; mod \; 2^{128} = 10000110 \dots \\ m_{2} &= c_{2} \oplus E_{K}(T_{2}) = 01100101 \dots \\ T_{3} &= ctr \oplus 3 \; mod \; 2^{128} = 10000110 \dots \\ m_{3} &= c_{3} \oplus E_{K}(T_{3}) = 01111001 \dots } \)
The plaintext is then the concatenation of the plaintext blocks, i.e., \( m = m_{1} \: \| \: m_{2} \: \| \: m_{3} \).