Decrypt AES ECB using python - python-3.x

I have some data i want to decrypt which is encrypted in AES ECB with PKCS5 padding using java. but i am having hard time decryptiing it. i tried many tutorials and stack overflow ans. but nothing worked for me. help me with this
i am trying like this
BLOCK_SIZE = 16
pad = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * \
chr(BLOCK_SIZE - len(s) % BLOCK_SIZE)
unpad = lambda s: s[:-ord(s[len(s) - 1:])]
def decrypt(key,enc):
enc = b64decode(enc)
cipher = AES.new(key.encode("utf8"), AES.MODE_ECB)
return unpad(cipher.decrypt(enc)).decode('utf8')
key = '0vlqRTgxr0C]X29C(}{M\\&TZErb$1!f{'
enc = 'T3cPMizpZj63+iVwXvlFUnD8Hld5XN4h3v3Ncd8YuIk='
but i am getting only empty string back

It looks like you are using the PyCrypto/PyCryptoDome package for encryption. Instead of writing your own padding function, it's easier to use the built-in one. Here's the example from the docs:
from Crypto.Util.Padding import pad, unpad
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
data = b'Unaligned' # 9 bytes
key = get_random_bytes(32)
iv = get_random_bytes(16)
cipher1 = AES.new(key, AES.MODE_CBC, iv)
ct = cipher1.encrypt(pad(data, 16))
cipher2 = AES.new(key, AES.MODE_CBC, iv)
pt = unpad(cipher2.decrypt(ct), 16)
assert(data == pt)
So in your case, you can get rid of the padding functions and simply rewrite the encrypt and decrypt functions to use PyCryptoDome's padding utils. I've done that for you here with two functions, encrypt and decrypt.
from Crypto.Util.Padding import pad, unpad
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
from base64 import b64encode,b64decode
key = get_random_bytes(32)
iv = get_random_bytes(16)
def encrypt(plaintext,key):
cipher = AES.new(key,AES.MODE_CBC,iv)
return b64encode(cipher.encrypt(pad(plaintext.encode(),16))).decode()
def decrypt(ciphertext,key):
cipher = AES.new(key,AES.MODE_CBC,iv)
return unpad(cipher.decrypt(b64decode(ciphertext.encode())),16).decode()
And testing it:
>>> encrypt("hello",key)
'aekD8rXrimLT12hFWg22ww=='
>>> decrypt('aekD8rXrimLT12hFWg22ww==',key)
'hello'
Note that I used CBC mode because ECB mode is insecure and shouldn't ever be used. Even CBC has weaknesses, and I would recommend you use CTR mode and an HMAC, or GCM mode which will take care of everything for you.

Related

Symmetric encryption of Python strings that get deciphered with correct and incorrect password

I want to create a symmetric encryption scheme that attempts to decipher regardless of the issued password being correct or not.
import base64
import os
from cryptography.fernet import Fernet
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
password = b"correct_password"
wrong_password = b"wrong_password"
salt = os.urandom(16)
kdf_1 = PBKDF2HMAC(
algorithm=hashes.SHA256(),
length=32,
salt=salt,
iterations=390000,
)
kdf_2 = PBKDF2HMAC(
algorithm=hashes.SHA256(),
length=32,
salt=salt,
iterations=390000,
)
key = base64.urlsafe_b64encode(kdf_1.derive(password))
wrong_key = base64.urlsafe_b64encode(kdf_2.derive(wrong_password))
f_1 = Fernet(key)
f_2 = Fernet(wrong_key)
token_1 = f_1.encrypt(b"Secret message!")
Now:
print(token_1)
> b'gAAAAABiM3FYV1-THq95gKksrrfX4nuHaUCP-ek7bA8EqcxbYvoy5Z8pG9HpUsU2KrspBPNtRB6XpsBH-PlQlL-db2b1N8LYJQ=='
Regular decryption:
f_1.decrypt(token_1)
b'Secret message!'
Perfect.
f_2.decrypt(token_1)
Token exception
Is there any option (or other Python3 lib) that won't enforce checks? Without any exception or other hints?

