Let's say that an attacker has the plaintext, the ciphertext and the IV of a specific message. If the attacker can control the ciphertext and the IV, could he forge valid plaintext? Let's say that the message is shorter than the block size, just a few bytes. Could the attacker change the value of the plaintext by changing the IV?
Consider the case where you encrypt the plaintext message
attack at noon!! using AES-CBC-256, with the key
7ac01f50605b8fcebd1c82ea6a6aacd6b112e8c9675b84cd77054b2f49668301 and the iv
echo -n 'attack at noon!!' | openssl aes-256-cbc -e -nopad -K 7ac01f50605b8fcebd1c82ea6a6aacd6b112e8c9675b84cd77054b2f49668301 -iv f822ee7b8c0a8ba40daa773b01d9485a | xxd -p
The plaintext message is one block in length (16 bytes), and no padding is used, so this produces one block of cipher text:
Naturally, if you decrypt the ciphertext above using the same key and iv, you get the original plaintext:
echo -n '8b2f9ede941cb6f3958d809510f579a5' | xxd -p -r | openssl aes-256-cbc -d -nopad -K 7ac01f50605b8fcebd1c82ea6a6aacd6b112e8c9675b84cd77054b2f49668301 -iv f822ee7b8c0a8ba40daa773b01d9485a
attack at noon!!
Now, an attacker who knows the original plaintext (
attack at noon!!), the ciphertext, and the iv wishes to modify the iv, so that upon decryption, the plaintext produced is
attack at dawn!!.
To see how this is done, refer to the diagram below (copied from https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation):
Consider point labeled E. E is the AES decryption of the first block (in the case, the only block) of ciphertext, using the key. We don't know the key, so we can't compute E...
Or, can we? Looking further, the first block of ciphertext is E XOR IV. The XOR function is unique in that: if A XOR B = C, then you can re-arrange A, B, and C in any order, and the expression still holds true - i.e. A XOR C = B, and B XOR C = A. So:
Plaintext = E XOR IV E = Plaintext XOR IV IV = E XOR Plaintext
So, knowing the original plaintext (
attack at noon!!) and the IV (
f822ee7b8c0a8ba40daa773b01d9485a), we can compute E. To do this, we use E = Plaintext XOR IV (above). First, use the following command to get the hex representation of the underlying ascii-decoded bytes of the plaintext:
echo -n 'attack at noon!!' | xxd -p
Now, XOR the plaintext and the IV to get E like so:
python3 -c "print (hex(0x61747461636b206174206e6f6f6e2121 ^ 0xf822ee7b8c0a8ba40daa773b01d9485a))"
So, E is
Now, we can compute what the IV should be, so that when the ciphertext is decrypted by AES-CBC with our specially crafted IV, and E gets XOR'd with this IV, the plaintext produced will be our wanted plaintext 'attack at dawn!!'. To do this, we use IV = E XOR Plaintext (above). First, get the hex representation of the underlying ascii-decoded bytes of the wanted plaintext, like we did before:
echo -n 'attack at dawn!!' | xxd -p
Now, XOR the the wanted plaintext with E to get the IV that we need, like so:
python3 -c "print (hex(0x61747461636b206174206461776e2121 ^ 0x99569a1aef61abc5798a19546eb7697b))"
Let's see if it worked. Let's use the decryption command above to decypt the ciphertext, using iv
f822ee7b8c0a8ba40daa7d3519d9485a in place of
echo -n '8b2f9ede941cb6f3958d809510f579a5' | xxd -p -r | openssl aes-256-cbc -d -nopad -K 7ac01f50605b8fcebd1c82ea6a6aacd6b112e8c9675b84cd77054b2f49668301 -iv f822ee7b8c0a8ba40daa7d3519d9485a
Sure enough, the plaintext produced is:
attack at dawn!!
***Special thanks to Ángel for helping me work through this in the comments under the question.