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
Related
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
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.
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
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?
So I'm trying to make a simple AES encrypt/decrypt system right now in Python... However when it decrypts it has a bunch of /xxx/xxx/xxx/xxx/ in front of the decrypted string. How do I clean it and make it print only the plaintext.
My code is:
import base64
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...')
print (msg)
print (base64.b64encode(msg))
print (cipher.decrypt(msg))
The output of decrypt looks like this:
b'\xfb\xb8\xf0\xc3\xffH\xfc~\x19[\xecy?\xf8\xcc\x80Attack at dawn...'
The initialization vector (IV) is part of your encrypted message (msg), but the ciphertext itself should contain the IV. This means that you have to remove the IV before decrypting, i.e. like this:
cipher.decrypt(msg[16:])
Next issue is that you shouldn't use the same AES instance for encryption and decryption. The AES instance contains internal buffers that cannot be easily refreshed.
key = b'Sixteen byte key'
# encryption
iv = Random.new().read(AES.block_size)
cipher = AES.new(key, AES.MODE_CFB, iv)
msg = iv + cipher.encrypt(b'Attack at dawn...')
print (msg)
print (base64.b64encode(msg))
# decryption
cipher = AES.new(key, AES.MODE_CFB, msg[:16])
print (cipher.decrypt(msg[16:]))
However when it decrypts it has a bunch of /xxx/xxx/xxx/xxx/ in front of the decrypted string.
You have much luck that you see the decrypted string at all at the end. This is only because the IV is prepended to the message and the inner workings of the CFB mode of operation. If you would have used the CTR mode, this would have looked much different.
The docs state:
That also means that you cannot reuse an object for encrypting or decrypting other data with the same key.
which is a bit cryptic, but if seems to mean you can't reuse cipher to decrypt. Also, I'm not sure why you concatenate iv to your encrypted message.
The code below works fine for me:
key = b'Sixteen byte key'
iv = Random.new().read(AES.block_size)
c = AES.new(key, AES.MODE_CFB, iv)
msg = c.encrypt('Attack at dawn...')
d = AES.new(key, AES.MODE_CFB, iv)
d.decrypt(msg)