Skip to content

Demonstrate how to use a padding oracle to break AES-CBC encrypted ciphertext (as seen on poodle).

License

Notifications You must be signed in to change notification settings

neuhalje/aes_padding_oracle_attack

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Using a Padding Oracle to crack AES in CBC mode

Incidents like the recent POODLE attack have shown that block ciphers in CBC Mode are vulnerable to certain attacks.

This repository implements an example attack against single blocks of AES-CBC encrypted ciphertext using a padding oracle to determine the plaintext. This is by no means an attack tool, it merely serves as an educational example for the padding oracle attack.

AES is not broken and padding oracle attacks are by no means new. But crypto is hard, and leaking seemingly innocent information (Is the plaintext padded correctly?) can have disastrous effects. Leaking information can happen by seemingly innocent ways, for a completely unrelated example see the Monty Hall 'paradoxon'.

The idea is that you read this text, and then dive into the source, starting from the tests.

Tests

TL;DR; Here are the tests that demonstrate the techniques used to achieve the goal. The tests (examples) build upon each other:

How does it work?

The attacks needs three things:

  • Prior encryption the plaintext has been padded according to PKCS#7
  • A ciphertext encrypted with a blockcipher in CBC mode (e.g. AES-CBC)
  • The oracle that tells me (the attacker), if a ciphertext I send it decrypts to a plaintext with valid padding

Padding with PKCS#7

AES (and many other) ciphers are so called block ciphers. The name comes from the fact that they operate in units of blocks (often 64 or 128 bit long) instead of single bytes (so called stream ciphers, e.g. RC4). Blocks ciphers cannot encrypt plaintext that is not a multiple of the block length.

In AES the block length is 128 bit, that is 16 bytes. If Alice wants to encrypt 10 bytes of plaintext (Hello Bob!) she needs to pad (fill up) the 10 byte message to 16 bytes. When Bob decrypts the message he needs to strip the padding.

This can be done, if Alice and Bob agree on a padding scheme. One such scheme is PKCS#7. PKCS#7 is very simple: If n bytes of padding (in this case n=6 bytes) need to be added, then add n times n.

E.g.

Hello_Bob! (10 bytes long) becomes Hello_Bob!\6\6\6\6\6\6 (16 bytes, the last 6 bytes have the value 6). Hi (2 bytes) is padded to Hi\14\14\14\14\14\14\14\14\14\14\14\14\14\14 (16 bytes, the last 14 bytes have the value 14).

Messages that end on a block size (e.g. message of 16 bytes) must also be padded. This is done by appending a complete padding block 16 16 .... 16.

When a message is decrypted the padding is verified. An invalid padding signals an error in the decryption process, e.g. due to the wrong key. E.g. a message ending with ... 3 1 3 would be a padding error because the last byte is 3 and this requires, that the last 3 bytes of the block are also 3.

Blockcipher Modi

CBC stands for Cipher Block Chaining and is one of several modi for block ciphers. A naive usage of a block cipher would follow the following algorithm to encryp a message of several blocks:

while plaintext.hasMoreBlocks
    plaintextBlock= plaintext.nextBlock
    ciphertextBlock= AES.encrypt(plaintextBlock)
    cipherTextStream.write(ciphertextBlock)

ECB

The naive implementation above is called the ECB mode (Electronic Code Book mode). ECB has several problems, for example the same plaintext block always encrypts to the same ciphertext block (under the same key). Say you have chat program that uses the following message format:

struct message {
        byte[16] sender;
        byte[16] recipient;
        ...
}

When these messages are encrypted using ECB, then an attacker cannot decipher sender oder recipient, but Alice ID always encrypts to the same 16 bytes. Once the attacker knows what the byte order for Alice is, he can detect all of Alice communications. In other words: an attacker can see that Alice wrote to Bob by just seeing the ciphertext.

There is a great example in Wikipedia that shows what happens, when images are encrypted with ECB mode!

CBC Mode

