Is there a way to parallelize AES-GCM encryption? - python-3.x

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

Related

Implementing Laravel crypt and decrypt functions in python

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.

RSA Encryption and Decryption using 2 files

So I have created 2 files one for encryption and other for decryption. I am able to encrypt the text but when it comes to decrypting I get an error (See bottom of question). I am able to export the Private_key.pem, public_key.pem and even the secret.txt file. I am able to read the private_key.pem in my decrypt.py script but it errors out. I believe the script thinks that the private_key it is using is not correct. I know this is wrong as I generate the public and private key, use the public key to encrypt and private to decrypt. If anyone can shed some light on this it would be greatly appreciated.
Encrypt.py
from Crypto import Cipher
from Crypto.Cipher import PKCS1_OAEP
from Crypto.PublicKey import RSA
from Crypto.PublicKey.pubkey import pubkey
def privKEY():
private_key = RSA.generate(4096)
return private_key
def pubKey():
public_Key = privKEY().publickey()
return public_Key
def convertPrivKey():
private_pem = privKEY().exportKey().decode()
with open('private_pem.pem','w') as pr:
pr.write(private_pem)
return private_pem
def convertPubKey():
public_pem = pubKey().exportKey().decode()
with open('public_pem.pem','w') as pu:
pu.write(public_pem)
return public_pem
def encrypt():
privKEY()
pubKey()
convertPrivKey()
convertPubKey()
message = 'Testing RSA Encryption'
message = message.encode()
pu_key = RSA.importKey(open('public_pem.pem','r').read())
print(pu_key)
cipher = PKCS1_OAEP.new(pu_key)
cipher_text = cipher.encrypt(message)
with open('secret.txt','w') as f:
f.write(str(cipher_text))
encrypt()
decrypt.py
from Crypto.Cipher import PKCS1_OAEP
from Crypto.PublicKey import RSA
def load_secure_file():
return open('secret.txt','r').read()
def pr_key_read():
pr_key = RSA.importKey(open('private_pem.pem','r').read())
return pr_key
def decrypt():
encrypted_text = load_secure_file()
pr_key = pr_key_read()
decrypt = PKCS1_OAEP.new(pr_key)
decrypted_message = decrypt.decrypt(encrypted_text)
return decrypted_message
decrypt()
ERROR:
PS Y:\Python\RSA> & C:/Anaconda/python.exe y:/Python/RSA/decrypt.py
Traceback (most recent call last):
File "y:/Python/RSA/decrypt.py", line 19, in <module>
decrypt()
File "y:/Python/RSA/decrypt.py", line 17, in decrypt
decrypted_message = decrypt.decrypt(encrypted_text)
File "C:\Anaconda\lib\site-packages\Crypto\Cipher\PKCS1_OAEP.py", line 195, in decrypt
raise ValueError("Ciphertext with incorrect length.")
ValueError: Ciphertext with incorrect length.
New Error:
Traceback (most recent call last):
File "y:/Python/RSA/decrypt.py", line 19, in <module>
decrypt()
File "y:/Python/RSA/decrypt.py", line 14, in decrypt
encrypted_text = load_secure_file()
File "y:/Python/RSA/decrypt.py", line 7, in load_secure_file
return open('secret.txt','r').read()
File "C:\Anaconda\lib\encodings\cp1252.py", line 23, in decode
return codecs.charmap_decode(input,self.errors,decoding_table)[0]
UnicodeDecodeError: 'charmap' codec can't decode byte 0x8d in position 30: character maps to <undefined>
Topaco is right: you're actually generating four keypairs, throwing away the first two, writing the private key from the third and the public key from the fourth. These keys don't match and thus don't work. You should generate one keypair and use the private and public halves of that pair. The following slightly simplified code works for me:
from Crypto import Cipher
from Crypto.Cipher import PKCS1_OAEP
from Crypto.PublicKey import RSA
# privKEY,pubKey
private_key = RSA.generate(2048) # shortened for testing
public_key = private_key.publickey()
# 'convert' really store
with open('private.pem','w') as pr:
pr.write(private_key.exportKey().decode())
with open('public.pem','w') as pu:
pu.write(public_key.exportKey().decode())
# encrypt
message = 'Testing RSA'.encode()
pu_key = RSA.importKey(open('public.pem','r').read())
ciphertext = PKCS1_OAEP.new(pu_key).encrypt(message)
with open('secret.txt','wb') as f:
f.write(ciphertext)
# decrypt
ciphertext = open('secret.txt','rb').read()
pr_key = RSA.importKey(open('private.pem','r').read())
decrypted = PKCS1_OAEP.new(pr_key).decrypt(ciphertext)
print(decrypted)
-->
b'Testing RSA'
The caveat that this only works for limited amount of data remains.

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/

