ระบุโหมด AES

Oct 22 2020

สมมติว่าฉันมี API ที่ยอมรับ Plaintext และ IV เป็นพารามิเตอร์อินพุตและส่งคืน ciphertext ฉันรู้ว่า API ใช้การเข้ารหัส AES 128 แต่ตอนนี้ฉันต้องระบุโหมดการเข้ารหัส (ECB, CBC, OFB, CFB หรือ CTR) ที่ใช้อยู่ ฉันจะระบุโหมดการเข้ารหัสได้อย่างไร? ข้อเสนอแนะคำแนะนำหรือคำแนะนำใด ๆ จะได้รับการชื่นชมมาก

ตัวอย่าง:

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

การตอบสนอง: 7fcb5212d14de7ddcc334ec31acec6ae

คำตอบ

4 Gilles'SO-stopbeingevil' Oct 22 2020 at 21:39

คุณมีกล่องดำที่เข้ารหัสข้อมูลและคุณกำลังทำงานภายใต้สมมติฐานที่ว่ากล่องดำนี้ใช้โหมดยอดนิยม (ECB, CBC, CTR, OFB หรือ CFB) ของการเข้ารหัส (ไม่ได้รับรองความถูกต้อง) ผ่านการเข้ารหัสบล็อก คุณสามารถส่งอินพุตข้อความธรรมดาเพื่อเข้ารหัสรวมทั้ง IV ที่คุณเลือกได้

ขั้นแรกคุณสามารถแยกแยะระหว่างโหมดสตรีมและโหมดที่ไม่ใช่สตรีมได้อย่างง่ายดาย:

  • 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.
3 SEJPM Oct 22 2020 at 09:13

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...).