M2Crypto.SMIME.PKCS7_Error: wrong tag

I'm a beginner in the cryptography area and I'm trying to do the fetch data from a singed data and I'm getting this error while doing the process
import base64
from M2Crypto import BIO, SMIME, X509
s = SMIME.SMIME()
encoded = base64.b64encode(data_input)
cooked_sig = b"\n".join(encoded[pos:pos + 76] for pos in range(0, len(encoded), 76))
buf = BIO.MemoryBuffer(sig)
p7 = SMIME.load_pkcs7_bio(buf)
I'm getting the mentioned error in the last line p7 = SMIME.load_pkcs7_bio(buf)
I've signed this data using cryptography package.
data_input will looks like this.
b'-----BEGIN PKCS7-----TUlNRS1WZXJzaW9uOiAxLjAKQ29udGVudC1UeXBlOiBtdWx0aXBhcnQvc2lnbmVkOyBwcm90b2Nv\nbD0iYXBwbGljYXRpb24veC1wa2NzNy1zaWduYXR1cmUiOyBtaWNhbGc9InNoYS0yNTYiOyBib3Vu\nZGFyeT0iLS0tLUEzNTBBQzNDMEFBRjhBRTE3OTE0RUE1NUE1MTM0QkVFIgoKVGhpcyBpcyBhbiBT\nL01JTUUgc2lnbmVkIG1lc3NhZ2UKCi0tLS0tLUEzNTBBQzNDMEFBRjhBRTE3OTE0RUE1NUE1MTM0\nQkVFCldlbGNvbWUgdG8gdGhlIHdvcmxkIG9mIGNyeXB0b2dyYXBoeQotLS0tLS1BMzUwQUMzQzBB\nQUY4QUUxNzkxNEVBNTVBNTEzNEJFRQpDb250ZW50LVR5cGU6IGFwcGxpY2F0aW9uL3gtcGtjczct\nc2lnbmF0dXJlOyBuYW1lPSJzbWltZS5wN3MiCkNvbnRlbnQtVHJhbnNmZXItRW5jb2Rpbmc6IGJh\nc2U2NApDb250ZW50LURpc3Bvc2l0aW9uOiBhdHRhY2htZW50OyBmaWxlbmFtZT0ic21pbWUucDdz\nIgoKTUlJRitnWUpLb1pJaHZjTkFRY0NvSUlGNnpDQ0JlY0NBUUV4RHpBTkJnbGdoa2dCWlFNRUFn\nRUZBREFMQmdrcQpoa2lHOXcwQkJ3R2dnZ05HTUlJRFFqQ0NBaXFnQXdJQkFnSVVQOHcyVFVkeng0\nZ20wLytEdUlWdGdtMjlpSjR3CkRRWUpLb1pJaHZjTkFRRUxCUUF3VGpFTE1Ba0dBMVVFQmhNQ1ZW\nTXhDVEFIQmdOVkJBZ01BREVKTUFjR0ExVUUKQnd3QU1Sb3dHQVlEVlFRS0RCRlVaWE4wSUU5eVoy\nRnVhWE5oZEdsdmJqRU5NQXNHQTFVRUF3d0VWR1Z6ZERBZQpGdzB5TVRBNE1UWXhNalF6TXpWYUZ3\nMHlNVEE0TWpZeE1qUXpNelZhTUU0eEN6QUpCZ05WQkFZVEFsVlRNUWt3CkJ3WURWUVFJREFBeENU\nQUhCZ05WQkFjTUFERWFNQmdHQTFVRUNnd1JWR1Z6ZENCUGNtZGhibWx6WVhScGIyNHgKRFRBTEJn\nTlZCQU1NQkZSbGMzUXdnZ0VpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElCRHdBd2dnRUtBb0lCQVFD\nNgpLcjczYVdsaGhZZzBZcGp1ZUtJcU9VT0dkaTQzZXpDdUc2WVFLOFNzNElFM2UzVDlEYmI3bUlI\nSXhKR3dIS09FCnpXVkxjTWZQOGtpVTJGK0EvUzd1ejVMWlRta1g3SlpBRWZMSTlxVWVraENKZS8z\nc2x3RW96bzRncy9DZDNBcFoKOWlZcVk4TEtvbjNUZHNWLy9DRHRTMjM5MW1jbHc4bG5VQkhXRFUx\nRUI3TEtEUDByazB4MHIxY0dRdzVPZWdiagpqTUlCcml2clEvL1R6TXJoYjZlQW1EWTB4VmdleXFQ\nQVg1R3dDNjJTOW5MWmN6bi9VcXFKNGExeUJGVmJwTVdhCkZwczhzMlFJK3I4K2FibmxMNW1LOVUr\nWmxaL0VsajJuUmwwcXFDQ005ZkNaZndudFFhcnNaRkFkYkVoUjdqbTMKNnpPNEgzM2JveEhWK0or\ndHQybHBBZ01CQUFHakdEQVdNQlFHQTFVZEVRUU5NQXVDQ1d4dlkyRnNhRzl6ZERBTgpCZ2txaGtp\nRzl3MEJBUXNGQUFPQ0FRRUFZS0E2OVYrMHBEVDhaSnYyQjVzc0d4RExHdjNoSHhYcHVjak4rMytp\nClpIVGFWd3pQdDFjL0ZkOEUyMUZsT1dDSHpPdVV0Y2x6YzBIYTJuamg4RkdLN0JCblNySGdWQ010\nSDR2TUl5eXYKc1VWd1Z1Tk1xYlhWd3BqeWxiS0drRnhOWXZoNC8wZWdueTZ1V21zMjMxMlVJNlFK\nRWZIeEt2cHU1Q0dqZXhCdwpZVGJQcFlYdzRJMDdrQ1JOR3R6elBFbWhCZ3poRmM5bVZpTkUzZTZL\nQTRDZzlneTY2Q0xrNUhudldERUo1M1J2ClRFeFFTNW1aUzFwbktsTk54d3Rxd3EwQ2JLN0VFRlpn\ndUNFWVJUTWxqQjdtTnJUVzBIdmdnVkRCVThmMFJyWVUKYnF5c2ZGUGFRK0hPRjI0WlFOVEVMaUFn\nNFRqY0ZETjZENG9nYjF5YzRMLzlvakdDQW5nd2dnSjBBZ0VCTUdZdwpUakVMTUFrR0ExVUVCaE1D\nVlZNeENUQUhCZ05WQkFnTUFERUpNQWNHQTFVRUJ3d0FNUm93R0FZRFZRUUtEQkZVClpYTjBJRTl5\nWjJGdWFYTmhkR2x2YmpFTk1Bc0dBMVVFQXd3RVZHVnpkQUlVUDh3MlRVZHp4NGdtMC8rRHVJVnQK\nZ20yOWlKNHdEUVlKWUlaSUFXVURCQUlCQlFDZ2dlUXdHQVlKS29aSWh2Y05BUWtETVFzR0NTcUdT\nSWIzRFFFSApBVEFjQmdrcWhraUc5dzBCQ1FVeER4Y05NakV3T0RFMk1USTBNek0xV2pBdkJna3Fo\na2lHOXcwQkNRUXhJZ1FnCldUTkE0SDZtM0RHdDhtVVZuSmNBMmNycURoUXhaTlRPODk2T29nZVZa\naFl3ZVFZSktvWklodmNOQVFrUE1Xd3cKYWpBTEJnbGdoa2dCWlFNRUFTb3dDd1lKWUlaSUFXVURC\nQUVXTUFzR0NXQ0dTQUZsQXdRQkFqQUtCZ2dxaGtpRwo5dzBEQnpBT0JnZ3Foa2lHOXcwREFnSUNB\nSUF3RFFZSUtvWklodmNOQXdJQ0FVQXdCd1lGS3c0REFnY3dEUVlJCktvWklodmNOQXdJQ0FTZ3dE\nUVlKS29aSWh2Y05BUUVCQlFBRWdnRUFkSVZ2ZmdoSWZUcUlMV1l1Skp2d3RQZGkKNUtHbTVOZ0tK\nRDJsT015SzRwSGlYcGtHQWEwaUhIa3drSVovQzcxdjFjZnBBMlphTVB5ZmI4QmFJbHdwRlNsWQp1\nSldHZzZJOVBHajRaaFZrVmo2bThYczc4TXFMeWNMTjJxSy9HWWFDWXZWZ0l1c0VDUlZaYjlPOFUr\nWndscXFwCjNWeVQwRmp0RklNNUtHL05JQlBlUTF5ekVKUm1MaU1ZcExnalg1QUt5ejVvbCtpOWpJ\nQXNjcnBWZEFhR2RFUlIKMHZURWtHWm5RZ0g0eis3L3lQSTdqSFIwTEttb1M4Q2N3aGQ5ajh2ZzF5\nQnY5elNkVUV3UTdFNHJobTZzdytKTApxMjJVVzdrSFRNUjlDVG1taVUzbno4K09UaElUQm9VcXlt\nbWtmendqNEFLcm5SZ0JNdFlzZmNvSnpzSElnZz09CgotLS0tLS1BMzUwQUMzQzBBQUY4QUUxNzkx\nNEVBNTVBNTEzNEJFRS0tCgo=-----END PKCS7-----'

