-
-
Save fideloper/c4806c504e46e8cdb00a to your computer and use it in GitHub Desktop.
import os | |
import base64 | |
import json | |
from Crypto.Cipher import AES | |
from phpserialize import loads | |
def decrypt(payload): | |
data = json.loads(base64.b64decode(payload)) | |
value = base64.b64decode(data['value']) | |
iv = base64.b64decode(data['iv']) | |
return unserialize(mcrypt_decrypt(value, iv)) | |
def mcrypt_decrypt(value, iv): | |
AES.key_size=128 | |
key=os.environ['APP_KEY'] | |
crypt_object=AES.new(key=key,mode=AES.MODE_CBC,IV=iv) | |
return crypt_object.decrypt(value) | |
def unserialize(serialized): | |
return loads(serialized) |
Traceback (most recent call last):
File "/var/www/html/adnsms/SMS-Shooting-Process/Helpers/crypt.py", line 66, in
decrypt(code)
File "/var/www/html/adnsms/SMS-Shooting-Process/Helpers/crypt.py", line 49, in decrypt
return unserialize(mcrypt_decrypt(value, iv))
File "/var/www/html/adnsms/SMS-Shooting-Process/Helpers/crypt.py", line 57, in mcrypt_decrypt
crypt_object=AES.new(key=key,mode=AES.MODE_CBC,IV=iv)
File "/var/www/html/adnsms/SMS-Shooting-Process/venv/lib/python3.8/site-packages/Crypto/Cipher/AES.py", line 232, in new
return _create_cipher(sys.modules[name], key, mode, *args, **kwargs)
File "/var/www/html/adnsms/SMS-Shooting-Process/venv/lib/python3.8/site-packages/Crypto/Cipher/init.py", line 79, in _create_cipher
return modes[mode](factory, **kwargs)
File "/var/www/html/adnsms/SMS-Shooting-Process/venv/lib/python3.8/site-packages/Crypto/Cipher/_mode_cbc.py", line 274, in _create_cbc_cipher
cipher_state = factory._create_base_cipher(kwargs)
File "/var/www/html/adnsms/SMS-Shooting-Process/venv/lib/python3.8/site-packages/Crypto/Cipher/AES.py", line 92, in _create_base_cipher
if len(key) not in key_size:
TypeError: argument of type 'int' is not iterable
I'm getting this error.. please help
Thanks for your reply. Let me check it
Laraves sems to be using 256 bit since a while
https://laravel.com/docs/5.5/encryption#using-the-encrypter
So I tested the above code in the "php artisan tinker" console, by replacing:
key=os.environ['APP_KEY']
with
key = b"tZMp17lQI70EEYqCsQfwLzlHm6tyaYWPAX66n7YA8KI="
where tZMp17lQI70EEYqCsQfwLzlHm6tyaYWPAX66n7YA8KI= is a string generated issuing the Laravel command
php artisan key:generate
that adds to Laravel's .env a line like:
APP_KEY=base64:tZMp17lQI70EEYqCsQfwLzlHm6tyaYWPAX66n7YA8KI=
I took just the part after "base64:".
With these small changes, I got the same error as @adamilleriam:
(repeated with both AES.key_size=256 or AES.key_size=128) : same error.
Traceback (most recent call last):
File "test.py", line 35, in <module>
decrypted = decrypt(payload)
File "test.py", line 14, in decrypt
return unserialize(mcrypt_decrypt(value, iv))
File "test.py", line 21, in mcrypt_decrypt
crypt_object=AES.new(key=key,mode=AES.MODE_CBC,IV=iv)
File "C:\Users\mcfoi\Desktop\pycrypt\venv\lib\site-packages\Crypto\Cipher\AES.py", line 232, in new
return _create_cipher(sys.modules[__name__], key, mode, *args, **kwargs)
File "C:\Users\mcfoi\Desktop\pycrypt\venv\lib\site-packages\Crypto\Cipher\__init__.py", line 79, in _create_cipher
return modes[mode](factory, **kwargs)
File "C:\Users\mcfoi\Desktop\pycrypt\venv\lib\site-packages\Crypto\Cipher\_mode_cbc.py", line 274, in _create_cbc_cipher
cipher_state = factory._create_base_cipher(kwargs)
File "C:\Users\mcfoi\Desktop\pycrypt\venv\lib\site-packages\Crypto\Cipher\AES.py", line 92, in _create_base_cipher
if len(key) not in key_size:
TypeError: argument of type 'int' is not iterable
Some hints:
-
In 2020 we should rely on
https://pycryptodome.readthedocs.io/en/latest/src/installation.html
as original pakage pycrypt is no longer developed
so use
pip install pycryptodome
-
While relying on pycryptodome, using in code:
AES.key_size=256
is EVIL as causes over-writing an internal list meant to check key size and this ultimately causes the reported error:
File "C:\Users\mcfoi\Desktop\pycrypt\venv\lib\site-packages\Crypto\Cipher\AES.py", line 97, in _create_base_cipher
if len(key) not in key_size:
TypeError: argument of type 'int' is not iterable
..stay tuned.. .. I am adding details here in future EDITS
HERE IS A TESTED WORKING SCRIPT
"""
Decode in Python a string encoded in Laravel 6.x
String ENCODED in Laravel 6.x with default pakage
Illuminate\Support\Facades\Crypt
and command like:
$encrypted = Crypt::encrypt('Hello world.');
Test in
php artisan tinker
>>use Illuminate\Support\Facades\Crypt;
>>$encrypted = Crypt::encrypt('Hello world.');
Strings DECODED in Python 3.7 (64bit) with just following requirements:
phpserialize==1.3
pycryptodome==3.9.7
NOTE: avoid using in Laravel
$encrypted = Crypt::encryptString('Hello world.');
as this does NOT serializes strings : not-serialized strings are not handled by this script.
"""
import os
import base64
import json
from Crypto.Cipher import AES
from phpserialize import loads
def decrypt(laravelEncrypedStringBase64, laravelAppKeyBase64):
# Decode from base64 Laravel encrypted string
dataJson = base64.b64decode(laravelEncrypedStringBase64)
# Load JSON
data = json.loads(dataJson)
# Extract actual encrypted message from JSON (other parts are IV and Signature)
value = base64.b64decode(data['value'])
# Extract Initialization Vector from JSON (required to create an AES decypher)
iv = base64.b64decode(data['iv'])
# Decode
key = base64.b64decode(laravelAppKeyBase64) # Laravel KEY comes base64Encoded from .env!
# Create an AES decypher
decrypter = aesDecrypterCBC(iv, key)
# Finally decypher the message
decriptedSerializedMessage = decrypter.decrypt(value)
# deserialize message
try :
# Attempt to deserialize message incase it was created in Laravel with Crypt::encrypt('Hello world.');
decriptedMessage = unserialize(decriptedSerializedMessage)
return str(decriptedMessage)
except:
raise Exception("Check you cyphered strings in Laravel using Crypt::encrypt() and NOT Crypt::encryptString()")
def aesDecrypterCBC(iv, _key):
decrypterAES_CBC = AES.new(key=_key,mode=AES.MODE_CBC,IV=iv)
return decrypterAES_CBC
def unserialize(serialized):
return loads(serialized)
if __name__ == "__main__":
laravelAppKeyBase64 = b"tZMp17lQI70EEYqCsQfwLzlHm6tyaYWPAX66n7YA8KI="
# Following string is obtained with: $encrypted = Crypt::encrypt('Hello world.');
laravelEncrypedString = b"eyJpdiI6ImZTQnQ0VEF1NkdWVXdneXRjXC85RjdBPT0iLCJ2YWx1ZSI6IlIxcjhkNDVOZFV3djZLMVVmK0RZQkFYTjBOelpxMEtEYmRRdlBlbHhIcnM9IiwibWFjIjoiNzk3NzI2NTQyOGZkYWRlN2NjZjBiYTUxNWI0YWJlOGU0YjI4MDg2YzI3ZDRlNmMzZTQwOTk3ZTI0YmI2ZTBmYiJ9"
# Following string is obtained with: $encrypted = Crypt::encryptString('Hello world.'); WILL NOT WORK!!
#laravelEncrypedString = b"eyJpdiI6Iko0aWpwNFdKU0g2WE95TFlWY2dHaFE9PSIsInZhbHVlIjoiRTFtTG14eTZQbTMrVzZxS0R6OFBEZz09IiwibWFjIjoiYzhhN2VlNThmNDczNGM2M2M5ZDJiNzQ4ZjEzM2MxMDg2M2FmMzFmZTgwNjE3NDYyOWEzYzU1NTNmMmU2OWRjYSJ9"
decrypted = decrypt(laravelEncrypedString, laravelAppKeyBase64)
print(decrypted)
Thanks @mcfoi
it's working for me also :)
Hello ^_^
I am seeing this a bit later, but I was looking for this same thing and now that I have tried it it has problems with the "json.loads" part.
Here is the exception I am getting
Traceback (most recent call last):
File "C:\Users\PC\AppData\Roaming\npm\node_modules\serverless\lib\plugins\aws
invokeLocal\runtimeWrappers\invoke.py", line 86, in
result = handler(input['event'], context)
File ".\sendMail.py", line 52, in sendMailSMTP
print(decrypt(secret, app_key))
File ".\sendMail.py", line 98, in decrypt
data = json.loads(dataJson)
File "C:\Users\PC\Anaconda3\lib\json_init_.py", line 343, in loads
s = s.decode(detect_encoding(s), 'surrogatepass')
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x8c in position 5: invalid
start byte
Can someone please help me with this, thanк you in advance
any update on the Crypt::encryptString hash?
Added mac validation code: https://gist.github.com/orian/f803a879abf7edc73966df44d65c6680
Based on: https://github.com/laravel/framework/blob/6cf003ae02582cf716c10a723ef6bc19690969e7/src/Illuminate/Encryption/Encrypter.php