Cryptology 101: Block Cipher Modes of Operation with Python example


Welcome to another Cryptology 101 article!

Today we will discuss block cipher modes of operation.

I know that the topic might not be fascinating, but it is worth to get through it even once.

Believe it or not, during job interviews, I was asked to briefly describe the topic not once, not twice.

We will also cover Python cryptographic libraries topic.

Let’s go 💣!

Where do we start?

If it is your first time here and you do not know what block ciphers are or what is the difference between symmetric and asymmetric cryptography, you better start with reading: Cryptology 101: Encryption

To reckon, let’s review what do we know yet:

Block cipher scheme – simplified

(block ciphers) are working on fixed-length groups of bits (blocks) – padded if needed.

Message M and Key K are divided into blocks, which are handed to the algorithm. Then in the “encryption black box,” magic happens, and the same amount of blocks as input (with the same length) is produced – and we have a ciphertext (so 128-bit message input provides 128-bit ciphertext). (and reverse)

Cryptology 101: Encryption

In the list of algorithms to memorize, the most important one was AES, Advanced Encryption Standard.

I used AES in Android Encryption: first step for secure notepad article to encrypt and decrypt data.


The Advanced Encryption Standard (AES) specifies a FIPS-approved cryptographic algorithm that can be used to protect electronic data. The AES algorithm is a symmetric block cipher that can encrypt (encipher) and decrypt (decipher) information.


The “AES/ECB/PKCS5Padding” was used with a 256-bit key.

In those two articles, I was promising to write about “operation modes.” But what does it mean? It means that we can force or bind individual blocks of data to strengthen the algorithm. But how?

Frequently asked questions

If you are here to know the questions and answers related to Block Cipher Modes of Operation, here are three of the most important:

(Answers based on: Block cipher mode of operation – Wikipedia)

  1. What is an operational mode?
    • A mode of operation describes how to repeatedly apply a cipher’s single-block operation to securely transform amounts of data larger than a block.
  2. What do we need it for?
    • Historically, encryption modes have been studied extensively regarding their error propagation properties under various data modification scenarios. Later development regarded integrity protection as an entirely separate cryptographic goal. Some modern modes of operation efficiently combine confidentiality and authenticity and are known as authenticated encryption modes.
  3. What are the most common?
    • Confidentiality only:
      • Electronic Codebook (ECB)
      • Cipher Block Chaining (CBC)
      • Cipher Feedback (CFB)
      • Output Feedback (OFB)
      • Counter (CTR)
    • Authenticated:
      • Galois/Counter Mode (GCM)
      • Synthetic initialization vector (SIV)
      • AES-GCM-SIV (a combination of above 2)
      • Counter with cipher block chaining message authentication code (CCM) aka unable to memorize

Now I’m going to describe them at a high level.

One by one

In December 1980 (yes, 40 years ago), FIPS announced FIPS-81 document – DES Modes of Operation. As you may recall, DES is the forerunner of AES. First, four of them (ECB, CBC, CFB, OFB) were described.

Let me describe them briefly with pros and cons.

Attention! The figures below, (E) or (D) close to the block cipher modes mark if it’s running on Encryption or Decryption mode.

Electronic Codebook (ECB)

It is named after conventional physical codebooks.
This mode is the simplest way to encrypt the message. It is divided into blocks, and each block is encrypted separately.

Electronic Codebook encryption and decryption

ECB mode can be susceptible to replay attacks.
ECB is the simplest one, but it is not recommended for use in cryptographic protocols. Why?

Because of the lack of diffusion in this method, ECB encrypts identical plaintext blocks into identical ciphertext blocks; it does not hide data patterns.

Please see below a simple comparison between plaintext, encrypted with ECB and CBC.

Plaintext vs ECB encryption vs CBC encryption

You can’t deny that even after encryption (with one of the strongest block ciphers) in ECB mode, the text is still readable in the image case. Now it is visible to the naked eye, that you should avoid it 😉

Cipher Block Chaining (CBC)

Now we have to introduce the concept of Initial Value (IV) aka Initialization Vector: It is a block of bits used to randomize and produce distinct ciphertexts even if the same plaintext is encrypted multiple times, without changing the key.

In the CBC mode, our message is XORed with the previous ciphertext block (or IV value) before being encrypted. Check out below:

