Source code for schrodinger.application.matsci.enc
"""
Utilities for encryption.
Copyright Schrodinger, LLC. All rights reserved.
"""
import os
from cryptography.fernet import Fernet
from schrodinger.utils import fileutils
ENC_KEYS_PATH = os.path.join(fileutils.get_mmshare_data_dir(), '.enc_keys')
ENC_FILE_EXT = '.enc'
CG_KEY_FILE_NAME = 'cg'
[docs]def get_encryption_key(key_file_name, key_file_path=None):
    """
    Return the encryption key for the given file name.  If the
    file doesn't exist then an encryption key will be created for
    it.
    :type key_file_name: str
    :param key_file_name: the key file name
    :type key_file_path: str or None
    :param key_file_path: the key file path, if None then the
        default Schrodinger path is used
    :rtype: bytes
    :return: the encryption key
    """
    if key_file_path is None:
        key_file_path = ENC_KEYS_PATH
    key_file_path = os.path.join(key_file_path, key_file_name)
    if os.path.exists(key_file_path):
        with open(key_file_path, 'rb') as f_handle:
            key = f_handle.read()
    else:
        key = Fernet.generate_key()
        with open(key_file_path, 'wb') as f_handle:
            f_handle.write(key)
    return key 
[docs]def write_encrypted_file(in_file_path, key_file_name, key_file_path=None):
    """
    Write an encrypted version of the given input file path.
    :type in_file_path: str
    :param in_file_path: the in file path to encrypt
    :type key_file_name: str
    :param key_file_name: the key file name to use in the encryption
    :type key_file_path: str or None
    :param key_file_path: the key file path, if None then the
        default Schrodinger path is used
    :raise ValueError: if there is a problem
    :rtype: str
    :return: the encrypted file path
    """
    if in_file_path.endswith(ENC_FILE_EXT):
        raise ValueError('encrypting an encrypted file is not supported')
    with open(in_file_path) as f_handle:
        text = f_handle.read()
    return write_encrypted_text(text,
                                in_file_path,
                                key_file_name,
                                key_file_path=key_file_path) 
[docs]def write_encrypted_text(text, in_file_path, key_file_name, key_file_path=None):
    """
    Write the unencrypted text to an encrypted file with the given
    path.
    :type text: str
    :param text: the text to encrypt
    :type in_file_path: str
    :param in_file_path: the file path to which to write the encrypted
        text
    :type key_file_name: str
    :param key_file_name: the key file name to use in the encryption
    :type key_file_path: str or None
    :param key_file_path: the key file path, if None then the
        default Schrodinger path is used
    :rtype: str
    :return: the encrypted file path
    """
    key = get_encryption_key(key_file_name, key_file_path=key_file_path)
    f_obj = Fernet(key)
    token = f_obj.encrypt(text.encode())
    out_file_path = in_file_path
    if not out_file_path.endswith(ENC_FILE_EXT):
        out_file_path += ENC_FILE_EXT
    with open(out_file_path, 'wb') as f_handle:
        f_handle.write(token)
    return out_file_path 
[docs]def get_unencrypted_text(in_file_path, key_file_name, key_file_path=None):
    """
    Return the unencrypted text for the given encrypted input file path.
    :type in_file_path: str
    :param in_file_path: the encrypted in file path to unencrypt
    :type key_file_name: str
    :param key_file_name: the key file name to use in the unencryption
    :type key_file_path: str or None
    :param key_file_path: the key file path, if None then the
        default Schrodinger path is used
    :raise ValueError: if there is a problem
    :rtype: str
    :return: the unencrypted text
    """
    if not in_file_path.endswith(ENC_FILE_EXT):
        raise ValueError('the input file is not encrypted')
    with open(in_file_path, 'rb') as f_handle:
        token = f_handle.read()
    key = get_encryption_key(key_file_name, key_file_path=key_file_path)
    f_obj = Fernet(key)
    text = f_obj.decrypt(token).decode()
    return text 
[docs]def write_unencrypted_file(in_file_path, key_file_name, key_file_path=None):
    """
    Write an unencrypted version for the given encrypted input file path.
    :type in_file_path: str
    :param in_file_path: the encrypted in file path to unencrypt
    :type key_file_name: str
    :param key_file_name: the key file name to use in the unencryption
    :type key_file_path: str or None
    :param key_file_path: the key file path, if None then the
        default Schrodinger path is used
    :rtype: str
    :return: the unencrypted file path
    """
    text = get_unencrypted_text(in_file_path,
                                key_file_name,
                                key_file_path=key_file_path)
    out_file_path = fileutils.splitext(in_file_path)[0]
    with open(out_file_path, 'w') as f_handle:
        f_handle.write(text)
    return out_file_path