Let's say I have an API that accepts Plaintext and IV as input parameter and returns the ciphertext. I know that API is using AES 128 encryption but now I need to identify which encryption mode (ECB, CBC, OFB, CFB, or CTR) it is using. How can I identify the encryption mode? Any suggestion, hint or guidance would be much appreciated.


curl "http://dev/api/v1.0/test?iv=00112233445566778899&text=01234567"

Response: 7fcb5212d14de7ddcc334ec31acec6ae

  • $\begingroup$ It has 32 hex = 128 bits. It should be ECB. $\endgroup$
    – kelalaka
    Commented Oct 22, 2020 at 9:01
  • 1
    $\begingroup$ @kelalaka note that it could also be CBC from that argument... $\endgroup$
    – SEJPM
    Commented Oct 22, 2020 at 9:05
  • $\begingroup$ Thanks for the comment! Much appreciated. The given example is CBC mode. The intent for asking this question is to understand how is the answer CBC? Or how did you identify it as ECB? What is the method or approach for identifying the mode? Why isn't it OFB/CFB/CTR? $\endgroup$
    – Alex
    Commented Oct 22, 2020 at 9:07
  • $\begingroup$ Well, if only the ciphertext is given you can't. Since the ciphertext is 128-bit then it can be ECB. As noted by SEJPM, however, the IV is supplied from the outside so it can be any other. $\endgroup$
    – kelalaka
    Commented Oct 22, 2020 at 9:14

2 Answers 2


You have a black box that encrypts data, and you're working under the assumption that this black box implements a popular mode (ECB, CBC, CTR, OFB or CFB) of (unauthenticated) encryption over a block cipher. You can submit input plaintexts to encrypt, as well as an IV of your choice.

First, you can easily distinguish between stream modes and non-stream modes:

  • CTR, OFB and CFB are stream cipher modes. The ciphertext always has the same length as the plaintext.
  • ECB and CBC can only encrypt whole blocks. The length of the ciphertext is always a multiple of the block length (16 bytes for AES, Camellia, ARIA, SM4).
  • There are non-stream modes for which the ciphertext has the same length as the plaintext, for example CTS on top of a mode such as CBC or XEX. But I won't consider them in this analysis.

So encrypt 1 byte. If you get 1 byte of ciphertext, it's a streaming mode. If you get 16 bytes, it's a whole-block mode with padding. If you get an error but encrypting 16 bytes work, it's a whole-block mode without padding.

Padding and block modes

ECB doesn't actually use an IV. So if you get the same output regardless of the IV, it's ECB, otherwise it probably isn't. But if it's a weirdly designed system, the IV could be used in a nonstandard way, for example a “quasi-ECB” could use ECB on IV+plaintext.

Encrypt two identical blocks. If the first two ciphertext blocks are identical, it's ECB. Otherwise, by elimitation, it's CBC. (There may or may not be a third block depending on the padding method.)

CBC (or ECB) padding normally increases the size of the ciphertext by 1 to 16 bytes. The reason that padding is always at least 1 byte is to make decryption unambiguous: if there were cases of empty padding, it would be impossible to tell by looking at the decrypted-but-not-yet-unpadded ciphertext. Most padding methods convey the length of the padding through the value of the last byte of the decrypted-but-not-yet-unpadded ciphertext. However it is possible to allow empty padding if the length of the plaintext is transmitted separately, or if the plaintext has known properties such as ending with a certain byte. (It's not a good idea, but we're talking about analyzing a badly designed system here.)

Distinguishing stream modes

(Notations: $E$ is the block encryption function, $||$ is string concatenation, $\oplus$ is bitwise xor, $+$ is addition on counter values, $\mathbf{0}$ is an all-bits zero block, $\mathbf{1}$ is a block where all bits are zero except that the last bit is 1.)

Because you can submit the same IV for encryption multiple times, it is possible to distinguish between stream modes. Let's look at how a two-block plaintext $P_1 || P_2$ is encrypted into a two-block ciphertext $C_1 || C_2$:

  • OFB: $C_1 = E(\mathrm{IV}) \oplus P_1$, $C_2 = E(E(\mathrm{IV})) \oplus P_2$
  • CFB: $C_1 = E(\mathrm{IV}) \oplus P_1$, $C_2 = E(E(\mathrm{IV}) \oplus P_1) \oplus P_2$
  • CTR: $C_1 = E(\mathrm{IV}) \oplus P_1$, $C_2 = E(\mathrm{IV}+1) \oplus P_2$