Cipher Block Chaining (CBC) encryption and decryption

CBC is one of the most commonly used modes of operation. It has some issues, such as:

  • it has to be sequential – cannot be parallelized; each subsequent block uses the previous one.
  • the message must be padded to a multiple of the cipher block size
  • error propagating – even a one-bit change in a plaintext or initialization vector (IV) affects all following ciphertext blocks

Cipher Feedback (CFB)

(Simplified) Cipher Feedback mode is similar to CBC in reverse. IV value is encrypted, and the output is XORed with plaintext. The result of this operation is taken as IV for the following block:

Cipher Feedback (CFB) encryption and decryption

In decryption mode, block cipher (e.g., AES) is running in encryption mode.

Again, encryption has to be sequential, and it is error propagating.

CFB surpasses CDC in case of padding – there is no need to pad the message to multiple cipher block size.

Output Feedback (OFB)

This mode is unusual – it changes the block cipher into a synchronous stream cipher!

If you do not remember the difference between block and stream cipher – I’m sending you back to encryption 101.

OFB generates a keystream block, which is XORed with the plaintext block to get the ciphertext:

Output Feedback (OFB) encryption and decryption

It does not propagate errors – one flipped bit in plaintext equals one flipped bit in the ciphertext.

As you can see in the figure, operations depend on previous ones, so they cannot be parallelized. BUT plaintext and ciphertext are used for final XOR. We can perform block cipher operations in advance, waiting for the closing XOR. 

In decryption mode, block cipher again is running in encryption mode.

Counter (CTR)

Last but not least. It is also known as Integer Counter Mode (ICM) or Segmented Integer Counter (SIC).

Like OFB, it is turning block cipher into a stream cipher. Each following keystream block is the result of encrypting values of a Counter. The counter is a result of a function that produces a sequence, incremented-by-one.

It can be (e.g.) the concatenation of IV/nonce (number used once) with the counter’s following values.

Counter (CTR) encryption and decryption

It is one of the most popular block ciphers’ modes of operation, and like OFB, it is not propagating errors.

In decryption mode, block cipher again is running in encryption mode.

Authenticated encryption

Modes described above provides confidentiality only.

But we can imagine the situation where we would like to authenticate the sender – we want him to sign the encrypted message not only using asymmetric-key cryptography.

Such modes of operation are way more complicated, but I would like you to be aware of their existence.

Galois/Counter Mode (GCM)

This one of the most popular – it combines well-known counter mode (described above) and Galois field multiplication, used for authentication.

GCM works with block ciphers with a block size of 128 bits.

Ciphertext contains the IV, ciphertext, and authentication tag.

Synthetic Initialization Vector (SIV)

It is described as ‘a nonce-misuse resistant block cipher mode.’.
It synthesizes IV using some pseudorandom function S2V.

S2V processes authentication data, plaintext, and authentication key.

The plaintext is encrypted with CTR mode (with encryption key), and the result is the concatenation of S2V output and CTR-mode ciphertext.

Synthetic Initialization Vector (SIV) authenticated encryption


This is an AES-specific mode of operation, which combines Galois/counter mode and SIV mode.

Its construction is defined in RFC 8452 and was published in April 2019 as AES-GCM-SIV: Nonce Misuse-Resistant Authenticated Encryption. In the abstract, we can read that:

This memo specifies two authenticated encryption algorithms that are
nonce misuse resistant — that is, they do not fail catastrophically
if a nonce is repeated.


Python cryptography

Ugh! That was kind of tough! Let’s switch to more pleasant topics: Python programming.

In other programming languages, like Java, .NET you can use a build-in Crypto library and forget about the issue. I even used it once on an Android Encryption article.

Additionally, if you are willing to use other libraries, there is a vast article comparing all of them on Wiki: Comparison of cryptography libraries.

But – as you can see – Python occurs there only once.

After simple googling, you can find (more or less up-to-date) libraries such as:

  • PyCrypto – dead for a few years, currently 145 issues raised,
  • PyNaCl – bindings for NaCl (aka libsodium) C library – which is active, but as you can see on the Comparison page, it is deplorable in block ciphers implementation (and, to be honest, they have more ‘no’s’ than ‘yeses.’ in general).
  • PyCa/Cryptography – seems like it is a living PyCrypto fork with 200+ contributors. In my opinion, – trustworthy.
  • PyCryptodome – my current choice, implemented a lot of cryptographic primitives, which will allow me to demonstrate here, on my blog, cryptography fundamentals 🙂