CBC improves ECB by preventing the "same plaintext encrypts to same ciphertext" problem. The idea is to always add the last ciphertextblock to the mix:

CBC Encryption

CBC Decryption

Images: Wikipedia

--- CBC encryption
ciphertextBlock= initialisationVector
while plaintext.hasMoreBlocks
    plaintextBlock= plaintext.nextBlock
    plaintextBlock= plaintextBlock XOR ciphertextBlock
    ciphertextBlock= AES.encrypt_ECB(plaintextBlock)
    cipherTextStream.write(ciphertextBlock)


--- CBC decryption
lastCiphertextBlock= initialisationVector
while ciphertext.hasMoreBlocks
    ciphertextBlock= ciphertext.nextBlock
    plaintextBlock= AES.decrypt_ECB(ciphertextBlock)
    plaintextBlock= plaintextBlock XOR lastCiphertextBlock
    plaintextTextStream.write(plaintextBlock)
    lastCiphertextBlock= ciphertextBlock

The Initialisation Vector needs to be transmitted together with the ciphertext but does not need to be kept secret. It acts as "ciphertext 0".

CBC mode is widely used, e.g. in SSL and SSH.

The Oracle Attack

The Oracle is a server that gives away an important information: Is decrypting this ciphertext padded correctly? The answer can either be transmitted as part of the protocol, or be infered from timing differences. The attack utilizes this information to infer the plaintext.

Glossary

  • Cn : the last block of ciphertext
  • Cn-1 : the second last block of ciphertext
  • Pn : The plaintext block of Cn
  • Pn* : A intermediate result for Cn.
  • Cn[15]: The 16th byte of Cn

Sketch of the attack

The decryption of the last block of ciphertext (Cn) in CBC works as follows (by definiton of CBC)

...
Pn* = ECB_Decrypt(Cn)
Pn  = Pn* XOR Cn-1

When the attacker manipulates the last byte of Cn-1 (Cn-1[15]) the last byte of Pn (Pn[15]) is changed. The idea is to force Pn[15] to the value 1 by manipulating the ciphertext, and utilizing the padding oracle.

Why? Thats why: When we know Pn[15] == 1, and we know Cn-1[15] we also know Pn*[15]!

     Pn  = Pn* XOR Cn-1  --- XOR Cn-1
 <=> Pn XOR Cn-1  = Pn*  --- when we know Pn and Cn-1, we know Pn*

The question now is: how do we know, that we guessed the correct tampering of Cn[15] and the Oracle decrypts the manipulated ciphertext to Pn[15] == 1?

Any plaintext ending in 1 has a valid PKCS#7 padding (of 1 byte). For nearly all other values the orcale will yield a padding error. So when the oracle doesn't return a padding error, the decrpyted ciphertext most likely ends in 1.

--- valid paddings
            01
         02 02
      03 03 03
   04 04 04 04
05 05 05 05 05
etc.

How to decrypt Pn[14] ... Pn[0]?

Decrypting Pn[14] works by extending the padding to a two byte padding. In other words: Set Pn[15] to 2, and use the oracle to find a Cn-1[14] that decrypts to 2.

Cn-1[15] = Pn*[15] XOR 2 -- This decrypts Pn[15] to Pn*[15] XOR Pn*[15] XOR 2 = 2

Forcing Pn[15] to a specific value is quite easy, when the plaintext is known. It is only necessary to manipulate Cn-1[15] (see above for the pseudo code).

How to decrypt the other blocks?

The padding oracle attacks only works against the last block. Attacking the blocks before the last block is very simple: to attack Cn-1 drop Cn, and now Cn-1 is the last block.

Counter Measures

The only effective way to counter this attack is to prevent information leakage. The easiest, and most reliable way is to create a signature (e.g. a HMAC) for the ciphertext. Verify before decrypting. When the signature is bad, reject the package. This will detect any tampering before the padding is checked.

About

Demonstrate how to use a padding oracle to break AES-CBC encrypted ciphertext (as seen on poodle).

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published