Cryptodome AES encrypt and decrypt - python

I'm struggling to find the issue within the code:
I've txt file on my desktop that i want to encrypt, then decrypt.
I'm using AES CBC as my encryption method.
Assume the file contain the following string:
bla bla top secret!!
I'm able to encrypt it successfully with the following line: modify(r"C:\Users\XXXXX\Desktop\TEST.txt", encrypt_file) output: W¢ìPY#Šÿb[l®«fì]ßQzýµá˺cØäûE
Then I'm trying to decrypt it with the following line modify(r"C:\Users\XXXXX\Desktop\TEST.txt", decrypt_file)
I'm getting the following exception: ValueError: Padding is incorrect.
If I remove the unpad function i can see the text is partical unencrypted as follow: bla bla top secrv€\Èu¢Þ#xH‹AÄ
I can't find whats wrong here.
Any help will be appreciated.
import os
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
HARD_CODED_KEY = b"SOME KEY"
iv = b'1234567812345678'
def encrypt_file(file, key, blocksize=16):
cipher = AES.new(key, AES.MODE_CBC, iv)
ciphertext = cipher.encrypt(pad(file, blocksize))
return ciphertext
def decrypt_file(file, key, blocksize=16):
cipher = AES.new(key, AES.MODE_CBC, iv)
cleartext = unpad(cipher.decrypt(file), blocksize)
return cleartext
def modify(file, crypt, blocksize=16):
with open(file, "r+b") as f:
plaintext = f.read(blocksize)
while plaintext:
ciphertext = crypt(plaintext, HARD_CODED_KEY, blocksize)
f.seek(-len(plaintext), 1) # go back to the same point before the read
f.write(ciphertext)
plaintext = f.read(blocksize)

Related

Encrypting mulitple files with hybrid encryptions, encountering error when decrypting

Basically, i am trying to encrypt 3 files in a folder with hybrid encryption, AES CBC. Successfully encrypted all the files, but having issues decrypting. The requirements for the task is:
2 seperate files, one for encrypting and one for decrypting
IV is 24 characters
IV can be hardcoded ,all files can use the same IV in or randomised (i randomised mine)
So far, only the last file is decrypted properly, the first 2 is giving me a ValueError error. However when i printed out the IV, it seems to be correct. Can someone advise me on this?
Encryption code
`#!/usr/bin/env python3
from base64 import b64encode
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from Crypto.Random import get_random_bytes
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
import glob
for item in glob.glob("*.txt"):
skey = get_random_bytes(16)
recipent_key = RSA.import_key(open("receiver.pem").read())
file_out = open("encrypted_key.bin", "wb")
cipher_rsa = PKCS1_OAEP.new(recipent_key)
enc_data = cipher_rsa.encrypt(skey)
file_out.write(enc_data)
file_out.close()
data_in = open(item, 'rb')
data = data_in.read()
data_in.close()
cipher = AES.new(skey, AES.MODE_CBC)
ct_bytes = cipher.encrypt(pad(data, AES.block_size))
iv = b64encode(cipher.iv).decode('utf-8')
ct = b64encode(ct_bytes).decode('utf-8')
skey = b64encode(skey).decode('utf-8')
print(iv, ct, skey)
datain = (iv, ct)
Fileout = open(item,'w')
Fileout.writelines(datain)
Fileout.close()
`
Decryption code
`#!/usr/bin/env python3
from base64 import b64decode
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
import os
import glob
for item in glob.glob("*.txt"):
file_in = open("encrypted_key.bin", "rb")
private_key = RSA.import_key(open("private.pem").read())
enc_data = file_in.read(private_key.size_in_bytes())
cipher_rsa = PKCS1_OAEP.new(private_key)
skey = cipher_rsa.decrypt(enc_data)
file_in.close()
in_file = open(item, "r")
data = in_file.read()
in_file.close()
print(data[0:24])
try:
iv = b64decode(data[0:24])
ct = b64decode(data[24:])
cipher = AES.new(skey, AES.MODE_CBC, iv)
pt = unpad(cipher.decrypt(ct), AES.block_size)
output = str(pt, 'utf-8')
print("the message was: ", output)
Fileout = open(item,'w')
Fileout.writelines(output)
Fileout.close()
except ValueError:
print("Incorrect decryption")
except KeyError:
print("incorrect key")
`
please send help :"")
EDIT: i realised, every round my loop goes, my key also randomise. that's the problem, i solved it :")

Python AES decryption - Padding is incorrect

