Implementing Laravel crypt and decrypt functions in python - python-3.x

I was able to find the decrypt function with a few researches, and now
I am trying to write laravel encrypt function using python.
I can decrypt using it:
class decrypter:
def __init__(cls, key):
cls.key = key
def decrypt(cls, text):
decoded_text = json.loads(base64.b64decode(text))
iv = base64.b64decode(decoded_text['iv'])
crypt_object = AES.new(key=cls.key, mode=AES.MODE_CBC, IV=iv)
decoded = base64.b64decode(decoded_text['value'])
decrypted = crypt_object.decrypt(decoded)
return unpad(decrypted, 16).decode('utf-8')
def decrypt_string(str):
try:
key = b"xxxx+xxxxxx+x+xxxx+xxxxx"
key = base64.b64decode(key)
msg = str
obj = decrypter(key)
decrypted = obj.decrypt(msg)
return decrypted
except Exception as e:
logla.logla(e, "decrypt_string")
print(e)
But I couldn't find a source for the encrypt method. There is a source I could find, but I couldn't run it.
enter link description here

For encryption, proceed in the opposite direction:
Create an IV
Pad plaintext
Save IV and ciphertext to JSON
Encode JSON with Base64
For encryption as in the linked code, additionally the MAC has to be generated and the PHP serialization has to be used:
import json
import base64
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from Crypto.Random import get_random_bytes
from Crypto.Hash import HMAC, SHA256
from phpserialize import loads, dumps
class encrypter:
def __init__(cls, key):
cls.key = key
def encrypt(cls, text):
text = dumps(text)
msg = pad(text, 16)
iv = get_random_bytes(16) # b'0123456789012345'
crypt_object = AES.new(key=cls.key, mode=AES.MODE_CBC, IV=iv)
encrypted = crypt_object.encrypt(msg)
ivB64 = base64.b64encode(iv)
encryptedB64 = base64.b64encode(encrypted)
mac = HMAC.new(cls.key, digestmod=SHA256).update(ivB64+encryptedB64).hexdigest()
json_string = json.dumps({'iv': ivB64.decode(), 'value': encryptedB64.decode(), 'mac': mac})
return base64.b64encode(json_string.encode())
def encrypt_string(str, key):
try:
msg = str.encode()
obj = encrypter(key)
encrypted = obj.encrypt(msg)
return encrypted
except Exception as e:
print(e)
# Test
keyB64 = b'MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDE='
key = base64.b64decode(keyB64)
plaintext= 'This is a test plaintext'
encrypted = encrypt_string(plaintext, key)
decrypted = decrypt_string(encrypted, key)
print(encrypted)
print(base64.b64decode(encrypted))
For the test-IV b'0123456789012345' the output is:
b'eyJpdiI6ICJNREV5TXpRMU5qYzRPVEF4TWpNME5RPT0iLCAidmFsdWUiOiAiTlE1djFpaWU1QnFoTWNwRlhNdUFSZ2N3YVlrNG5CZlJyYmRKUGRna3FDcUN6NEZ6ZDhSOHhIUy95N1N3TWlQTyIsICJtYWMiOiAiYmYwNGJjMWEyN2NhNWUzMGFlYTdjZTI4Y2FkYTBlZGVjOGEwMzc3NWZhODVhMDc2MGRhODUzNDc1OTBmYmNmZCJ9'
b'{"iv": "MDEyMzQ1Njc4OTAxMjM0NQ==", "value": "NQ5v1iie5BqhMcpFXMuARgcwaYk4nBfRrbdJPdgkqCqCz4Fzd8R8xHS/y7SwMiPO", "mac": "bf04bc1a27ca5e30aea7ce28cada0edec8a03775fa85a0760da85347590fbcfd"}'
The linked code produces the same output using the same plaintext, key, and test-IV.

Related

Is there a way to parallelize AES-GCM encryption?

