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".
While ASCII is sufficient for basic English text, modern cryptographic applications often need to handle international characters. Unicode standards like UTF-8 extend ASCII and can encode virtually all characters from all writing systems. In UTF-8, ASCII characters still use a single byte, while other characters may use 2-4 bytes.
Modern cryptographic algorithms typically operate on bytes (8-bit units) or words (groups of bytes). The binary representation shown above organizes characters into bytes, which serve as the fundamental unit for cryptographic operations in algorithms like AES, where data is processed in 128-bit (16-byte) blocks.
Notice the relationship between the different representations:
It's important to note that encoding (converting characters to numbers or binary) is not the same as encryption. Encoding is a standardized, reversible process with no secret key. Anyone knowing the encoding scheme can decode the message. Encryption, on the other hand, requires a key to reverse the process, providing actual security.
Several other encoding schemes are commonly used in cryptographic applications:
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 \):
These operations work on each bit position independently when applied to longer bit strings. Let A = 10110110
and B = 11001101
:
Operation | Bit Values | Description |
---|---|---|
NOT A | NOT 10110110 = 01001001 |
Each bit flipped |
A AND B | 10110110 AND 11001101 = 10000100 |
Bitwise AND of each position |
A OR B | 10110110 OR 11001101 = 11111111 |
Bitwise OR of each position |
A XOR B | 10110110 XOR 11001101 = 01111011 |
Bitwise XOR of each position |
These operations are represented differently across contexts:
Bitwise operations are fundamental to modern cryptography:
XOR has special properties that make it valuable in cryptography:
These properties allow operations like: C = P \(\oplus\) K (encryption), P = C \(\oplus\) K (decryption)
Other important operations in cryptography include:
These operations are fundamental components in many encryption algorithms and hash functions.
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.
Formally, Eve's "advantage" in these security games is defined as the absolute difference between 1/2 and the probability that Eve correctly distinguishes the scenarios: |Pr[Eve guesses correctly] - 1/2|. We say this advantage is "negligible" if it decreases faster than any polynomial in the security parameter (typically the key length).
The security properties of symmetric ciphers depend heavily on their modes of operation:
The initialization vector (IV) or nonce is crucial for providing the randomness needed for CPA security.
CPA security is often referred to as "semantic security" or "indistinguishability under chosen plaintext attack" (IND-CPA). These terms all describe the same fundamental security property: an adversary cannot extract meaningful information about the plaintext from the ciphertext, even when they can obtain encryptions of chosen messages.
These security definitions have important practical consequences:
Block ciphers like DES or AES encrypt fixed-size blocks of data (56 bits for DES, 128 bits for AES). But what happens when we need to encrypt larger messages?
This is where modes of operation come in - they define how to apply a block cipher repeatedly to securely encrypt messages of any size.
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.
Mode | Requires IV | Parallel Encryption | Parallel Decryption | Error Propagation | Security Considerations |
---|---|---|---|---|---|
ECB | No | Yes | Yes | Limited to single block | Not recommended for messages longer than one block |
CBC | Yes | No | Yes | Affects current and next block | Secure when used with unpredictable IV |
CFB | Yes | No | No | Affects current and all subsequent blocks | Works as a stream cipher |
OFB | Yes | No | No | Limited to current block position | Requires unique IV for each encryption |
CTR | Yes (counter) | Yes | Yes | Limited to current block position | Modern, recommended mode when properly implemented |
Notice how identical plaintext blocks produce identical ciphertext blocks
Each block's encryption depends on the previous ciphertext block
Understanding the vulnerabilities of each mode is crucial for secure implementation. Even with strong underlying block ciphers like AES, improper mode usage can lead to serious security compromises.
The most serious vulnerability in ECB mode is that identical plaintext blocks encrypt to identical ciphertext blocks when using the same key.
Because each block is encrypted independently:
Occurs when an application reveals whether the padding of an encrypted message is correct:
Browser Exploit Against SSL/TLS:
Exploits the chaining mechanism to make predictable changes to plaintext:
Attack | OFB Mode | CFB Mode | CTR Mode |
---|---|---|---|
Key/IV Reuse | Critical vulnerability Allows XORing ciphertexts to recover plaintexts |
Critical vulnerability Allows XORing ciphertexts to recover plaintexts |
Critical vulnerability Makes the mode completely insecure |
Malleability | Highly malleable Bits can be flipped predictably |
Malleable Bits can be flipped with limited propagation |
Highly malleable Any bit can be flipped independently |
Short Cycle | Possible if key stream enters a cycle before full encryption | Not vulnerable | Not vulnerable with proper implementation |
Counter/Nonce Prediction | Not applicable | Not applicable | Vulnerable if counter is predictable |
The most dangerous attack for all stream cipher-like modes occurs when the same keystream is used twice:
\( c_{1} \oplus c_{2} = (m_{1} \oplus k) \oplus (m_{2} \oplus k) = m_{1} \oplus m_{2} \)
This allows attackers to recover information about both plaintexts, especially when one message is known or has predictable content.
Modern cryptographic systems rarely use raw block cipher modes. Instead, they use Authenticated Encryption with Associated Data (AEAD) modes that provide both confidentiality and integrity:
Key exchange | |
Alice and Bob agree on the key \( K \). | |
Encryption | |
Alice:
|
|
Alice sends the ciphertext blocks \( c \) to Bob. | |
Decryption | |
Bob:
|
Key exchange | |
Alice and Bob agree on the key \( K \). | |
Encryption | |
Alice:
|
|
Alice sends the ciphertext blocks \( c \) to Bob. | |
Decryption | |
Bob:
|
Key exchange | |
Alice and Bob agree on the key \( K \). | |
Encryption | |
Alice:
|
|
Alice sends the ciphertext blocks \( c \) to Bob. | |
Decryption | |
Bob:
|
Key exchange | |
Alice and Bob agree on the key \( K \). | |
Encryption | |
Alice:
|
|
Alice sends the ciphertext blocks \( c \) to Bob. | |
Decryption | |
Bob:
|
Key exchange | |
Alice and Bob agree on the key \( K \). | |
Encryption | |
Alice:
|
|
Alice sends the ciphertext blocks \( c \) to Bob. | |
Decryption | |
Bob:
|
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} \).