Getting incorrect size (in bytes) of AES encrypted data using Python3

I am doing the encryption of text using AES in python.
Size of input message is 16 bytes (128 bits).
But when I am checking the size of encrypted data, it is showing 32 bytes.
Size of encrypted data should be a 16 bytes.
What is wrong in my code ?
Please help me.
Below is the code:
import binascii
from os import urandom
from Crypto.Cipher import AES
def get_text_size(txt):
return len(txt.encode('utf-8'))
def convert_byte_to_str(bt):
return bt.decode("utf-8")
secret_key = urandom(16)
iv = urandom(16)
obj = AES.new(secret_key, AES.MODE_CBC, iv)
message = 'Sample test text'
print('Original message is: ', message)
print('Size of original message is: ', get_text_size(message))
encrypted_text = obj.encrypt(b'Sample test text')
print('The encrypted text', encrypted_text)
encrypted_text_size = get_text_size(convert_byte_to_str(binascii.hexlify(encrypted_text)))
print('Size of encrypted text is: ', encrypted_text_size)
Output of the code:
Original message is: Sample test text
Size of original message is: 16
The encrypted text b'\xf1\x9f\xee\xc9\x88\xa0eg\xd1\xf3Nz\xe4\xf7-\xc7'
Size of encrypted text is: 32