I am fairly new to AES en/decrypting so bare with me.
Using the Crypto (Cryptodome) Library, I am trying to decrypt a message with a known key and a known iv as String.
from base64 import b64decode
from Crypto.Cipher import AES
from Crypto.Util import Padding
key = "some_key_as_string" #
key = base64.b64decode(key)
key = key.rjust(16, "0")
iv = "some_iv_as_string"
iv = b64decode(iv)
cipher = AES.new(key, AES.MODE_CBC, iv)
ct = b'Test_ciphertext'
ct = ct.ljust(16, "0")
message = Padding.unpad(cipher.decrypt(ct), AES.block_size)
However this gives me an Error called 'Padding not correct' which I am not able to remove by myself.
The keysize should be 256 bit, not sure if I included this with the encoding.
Can you tell me what I am missing here?
Edit: I should add that rjust only worked for me when I encoded the "0".
So instead of
key = key.rjust(16, "0")
I used
r = str.encode("0")
key = key.rjust(16, r)
as well for the ct

Unable to Decrypt a file using Key in Python

I have a video file which I am trying decrypt . The key is stored in a file. For some reasons it's not working and giving me this error "TypeError: Object type <class 'str'> cannot be passed to C code"
DecryptFile function I wrote takes 3 parameters
input file name ("input.ts")
output file name ("output.ts")
key for decryption ("k.kjs").
What I want it to do is decrypt the file with the key provided and save it with output name I gave . I am using Python 3.7.1
from Crypto.Cipher import AES
import os
def DecryptFile(infile,outfile,keyfile):
data = open(infile,"rb").read()
key = open(keyfile,"rb").read()
print(type(data))
iv = '\x00'*15 + chr(1)
aes_crypter = AES.new(key, AES.MODE_CBC, iv)
a = aes_crypter.decrypt(data)
with open(outfile, 'wb') as out_file:
out_file.write(a)
DecryptFile("input.ts","output.ts","k.kjs")
According to [ReadTheDocs.PyCryptodome]: AES - Crypto.Cipher.AES.new(key, mode, *args, **kwargs), iv should be:
Of type bytes
A kwarg
To get past this error, modify 2 lines of your code:
# ...
iv = b'\x00' * 15 + b'\x01'
aes_crypter = AES.new(key, AES.MODE_CBC, iv=iv)
# ...

AES: Input strings must be a multiple of 16 in length

I want to make a script to decrypt my filess, but when I try to run my script then show me this message , how can I fix it?
Traceback (most recent call last): File "F:\bug_bounty\decrypt.py",
line 46, in File "F:\bug_bounty\decrypt.py", line 24, in
decrypt File
"C:\Python27\lib\site-packages\Crypto\Cipher\blockalgo.py", line 295,
in decrypt
return self._cipher.decrypt(ciphertext) ValueError: Input strings must be a multiple of 16 in length
from Crypto.Hash import SHA256
from Crypto.Cipher import AES
import os
import random
import sys
def decrypt(key, filename):
outFile = os.path.join(os.path.dirname(filename),
os.path.basename(filename[11:]))
chunksize = 64 * 1024
with open(filename, 'rb') as infile:
filesize = infile.read(16)
IV = infile.read(16)
decryptor = AES.new(key, AES.MODE_CBC, IV)
with open(outFile, 'wb') as outfile:
while True:
chunk = infile.read(chunksize)
if len(chunk) == 0:
break
outfile.write(decryptor.decrypt(chunk))
outfile.truncate(int(filesize))
def allfiles():
allFiles = []
for (root, subfiles, files) in os.walk(os.getcwd()):
for names in files:
allFiles.append(os.path.join(root, names))
return allFiles
password = 'M4st3rRul3zs'
files = allfiles();
for filename in files:
if os.path.basename(filename).startswith("(encrypted)"):
print "%s is already encrypted" %filename
pass
else:
decrypt(SHA256.new(password).digest(), filename)
print "Done decrypting %s" %filename
"""os.remove(filename)"""
Here is the small trick you could use while encrypting the data if your data size is not large.
plaintext = "some text"
encryptor = AES.new(key, AES.MODE_CBC, iv)
ciphertext = encryptor.encrypt(plaintext*16)
This will ensure that your input data is a multiple of 16. And of course, you would like to get the original data back when decrypting.
cipher = AES.new(key, AES.MODE_CBC, iv)
decrypttext = cipher.decrypt(ciphertext)
decrypttext = decrypttext[0:len(plaintext)]
Now, decrpyttext has your original plaintext.
From Crypto++ wiki.
The block size is determined by AES::BLOCKSIZE. For AES, this is
always 16 bytes
AES is a block cipher, it works on 16-byte (128-bit) blocks. It can't work with data smaller or bigger than 16 bytes. Smaller data needs to be padded until they're 16 bytes, and larger data needs to be split into 16-byte blocks.
Also there are algorithms that help you achieve just that (work on data larger than the cipher's block size), they're called block cipher modes of operation.
Have a look at this How to encrypt more than 16 bytes using AES?
ValueError: Input strings must be a multiple of 16 in length
That is because AES works with blocks of 128 bits (16 chars). You can consider adding padding to fix this.
AES works with blocks of 16 chars. This how you can add extra padding
import random
import string
plaintext = "Encrypt me"
encryptor = AES.new(key, AES.MODE_CBC, iv)
while len(bytes(plaintext, encoding='utf-8')) % 16 != 0:
plaintext = plaintext + random.choice(string.ascii_letters)
ciphertext = encryptor.encrypt(plaintext)

How can I encrypt .docx files with AES & pycrypto without corrupting the files

I've got this bit of python code that I want to use to encrypt various kinds of files with AES 256. I am using the pycrypto module. It works fine for most files (exe, deb, jpg, pdf, txt) but when it comes to office files (docx, xlsx, ppt etc) the file is corrupted upon decryption and will no open (nor can it be repaired) in LibreOffice. I am using Linux mint, python 2.7.6, pycrypto 2.6.1. I'm still a bit of a noob so I'd appreciate it if you could give me code examples of the corrections you'd recommend.
Thanks
from Crypto import Random
from Crypto.Cipher import AES
import os
def pad(s):
return s + b"\0" * (AES.block_size - len(s) % AES.block_size)
def encrypt(message, key, key_size=256):
message = pad(message)
iv = Random.new().read(AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, iv)
return iv + cipher.encrypt(message)
def decrypt(ciphertext, key):
iv = ciphertext[:AES.block_size]
cipher = AES.new(key, AES.MODE_CBC, iv)
plaintext = cipher.decrypt(ciphertext[AES.block_size:])
return plaintext.rstrip(b"\0")
def encrypt_file(file_name, key):
with open(file_name, 'rb') as fo:
plaintext = fo.read()
enc = encrypt(plaintext, key)
with open(file_name + ".enc", 'wb') as fo:
fo.write(enc)
def decrypt_file(file_name, key):
with open(file_name, 'rb') as fo:
ciphertext = fo.read()
dec = decrypt(ciphertext, key)
with open(file_name[:-4], 'wb') as fo:
fo.write(dec)
key = b'\xbf\xc0\x85)\x10nc\x94\x02)j\xdf\xcb\xc4\x94\x9d(\x9e[EX\xc8\xd5\xbfI{\xa2$\x05(\xd5\x18'
encrypt_file('file.docx', key)
The problem is here
plaintext.rstrip(b"\0")
I have run the program and see the reason is:
There was a bug in here that caused the last bytes of the original file to be discarded if they happened to have the same value as the padding bytes!
To fix this issue, we have to store how many padding bytes were used during encryption, then remove them during decryption. Here is my code, it works for me (tested with word and excel 2013 files, pdf, jpg). Let me know if still some bugs.
from Crypto import Random
from Crypto.Cipher import AES
import hashlib
def pad(s):
padding_size = AES.block_size - len(s) % AES.block_size
return s + b"\0" * padding_size, padding_size
def encrypt(message, key, key_size=256):
message, padding_size = pad(message)
iv = Random.new().read(AES.block_size)
cipher = AES.new(key, AES.MODE_CFB, iv)
enc_bytes = iv + cipher.encrypt(message) + bytes([padding_size])
return enc_bytes
def decrypt(ciphertext, key):
iv = ciphertext[:AES.block_size]
cipher = AES.new(key, AES.MODE_CFB, iv)
plaintext = cipher.decrypt(ciphertext[AES.block_size:-1])
padding_size = ciphertext[-1] * (-1)
return plaintext[:padding_size]
def encrypt_file(file_name, key):
with open(file_name, 'rb') as fo:
plaintext = fo.read()
enc = encrypt(plaintext, key)
with open(file_name + ".enc", 'wb') as fo:
fo.write(enc)
def decrypt_file(file_name, key):
with open(file_name, 'rb') as fo:
ciphertext = fo.read()
dec = decrypt(ciphertext, key)
with open('processed_' + file_name[:-4], 'wb') as fo:
fo.write(dec)
key = 'Quan'
hash_object = hashlib.md5(key.encode())
while True:
filename = input('File: ')
en_de = input('En or De?')
if en_de.upper() == 'EN':
encrypt_file(filename, hash_object.hexdigest())
elif en_de.upper() == 'DE':
decrypt_file(filename, hash_object.hexdigest())
else:
print('Did not pick either en or de!')
cont = input('Continue?')
if cont.upper() == 'N':
break
If you need to add padding to make the plaintext a multiple of 16 bytes, the extra bytes need to be stripped before you write the decrypted data. This means you will need to somehow include the number of pad bytes added with the padding before you encrypt it. See PKCS#7 for one possible technique. There are a number of other schemes as well.

Categories