Right now, I have 8GB of data to encrypt, and I've come up with a short python module (using pyCryptoDome) that will work. When I encrypt the data, a single core is almost 100%, the other only 5%. It takes, like, 10min.(Note: My computer is a 10-year-old dual-core intel i5.)
Module:
import hashlib
from Crypto.Cipher import AES, ARC4
from Crypto.Random import get_random_bytes
class AESCipher(Cipher):
#classmethod
def encrypt(cls, key, message):
salt = get_random_bytes(AES.block_size)
# use the Scrypt KDF to get a private key from the password
private_key = hashlib.scrypt(
key.encode(), salt=salt, n=2**14, r=8, p=1, dklen=32)
# create cipher config
cipher_config = AES.new(private_key, AES.MODE_GCM)
# return a dictionary with the encrypted text
cipher_text, tag = cipher_config.encrypt_and_digest(message)
encrypted_dict = {
'cipher_text': b64encode(cipher_text).decode('utf-8'),
'salt': b64encode(salt).decode('utf-8'),
'nonce': b64encode(cipher_config.nonce).decode('utf-8'),
'tag': b64encode(tag).decode('utf-8')
}
encrypted = compress(bytes(dumps(encrypted_dict), "utf-8"))
return encrypted
#classmethod
def decrypt(cls, key, message):
enc_dict = loads(decompress(message))
# decode the dictionary entries from base64
salt = b64decode(enc_dict['salt'])
cipher_text = b64decode(enc_dict['cipher_text'])
nonce = b64decode(enc_dict['nonce'])
tag = b64decode(enc_dict['tag'])
# generate the private key from the password and salt
private_key = hashlib.scrypt(
key.encode(), salt=salt, n=2**14, r=8, p=1, dklen=32)
# create the cipher config
cipher = AES.new(private_key, AES.MODE_GCM, nonce=nonce)
# decrypt the cipher text
decrypted = cipher.decrypt_and_verify(cipher_text, tag)
return decrypted

How to encrypt and decrypt a string with a password with python

I'm making a small password manager for personal use. I was wondering if i could create an encrypted string with a password. this password will be a string or byte. i also looked at the Fernet class from cryptography but I want to be abel to remember the password so that is no option. I also want to decrypt it.
Check out https://pypi.org/project/pycrypto/
Example from the site (which seems to be what you need):
>>> from Crypto.Cipher import AES
>>> obj = AES.new('This is a key123', AES.MODE_CBC, 'This is an IV456')
>>> message = "The answer is no"
>>> ciphertext = obj.encrypt(message)
>>> ciphertext
'\xd6\x83\x8dd!VT\x92\xaa`A\x05\xe0\x9b\x8b\xf1'
>>> obj2 = AES.new('This is a key123', AES.MODE_CBC, 'This is an IV456')
>>> obj2.decrypt(ciphertext)
'The answer is no'
Give a try with this tiny python module acting as a wrapper to cryptography
pip install pyeasyencrypt
Example of code:
import logging, os
# pip install pyeasyencrypt
from pyeasyencrypt.pyeasyencrypt import encrypt_string, decrypt_string
level = os.getenv("LOGGER", "INFO")
logging.basicConfig(level=level)
logger = logging.getLogger(__name__)
def main():
logger.info("Example")
clear_string = 'stringA'
password = "my password"
encrypted_string = encrypt_string(clear_string, password)
decrypted_string = decrypt_string(encrypted_string, password)
logger.info(f"clear_string={clear_string} decrypted_string={decrypt_string} password={password} encrypted_string={encrypted_string}")
logger.debug("Done")
if __name__ == '__main__':
main()
For more details of the source code check out at github https://github.com/redcorjo/pyeasyencrypt
https://pypi.org/project/pyeasyencrypt/

Python cryptograpy.fernet doesn't decrypt symbols properly as expected