Multiprocessing to brute force missing chars in b64-encoded data using generators - possible/how to?

Working with processing data that I receive as b64-encoded strings. For some reason I received data the other day where a set of the b64-encoded strings had four white space chars in them, making the decoded output incorrect. I made a small python script to brute force the missing characters that did the job, but I wanted to see if I can improve the speed by multiprocessing.
I'm not that familiar with using generators so it seems like this is throwing me off in the process of making it work together with multiprocessing.
Following sample code isn't the exact code I'm working with, but similar enough.
import base64
from maskprocessor import maskprocessor as maskproc
from tqdm import tqdm
import string
import multiprocessing as mp
NCORE = 8
KEY = b"some decryption key"
printable_chars = set(bytes(string.printable, 'ascii'))
def printable(data):
return True if all(char in printable_chars for char in data) else False
def decrypt(cipher):
try:
plain = base64.b64decode(cipher) #someDecryptAlgo(KEY, base64.b64decode(cipher))
return plain
except:
return None
def slow_generator(ciphers):
def gen_to_queue(input_q, ciphers):
for cipher in ciphers:
input_q.put(cipher)
for _ in range(NCORE):
input_q.put((None,None))
def process(input_q, output_q):
while True:
cipher = input_q.get()
if cipher is None:
output_q.put(None)
break
output_q.put((cipher, decrypt(cipher)))
input_q = mp.Queue(maxsize=NCORE * 2)
output_q = mp.Queue(maxsize=NCORE * 2)
gen_pool = mp.Pool(1, initializer=gen_to_queue, initargs=(input_q, ciphers))
pool = mp.Pool(NCORE, initializer=process, initargs=(input_q, output_q))
finished_workers = 0
while True:
cipher, plain = output_q.get()
if plain is None:
finished_workers += 1
if finished_workers == NCORE:
break
else:
yield cipher, plain
if __name__ == "__main__":
actual_msg = "All your base are belong to us"
actual_data_b64 = b'QWxsIHlvdXIgYmFzZSBhcmUgYmVsb25nIHRvIHVz' # "All your base are belong to us
received_data_b64 = b'QWxsI lvdXIgY FzZSBhcmUg mVsb25n HRvIHVz'
charset = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/"
n_ws = received_data_b64.decode('utf-8').count(' ')
g = maskproc(received_data_b64.decode('utf-8').replace(' ', '?1'), custom_charset1=charset)
output = slow_generator(g)
for cipher, plain in zip(x[0], x[1]):
if printable(plain):
if plain.decode('utf-8') == actual_msg:
print(f"Found correct cipher: {cipher}")
print(f"Secret message: {plain}")
break
The decoded b64 data is then decrypted using a static key, so the function for checking if I've found the correct bytes is obviously more complex than in the sample above, but I think the sample represents the same problem I got, making the generator work with multiprocessing. There is no reading/writing files involved.
I'd like to avoid creating a list of all the candidates that the maskproc generator creates but so far I haven't been able to make multiprocessing work without doing this, and thus I wonder if anyone got some pointers for how to do this?
Edit: Say I want to run N (4/8/16/etc) processes in parallel, could it be an idea to make a list of length N with candidates that is then processed and in this way avoid having to make a list of length 64^4?
Edit2: Changed code to the one adopted from https://stackoverflow.com/a/58832140/853898
Edit3: Think I managed to get it working. Now to only find a way to implement a tqdm progress bar, if possible.
import base64
from maskprocessor import maskprocessor as maskproc
from tqdm import tqdm
import string
import multiprocessing as mp
NCORE = 8
KEY = b"some decryption key"
printable_chars = set(bytes(string.printable, 'ascii'))
def printable(data):
return True if all(char in printable_chars for char in data) else False
def decrypt(cipher):
try:
plain = base64.b64decode(cipher) #someDecryptAlgo(KEY, base64.b64decode(cipher))
return plain
except:
return None
def slow_generator(ciphers):
def gen_to_queue(input_q, ciphers):
for cipher in ciphers:
input_q.put(cipher)
for _ in range(NCORE):
input_q.put(None)
def process(input_q, output_q):
while True:
cipher = input_q.get()
if cipher is None:
output_q.put((None, None))
break
output_q.put((cipher, decrypt(cipher)))
input_q = mp.Queue(maxsize=NCORE * 2)
output_q = mp.Queue(maxsize=NCORE * 2)
gen_pool = mp.Pool(1, initializer=gen_to_queue, initargs=(input_q, ciphers))
pool = mp.Pool(NCORE, initializer=process, initargs=(input_q, output_q))
finished_workers = 0
while True:
cipher, plain = output_q.get()
if plain is None:
finished_workers += 1
if finished_workers == NCORE:
break
else:
yield cipher, plain
if __name__ == "__main__":
actual_msg = "All your base are belong to us"
actual_data_b64 = b'QWxsIHlvdXIgYmFzZSBhcmUgYmVsb25nIHRvIHVz' # "All your base are belong to us
received_data_b64 = b'QWxsI lvdXIgY FzZSBhcmUg mVsb25n HRvIHVz'
#charset = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/"
charset = "HmYI"
n_ws = received_data_b64.decode('utf-8').count(' ')
g = maskproc(received_data_b64.decode('utf-8').replace(' ', '?1'), custom_charset1=charset)
output = slow_generator(g)
for cipher, plain in output:
if printable(plain):
if plain.decode('utf-8') == actual_msg:
print(f"Found correct cipher: {cipher}")
print(f"Secret message: {plain}")
break

