"""Encryption. To make sure the data entered by our users in the forms is secure (even if https is enabled), we create a transaction token, a rsa public and private key which end up being stored in DynamoDB. When the user sends over the encrypted information using the public key, we decrypt the data using the private key stored in dynamodb. """ import os import shlex import subprocess import uuid import rsa from sukimu.operations import Equal from auth import config from auth.models.rsa_key import RsaKey from auth.utils import date from auth.utils import response def create(): """Create a new key and an token. The public key and private key are generated using the rsa library, and saved into the database. The logic, however, removes from the response the private_key if successful. Returns: Response: the encryption response. """ token = str(uuid.uuid4()).replace('-', '') public_key, private_key = rsa.newkeys(config.RSA_LENGTH) private_key = private_key.save_pkcs1(format='PEM') response = RsaKey.create( token=token, public_key=create_openssl_public_key(private_key), private_key=private_key, date=int(date.now_utc_timestamp())) if not response.success: return response response.message.pop('private_key') return response def create_openssl_public_key(private_key): """Create the openssl public key. Args: private_key (binary): the private key that creates the public key. Returns: binary: the binary pem key from openssl. """ path = '/tmp/{}'.format(str(uuid.uuid4())) keyfile = open(path, 'wb+') keyfile.write(private_key) keyfile.close() args = shlex.split('openssl rsa -pubout -in {}'.format(path)) output, error = subprocess.Popen( args, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() os.remove(path) return output def decode(rsa_key_token, value): """Decode the values from a key. Args: rsa_key_token (str): the token of the Rsa Key. values (dict): values to decrypt. Returns: Response: contains the decoded value as message. """ key = RsaKey.fetch_one(token=Equal(rsa_key_token)) if not key.success: return key if key.date + config.RSA_EXPIRATION < date.now_utc_timestamp(): return response.create_error_response(errors=dict( token='The token you are using has expired.')) private_key = rsa.PrivateKey.load_pkcs1(key.private_key) return response.Response(message=rsa.decrypt(value, private_key))