How to implement RSA encryption/decryption on python dictionary?

I am implementing RSA encryption/decryption. The data which is to be encrypted contains different data types. Hence I have used dictionary in python. However I am getting errors. I am attaching code snippet. Please provide solution !! Thank you.
import base64
from cryptography.fernet import Fernet
import os
import hashlib
from cryptography.hazmat.backends import default_backend
from Crypto.PublicKey import RSA
from cryptography.hazmat.primitives.asymmetric import padding
from Crypto import Random
class SplitStore:
....
def encrPayload(self, payload):
modulus_length = 256 * 13 # use larger value in production
privatekey = RSA.generate(modulus_length, Random.new().read)
public_key = privatekey.publickey()
private_pem = privatekey.exportKey().decode()
with open('private_pem.pem', 'w') as pr:
pr.write(private_pem)
byte_payload = payload.encode('utf-8', 'strict')
#print("Byte Payload:{} ".format(byte_payload))
encrypted_payload = public_key.encrypt(byte_payload, 32)[0]
#print("type:{}".format(type(encrypted_payload)))
#print("\nEncrpted METADATA: {}".format(encrypted_payload))
bchain_file = open("blockchain/file.dat", "wb")
bchain_file.write((encrypted_payload))
def createMetaData(self):
time_stamp = os.stat("/home/pc-01/sample.pdf").st_ctime
#print("\nTIMESTAMP: {}".format(time_stamp))
hash_data = hashlib.sha512(self.pdfReader).hexdigest()
#print("\nHASHDATA : {}".format(hash_data))
secret_keys = self.j #j is a list of keys
#print("List of secret keys: {}".format(self.j))
#print("String conv: " + str(secret_keys[0]))
#Creating a dictionary
payload = {
"time_stamp" : time_stamp, #int
"hash" : hash_data, #string
"keys" : secret_keys #list
}
#print("\nPAYLOAD: " + payload)
return payload
...
def main():
s1 = SplitStore()
s1.initializeData()
...
if __name__ == "__main__":
main()
secret_keys in payload is a list containing keys in bytes format. After running the code I get following error:
Traceback (most recent call last):
....... chunks = self.iterencode(o, _one_shot=True)
File "/usr/lib/python3.5/json/encoder.py", line 256, in iterencode return _iterencode(o, 0)
File "/usr/lib/python3.5/json/encoder.py", line 179, in default raise TypeError(repr(o) + " is not JSON serializable")
TypeError: b'Vm3pb7XRJ4W_8M1ShKHAGiuDa2PT1DN_0ncjf0hmNJU=' is not JSON serializable
Is there any way to solve this issue?
If the problem isn't with the bytes as described below, you can narrow down on what causes the issue by following this answer and figuring out which of your variables are not serializable.
Your items in secret_keys are bytes, which are not JSON serializable. So you'll have to convert them to normal str objects. You can do so via the decode method as follows:
plainstr = bytestr.decode("utf-8")
# The encoding passed need not be "utf-8", but it is quite common
Similarly, you can encode a str to bytes as follows:
encodedstr = plainstr.encode("utf-8")

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)

Resources