CBC mode AES encryption problem with Pycrypto

I have the following code running like a charm
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
key = b'Sixteen byte key'
data = 'some text to encrypt'.encode("UTF-8")
data = pad(data, AES.block_size)
encryptor = AES.new(key, AES.MODE_CBC)
iv = encryptor.IV
decryptor = AES.new(key, AES.MODE_CBC, IV=iv)
ciphertext = encryptor.encrypt(data)
print(ciphertext)
plaintext = decryptor.decrypt(ciphertext)
print(unpad(plaintext, 16))
But when I try to convert to a function I got an padding error. My adapted code is
def cbc(msg, op):
key = b'Sixteen byte key'
encryptor = AES.new(key, AES.MODE_CBC)
iv = encryptor.IV
decryptor = AES.new(key, AES.MODE_CBC, IV=iv)
if op == 1:
data = msg.encode("UTF-8")
data = pad(data, AES.block_size)
ciphertext = encryptor.encrypt(data)
print(ciphertext)
else:
plaintext = decryptor.decrypt(msg)
print(unpad(plaintext, 16))
My log is
Traceback (most recent call last):
File "D:/Google Drive/max/AES.py", line 48, in <module>
cbc(b'*\xd3\xc1Y\xc2f;\xf0\xc0#\xd9E\xc5x\x11\xb4', 2)
File "D:/Google Drive/max/AES.py", line 19, in cbc
print(unpad(plaintext, 16))
File "C:\Users\Evilmaax\AppData\Local\Programs\Python\Python36\lib\site-packages\Crypto\Util\Padding.py", line 90, in unpad
raise ValueError("Padding is incorrect.")
ValueError: Padding is incorrect.
Error occurs in else statement when I try to decrypt a byte message like *\xd3\xc1Y\xc2f;\xf0\xc0#\xd9E\xc5x\x11\xb4. Important: This message was generated by the if statement of same function.
Does anyone know why this happens?
__________________________________________________________
EDIT: Using Rob Napier's tip (thank you so much) I solved the problem. If you experiencing the same issue, this is a functional version:
def cbc(key, data, op):
if op == 1:
cipher = AES.new(key, AES.MODE_CBC, iv)
data = key.encrypt(data)
print(f"Coded text: {data}")
else:
decipher = AES.new(key, AES.MODE_CBC, IV=iv)
print(f'Plaintext: {unpad(decipher.decrypt(data), BLOCK_SIZE).decode("utf-8")}')
You're generating a random IV, which is good, but you then throw it away, which means you can't decrypt the data.
This line creates an encryptor with a random IV:
encryptor = AES.new(key, AES.MODE_CBC)
This line creates a decryptor with the same IV:
decryptor = AES.new(key, AES.MODE_CBC, IV=iv)
That's fine in your initial code, but you don't save the IV anywhere, so when you put it in a function which you call twice, you're trying to decrypt with a different IV than you encrypted with.
You need to save the IV as part of the cipher text, and use it during decryption. If you want an example of such a format, see the RNCryptor spec, and if you want to see an example in Python, see RNCryptor-python.

Resources