Folks, I'm writing a simple cli tool to encrypt a text and decrypt based on the passed arguments.
It works fine when I use only text. But It behaves strange when I pass some symbols.
MY SOURCE CODE
import argparse
from cryptography.fernet import Fernet
def generate_key():
"""
Generates a key and save it into a file
"""
key = Fernet.generate_key()
with open("secret.key", "wb") as key_file:
key_file.write(key)
return key
def load_key():
"""
Loads the key named 'secret.key' from current directory
"""
return open("secret.key", "rb").read()
def encrypt_message(message):
"""
Encrypts a message
"""
key = load_key()
encoded_msg = message.encode()
f = Fernet(key)
encrypted_message = f.encrypt(encoded_msg)
with open("encrypted.txt", "wb") as encrypted_file:
encrypted_file.write(encrypted_message)
return encrypted_message
def decrypt_message(encrypted_msg):
"""
Decrypt an encrypted message
"""
key = load_key()
f = Fernet(key)
decrypted_message = f.decrypt(encrypted_msg)
return decrypted_message.decode()
def Main():
parser = argparse.ArgumentParser()
parser.add_argument("-e", "--en_crypt", help="Pass the text to encrypt as an argument")
parser.add_argument("-d", "--de_crypt", help="Pass the text to decrypt as an argument", action="store_true")
parser.add_argument("-k", "--key", help="Generate the 'secret.key' file", action="store_true")
args = parser.parse_args()
if args.en_crypt:
enc = encrypt_message(args.en_crypt)
print(enc)
if args.de_crypt:
with open("encrypted.txt", "rb") as file:
txt = file.read()
print(decrypt_message(txt))
if args.key:
result = generate_key()
print("Key Generated -> " + str(result))
if __name__ == "__main__":
Main()
MY TEST-CASE 1 - (This is successfully decrypting the text passed)
$ python3 01_crypt.py -k
Key Generated -> b'N5Ll6414I8nvcMlBytk8VwdFC4oVZZZMTCVTLpQ9big='
$ python3 01_crypt.py -e "Some Sample Text to Encrypt"
b'gAAAAABfVMU3JxZOrwLIudKLAqzq5IhivhhkyvJ6TMDxM-MmVQywo4AiZ1zGK5F5gO5JFXfHznV5zPjz6sD8qhOpIR_60Hq4_YLVIV0ztPAWBjln6reg1S0='
$ python3 01_crypt.py -d
Some Sample Text to Encrypt
MY TEST-CASE 2 - (This is not working as expected)
$ python3 01_crypt.py -k
Key Generated -> b'UDUpsIP-Ltjz8XGm-BUSwApXYE_L8eFl6rmE1yBbYW4='
$ python3 01_crypt.py -e "P#$$w0rD"
b'gAAAAABfVMX4tSIU4T1CM5Sw9jGR_O2cuIhccEM4htVTkerQD0YxWuCoUZeDWOeMIfpcP4HV7vYKmrxD22sf7yk27hGCdx0jQA=='
$ python3 01_crypt.py -d
P#4103w0rD
As per the test-case 2, My expected output should be same as the encrypted one P#$$w0rD but instead it shows as P#4103w0rD
I'm clueless why this happen. Am I missing something important? Please advice.
Thanks in Advance!
ADDITIONAL NOTE
When I try the same facility without argparse It works as expected. Please review the code below,
from cryptography.fernet import Fernet
def key_generate():
"""
Generates a key and save it into a file
"""
key = Fernet.generate_key()
with open("secret.key", "wb") as key_file:
key_file.write(key)
return key
def load_keys():
"""
Loads the generated key named 'secret.key' from current directory
"""
return open("secret.key", "rb").read()
def encrypt_message(message):
"""
Encrypts a message
"""
key = load_keys()
encoded_msg = message.encode()
f = Fernet(key)
encrypted_message = f.encrypt(encoded_msg)
return encrypted_message
def decrypt_message(encrypted_msg):
"""
Decrypt an encrypted message
"""
key = load_keys()
f = Fernet(key)
decrypted_message = f.decrypt(encrypted_msg)
# print(type(encrypted_msg))
return decrypted_message.decode()
if __name__ == "__main__":
key_generate()
load_keys()
PLAINTEXT = "P#$$w0rD"
print("Plain Text", PLAINTEXT)
ENCRYPTED_TEXT = encrypt_message(PLAINTEXT)
print("Encrypted Text", ENCRYPTED_TEXT)
DECRYPTED_TEXT = decrypt_message(ENCRYPTED_TEXT)
print("Decrypted Text", DECRYPTED_TEXT)
OUTPUT
$python3 02_decrypt.py
Plain Text P#$$w0rD
Encrypted Text b'gAAAAABfVMfzv7H--aTCaUBdHVs05VRbFmuqpnrt-7k1NCTY9FrGMZKH8y2pkKqZsu5oxRqRgp5DzyRHZhfmA9p_cgNniWfsNw=='
Decrypted Text P#$$w0rD
The above behaviour makes me suspect, argparse could be culprit. Please advice.
Argparse is not at fault, your usage of your shell is.
python3 01_crypt.py -e "P#$$w0rD"
has your Unix shell substitute the current PID for $$ (which happened to be 4103).
Use single quotes to avoid the substitution.
python3 01_crypt.py -e 'P#$$w0rD'

