Decrypt in python pycryptodome AES CBC mode 256 - python

Followed the example here:
https://pycryptodome.readthedocs.io/en/latest/src/cipher/classic.html#cbc-mode
Also can decrypt in online encryption/decryption services.
My example is not working:
import hashlib
from base64 import b64encode, b64decode
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
def decipher():
secret_key = 'secret key'
secret_iv = 'secret iv'
key = hashlib.sha256(secret_key.encode('utf-8')).hexdigest()[:32].encode("utf-8")
iv = hashlib.sha256(secret_iv.encode('utf-8')).hexdigest()[:16].encode("utf-8")
s = 'HNAQf+1/fZXxzGTdVUs1qg=='
s = str.encode(s)
cipher = AES.new(key, AES.MODE_CBC, iv=iv)
plain_text = unpad(cipher.decrypt(s), AES.block_size) #<-- this line
return plain_text
ValueError: Data must be padded to 16 byte boundary in CBC mode

Related

pycryptodome & AES CBC : failing to decrypt a string

I'm trying to implement a simple encryption-decryption script with pycryptodome and AES-CBC, that is:
no iv,
no padding, therefore the string to encrypt is stripped do 16 characters
key is not random and is a fixed string.
However I fail by decrypting the message.
Here is the script:
from Crypto.Cipher import AES
from Crypto import Random
#import itertools
plain_text = "This is the text to encrypt"
key = "0361231230000000"
def encrypt(plain_text, key):
key = bytes(key, "UTF-8")
cipher = AES.new(key, AES.MODE_CBC)
print("Encryption Cipher: ", cipher)
# When there is no padding, the block size must equal the cipher length
# Padding is necessary for texts with length different from 16 bytes
cbytes = cipher.encrypt(bytes(plain_text[:16], "UTF-8"))
return cbytes
def decrypt(enc_text):
k = bytes(key, "UTF-8")
cipher = AES.new(k, AES.MODE_CBC)
print("Decryption Cipher: ")
return cipher.decrypt(enc_text).decode("UTF-8")
if __name__ == "__main__":
enc_text = encrypt(plain_text, key)
print(enc_text)
dec_text = decrypt(enc_text)
print(dec_text)
The error message is the following one:
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte
If in the decryption process I replace "UTF-8" by "Latin-1", the output does not match:
Decryption Cipher:
Ï(¨e¨^î
What did I miss ?
Unlike ECB, CBC does require an initialization vector. As the documentation says:
If [iv argument] not provided, a random byte string is generated (you must then read its value with the iv attribute).
To apply that to your code:
from Crypto.Cipher import AES
from Crypto import Random
plain_text = "This is the text to encrypt"
key = b"0361231230000000"
def encrypt(plain_text, key):
cipher = AES.new(key, AES.MODE_CBC)
b = plain_text.encode("UTF-8")
return cipher.iv, cipher.encrypt(b)
def decrypt(iv, enc_text):
cipher = AES.new(key, AES.MODE_CBC, iv=iv)
return cipher.decrypt(enc_text).decode("UTF-8")
if __name__ == "__main__":
iv, enc_text = encrypt(plain_text[:16], key)
dec_text = decrypt(iv, enc_text)
print(dec_text)

can somebody tell me what went wrong, when I am trying to decrypt the ciphertext that I encrypted, it tells me that my padding is incorrect

when trying to decrypt my plaintext, it's giving me a value error.
mesg = b'b235dd55aae34e97a054b05c09777e18'
decipher = AES.new(key,AES.MODE_CBC,iv)
plaintext = decipher.decrypt(mesg)
truetext = unpad(plaintext,block_size=16)
print(hexa(truetext).decode())
the output says that
ValueError: Padding is incorrect.
even though I encrypted the plaintext myself using
plaintext = b"hello world"
ciphertext = cipher.encrypt(pad(plaintext,16))
print(hexa(ciphertext).decode())
here is what my simple encryption/decryption looks like
#Pycryptodome
#unable to decrypt, padding problem
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
from Crypto.Util.Padding import pad, unpad
from binascii import hexlify as hexa
key = get_random_bytes(16)
iv = get_random_bytes(16)
cipher = AES.new(key,AES.MODE_CBC,iv)
plaintext = b"hello world"
ciphertext = cipher.encrypt(pad(plaintext,16))
print(hexa(ciphertext).decode())
mesg = b'b235dd55aae34e97a054b05c09777e18'
decipher = AES.new(key,AES.MODE_CBC,iv)
plaintext = decipher.decrypt(mesg)
truetext = unpad(plaintext,block_size=16)
print(hexa(truetext).decode())
Use this code instead.
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
from Crypto.Util.Padding import pad, unpad
from binascii import hexlify as hexa
key = get_random_bytes(16)
iv = get_random_bytes(16)
cipher = AES.new(key,AES.MODE_CBC,iv)
plaintext = b"hello world"
ciphertext = cipher.encrypt(pad(plaintext,16))
print(hexa(ciphertext).decode())
# mesg = b'b235dd55aae34e97a054b05c09777e18'
# can't be decrypted with different key/iv pair
decipher = AES.new(key,AES.MODE_CBC,iv)
plaintext = decipher.decrypt(ciphertext) # decrypt ciphertext instead
truetext = unpad(plaintext,block_size=16)
print(hexa(truetext).decode())
Your problem seems like(since i don't know key and iv of msg) is that when msg is decrypted and un-padded using pkcs7 the padding is not correct since pkcs7 check if message is padded correctly afterward (check wikipedia) and throws an error if message is not correctly padded.In summery, a plaintext encrypted with a specific key/iv pair, it's ciphertext must also be decrypted using same key/iv pair used during encryption otherwise your message will be decrypted to nonsense or result in wrong padding error.

AES CTR Mode Encryption with HMAC

I am trying to implement AES CTR encryption mode with HMAC authentication for messages.
It's encrypting and decrypting fine as long as the key length is 64 bytes, since AES key and HMAC key are being derived from this key.
Questions
Is it safe to append IV or nonce to the encrypted messages?
Is it safe to append HMAC digest to append to the messages?
Using Pycryptodome
Code
import os
import zlib
from Crypto.Hash import HMAC
from Crypto.Hash import SHA256
from Crypto.Cipher import AES
from Crypto.Util import Counter
import zlib
def encrypt(full_key, plaintext):
if len(full_key) != 64:
raise Exception("FULL key length shall be equal to 64")
key = full_key[:len(full_key) //2]
# Use the last half as the HMAC key
hmac_key = full_key[len(full_key) // 2:]
if isinstance(plaintext, str):
plaintext = plaintext.encode()
compressed = zlib.compress(plaintext, 5)
print (f"compressed plaintext {compressed}")
# Choose a random, 16-byte IV.
iv = os.urandom(16)
# Convert the IV to a Python integer.
iv_int = int(binascii.hexlify(iv), 16)
# Create a new Counter object with IV = iv_int.
ctr = Counter.new(128, initial_value=iv_int)
# Create AES-CTR cipher.
aes = AES.new(key, AES.MODE_CTR, counter=ctr)
# Encrypt and return IV and ciphertext.
ciphertext = aes.encrypt(compressed)
hmac_obj = HMAC.new(hmac_key, compressed, SHA256)
mac = hmac_obj.digest()
return iv+ciphertext+mac
def decrypt(key, ciphertext):
# Initialize counter for decryption. iv should be the same as the output of
# encrypt().
if len(full_key) != 64:
raise Exception("FULL key length shall be equal to 64")
key = full_key[:len(full_key) //2]
# Use the last half as the HMAC key
hmac_key = full_key[len(full_key) // 2:]
mac_length = 32
iv_length = 16
iv = ciphertext[:16]
mac = ciphertext[-mac_length:]
_ciphertext = ciphertext[iv_length:-mac_length]
iv_int = int(iv.hex(), 16)
ctr = Counter.new(128, initial_value=iv_int)
# Create AES-CTR cipher.
aes = AES.new(key, AES.MODE_CTR, counter=ctr)
ciphertext = aes.decrypt(_ciphertext)
# Extract the MAC from the end of the file
hmac_obj = HMAC.new(hmac_key, ciphertext, SHA256)
computed_mac = hmac_obj.digest()
if computed_mac != mac:
raise Exception("Messege integrity violated")
plaintext= zlib.decompress(ciphertext)
# Decrypt and return the plaintext.
return plaintext

PyCrypto Not Printing Properly

Hi so before I was getting the IV in front (decrypted value of IV I believe it was) of the decrypted string. Now I don't get the string... How do I make this work, been trying for hours now...
My code:
from Crypto.Cipher import AES
import hashlib
import base64
import os
import string
iv = os.urandom(16)
key = hashlib.sha256(b'mypassword123').digest()
plaintext = (b'the password is totally not secure')
cipher = AES.new(key, AES.MODE_CFB, iv)
ciphertext = iv + cipher.encrypt(plaintext)
print (ciphertext)
print ("IV = ",iv)
ciphertext = ciphertext.split(iv)
ciphertext = str(ciphertext)[1].strip()
plaintext = cipher.decrypt(ciphertext)
print (plaintext)
encrypt will change cipher, you have to make a new one;
and str will change byte to repr(byte), like below:
a=b'xxx'
str(a) # "b'xxx'"
from Crypto.Cipher import AES
import hashlib
import base64
import os
import string
iv = os.urandom(16)
key = hashlib.sha256(b'mypassword123').digest()
plaintext = (b'the password is totally not secure')
cipher = AES.new(key, AES.MODE_CFB, iv)
ciphertext = iv + cipher.encrypt(plaintext)
print (ciphertext)
print ("IV = ",iv)
ciphertext = ciphertext.split(iv)
ciphertext = ciphertext[1]
cipher2 = AES.new(key, AES.MODE_CFB, iv)
plaintext = cipher2.decrypt(ciphertext)
print (plaintext)
detail see pycrypto

Understand pycrypto example

As an example, encryption can be done as follows:
>>> from Crypto.Cipher import AES
>>> from Crypto import Random
>>>
>>> key = b'Sixteen byte key'
>>> iv = Random.new().read(AES.block_size)
>>> cipher = AES.new(key, AES.MODE_CFB, iv)
>>> msg = iv + cipher.encrypt(b'Attack at dawn')
when i execute 'msg' out on the interpreter i receive
b'D\x9e\nRF\xb9\xe3\xa0%vN\xe8bC\xe7\r8\xec\xae\x84\x9b\xf9\x11\xdc\xdf\xcb\xf4\xfev\x9b'
i understand that this is the 'key' variable being the 'Sixteen byte key' in byte form.
Now that the 'msg' is encrypted what can I do to decrypt this message?

Categories

Resources