Let's use this to construct a way to distinguish these three modes.

  1. Encrypt a one-block all-bits-zero plaintext with an all-bits-zero IV. No matter which of these three modes the black box implement, the output is $E(\mathbf{0})$.
  2. Encrypt a one-block all-bits-zero plaintext with the IV $E(\mathbf{0})$. The output is $E(E(\mathbf{0}))$.
  3. Encrypt a one-block all-bits-zero plaintext with the IV $\mathbf{1}$ (all-bits-zero except that the last bit is 1). The output is $E(\mathbf{1})$.
  4. Encrypt a one-block all-bits-zero plaintext with the IV $E(\mathbf{0}) \oplus \mathbf{1}$. The output is $E(E(\mathbf{0}) \oplus \mathbf{1})$.
  5. Now encrypt a two-block plaintext: $\mathrm{IV} = \mathbf{0}$, $P_1 = \mathbf{1}$, $P_2 = \mathbf{0}$. Look at the second block of the ciphertext.
    • OFB: $C_2 = E(E(\mathbf{0}))$ (calculated at step 2).
    • CFB: $C_2 = E(E(\mathbf{0}) \oplus \mathbf{1})$ (calculated at step 4).
    • CTR: $E(\mathrm{0} + 1)$. This is usually $E(\mathrm{1})$ (calculated at step 3) but may be different if the CTR implementation does the counter incrementation differently.
  • $\begingroup$ Thanks for such a detailed answer! This made things clear for me. I think using your guidance I was able to create a distinguisher for CBC and would like to know if its correct or not: I'm using IV 0 and P1 0 for solving. Notations have same meaning as described above. Step 1: Get Cipher C1 = E(P1 ⊕ IV) = E(0) Step 2: Get Cipher C2 = E(P1 ⊕ C1) = E(C1), Step 3: Encrypt 2 blocks of plain-text i.e. P1||P1: C1||C2 = E(P1||P1 ⊕ IV) $\endgroup$
    – Alex
    Commented Oct 23, 2020 at 7:21
  • $\begingroup$ And one more question: I have the another API: curl "http://dev/api/v1.0/test-1?iv=00000000000000000000000000000000&text=00000000000000000000000000000000" {"ciphertext":"e910b119321663b062ca59d3f09a95f6282397de97904f8267638c5f234b1ee7"} In this case the cipher text is multiple of 16 byte block but using the distinguisher mentioned in my above comment this is not a CBC. This not an ECB either since when I tried 2 identical plain-text block the output wasn't identical ciphers. So could this be padded stream mode or some other mode? $\endgroup$
    – Alex
    Commented Oct 23, 2020 at 7:45
  • $\begingroup$ @Alex Your calculations are correct except that the result for step 3 doesn't make sense (C1||C2 is two blocks). If you encrypt $\mathbf{0}||\mathbf{0}$, you get $E(\mathbf{0}) || E(E(\mathbf{0}))$. But that's with unpadded CBC. Since a 16-byte plaintext results in a 32-byte plaintext, this is probably CBC with padding. $\endgroup$ Commented Oct 23, 2020 at 8:20
  • $\begingroup$ In step 3 I'm encrypting 2 blocks of plain-text (P1||P2) so it is not 16-byte but indeed 32-byte plaintext and it results in cipher text which is 48 byte. The first 32 byte is the cipher text (C1||C2) and the last 16 byte padding. I hope that makes sense! But what do you think about the second question? In my second question I don't think its CBC so could it be a padded stream mode or some different mode? $\endgroup$
    – Alex
    Commented Oct 23, 2020 at 8:34
  • $\begingroup$ @Alex CBC is the only common mode with padding (and ECB but thankfully it's not that common). Stream modes don't have padding. What you've posted so far is consistent with CBC+padding. $\endgroup$ Commented Oct 23, 2020 at 8:39

How can I identify the encryption mode?

You can't fully identify this mode without sending around $2^{64}$ish bytes of data under the same key, as only then the streaming modes (CFB, OFB, CTR) start to break down in security in different ways.

However you can be sure that if you see a ciphertext that is not a multiple of the block length (16 bytes for AES) then you have one of CFB, OFB or CTR (or a mode similar streaming mode or one built on top of any of them).

Now, if you always get outputs that are a multiple of the blocklength, then it is likely that it's CBC or ECB mode. You can distinguish these two based on the classic ECB vulnerability which CBC doesn't have: Equal blocks of inputs are processed to equal blocks of outputs. In practice this means that you could simply send 32 all-0 bytes and if you get something back that shows two 16-byte sequences which are the same, you have ECB otherwise CBC. Alternatively if in you specify different IVs for the same plaintext and still get the same ciphertext back, you also know ECB is used (though CBC IVs really should be picked at random and not by the adversary...).

  • $\begingroup$ Thanks for the detailed reply! I've been already trying to exploit the ECB vulnerability but so far no luck.. May be since I'm new in this field I'm not doing something properly :( Here's my attempt based on your guidance: curl "http://dev/api/v1.0/test?iv=00000000000000000000000000000000&text=00000000000000000000000000000000" {Response:"b'ebc95850798949f85130f30d37b7e2f58103e9c2fb067bb75a0a764e5ed379f6'"} $\endgroup$
    – Alex
    Commented Oct 22, 2020 at 9:33
  • 1
    $\begingroup$ @Alex that's 16 bytes in the text, you need 32 for for the duplicate ECB block issue to show up (64 hex characters). Or you can try the iv-ignoring approach. $\endgroup$
    – SEJPM
    Commented Oct 22, 2020 at 9:39
  • 3
    $\begingroup$ @Alex: Because the question leaves the choice of IV (as well as plaintext), and assuming the key is fixed, we can go a step further than in the answer, and identify all common modes. For example, with fixed repeating plaintext of a few blocks, if increasing the IV by 1 shifts the ciphertext by one block, we have positively identified CTR with full-width IV (one block). However this might not happen here even if the mode was CTR, because the IV seems shorter than one block (which is common with CTR). There are other distinguishers for other modes, and not so many common modes. $\endgroup$
    – fgrieu
    Commented Oct 22, 2020 at 10:00
  • $\begingroup$ Thanks guys for useful hints and guidance! This is my first question here and I'm extremely thankful for your kind support $\endgroup$
    – Alex
    Commented Oct 23, 2020 at 7:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.