Getting Exception: Object type <class 'str'> cannot be passed to C code

I install pip install pycryptodome on Python 3.7.2. I'm getting above exception for obj = AES.new(key, AES.MODE_CBC, iv) line. my code is:
from Crypto import Random
from Crypto.Cipher import AES
import random
def get_encryption():
try:
str = "This is input string"
key = b'abcdefghijklmnop'
iv = Random.new().read(AES.block_size)
obj = AES.new(key, AES.MODE_CBC, iv)
encrypted = obj.encrypt(str)
print(encrypted)
except Exception as e:
print(e)
I tried to all the way but not getting how to solve it.
After tried all the way I got solution. I converted key string into bytes.
code is:
from Crypto import Random
from Crypto.Cipher import AES
import random
def get_encryption():
try:
strmsg = "This is input string"
key = 'abcdefghijklmnop'
key1 = str.encode(key)
iv = Random.new().read(AES.block_size)
obj = AES.new(key1, AES.MODE_CBC, iv)
encrypted = obj.encrypt(str.encode(strmsg))
print(encrypted)
except Exception as e:
print(e)
//First pip install pycryptodome -- (pycrypto is obsolete and gives issues)
// pip install pkcs7
from Crypto import Random
from Crypto.Cipher import AES
import base64
from pkcs7 import PKCS7Encoder
from app_settings.views import retrieve_settings # my custom settings
app_secrets = retrieve_settings(file_name='secrets');
def encrypt_data(text_data):
#limit to 32 bytes because my encryption key was too long
#yours could just be 'abcdefghwhatever'
encryption_key = app_secrets['ENCRYPTION_KEY'][:32];
#convert to bytes. same as bytes(encryption_key, 'utf-8')
encryption_key = str.encode(encryption_key);
#pad
encoder = PKCS7Encoder();
raw = encoder.encode(text_data) # Padding
iv = Random.new().read(AES.block_size )
# no need to set segment_size=BLAH
cipher = AES.new( encryption_key, AES.MODE_CBC, iv )
encrypted_text = base64.b64encode( iv + cipher.encrypt( str.encode(raw) ) )
return encrypted_text;
The easiest way to convert the string to bytes is using the binascii lib:
from binascii import unhexlify, hexlify
def aes_encript(key, msg):
c = unhexlify(key)
m = unhexlify(msg)
cipher = AES.new(c, AES.MODE_ECB)
msg_en = cipher.encrypt(m)
return hexlify(msg_en)

NameError while calling module, declaring default values in a class function

