A text s
has been encrypted with:
s2 = iv + Crypto.Cipher.AES.new(Crypto.Hash.SHA256.new(pwd).digest(),
Crypto.Cipher.AES.MODE_CFB,
iv).encrypt(s.encode())
Then, later, a user inputs the password pwd2
and we decrypt it with:
iv, cipher = s2[:Crypto.Cipher.AES.block_size], s2[Crypto.Cipher.AES.block_size:]
s3 = Crypto.Cipher.AES.new(Crypto.Hash.SHA256.new(pwd2).digest(),
Crypto.Cipher.AES.MODE_CFB,
iv).decrypt(cipher)
Problem: the last line works even if the entered password pw2
is wrong. Of course the decrypted text will be random chars, but no error is triggered.
Question: how to make Crypto.Cipher.AES.new(...).decrypt(cipher)
fail if the password pw2
is incorrect? Or at least how to detect a wrong password?
Here is a linked question: Making AES decryption fail if invalid password and here a discussion about the cryptographic part (less programming) of the question: AES, is this method to say “The password you entered is wrong” secure? .
AES provides confidentiality but not integrity out of the box - to get integrity too, you have a few options. The easiest and arguably least prone to "shooting yourself in the foot" is to just use AES-GCM - see this Python example or this one.
You could also use an HMAC, but this generally requires managing two distinct keys and has a few more moving parts. I would recommend the first option if it is available to you.
A side note, SHA-256 isn't a very good KDF to use when converting a user created password to an encryption key. Popular password hashing algorithms are better at this - have a look at Argon2, bcrypt or PBKDF2.
Edit: The reason SHA-256 is a bad KDF is the same reason it makes a bad password hash function - it's just too fast. A user created password of, say, 128 bits will usually contain far less entropy than a random sequence of 128 bits - people like to pick words, meaningful sequences etc. Hashing this once with SHA-256 doesn't really alleviate this issue. But hashing it with a construct like Argon2 that is designed to be slow makes a brute-force attack far less viable.