I made the following observation with an AES encrypt/decrypt example which is very counter intuitive for me.
I tried to encrypt and the decrypt a simple payload with AES in CBC mode. My understanding is/was that the initialization vector does not have to be secret, according to this answer: https://security.stackexchange.com/a/17046. And in most examples that I have seen the initialization vector is a non random part of the encrypted payload.
But by changing the initialization vector I was able to change the message during encryption.
See for example this python example which I copied and adapted from https://mcmap.net/q/125539/-encrypt-and-decrypt-using-pycrypto-aes-256.
I set a hardcoded iv
for encrypt
and I slightly adapted the iv
for decrypt
.
With this change I could change the message from "hello world"
to "hello!world"
.
import base64
import hashlib
from Crypto.Cipher import AES
class AESCipher(object):
def __init__(self, key):
self.bs = AES.block_size
self.key = hashlib.sha256(key.encode()).digest()
def encrypt(self, raw):
raw = self._pad(raw)
#iv = Random.new().read(AES.block_size)
# | here is the difference to the iv from decrypt
iv = b'\xe2\xe0l3H\xc42*N\xb0\x152\x98\x9cBh'
cipher = AES.new(self.key, AES.MODE_CBC, iv)
code = cipher.encrypt((raw.encode()))
return base64.b64encode(iv + code)
def decrypt(self, enc):
enc = base64.b64decode(enc)
#iv = enc[:AES.block_size]
# | here is the difference to the iv from encrypt
iv = b'\xe2\xe0l3H\xc52*N\xb0\x152\x98\x9cBh'
cipher = AES.new(self.key, AES.MODE_CBC, iv)
return self._unpad(cipher.decrypt(enc[AES.block_size:])).decode('utf-8')
def _pad(self, s):
return s + (self.bs - len(s) % self.bs) * chr(self.bs - len(s) % self.bs)
@staticmethod
def _unpad(s):
return s[:-ord(s[len(s) - 1:])]
if __name__ == '__main__':
text = "hello world"
print(text) # -> "hello world"
aes = AESCipher("F56hnXWaUWMh6ThQZ5l3mBg9zHFx6vQg")
payload = aes.encrypt(text)
print(aes.decrypt(payload)) # -> "hello!world"
The result of this simple example is completly counter-intuitive for me.
It seems that someone in the middle can take the payload, change the iv
slightly and by doing so change the decrypted message without even knowing the secret key!
In my understanding it should not be that easy to change the content of the encrypted message by just changing the initialization vector. Changing the initialization vector should result in a completly different result!
Is there something wrong with my thinking?
Could you help me clarify my misunderstanding?