I'm trying to understand Public Key encryption so I wrote this little module using PyCryptodome and the RSA/PKCS1_OAEP module on Python 3 to help me along. However, I keep getting an error:
NameError: name 'aesenc' is not defined
This is a two part question:
In standalone code (outside a class) the arg = default_val code will work, but I'm pretty sure this code will throw an error (assuming I fix question #2). I also know I can't use self.default_val as that needs an object to be created first. How do I assign a default value (in this case, the private/public key of the object?)
With regard to the error message, a vgrep reveals that the suite has been declared before its been called but I still get the NameError. Can someone please take a look and let me know what I'm doing wrong?
Modules: (Breaking into parts as SO keeps jumbling the code)
from passlib.context import CryptContext
from Crypto.Cipher import AES, PKCS1_OAEP
from Crypto.PublicKey import RSA
from Crypto import Random
from Crypto.Random import get_random_bytes
The Class:
class statEnc:
pubcipher = None
privcipher = None
pubkeystr = None
privkeystr = None
sessionkey = None
def __init__(self, pubkeystr = None, privkeystr = None, sessionkey = None):
self.pubkeystr = pubkeystr
self.privkeystr = privkeystr
self.sessionkey = sessionkey
if pubkeystr == None or privkeystr == None: #if blank, generate keys
self.random_generator = Random.new().read
self.keys = RSA.generate(1024, self.random_generator)
self.pubkey = self.keys.publickey()
self.pubkeystr = self.pubkey.exportKey(format='PEM',
passphrase=None,
pkcs=1)
self.pubcipher = PKCS1_OAEP.new(self.pubkey)
self.privcipher = PKCS1_OAEP.new(self.keys)
self.privkeystr = self.keys.exportKey(format='PEM',
passphrase=None,
pkcs=1)
self.privkey = self.keys.exportKey()
else: #import the keys
self.pubkey = RSA.importKey(pubkeystr)
self.pubcipher = PKCS1_OAEP.new(pubkey)
self.privkey = RSA.importKey(privkeystr)
self.pubcipher = PKCS1_OAEP.new(privkey)
if sessionkey == None:
sessionkey = get_random_bytes(16)
else:
self.sessionkey = sessionkey
def encrypt_val(self, session_key, cipher = pubcipher):
# a little ditty to hep encrypt the AES session key
try:
session_key = session_key.encode('utf8')
except:
pass
ciphertext = cipher.encrypt(session_key)
return ciphertext
def decrypt_val(self, ciphertext, cipher = privcipher):
# a little ditty to hep decrypt the AES session key
session_key = cipher.decrypt(ciphertext)
try:
session_key = session_key.decode('utf8')
except:
pass
return session_key
def aesenc(self, data, *args):
#encrypt the payload using AES
key = ''
if args:
if 'str' in str(type(args[0])):
try:
key = int(args[0])
except:
key = get_random_bytes(16)
else:
key = get_random_bytes(16)
try:
data = data.encode('utf8')
except:
pass
cipher = AES.new(key, AES.MODE_EAX)
ciphertext, tag = cipher.encrypt_and_digest(data)
aesencdict = {
'ciphertext' : ciphertext,
'tag' : tag,
'nonce' : cipher.nonce ,
'key' : key
}
return(aesencdict)
def aesdec(self, aesdict):
#decrypt the AES encrypted payload
cipher = AES.new(aesdict['key'], AES.MODE_EAX, aesdict['nonce'])
data = cipher.decrypt_and_verify(aesdict['ciphertext'], aesdict['tag'])
try:
data = data.decode('utf8')
except:
pass
return data
def end2enc(self, val, cipher = pubcipher):
# a master function to first encrypt the payload
val = str(val)
encval = aesenc(val)
# and then PK encrypt the key
encval['key'] = encrypt_val(encval['key'], cipher)
return encval
def end2dec(self, encval, cipher = privcipher):
encval['key'] = decrypt_val(encval['key'], cipher)
outval = aesdec(encval['aesdict'], encval['key'])
return outval
Test function and main:
def test():
val = { 'test' : "hello"}
keypair = statEnc()
print(str(type(keypair)))
encval = keypair.end2enc(val, keypair.pubcipher)
outval = keypair.end2dec(encval, keypair.privcipher)
print(val, outval)
if val == eval(outval):
return(val)
else:
return False
if __name__ == '__main__':
test()
[UPDATE]
The Traceback is as follows:
[guha#katana stat]$ python statenc.py
<class '__main__.statEnc'>
Traceback (most recent call last):
File "statenc.py", line 124, in <module>
test()
File "statenc.py", line 115, in test
encval = keypair.end2enc(val, keypair.pubcipher)
File "statenc.py", line 100, in end2enc
encval = aesenc(val)
NameError: name 'aesenc' is not defined
Slept over my question and woke up with a fresh mind, and voila! the answer presented itself.
The answer to the second question is as follows:
2. putting a simple 'self.' solves the problem - i was calling 'aesenc(params)' instead of 'self.aesenc(params)'. Stupid of me, really.
Question 1 is answered in this SO question.

Resources