Today I would like to show you how to encrypt images witch PyCryptodome and PIL library.

PyCryptodome supports ECB, CBC, CFB, OFB, CTR and OpenPGP modes for confidential only. For authenticated encryption, we can use CCM, EAX, GCM, SIV, and others. For a full list of features, visit: Features – PyCryptodome docs

I’ve prepared two simple images to demonstrate the difference between operation modes (ECB vs. Rest of World).

HFOC.png – plaintext
secret.png – plaintext

I’m going to start my script by loading them:

import PIL.Image as Image
from Crypto.Cipher import AES

secret ='secret.png')
hfoc ='hfoc.png')

As you can see, I’m using PyCryptodome library – bear in mind that if you want to use it too, you need to install it first:

pip install pycryptodome

And I’ve prepared the image_encrypt function, which takes img, operational mode, IV, and key.

def image_encrypt(img, mode, iv, key):

We need to convert images to bytes, initiate AES instance…

    bImg = img.tobytes()
    if mode == AES.MODE_ECB:
        cipher =, mode)
        cipher =, mode, iv)

encrypt bytes and convert them back into Image 🙂

    m = cipher.encrypt(bImg)
    enc_img = Image.frombytes('RGBA', img.size, m, 'raw')
    return enc_img

Even with random key b'tDSqLEEBjSz8MF4z' ECB is still much worse than CBC with b'0000000000000000' both as IV and encrytpion key…

Plaintext vs ECB encryption vs CBC encryption

Check out how it went for secret.png:

secret.png ECB encrypted

Still visible, right? After CBC encryption…

secret.png CBC encrypted

looks like pure random 😉

If you want to recreate the experiment, code below:

import PIL.Image as Image
from Crypto.Cipher import AES

secret ='secret.png')
hfoc ='hfoc.png')

def image_encrypt(img, mode, iv, key):
    bImg = img.tobytes()
    if mode == AES.MODE_ECB:
        cipher =, mode)
        cipher =, mode, iv)
    m = cipher.encrypt(bImg)
    enc_img = Image.frombytes('RGBA', img.size, m, 'raw')
    return enc_img

print('===== ECB MODE =====')
print('HFOC encrypted with random key:')
print('key: ' + 'tDSqLEEBjSz8MF4z')
image_encrypt(hfoc, AES.MODE_ECB, '', b'tDSqLEEBjSz8MF4z').save(
print('SECRET encrypted with random key:')
print('key: ' + 'tDSqLEEBjSz8MF4z')
image_encrypt(secret, AES.MODE_ECB, '', b'tDSqLEEBjSz8MF4z').save(
print('===== CBC MODE =====')
print('HFOC CBC:')
image_encrypt(hfoc, AES.MODE_CBC, b'0000000000000000',
print('SECRET CBC:')
image_encrypt(secret, AES.MODE_CBC, b'0000000000000000',


That was a long run. I do enjoy crypto-related topics, and I’m very proud of my SIV figure. I hope you liked it too, and block cipher modes of operation are now much clearer to you!

I encourage you to experiment with my script on your own and check the second recommended crypto library: PyCa/Cryptography.

I will one day further explore the crypto libraries topic, so – stay tuned!

If you would like to reach out to me, do not hesitate and go to contact me!

Source code for this project on my Github: HeadFullOfCiphers/PythonImgCipherModes

This article is part of the #cryptology101 series. Please check out related posts:

Reference list:

  2. PyCryptodome docs
  3. PyCa/Cryptography docs
  4. Comparison of cryptography libraries – Wikipedia page
  5. RFC 8452 – AES-GCM-SIV
  6. Block cipher mode of operation – Wikipedia page

3 thoughts on “Cryptology 101: Block Cipher Modes of Operation with Python example

Add yours

  1. Thanks for this walkthrough!
    The pics are really nice! I’m wondering what tool you’re using to create them… 🙂


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Blog at

Up ↑

%d bloggers like this: