From 803d1c910f1db891c842b8bc2ead42c7d53ddfcd Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Wed, 22 Sep 2021 16:27:36 +0200 Subject: [PATCH 1/6] Island: Separate password and key encryption --- .../field_encryptors/string_list_encryptor.py | 2 +- .../cc/resources/configuration_export.py | 6 +- .../cc/resources/configuration_import.py | 7 +- monkey/monkey_island/cc/server_setup.py | 2 +- .../{encryptor.py => key_encryptor.py} | 28 +++----- .../technique_report_tools.py | 2 +- monkey/monkey_island/cc/services/config.py | 2 +- .../services/telemetry/processing/exploit.py | 2 +- .../telemetry/processing/system_info.py | 2 +- .../cc/services/utils/encryption.py | 59 ---------------- .../cc/services/utils/i_encryptor.py | 20 ++++++ .../cc/services/utils/key_encryption.py | 38 +++++++++++ .../cc/services/utils/password_encryption.py | 67 +++++++++++++++++++ .../scoutsuite/scoutsuite_auth_service.py | 2 +- .../test_string_list_encryptor.py | 2 +- .../cc/resources/test_configuration_import.py | 5 +- ...est_encryptor.py => test_key_encryptor.py} | 2 +- .../cc/services/utils/test_encryption.py | 19 +++--- .../test_scoutsuite_auth_service.py | 2 +- 19 files changed, 165 insertions(+), 104 deletions(-) rename monkey/monkey_island/cc/server_utils/{encryptor.py => key_encryptor.py} (54%) delete mode 100644 monkey/monkey_island/cc/services/utils/encryption.py create mode 100644 monkey/monkey_island/cc/services/utils/i_encryptor.py create mode 100644 monkey/monkey_island/cc/services/utils/key_encryption.py create mode 100644 monkey/monkey_island/cc/services/utils/password_encryption.py rename monkey/tests/unit_tests/monkey_island/cc/server_utils/{test_encryptor.py => test_key_encryptor.py} (89%) diff --git a/monkey/monkey_island/cc/models/utils/field_encryptors/string_list_encryptor.py b/monkey/monkey_island/cc/models/utils/field_encryptors/string_list_encryptor.py index 63801cf69..91464c1fa 100644 --- a/monkey/monkey_island/cc/models/utils/field_encryptors/string_list_encryptor.py +++ b/monkey/monkey_island/cc/models/utils/field_encryptors/string_list_encryptor.py @@ -1,7 +1,7 @@ from typing import List from monkey_island.cc.models.utils.field_encryptors.i_field_encryptor import IFieldEncryptor -from monkey_island.cc.server_utils.encryptor import get_encryptor +from monkey_island.cc.server_utils.key_encryptor import get_encryptor class StringListEncryptor(IFieldEncryptor): diff --git a/monkey/monkey_island/cc/resources/configuration_export.py b/monkey/monkey_island/cc/resources/configuration_export.py index 4a7aeec24..c9565011b 100644 --- a/monkey/monkey_island/cc/resources/configuration_export.py +++ b/monkey/monkey_island/cc/resources/configuration_export.py @@ -5,7 +5,7 @@ from flask import request from monkey_island.cc.resources.auth.auth import jwt_required from monkey_island.cc.services.config import ConfigService -from monkey_island.cc.services.utils.encryption import encrypt_string +from monkey_island.cc.services.utils.password_encryption import PasswordBasedEncryptor class ConfigurationExport(flask_restful.Resource): @@ -20,6 +20,8 @@ class ConfigurationExport(flask_restful.Resource): if should_encrypt: password = data["password"] plaintext_config = json.dumps(plaintext_config) - config_export = encrypt_string(plaintext_config, password) + + pb_encryptor = PasswordBasedEncryptor(password) + config_export = pb_encryptor.encrypt(plaintext_config) return {"config_export": config_export, "encrypted": should_encrypt} diff --git a/monkey/monkey_island/cc/resources/configuration_import.py b/monkey/monkey_island/cc/resources/configuration_import.py index efa1d79a7..99b43f3ba 100644 --- a/monkey/monkey_island/cc/resources/configuration_import.py +++ b/monkey/monkey_island/cc/resources/configuration_import.py @@ -9,10 +9,10 @@ from flask import request from common.utils.exceptions import InvalidConfigurationError from monkey_island.cc.resources.auth.auth import jwt_required from monkey_island.cc.services.config import ConfigService -from monkey_island.cc.services.utils.encryption import ( +from monkey_island.cc.services.utils.password_encryption import ( InvalidCiphertextError, InvalidCredentialsError, - decrypt_ciphertext, + PasswordBasedEncryptor, is_encrypted, ) @@ -72,7 +72,8 @@ class ConfigurationImport(flask_restful.Resource): try: config = request_contents["config"] if ConfigurationImport.is_config_encrypted(request_contents["config"]): - config = decrypt_ciphertext(config, request_contents["password"]) + pb_encryptor = PasswordBasedEncryptor(request_contents["password"]) + config = pb_encryptor.decrypt(config) return json.loads(config) except (JSONDecodeError, InvalidCiphertextError): logger.exception( diff --git a/monkey/monkey_island/cc/server_setup.py b/monkey/monkey_island/cc/server_setup.py index 35879a1d4..5ed167126 100644 --- a/monkey/monkey_island/cc/server_setup.py +++ b/monkey/monkey_island/cc/server_setup.py @@ -27,8 +27,8 @@ from monkey_island.cc.server_utils.consts import ( # noqa: E402 GEVENT_EXCEPTION_LOG, MONGO_CONNECTION_TIMEOUT, ) -from monkey_island.cc.server_utils.encryptor import initialize_encryptor # noqa: E402 from monkey_island.cc.server_utils.island_logger import reset_logger, setup_logging # noqa: E402 +from monkey_island.cc.server_utils.key_encryptor import initialize_encryptor # noqa: E402 from monkey_island.cc.services.initialize import initialize_services # noqa: E402 from monkey_island.cc.services.reporting.exporter_init import populate_exporter_list # noqa: E402 from monkey_island.cc.services.utils.network_utils import local_ip_addresses # noqa: E402 diff --git a/monkey/monkey_island/cc/server_utils/encryptor.py b/monkey/monkey_island/cc/server_utils/key_encryptor.py similarity index 54% rename from monkey/monkey_island/cc/server_utils/encryptor.py rename to monkey/monkey_island/cc/server_utils/key_encryptor.py index ab9bc617a..e41cf56f4 100644 --- a/monkey/monkey_island/cc/server_utils/encryptor.py +++ b/monkey/monkey_island/cc/server_utils/key_encryptor.py @@ -1,17 +1,16 @@ -import base64 import os # PyCrypto is deprecated, but we use pycryptodome, which uses the exact same imports but # is maintained. from Crypto import Random # noqa: DUO133 # nosec: B413 -from Crypto.Cipher import AES # noqa: DUO133 # nosec: B413 from monkey_island.cc.server_utils.file_utils import open_new_securely_permissioned_file +from monkey_island.cc.services.utils.key_encryption import KeyBasedEncryptor _encryptor = None -class Encryptor: +class DataStoreEncryptor: _BLOCK_SIZE = 32 _PASSWORD_FILENAME = "mongo_key.bin" @@ -32,30 +31,19 @@ class Encryptor: with open(password_file, "rb") as f: self._cipher_key = f.read() - def _pad(self, message): - return message + (self._BLOCK_SIZE - (len(message) % self._BLOCK_SIZE)) * chr( - self._BLOCK_SIZE - (len(message) % self._BLOCK_SIZE) - ) - - def _unpad(self, message: str): - return message[0 : -ord(message[len(message) - 1])] - def enc(self, message: str): - cipher_iv = Random.new().read(AES.block_size) - cipher = AES.new(self._cipher_key, AES.MODE_CBC, cipher_iv) - return base64.b64encode(cipher_iv + cipher.encrypt(self._pad(message).encode())).decode() + key_encryptor = KeyBasedEncryptor(self._cipher_key) + return key_encryptor.encrypt(message) - def dec(self, enc_message): - enc_message = base64.b64decode(enc_message) - cipher_iv = enc_message[0 : AES.block_size] - cipher = AES.new(self._cipher_key, AES.MODE_CBC, cipher_iv) - return self._unpad(cipher.decrypt(enc_message[AES.block_size :]).decode()) + def dec(self, enc_message: str): + key_encryptor = KeyBasedEncryptor(self._cipher_key) + return key_encryptor.decrypt(enc_message) def initialize_encryptor(password_file_dir): global _encryptor - _encryptor = Encryptor(password_file_dir) + _encryptor = DataStoreEncryptor(password_file_dir) def get_encryptor(): diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/technique_report_tools.py b/monkey/monkey_island/cc/services/attack/technique_reports/technique_report_tools.py index 0a9a1045b..6a431f35a 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/technique_report_tools.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/technique_report_tools.py @@ -1,4 +1,4 @@ -from monkey_island.cc.server_utils.encryptor import get_encryptor +from monkey_island.cc.server_utils.key_encryptor import get_encryptor def parse_creds(attempt): diff --git a/monkey/monkey_island/cc/services/config.py b/monkey/monkey_island/cc/services/config.py index ba4083286..26e3ab971 100644 --- a/monkey/monkey_island/cc/services/config.py +++ b/monkey/monkey_island/cc/services/config.py @@ -19,7 +19,7 @@ from common.config_value_paths import ( USER_LIST_PATH, ) from monkey_island.cc.database import mongo -from monkey_island.cc.server_utils.encryptor import get_encryptor +from monkey_island.cc.server_utils.key_encryptor import get_encryptor from monkey_island.cc.services.config_manipulator import update_config_per_mode from monkey_island.cc.services.config_schema.config_schema import SCHEMA from monkey_island.cc.services.mode.island_mode_service import ModeNotSetError, get_mode diff --git a/monkey/monkey_island/cc/services/telemetry/processing/exploit.py b/monkey/monkey_island/cc/services/telemetry/processing/exploit.py index 7fa5654c5..0a0ccce15 100644 --- a/monkey/monkey_island/cc/services/telemetry/processing/exploit.py +++ b/monkey/monkey_island/cc/services/telemetry/processing/exploit.py @@ -3,7 +3,7 @@ import copy import dateutil from monkey_island.cc.models import Monkey -from monkey_island.cc.server_utils.encryptor import get_encryptor +from monkey_island.cc.server_utils.key_encryptor import get_encryptor from monkey_island.cc.services.config import ConfigService from monkey_island.cc.services.edge.displayed_edge import EdgeService from monkey_island.cc.services.node import NodeService diff --git a/monkey/monkey_island/cc/services/telemetry/processing/system_info.py b/monkey/monkey_island/cc/services/telemetry/processing/system_info.py index 73a81e332..1bcc61ecd 100644 --- a/monkey/monkey_island/cc/services/telemetry/processing/system_info.py +++ b/monkey/monkey_island/cc/services/telemetry/processing/system_info.py @@ -1,6 +1,6 @@ import logging -from monkey_island.cc.server_utils.encryptor import get_encryptor +from monkey_island.cc.server_utils.key_encryptor import get_encryptor from monkey_island.cc.services.config import ConfigService from monkey_island.cc.services.node import NodeService from monkey_island.cc.services.telemetry.processing.system_info_collectors.system_info_telemetry_dispatcher import ( # noqa: E501 diff --git a/monkey/monkey_island/cc/services/utils/encryption.py b/monkey/monkey_island/cc/services/utils/encryption.py deleted file mode 100644 index ae4af2257..000000000 --- a/monkey/monkey_island/cc/services/utils/encryption.py +++ /dev/null @@ -1,59 +0,0 @@ -import base64 -import io -import logging - -import pyAesCrypt - -BUFFER_SIZE = pyAesCrypt.crypto.bufferSizeDef - -logger = logging.getLogger(__name__) - - -def encrypt_string(plaintext: str, password: str) -> str: - plaintext_stream = io.BytesIO(plaintext.encode()) - ciphertext_stream = io.BytesIO() - - pyAesCrypt.encryptStream(plaintext_stream, ciphertext_stream, password, BUFFER_SIZE) - - ciphertext_b64 = base64.b64encode(ciphertext_stream.getvalue()) - logger.info("String encrypted.") - - return ciphertext_b64.decode() - - -def decrypt_ciphertext(ciphertext: str, password: str) -> str: - ciphertext = base64.b64decode(ciphertext) - ciphertext_stream = io.BytesIO(ciphertext) - plaintext_stream = io.BytesIO() - - ciphertext_stream_len = len(ciphertext_stream.getvalue()) - - try: - pyAesCrypt.decryptStream( - ciphertext_stream, - plaintext_stream, - password, - BUFFER_SIZE, - ciphertext_stream_len, - ) - except ValueError as ex: - if str(ex).startswith("Wrong password"): - logger.info("Wrong password provided for decryption.") - raise InvalidCredentialsError - else: - logger.info("The corrupt ciphertext provided.") - raise InvalidCiphertextError - return plaintext_stream.getvalue().decode("utf-8") - - -def is_encrypted(ciphertext: str) -> bool: - ciphertext = base64.b64decode(ciphertext) - return ciphertext.startswith(b"AES") - - -class InvalidCredentialsError(Exception): - """ Raised when password for decryption is invalid """ - - -class InvalidCiphertextError(Exception): - """ Raised when ciphertext is corrupted """ diff --git a/monkey/monkey_island/cc/services/utils/i_encryptor.py b/monkey/monkey_island/cc/services/utils/i_encryptor.py new file mode 100644 index 000000000..d83198b7b --- /dev/null +++ b/monkey/monkey_island/cc/services/utils/i_encryptor.py @@ -0,0 +1,20 @@ +from abc import ABC, abstractmethod +from typing import Any + + +class IEncryptor(ABC): + @abstractmethod + def encrypt(self, plaintext: Any) -> Any: + """Encrypts data and returns the ciphertext. + :param plaintext: Data that will be encrypted + :return: Ciphertext generated by encrypting value + :rtype: Any + """ + + @abstractmethod + def decrypt(self, ciphertext: Any): + """Decrypts data and returns the plaintext. + :param ciphertext: Ciphertext that will be decrypted + :return: Plaintext generated by decrypting value + :rtype: Any + """ diff --git a/monkey/monkey_island/cc/services/utils/key_encryption.py b/monkey/monkey_island/cc/services/utils/key_encryption.py new file mode 100644 index 000000000..cb8366da8 --- /dev/null +++ b/monkey/monkey_island/cc/services/utils/key_encryption.py @@ -0,0 +1,38 @@ +import base64 +import logging + +# PyCrypto is deprecated, but we use pycryptodome, which uses the exact same imports but +# is maintained. +from Crypto import Random # noqa: DUO133 # nosec: B413 +from Crypto.Cipher import AES # noqa: DUO133 # nosec: B413 + +from monkey_island.cc.services.utils.i_encryptor import IEncryptor + +logger = logging.getLogger(__name__) + + +class KeyBasedEncryptor(IEncryptor): + + _BLOCK_SIZE = 32 + + def __init__(self, key: bytes): + self._key = key + + def encrypt(self, plaintext: str) -> str: + cipher_iv = Random.new().read(AES.block_size) + cipher = AES.new(self._key, AES.MODE_CBC, cipher_iv) + return base64.b64encode(cipher_iv + cipher.encrypt(self._pad(plaintext).encode())).decode() + + def decrypt(self, ciphertext: str): + enc_message = base64.b64decode(ciphertext) + cipher_iv = enc_message[0 : AES.block_size] + cipher = AES.new(self._key, AES.MODE_CBC, cipher_iv) + return self._unpad(cipher.decrypt(enc_message[AES.block_size :]).decode()) + + def _pad(self, message): + return message + (self._BLOCK_SIZE - (len(message) % self._BLOCK_SIZE)) * chr( + self._BLOCK_SIZE - (len(message) % self._BLOCK_SIZE) + ) + + def _unpad(self, message: str): + return message[0 : -ord(message[len(message) - 1])] diff --git a/monkey/monkey_island/cc/services/utils/password_encryption.py b/monkey/monkey_island/cc/services/utils/password_encryption.py new file mode 100644 index 000000000..1854722e8 --- /dev/null +++ b/monkey/monkey_island/cc/services/utils/password_encryption.py @@ -0,0 +1,67 @@ +import base64 +import io +import logging + +import pyAesCrypt + +from monkey_island.cc.services.utils.i_encryptor import IEncryptor + +logger = logging.getLogger(__name__) + + +class PasswordBasedEncryptor(IEncryptor): + + _BUFFER_SIZE = pyAesCrypt.crypto.bufferSizeDef + + def __init__(self, password: str): + self.password = password + + def encrypt(self, plaintext: str) -> str: + plaintext_stream = io.BytesIO(plaintext.encode()) + ciphertext_stream = io.BytesIO() + + pyAesCrypt.encryptStream( + plaintext_stream, ciphertext_stream, self.password, self._BUFFER_SIZE + ) + + ciphertext_b64 = base64.b64encode(ciphertext_stream.getvalue()) + logger.info("String encrypted.") + + return ciphertext_b64.decode() + + def decrypt(self, ciphertext: str): + ciphertext = base64.b64decode(ciphertext) + ciphertext_stream = io.BytesIO(ciphertext) + plaintext_stream = io.BytesIO() + + ciphertext_stream_len = len(ciphertext_stream.getvalue()) + + try: + pyAesCrypt.decryptStream( + ciphertext_stream, + plaintext_stream, + self.password, + self._BUFFER_SIZE, + ciphertext_stream_len, + ) + except ValueError as ex: + if str(ex).startswith("Wrong password"): + logger.info("Wrong password provided for decryption.") + raise InvalidCredentialsError + else: + logger.info("The corrupt ciphertext provided.") + raise InvalidCiphertextError + return plaintext_stream.getvalue().decode("utf-8") + + +class InvalidCredentialsError(Exception): + """ Raised when password for decryption is invalid """ + + +class InvalidCiphertextError(Exception): + """ Raised when ciphertext is corrupted """ + + +def is_encrypted(ciphertext: str) -> bool: + ciphertext = base64.b64decode(ciphertext) + return ciphertext.startswith(b"AES") diff --git a/monkey/monkey_island/cc/services/zero_trust/scoutsuite/scoutsuite_auth_service.py b/monkey/monkey_island/cc/services/zero_trust/scoutsuite/scoutsuite_auth_service.py index 36eae6271..0d423bd6a 100644 --- a/monkey/monkey_island/cc/services/zero_trust/scoutsuite/scoutsuite_auth_service.py +++ b/monkey/monkey_island/cc/services/zero_trust/scoutsuite/scoutsuite_auth_service.py @@ -5,7 +5,7 @@ from ScoutSuite.providers.base.authentication_strategy import AuthenticationExce from common.cloud.scoutsuite_consts import CloudProviders from common.config_value_paths import AWS_KEYS_PATH from common.utils.exceptions import InvalidAWSKeys -from monkey_island.cc.server_utils.encryptor import get_encryptor +from monkey_island.cc.server_utils.key_encryptor import get_encryptor from monkey_island.cc.services.config import ConfigService diff --git a/monkey/tests/unit_tests/monkey_island/cc/models/utils/field_encryptors/test_string_list_encryptor.py b/monkey/tests/unit_tests/monkey_island/cc/models/utils/field_encryptors/test_string_list_encryptor.py index 53b004401..fe8af8e0d 100644 --- a/monkey/tests/unit_tests/monkey_island/cc/models/utils/field_encryptors/test_string_list_encryptor.py +++ b/monkey/tests/unit_tests/monkey_island/cc/models/utils/field_encryptors/test_string_list_encryptor.py @@ -1,7 +1,7 @@ import pytest from monkey_island.cc.models.utils.field_encryptors.string_list_encryptor import StringListEncryptor -from monkey_island.cc.server_utils.encryptor import initialize_encryptor +from monkey_island.cc.server_utils.key_encryptor import initialize_encryptor MOCK_STRING_LIST = ["test_1", "test_2"] EMPTY_LIST = [] diff --git a/monkey/tests/unit_tests/monkey_island/cc/resources/test_configuration_import.py b/monkey/tests/unit_tests/monkey_island/cc/resources/test_configuration_import.py index 989994cb6..45ef8daaf 100644 --- a/monkey/tests/unit_tests/monkey_island/cc/resources/test_configuration_import.py +++ b/monkey/tests/unit_tests/monkey_island/cc/resources/test_configuration_import.py @@ -6,7 +6,7 @@ from tests.unit_tests.monkey_island.cc.services.utils.test_encryption import PAS from common.utils.exceptions import InvalidConfigurationError from monkey_island.cc.resources.configuration_import import ConfigurationImport -from monkey_island.cc.services.utils.encryption import encrypt_string +from monkey_island.cc.services.utils.password_encryption import PasswordBasedEncryptor def test_is_config_encrypted__json(monkey_config_json): @@ -15,7 +15,8 @@ def test_is_config_encrypted__json(monkey_config_json): @pytest.mark.slow def test_is_config_encrypted__ciphertext(monkey_config_json): - encrypted_config = encrypt_string(monkey_config_json, PASSWORD) + pb_encryptor = PasswordBasedEncryptor(PASSWORD) + encrypted_config = pb_encryptor.encrypt(monkey_config_json) assert ConfigurationImport.is_config_encrypted(encrypted_config) diff --git a/monkey/tests/unit_tests/monkey_island/cc/server_utils/test_encryptor.py b/monkey/tests/unit_tests/monkey_island/cc/server_utils/test_key_encryptor.py similarity index 89% rename from monkey/tests/unit_tests/monkey_island/cc/server_utils/test_encryptor.py rename to monkey/tests/unit_tests/monkey_island/cc/server_utils/test_key_encryptor.py index 0ca724d44..f7097ec00 100644 --- a/monkey/tests/unit_tests/monkey_island/cc/server_utils/test_encryptor.py +++ b/monkey/tests/unit_tests/monkey_island/cc/server_utils/test_key_encryptor.py @@ -1,6 +1,6 @@ import os -from monkey_island.cc.server_utils.encryptor import get_encryptor, initialize_encryptor +from monkey_island.cc.server_utils.key_encryptor import get_encryptor, initialize_encryptor PASSWORD_FILENAME = "mongo_key.bin" diff --git a/monkey/tests/unit_tests/monkey_island/cc/services/utils/test_encryption.py b/monkey/tests/unit_tests/monkey_island/cc/services/utils/test_encryption.py index fd3191f50..029e8201f 100644 --- a/monkey/tests/unit_tests/monkey_island/cc/services/utils/test_encryption.py +++ b/monkey/tests/unit_tests/monkey_island/cc/services/utils/test_encryption.py @@ -4,10 +4,9 @@ from tests.unit_tests.monkey_island.cc.services.utils.ciphertexts_for_encryption VALID_CIPHER_TEXT, ) -from monkey_island.cc.services.utils.encryption import ( +from monkey_island.cc.services.utils.password_encryption import ( InvalidCredentialsError, - decrypt_ciphertext, - encrypt_string, + PasswordBasedEncryptor, ) MONKEY_CONFIGS_DIR_PATH = "monkey_configs" @@ -18,23 +17,27 @@ INCORRECT_PASSWORD = "goodbye321" @pytest.mark.slow def test_encrypt_decrypt_string(monkey_config_json): - encrypted_config = encrypt_string(monkey_config_json, PASSWORD) - assert decrypt_ciphertext(encrypted_config, PASSWORD) == monkey_config_json + pb_encryptor = PasswordBasedEncryptor(PASSWORD) + encrypted_config = pb_encryptor.encrypt(monkey_config_json) + assert pb_encryptor.decrypt(encrypted_config) == monkey_config_json @pytest.mark.slow def test_decrypt_string__wrong_password(monkey_config_json): + pb_encryptor = PasswordBasedEncryptor(INCORRECT_PASSWORD) with pytest.raises(InvalidCredentialsError): - decrypt_ciphertext(VALID_CIPHER_TEXT, INCORRECT_PASSWORD) + pb_encryptor.decrypt(VALID_CIPHER_TEXT) @pytest.mark.slow def test_decrypt_string__malformed_corrupted(): + pb_encryptor = PasswordBasedEncryptor(PASSWORD) with pytest.raises(ValueError): - decrypt_ciphertext(MALFORMED_CIPHER_TEXT_CORRUPTED, PASSWORD) + pb_encryptor.decrypt(MALFORMED_CIPHER_TEXT_CORRUPTED) @pytest.mark.slow def test_decrypt_string__no_password(monkey_config_json): + pb_encryptor = PasswordBasedEncryptor("") with pytest.raises(InvalidCredentialsError): - decrypt_ciphertext(VALID_CIPHER_TEXT, "") + pb_encryptor.decrypt(VALID_CIPHER_TEXT) diff --git a/monkey/tests/unit_tests/monkey_island/cc/services/zero_trust/scoutsuite/test_scoutsuite_auth_service.py b/monkey/tests/unit_tests/monkey_island/cc/services/zero_trust/scoutsuite/test_scoutsuite_auth_service.py index faea76f4f..af47d51b5 100644 --- a/monkey/tests/unit_tests/monkey_island/cc/services/zero_trust/scoutsuite/test_scoutsuite_auth_service.py +++ b/monkey/tests/unit_tests/monkey_island/cc/services/zero_trust/scoutsuite/test_scoutsuite_auth_service.py @@ -5,7 +5,7 @@ import pytest from common.config_value_paths import AWS_KEYS_PATH from monkey_island.cc.database import mongo -from monkey_island.cc.server_utils.encryptor import get_encryptor, initialize_encryptor +from monkey_island.cc.server_utils.key_encryptor import get_encryptor, initialize_encryptor from monkey_island.cc.services.config import ConfigService from monkey_island.cc.services.zero_trust.scoutsuite.scoutsuite_auth_service import ( is_aws_keys_setup, From a661dc4fe60e1e6df33ee238050c3718081afa2f Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Wed, 22 Sep 2021 22:48:13 +0200 Subject: [PATCH 2/6] Island: Refactor encryptors All encryptors are moved to server_utils/encryption. They were renamed according to the class name. Everywhere that we had use the encryptors I have updated the names. Unit tests are also moved to UTs server_utils/encryption. --- .../utils/field_encryptors/string_list_encryptor.py | 2 +- .../monkey_island/cc/resources/configuration_export.py | 4 +++- .../monkey_island/cc/resources/configuration_import.py | 4 ++-- monkey/monkey_island/cc/server_setup.py | 4 +++- .../cc/server_utils/encryption/__init__.py | 0 .../data_store_encryptor.py} | 10 +++++----- .../utils => server_utils/encryption}/i_encryptor.py | 0 .../encryption/key_based_encryptor.py} | 2 +- .../encryption/password_based_encryption.py} | 2 +- .../attack/technique_reports/technique_report_tools.py | 2 +- monkey/monkey_island/cc/services/config.py | 2 +- .../cc/services/telemetry/processing/exploit.py | 2 +- .../cc/services/telemetry/processing/system_info.py | 2 +- .../zero_trust/scoutsuite/scoutsuite_auth_service.py | 2 +- monkey/tests/unit_tests/monkey_island/cc/conftest.py | 2 +- .../field_encryptors/test_string_list_encryptor.py | 2 +- .../cc/resources/test_configuration_import.py | 8 ++++++-- .../test_data_store_encryptor.py} | 5 ++++- .../encryption/test_password_based_encryption.py} | 2 +- .../scoutsuite/test_scoutsuite_auth_service.py | 5 ++++- 20 files changed, 38 insertions(+), 24 deletions(-) create mode 100644 monkey/monkey_island/cc/server_utils/encryption/__init__.py rename monkey/monkey_island/cc/server_utils/{key_encryptor.py => encryption/data_store_encryptor.py} (81%) rename monkey/monkey_island/cc/{services/utils => server_utils/encryption}/i_encryptor.py (100%) rename monkey/monkey_island/cc/{services/utils/key_encryption.py => server_utils/encryption/key_based_encryptor.py} (94%) rename monkey/monkey_island/cc/{services/utils/password_encryption.py => server_utils/encryption/password_based_encryption.py} (96%) rename monkey/tests/unit_tests/monkey_island/cc/server_utils/{test_key_encryptor.py => encryption/test_data_store_encryptor.py} (86%) rename monkey/tests/unit_tests/monkey_island/cc/{services/utils/test_encryption.py => server_utils/encryption/test_password_based_encryption.py} (94%) diff --git a/monkey/monkey_island/cc/models/utils/field_encryptors/string_list_encryptor.py b/monkey/monkey_island/cc/models/utils/field_encryptors/string_list_encryptor.py index 91464c1fa..8cde30af0 100644 --- a/monkey/monkey_island/cc/models/utils/field_encryptors/string_list_encryptor.py +++ b/monkey/monkey_island/cc/models/utils/field_encryptors/string_list_encryptor.py @@ -1,7 +1,7 @@ from typing import List from monkey_island.cc.models.utils.field_encryptors.i_field_encryptor import IFieldEncryptor -from monkey_island.cc.server_utils.key_encryptor import get_encryptor +from monkey_island.cc.server_utils.encryption.data_store_encryptor import get_encryptor class StringListEncryptor(IFieldEncryptor): diff --git a/monkey/monkey_island/cc/resources/configuration_export.py b/monkey/monkey_island/cc/resources/configuration_export.py index c9565011b..089e9c813 100644 --- a/monkey/monkey_island/cc/resources/configuration_export.py +++ b/monkey/monkey_island/cc/resources/configuration_export.py @@ -4,8 +4,10 @@ import flask_restful from flask import request from monkey_island.cc.resources.auth.auth import jwt_required +from monkey_island.cc.server_utils.encryption.password_based_encryption import ( + PasswordBasedEncryptor, +) from monkey_island.cc.services.config import ConfigService -from monkey_island.cc.services.utils.password_encryption import PasswordBasedEncryptor class ConfigurationExport(flask_restful.Resource): diff --git a/monkey/monkey_island/cc/resources/configuration_import.py b/monkey/monkey_island/cc/resources/configuration_import.py index 99b43f3ba..c4b64a363 100644 --- a/monkey/monkey_island/cc/resources/configuration_import.py +++ b/monkey/monkey_island/cc/resources/configuration_import.py @@ -8,13 +8,13 @@ from flask import request from common.utils.exceptions import InvalidConfigurationError from monkey_island.cc.resources.auth.auth import jwt_required -from monkey_island.cc.services.config import ConfigService -from monkey_island.cc.services.utils.password_encryption import ( +from monkey_island.cc.server_utils.encryption.password_based_encryption import ( InvalidCiphertextError, InvalidCredentialsError, PasswordBasedEncryptor, is_encrypted, ) +from monkey_island.cc.services.config import ConfigService logger = logging.getLogger(__name__) diff --git a/monkey/monkey_island/cc/server_setup.py b/monkey/monkey_island/cc/server_setup.py index 5ed167126..e5d4dc47e 100644 --- a/monkey/monkey_island/cc/server_setup.py +++ b/monkey/monkey_island/cc/server_setup.py @@ -27,8 +27,10 @@ from monkey_island.cc.server_utils.consts import ( # noqa: E402 GEVENT_EXCEPTION_LOG, MONGO_CONNECTION_TIMEOUT, ) +from monkey_island.cc.server_utils.encryption.data_store_encryptor import ( # noqa: E402 + initialize_encryptor, +) from monkey_island.cc.server_utils.island_logger import reset_logger, setup_logging # noqa: E402 -from monkey_island.cc.server_utils.key_encryptor import initialize_encryptor # noqa: E402 from monkey_island.cc.services.initialize import initialize_services # noqa: E402 from monkey_island.cc.services.reporting.exporter_init import populate_exporter_list # noqa: E402 from monkey_island.cc.services.utils.network_utils import local_ip_addresses # noqa: E402 diff --git a/monkey/monkey_island/cc/server_utils/encryption/__init__.py b/monkey/monkey_island/cc/server_utils/encryption/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/monkey/monkey_island/cc/server_utils/key_encryptor.py b/monkey/monkey_island/cc/server_utils/encryption/data_store_encryptor.py similarity index 81% rename from monkey/monkey_island/cc/server_utils/key_encryptor.py rename to monkey/monkey_island/cc/server_utils/encryption/data_store_encryptor.py index e41cf56f4..bdcfb97d4 100644 --- a/monkey/monkey_island/cc/server_utils/key_encryptor.py +++ b/monkey/monkey_island/cc/server_utils/encryption/data_store_encryptor.py @@ -4,8 +4,8 @@ import os # is maintained. from Crypto import Random # noqa: DUO133 # nosec: B413 +from monkey_island.cc.server_utils.encryption.key_based_encryptor import KeyBasedEncryptor from monkey_island.cc.server_utils.file_utils import open_new_securely_permissioned_file -from monkey_island.cc.services.utils.key_encryption import KeyBasedEncryptor _encryptor = None @@ -22,6 +22,8 @@ class DataStoreEncryptor: else: self._init_key(password_file) + self._key_base_encryptor = KeyBasedEncryptor(self._cipher_key) + def _init_key(self, password_file_path: str): self._cipher_key = Random.new().read(self._BLOCK_SIZE) with open_new_securely_permissioned_file(password_file_path, "wb") as f: @@ -32,12 +34,10 @@ class DataStoreEncryptor: self._cipher_key = f.read() def enc(self, message: str): - key_encryptor = KeyBasedEncryptor(self._cipher_key) - return key_encryptor.encrypt(message) + return self._key_base_encryptor.encrypt(message) def dec(self, enc_message: str): - key_encryptor = KeyBasedEncryptor(self._cipher_key) - return key_encryptor.decrypt(enc_message) + return self._key_base_encryptor.decrypt(enc_message) def initialize_encryptor(password_file_dir): diff --git a/monkey/monkey_island/cc/services/utils/i_encryptor.py b/monkey/monkey_island/cc/server_utils/encryption/i_encryptor.py similarity index 100% rename from monkey/monkey_island/cc/services/utils/i_encryptor.py rename to monkey/monkey_island/cc/server_utils/encryption/i_encryptor.py diff --git a/monkey/monkey_island/cc/services/utils/key_encryption.py b/monkey/monkey_island/cc/server_utils/encryption/key_based_encryptor.py similarity index 94% rename from monkey/monkey_island/cc/services/utils/key_encryption.py rename to monkey/monkey_island/cc/server_utils/encryption/key_based_encryptor.py index cb8366da8..49f67a34b 100644 --- a/monkey/monkey_island/cc/services/utils/key_encryption.py +++ b/monkey/monkey_island/cc/server_utils/encryption/key_based_encryptor.py @@ -6,7 +6,7 @@ import logging from Crypto import Random # noqa: DUO133 # nosec: B413 from Crypto.Cipher import AES # noqa: DUO133 # nosec: B413 -from monkey_island.cc.services.utils.i_encryptor import IEncryptor +from monkey_island.cc.server_utils.encryption.i_encryptor import IEncryptor logger = logging.getLogger(__name__) diff --git a/monkey/monkey_island/cc/services/utils/password_encryption.py b/monkey/monkey_island/cc/server_utils/encryption/password_based_encryption.py similarity index 96% rename from monkey/monkey_island/cc/services/utils/password_encryption.py rename to monkey/monkey_island/cc/server_utils/encryption/password_based_encryption.py index 1854722e8..da4736e16 100644 --- a/monkey/monkey_island/cc/services/utils/password_encryption.py +++ b/monkey/monkey_island/cc/server_utils/encryption/password_based_encryption.py @@ -4,7 +4,7 @@ import logging import pyAesCrypt -from monkey_island.cc.services.utils.i_encryptor import IEncryptor +from monkey_island.cc.server_utils.encryption.i_encryptor import IEncryptor logger = logging.getLogger(__name__) diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/technique_report_tools.py b/monkey/monkey_island/cc/services/attack/technique_reports/technique_report_tools.py index 6a431f35a..88243de5d 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/technique_report_tools.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/technique_report_tools.py @@ -1,4 +1,4 @@ -from monkey_island.cc.server_utils.key_encryptor import get_encryptor +from monkey_island.cc.server_utils.encryption.data_store_encryptor import get_encryptor def parse_creds(attempt): diff --git a/monkey/monkey_island/cc/services/config.py b/monkey/monkey_island/cc/services/config.py index 26e3ab971..7f69928c0 100644 --- a/monkey/monkey_island/cc/services/config.py +++ b/monkey/monkey_island/cc/services/config.py @@ -19,7 +19,7 @@ from common.config_value_paths import ( USER_LIST_PATH, ) from monkey_island.cc.database import mongo -from monkey_island.cc.server_utils.key_encryptor import get_encryptor +from monkey_island.cc.server_utils.encryption.data_store_encryptor import get_encryptor from monkey_island.cc.services.config_manipulator import update_config_per_mode from monkey_island.cc.services.config_schema.config_schema import SCHEMA from monkey_island.cc.services.mode.island_mode_service import ModeNotSetError, get_mode diff --git a/monkey/monkey_island/cc/services/telemetry/processing/exploit.py b/monkey/monkey_island/cc/services/telemetry/processing/exploit.py index 0a0ccce15..246176a8d 100644 --- a/monkey/monkey_island/cc/services/telemetry/processing/exploit.py +++ b/monkey/monkey_island/cc/services/telemetry/processing/exploit.py @@ -3,7 +3,7 @@ import copy import dateutil from monkey_island.cc.models import Monkey -from monkey_island.cc.server_utils.key_encryptor import get_encryptor +from monkey_island.cc.server_utils.encryption.data_store_encryptor import get_encryptor from monkey_island.cc.services.config import ConfigService from monkey_island.cc.services.edge.displayed_edge import EdgeService from monkey_island.cc.services.node import NodeService diff --git a/monkey/monkey_island/cc/services/telemetry/processing/system_info.py b/monkey/monkey_island/cc/services/telemetry/processing/system_info.py index 1bcc61ecd..3cc1dc560 100644 --- a/monkey/monkey_island/cc/services/telemetry/processing/system_info.py +++ b/monkey/monkey_island/cc/services/telemetry/processing/system_info.py @@ -1,6 +1,6 @@ import logging -from monkey_island.cc.server_utils.key_encryptor import get_encryptor +from monkey_island.cc.server_utils.encryption.data_store_encryptor import get_encryptor from monkey_island.cc.services.config import ConfigService from monkey_island.cc.services.node import NodeService from monkey_island.cc.services.telemetry.processing.system_info_collectors.system_info_telemetry_dispatcher import ( # noqa: E501 diff --git a/monkey/monkey_island/cc/services/zero_trust/scoutsuite/scoutsuite_auth_service.py b/monkey/monkey_island/cc/services/zero_trust/scoutsuite/scoutsuite_auth_service.py index 0d423bd6a..3ac6a7861 100644 --- a/monkey/monkey_island/cc/services/zero_trust/scoutsuite/scoutsuite_auth_service.py +++ b/monkey/monkey_island/cc/services/zero_trust/scoutsuite/scoutsuite_auth_service.py @@ -5,7 +5,7 @@ from ScoutSuite.providers.base.authentication_strategy import AuthenticationExce from common.cloud.scoutsuite_consts import CloudProviders from common.config_value_paths import AWS_KEYS_PATH from common.utils.exceptions import InvalidAWSKeys -from monkey_island.cc.server_utils.key_encryptor import get_encryptor +from monkey_island.cc.server_utils.encryption.data_store_encryptor import get_encryptor from monkey_island.cc.services.config import ConfigService diff --git a/monkey/tests/unit_tests/monkey_island/cc/conftest.py b/monkey/tests/unit_tests/monkey_island/cc/conftest.py index c14524411..438ee3fef 100644 --- a/monkey/tests/unit_tests/monkey_island/cc/conftest.py +++ b/monkey/tests/unit_tests/monkey_island/cc/conftest.py @@ -5,7 +5,7 @@ import os import pytest from tests.unit_tests.monkey_island.cc.mongomock_fixtures import * # noqa: F401,F403,E402 -from tests.unit_tests.monkey_island.cc.services.utils.test_encryption import ( +from tests.unit_tests.monkey_island.cc.server_utils.encryption.test_password_based_encryption import ( # noqa: E501 MONKEY_CONFIGS_DIR_PATH, STANDARD_PLAINTEXT_MONKEY_CONFIG_FILENAME, ) diff --git a/monkey/tests/unit_tests/monkey_island/cc/models/utils/field_encryptors/test_string_list_encryptor.py b/monkey/tests/unit_tests/monkey_island/cc/models/utils/field_encryptors/test_string_list_encryptor.py index fe8af8e0d..1428a0009 100644 --- a/monkey/tests/unit_tests/monkey_island/cc/models/utils/field_encryptors/test_string_list_encryptor.py +++ b/monkey/tests/unit_tests/monkey_island/cc/models/utils/field_encryptors/test_string_list_encryptor.py @@ -1,7 +1,7 @@ import pytest from monkey_island.cc.models.utils.field_encryptors.string_list_encryptor import StringListEncryptor -from monkey_island.cc.server_utils.key_encryptor import initialize_encryptor +from monkey_island.cc.server_utils.encryption.data_store_encryptor import initialize_encryptor MOCK_STRING_LIST = ["test_1", "test_2"] EMPTY_LIST = [] diff --git a/monkey/tests/unit_tests/monkey_island/cc/resources/test_configuration_import.py b/monkey/tests/unit_tests/monkey_island/cc/resources/test_configuration_import.py index 45ef8daaf..ac72f01c2 100644 --- a/monkey/tests/unit_tests/monkey_island/cc/resources/test_configuration_import.py +++ b/monkey/tests/unit_tests/monkey_island/cc/resources/test_configuration_import.py @@ -1,12 +1,16 @@ import pytest +from tests.unit_tests.monkey_island.cc.server_utils.encryption.test_password_based_encryption import ( # noqa: E501 + PASSWORD, +) from tests.unit_tests.monkey_island.cc.services.utils.ciphertexts_for_encryption_test import ( MALFORMED_CIPHER_TEXT_CORRUPTED, ) -from tests.unit_tests.monkey_island.cc.services.utils.test_encryption import PASSWORD from common.utils.exceptions import InvalidConfigurationError from monkey_island.cc.resources.configuration_import import ConfigurationImport -from monkey_island.cc.services.utils.password_encryption import PasswordBasedEncryptor +from monkey_island.cc.server_utils.encryption.password_based_encryption import ( + PasswordBasedEncryptor, +) def test_is_config_encrypted__json(monkey_config_json): diff --git a/monkey/tests/unit_tests/monkey_island/cc/server_utils/test_key_encryptor.py b/monkey/tests/unit_tests/monkey_island/cc/server_utils/encryption/test_data_store_encryptor.py similarity index 86% rename from monkey/tests/unit_tests/monkey_island/cc/server_utils/test_key_encryptor.py rename to monkey/tests/unit_tests/monkey_island/cc/server_utils/encryption/test_data_store_encryptor.py index f7097ec00..e3dbd8afa 100644 --- a/monkey/tests/unit_tests/monkey_island/cc/server_utils/test_key_encryptor.py +++ b/monkey/tests/unit_tests/monkey_island/cc/server_utils/encryption/test_data_store_encryptor.py @@ -1,6 +1,9 @@ import os -from monkey_island.cc.server_utils.key_encryptor import get_encryptor, initialize_encryptor +from monkey_island.cc.server_utils.encryption.data_store_encryptor import ( + get_encryptor, + initialize_encryptor, +) PASSWORD_FILENAME = "mongo_key.bin" diff --git a/monkey/tests/unit_tests/monkey_island/cc/services/utils/test_encryption.py b/monkey/tests/unit_tests/monkey_island/cc/server_utils/encryption/test_password_based_encryption.py similarity index 94% rename from monkey/tests/unit_tests/monkey_island/cc/services/utils/test_encryption.py rename to monkey/tests/unit_tests/monkey_island/cc/server_utils/encryption/test_password_based_encryption.py index 029e8201f..cb3756e40 100644 --- a/monkey/tests/unit_tests/monkey_island/cc/services/utils/test_encryption.py +++ b/monkey/tests/unit_tests/monkey_island/cc/server_utils/encryption/test_password_based_encryption.py @@ -4,7 +4,7 @@ from tests.unit_tests.monkey_island.cc.services.utils.ciphertexts_for_encryption VALID_CIPHER_TEXT, ) -from monkey_island.cc.services.utils.password_encryption import ( +from monkey_island.cc.server_utils.encryption.password_based_encryption import ( InvalidCredentialsError, PasswordBasedEncryptor, ) diff --git a/monkey/tests/unit_tests/monkey_island/cc/services/zero_trust/scoutsuite/test_scoutsuite_auth_service.py b/monkey/tests/unit_tests/monkey_island/cc/services/zero_trust/scoutsuite/test_scoutsuite_auth_service.py index af47d51b5..12809dfa8 100644 --- a/monkey/tests/unit_tests/monkey_island/cc/services/zero_trust/scoutsuite/test_scoutsuite_auth_service.py +++ b/monkey/tests/unit_tests/monkey_island/cc/services/zero_trust/scoutsuite/test_scoutsuite_auth_service.py @@ -5,7 +5,10 @@ import pytest from common.config_value_paths import AWS_KEYS_PATH from monkey_island.cc.database import mongo -from monkey_island.cc.server_utils.key_encryptor import get_encryptor, initialize_encryptor +from monkey_island.cc.server_utils.encryption.data_store_encryptor import ( + get_encryptor, + initialize_encryptor, +) from monkey_island.cc.services.config import ConfigService from monkey_island.cc.services.zero_trust.scoutsuite.scoutsuite_auth_service import ( is_aws_keys_setup, From 1b91616778c971c87a7029b89bf256edd6a6feba Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Thu, 23 Sep 2021 12:44:05 +0200 Subject: [PATCH 3/6] Island: Add explanation for KBE and PBE KeyBasedEncryptor and PasswordBasedEncryptor --- .../encryption/data_store_encryptor.py | 20 +++++++++---------- .../encryption/key_based_encryptor.py | 8 ++++++++ .../encryption/password_based_encryption.py | 8 ++++++++ 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/monkey/monkey_island/cc/server_utils/encryption/data_store_encryptor.py b/monkey/monkey_island/cc/server_utils/encryption/data_store_encryptor.py index bdcfb97d4..f2b989816 100644 --- a/monkey/monkey_island/cc/server_utils/encryption/data_store_encryptor.py +++ b/monkey/monkey_island/cc/server_utils/encryption/data_store_encryptor.py @@ -12,15 +12,15 @@ _encryptor = None class DataStoreEncryptor: _BLOCK_SIZE = 32 - _PASSWORD_FILENAME = "mongo_key.bin" + _KEY_FILENAME = "mongo_key.bin" - def __init__(self, password_file_dir): - password_file = os.path.join(password_file_dir, self._PASSWORD_FILENAME) + def __init__(self, key_file_dir): + key_file = os.path.join(key_file_dir, self._KEY_FILENAME) - if os.path.exists(password_file): - self._load_existing_key(password_file) + if os.path.exists(key_file): + self._load_existing_key(key_file) else: - self._init_key(password_file) + self._init_key(key_file) self._key_base_encryptor = KeyBasedEncryptor(self._cipher_key) @@ -29,8 +29,8 @@ class DataStoreEncryptor: with open_new_securely_permissioned_file(password_file_path, "wb") as f: f.write(self._cipher_key) - def _load_existing_key(self, password_file): - with open(password_file, "rb") as f: + def _load_existing_key(self, key_file): + with open(key_file, "rb") as f: self._cipher_key = f.read() def enc(self, message: str): @@ -40,10 +40,10 @@ class DataStoreEncryptor: return self._key_base_encryptor.decrypt(enc_message) -def initialize_encryptor(password_file_dir): +def initialize_encryptor(key_file_dir): global _encryptor - _encryptor = DataStoreEncryptor(password_file_dir) + _encryptor = DataStoreEncryptor(key_file_dir) def get_encryptor(): diff --git a/monkey/monkey_island/cc/server_utils/encryption/key_based_encryptor.py b/monkey/monkey_island/cc/server_utils/encryption/key_based_encryptor.py index 49f67a34b..0331c7e70 100644 --- a/monkey/monkey_island/cc/server_utils/encryption/key_based_encryptor.py +++ b/monkey/monkey_island/cc/server_utils/encryption/key_based_encryptor.py @@ -10,6 +10,14 @@ from monkey_island.cc.server_utils.encryption.i_encryptor import IEncryptor logger = logging.getLogger(__name__) +# KBE is an encryption method which use random key of specific length +# and AES block cipher to encrypt/decrypt the data. The key is more complex +# one and hard to remember than user provided one. This class provides more secure way of +# encryption compared to PBE because of the random and complex key. +# We can merge the two into the one encryption method but then we lose the entropy +# of the key with whatever key derivation function we use. +# Note: password != key + class KeyBasedEncryptor(IEncryptor): diff --git a/monkey/monkey_island/cc/server_utils/encryption/password_based_encryption.py b/monkey/monkey_island/cc/server_utils/encryption/password_based_encryption.py index da4736e16..d699c4e5a 100644 --- a/monkey/monkey_island/cc/server_utils/encryption/password_based_encryption.py +++ b/monkey/monkey_island/cc/server_utils/encryption/password_based_encryption.py @@ -8,6 +8,14 @@ from monkey_island.cc.server_utils.encryption.i_encryptor import IEncryptor logger = logging.getLogger(__name__) +# PBE as implemented takes low-entropy, user provided password and it adds some +# entropy to it and encrypts/decrypts the data. This implementation uses AES256-CBC +# and it is less secure encryption then KeyBasedEncryptor. +# The security of it depends on what will the user provide as password. +# We can merge the two into the one encryption method but then we lose the entropy +# of the key with whatever key derivation function we use. +# Note: password != key + class PasswordBasedEncryptor(IEncryptor): From 071a4eb1a7de7ae40601c0c6d5ac8faa7e59b381 Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Thu, 23 Sep 2021 17:52:15 +0200 Subject: [PATCH 4/6] Island: Add IEncryptor to __init__ Dnt abbrev in PassworBasedEncryptor and KeyBasedEncryptor Add comment for review and evaluate the padding function --- .../monkey_island/cc/server_utils/encryption/__init__.py | 1 + .../cc/server_utils/encryption/key_based_encryptor.py | 7 ++++--- .../server_utils/encryption/password_based_encryption.py | 4 ++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/monkey/monkey_island/cc/server_utils/encryption/__init__.py b/monkey/monkey_island/cc/server_utils/encryption/__init__.py index e69de29bb..d15968ca7 100644 --- a/monkey/monkey_island/cc/server_utils/encryption/__init__.py +++ b/monkey/monkey_island/cc/server_utils/encryption/__init__.py @@ -0,0 +1 @@ +from monkey_island.cc.server_utils.encryption.i_encryptor import IEncryptor # noqa: F401 diff --git a/monkey/monkey_island/cc/server_utils/encryption/key_based_encryptor.py b/monkey/monkey_island/cc/server_utils/encryption/key_based_encryptor.py index 0331c7e70..b5fe92d96 100644 --- a/monkey/monkey_island/cc/server_utils/encryption/key_based_encryptor.py +++ b/monkey/monkey_island/cc/server_utils/encryption/key_based_encryptor.py @@ -6,14 +6,14 @@ import logging from Crypto import Random # noqa: DUO133 # nosec: B413 from Crypto.Cipher import AES # noqa: DUO133 # nosec: B413 -from monkey_island.cc.server_utils.encryption.i_encryptor import IEncryptor +from monkey_island.cc.server_utils.encryption import IEncryptor logger = logging.getLogger(__name__) -# KBE is an encryption method which use random key of specific length +# KeyBasedEncryptor is an encryption method which use random key of specific length # and AES block cipher to encrypt/decrypt the data. The key is more complex # one and hard to remember than user provided one. This class provides more secure way of -# encryption compared to PBE because of the random and complex key. +# encryption compared to PasswordBasedEncryptor because of the random and complex key. # We can merge the two into the one encryption method but then we lose the entropy # of the key with whatever key derivation function we use. # Note: password != key @@ -37,6 +37,7 @@ class KeyBasedEncryptor(IEncryptor): cipher = AES.new(self._key, AES.MODE_CBC, cipher_iv) return self._unpad(cipher.decrypt(enc_message[AES.block_size :]).decode()) + # TODO: Review and evaluate the security of the padding function def _pad(self, message): return message + (self._BLOCK_SIZE - (len(message) % self._BLOCK_SIZE)) * chr( self._BLOCK_SIZE - (len(message) % self._BLOCK_SIZE) diff --git a/monkey/monkey_island/cc/server_utils/encryption/password_based_encryption.py b/monkey/monkey_island/cc/server_utils/encryption/password_based_encryption.py index d699c4e5a..20708ce31 100644 --- a/monkey/monkey_island/cc/server_utils/encryption/password_based_encryption.py +++ b/monkey/monkey_island/cc/server_utils/encryption/password_based_encryption.py @@ -4,11 +4,11 @@ import logging import pyAesCrypt -from monkey_island.cc.server_utils.encryption.i_encryptor import IEncryptor +from monkey_island.cc.server_utils.encryption import IEncryptor logger = logging.getLogger(__name__) -# PBE as implemented takes low-entropy, user provided password and it adds some +# PasswordBasedEncryptor as implemented takes low-entropy, user provided password and it adds some # entropy to it and encrypts/decrypts the data. This implementation uses AES256-CBC # and it is less secure encryption then KeyBasedEncryptor. # The security of it depends on what will the user provide as password. From e0779347b2862e0d8f6c18da98f91142beaa6a81 Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Thu, 23 Sep 2021 18:42:40 +0200 Subject: [PATCH 5/6] Island: Add all imports from encryption to __init__ Now the imports are shorter by one directory. Check the __init__ in encryption. --- .flake8 | 1 + .../field_encryptors/string_list_encryptor.py | 2 +- .../cc/resources/configuration_export.py | 4 +--- .../cc/resources/configuration_import.py | 2 +- monkey/monkey_island/cc/server_setup.py | 4 +--- .../cc/server_utils/encryption/__init__.py | 14 +++++++++++++- .../encryption/data_store_encryptor.py | 2 +- .../technique_reports/technique_report_tools.py | 2 +- monkey/monkey_island/cc/services/config.py | 2 +- .../cc/services/telemetry/processing/exploit.py | 2 +- .../services/telemetry/processing/system_info.py | 2 +- .../scoutsuite/scoutsuite_auth_service.py | 2 +- .../field_encryptors/test_string_list_encryptor.py | 2 +- .../cc/resources/test_configuration_import.py | 4 +--- .../encryption/test_data_store_encryptor.py | 5 +---- .../encryption/test_password_based_encryption.py | 5 +---- .../scoutsuite/test_scoutsuite_auth_service.py | 5 +---- pyproject.toml | 1 + 18 files changed, 30 insertions(+), 31 deletions(-) diff --git a/.flake8 b/.flake8 index 97d903b8f..213c030a2 100644 --- a/.flake8 +++ b/.flake8 @@ -5,6 +5,7 @@ exclude = monkey/monkey_island/cc/ui,vulture_allowlist.py show-source = True max-complexity = 10 max-line-length = 100 +per-file-ignores = __init__.py:F401 ### ignore "whitespace before ':'", "line break before binary operator" for ### compatibility with black, and cyclomatic complexity (for now). diff --git a/monkey/monkey_island/cc/models/utils/field_encryptors/string_list_encryptor.py b/monkey/monkey_island/cc/models/utils/field_encryptors/string_list_encryptor.py index 8cde30af0..ab9b6a3e5 100644 --- a/monkey/monkey_island/cc/models/utils/field_encryptors/string_list_encryptor.py +++ b/monkey/monkey_island/cc/models/utils/field_encryptors/string_list_encryptor.py @@ -1,7 +1,7 @@ from typing import List from monkey_island.cc.models.utils.field_encryptors.i_field_encryptor import IFieldEncryptor -from monkey_island.cc.server_utils.encryption.data_store_encryptor import get_encryptor +from monkey_island.cc.server_utils.encryption import get_encryptor class StringListEncryptor(IFieldEncryptor): diff --git a/monkey/monkey_island/cc/resources/configuration_export.py b/monkey/monkey_island/cc/resources/configuration_export.py index 089e9c813..c550acc7d 100644 --- a/monkey/monkey_island/cc/resources/configuration_export.py +++ b/monkey/monkey_island/cc/resources/configuration_export.py @@ -4,9 +4,7 @@ import flask_restful from flask import request from monkey_island.cc.resources.auth.auth import jwt_required -from monkey_island.cc.server_utils.encryption.password_based_encryption import ( - PasswordBasedEncryptor, -) +from monkey_island.cc.server_utils.encryption import PasswordBasedEncryptor from monkey_island.cc.services.config import ConfigService diff --git a/monkey/monkey_island/cc/resources/configuration_import.py b/monkey/monkey_island/cc/resources/configuration_import.py index c4b64a363..6c0575e94 100644 --- a/monkey/monkey_island/cc/resources/configuration_import.py +++ b/monkey/monkey_island/cc/resources/configuration_import.py @@ -8,7 +8,7 @@ from flask import request from common.utils.exceptions import InvalidConfigurationError from monkey_island.cc.resources.auth.auth import jwt_required -from monkey_island.cc.server_utils.encryption.password_based_encryption import ( +from monkey_island.cc.server_utils.encryption import ( InvalidCiphertextError, InvalidCredentialsError, PasswordBasedEncryptor, diff --git a/monkey/monkey_island/cc/server_setup.py b/monkey/monkey_island/cc/server_setup.py index e5d4dc47e..7d8bf2d9f 100644 --- a/monkey/monkey_island/cc/server_setup.py +++ b/monkey/monkey_island/cc/server_setup.py @@ -27,9 +27,7 @@ from monkey_island.cc.server_utils.consts import ( # noqa: E402 GEVENT_EXCEPTION_LOG, MONGO_CONNECTION_TIMEOUT, ) -from monkey_island.cc.server_utils.encryption.data_store_encryptor import ( # noqa: E402 - initialize_encryptor, -) +from monkey_island.cc.server_utils.encryption import initialize_encryptor # noqa: E402 from monkey_island.cc.server_utils.island_logger import reset_logger, setup_logging # noqa: E402 from monkey_island.cc.services.initialize import initialize_services # noqa: E402 from monkey_island.cc.services.reporting.exporter_init import populate_exporter_list # noqa: E402 diff --git a/monkey/monkey_island/cc/server_utils/encryption/__init__.py b/monkey/monkey_island/cc/server_utils/encryption/__init__.py index d15968ca7..e245575eb 100644 --- a/monkey/monkey_island/cc/server_utils/encryption/__init__.py +++ b/monkey/monkey_island/cc/server_utils/encryption/__init__.py @@ -1 +1,13 @@ -from monkey_island.cc.server_utils.encryption.i_encryptor import IEncryptor # noqa: F401 +from monkey_island.cc.server_utils.encryption.i_encryptor import IEncryptor +from monkey_island.cc.server_utils.encryption.key_based_encryptor import KeyBasedEncryptor +from monkey_island.cc.server_utils.encryption.password_based_encryption import ( + InvalidCiphertextError, + InvalidCredentialsError, + PasswordBasedEncryptor, + is_encrypted, +) +from monkey_island.cc.server_utils.encryption.data_store_encryptor import ( + DataStoreEncryptor, + get_encryptor, + initialize_encryptor, +) diff --git a/monkey/monkey_island/cc/server_utils/encryption/data_store_encryptor.py b/monkey/monkey_island/cc/server_utils/encryption/data_store_encryptor.py index f2b989816..f4125e1bf 100644 --- a/monkey/monkey_island/cc/server_utils/encryption/data_store_encryptor.py +++ b/monkey/monkey_island/cc/server_utils/encryption/data_store_encryptor.py @@ -4,7 +4,7 @@ import os # is maintained. from Crypto import Random # noqa: DUO133 # nosec: B413 -from monkey_island.cc.server_utils.encryption.key_based_encryptor import KeyBasedEncryptor +from monkey_island.cc.server_utils.encryption import KeyBasedEncryptor from monkey_island.cc.server_utils.file_utils import open_new_securely_permissioned_file _encryptor = None diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/technique_report_tools.py b/monkey/monkey_island/cc/services/attack/technique_reports/technique_report_tools.py index 88243de5d..8e8938d93 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/technique_report_tools.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/technique_report_tools.py @@ -1,4 +1,4 @@ -from monkey_island.cc.server_utils.encryption.data_store_encryptor import get_encryptor +from monkey_island.cc.server_utils.encryption import get_encryptor def parse_creds(attempt): diff --git a/monkey/monkey_island/cc/services/config.py b/monkey/monkey_island/cc/services/config.py index 7f69928c0..d5da366d6 100644 --- a/monkey/monkey_island/cc/services/config.py +++ b/monkey/monkey_island/cc/services/config.py @@ -19,7 +19,7 @@ from common.config_value_paths import ( USER_LIST_PATH, ) from monkey_island.cc.database import mongo -from monkey_island.cc.server_utils.encryption.data_store_encryptor import get_encryptor +from monkey_island.cc.server_utils.encryption import get_encryptor from monkey_island.cc.services.config_manipulator import update_config_per_mode from monkey_island.cc.services.config_schema.config_schema import SCHEMA from monkey_island.cc.services.mode.island_mode_service import ModeNotSetError, get_mode diff --git a/monkey/monkey_island/cc/services/telemetry/processing/exploit.py b/monkey/monkey_island/cc/services/telemetry/processing/exploit.py index 246176a8d..bd78e1fe8 100644 --- a/monkey/monkey_island/cc/services/telemetry/processing/exploit.py +++ b/monkey/monkey_island/cc/services/telemetry/processing/exploit.py @@ -3,7 +3,7 @@ import copy import dateutil from monkey_island.cc.models import Monkey -from monkey_island.cc.server_utils.encryption.data_store_encryptor import get_encryptor +from monkey_island.cc.server_utils.encryption import get_encryptor from monkey_island.cc.services.config import ConfigService from monkey_island.cc.services.edge.displayed_edge import EdgeService from monkey_island.cc.services.node import NodeService diff --git a/monkey/monkey_island/cc/services/telemetry/processing/system_info.py b/monkey/monkey_island/cc/services/telemetry/processing/system_info.py index 3cc1dc560..4d54af4d8 100644 --- a/monkey/monkey_island/cc/services/telemetry/processing/system_info.py +++ b/monkey/monkey_island/cc/services/telemetry/processing/system_info.py @@ -1,6 +1,6 @@ import logging -from monkey_island.cc.server_utils.encryption.data_store_encryptor import get_encryptor +from monkey_island.cc.server_utils.encryption import get_encryptor from monkey_island.cc.services.config import ConfigService from monkey_island.cc.services.node import NodeService from monkey_island.cc.services.telemetry.processing.system_info_collectors.system_info_telemetry_dispatcher import ( # noqa: E501 diff --git a/monkey/monkey_island/cc/services/zero_trust/scoutsuite/scoutsuite_auth_service.py b/monkey/monkey_island/cc/services/zero_trust/scoutsuite/scoutsuite_auth_service.py index 3ac6a7861..ece015935 100644 --- a/monkey/monkey_island/cc/services/zero_trust/scoutsuite/scoutsuite_auth_service.py +++ b/monkey/monkey_island/cc/services/zero_trust/scoutsuite/scoutsuite_auth_service.py @@ -5,7 +5,7 @@ from ScoutSuite.providers.base.authentication_strategy import AuthenticationExce from common.cloud.scoutsuite_consts import CloudProviders from common.config_value_paths import AWS_KEYS_PATH from common.utils.exceptions import InvalidAWSKeys -from monkey_island.cc.server_utils.encryption.data_store_encryptor import get_encryptor +from monkey_island.cc.server_utils.encryption import get_encryptor from monkey_island.cc.services.config import ConfigService diff --git a/monkey/tests/unit_tests/monkey_island/cc/models/utils/field_encryptors/test_string_list_encryptor.py b/monkey/tests/unit_tests/monkey_island/cc/models/utils/field_encryptors/test_string_list_encryptor.py index 1428a0009..9af487e24 100644 --- a/monkey/tests/unit_tests/monkey_island/cc/models/utils/field_encryptors/test_string_list_encryptor.py +++ b/monkey/tests/unit_tests/monkey_island/cc/models/utils/field_encryptors/test_string_list_encryptor.py @@ -1,7 +1,7 @@ import pytest from monkey_island.cc.models.utils.field_encryptors.string_list_encryptor import StringListEncryptor -from monkey_island.cc.server_utils.encryption.data_store_encryptor import initialize_encryptor +from monkey_island.cc.server_utils.encryption import initialize_encryptor MOCK_STRING_LIST = ["test_1", "test_2"] EMPTY_LIST = [] diff --git a/monkey/tests/unit_tests/monkey_island/cc/resources/test_configuration_import.py b/monkey/tests/unit_tests/monkey_island/cc/resources/test_configuration_import.py index ac72f01c2..fb397f234 100644 --- a/monkey/tests/unit_tests/monkey_island/cc/resources/test_configuration_import.py +++ b/monkey/tests/unit_tests/monkey_island/cc/resources/test_configuration_import.py @@ -8,9 +8,7 @@ from tests.unit_tests.monkey_island.cc.services.utils.ciphertexts_for_encryption from common.utils.exceptions import InvalidConfigurationError from monkey_island.cc.resources.configuration_import import ConfigurationImport -from monkey_island.cc.server_utils.encryption.password_based_encryption import ( - PasswordBasedEncryptor, -) +from monkey_island.cc.server_utils.encryption import PasswordBasedEncryptor def test_is_config_encrypted__json(monkey_config_json): diff --git a/monkey/tests/unit_tests/monkey_island/cc/server_utils/encryption/test_data_store_encryptor.py b/monkey/tests/unit_tests/monkey_island/cc/server_utils/encryption/test_data_store_encryptor.py index e3dbd8afa..fa135c345 100644 --- a/monkey/tests/unit_tests/monkey_island/cc/server_utils/encryption/test_data_store_encryptor.py +++ b/monkey/tests/unit_tests/monkey_island/cc/server_utils/encryption/test_data_store_encryptor.py @@ -1,9 +1,6 @@ import os -from monkey_island.cc.server_utils.encryption.data_store_encryptor import ( - get_encryptor, - initialize_encryptor, -) +from monkey_island.cc.server_utils.encryption import get_encryptor, initialize_encryptor PASSWORD_FILENAME = "mongo_key.bin" diff --git a/monkey/tests/unit_tests/monkey_island/cc/server_utils/encryption/test_password_based_encryption.py b/monkey/tests/unit_tests/monkey_island/cc/server_utils/encryption/test_password_based_encryption.py index cb3756e40..d00609481 100644 --- a/monkey/tests/unit_tests/monkey_island/cc/server_utils/encryption/test_password_based_encryption.py +++ b/monkey/tests/unit_tests/monkey_island/cc/server_utils/encryption/test_password_based_encryption.py @@ -4,10 +4,7 @@ from tests.unit_tests.monkey_island.cc.services.utils.ciphertexts_for_encryption VALID_CIPHER_TEXT, ) -from monkey_island.cc.server_utils.encryption.password_based_encryption import ( - InvalidCredentialsError, - PasswordBasedEncryptor, -) +from monkey_island.cc.server_utils.encryption import InvalidCredentialsError, PasswordBasedEncryptor MONKEY_CONFIGS_DIR_PATH = "monkey_configs" STANDARD_PLAINTEXT_MONKEY_CONFIG_FILENAME = "monkey_config_standard.json" diff --git a/monkey/tests/unit_tests/monkey_island/cc/services/zero_trust/scoutsuite/test_scoutsuite_auth_service.py b/monkey/tests/unit_tests/monkey_island/cc/services/zero_trust/scoutsuite/test_scoutsuite_auth_service.py index 12809dfa8..3df67330c 100644 --- a/monkey/tests/unit_tests/monkey_island/cc/services/zero_trust/scoutsuite/test_scoutsuite_auth_service.py +++ b/monkey/tests/unit_tests/monkey_island/cc/services/zero_trust/scoutsuite/test_scoutsuite_auth_service.py @@ -5,10 +5,7 @@ import pytest from common.config_value_paths import AWS_KEYS_PATH from monkey_island.cc.database import mongo -from monkey_island.cc.server_utils.encryption.data_store_encryptor import ( - get_encryptor, - initialize_encryptor, -) +from monkey_island.cc.server_utils.encryption import get_encryptor, initialize_encryptor from monkey_island.cc.services.config import ConfigService from monkey_island.cc.services.zero_trust.scoutsuite.scoutsuite_auth_service import ( is_aws_keys_setup, diff --git a/pyproject.toml b/pyproject.toml index 05c8dfe81..88da84d42 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,6 +12,7 @@ include_trailing_comma = true force_grid_wrap = 0 use_parentheses = true ensure_newline_before_comments = true +skip_glob="**/__init__.py" [tool.pytest.ini_options] minversion = "6.0" From e2ede289674142d23c70d37ed951a94238790b7e Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Thu, 23 Sep 2021 19:04:22 +0200 Subject: [PATCH 6/6] Island: Rename get_encryptor and initialize_encryptor Renamed to get_datastore_encryptor and initialize_datastore_encryptor --- .../field_encryptors/string_list_encryptor.py | 6 ++-- monkey/monkey_island/cc/server_setup.py | 4 +-- .../cc/server_utils/encryption/__init__.py | 4 +-- .../encryption/data_store_encryptor.py | 4 +-- .../technique_report_tools.py | 6 ++-- monkey/monkey_island/cc/services/config.py | 30 ++++++++++--------- .../services/telemetry/processing/exploit.py | 4 +-- .../telemetry/processing/system_info.py | 4 +-- .../scoutsuite/scoutsuite_auth_service.py | 4 +-- .../test_string_list_encryptor.py | 4 +-- .../encryption/test_data_store_encryptor.py | 19 +++++++----- .../test_scoutsuite_auth_service.py | 9 ++++-- 12 files changed, 53 insertions(+), 45 deletions(-) diff --git a/monkey/monkey_island/cc/models/utils/field_encryptors/string_list_encryptor.py b/monkey/monkey_island/cc/models/utils/field_encryptors/string_list_encryptor.py index ab9b6a3e5..089155289 100644 --- a/monkey/monkey_island/cc/models/utils/field_encryptors/string_list_encryptor.py +++ b/monkey/monkey_island/cc/models/utils/field_encryptors/string_list_encryptor.py @@ -1,14 +1,14 @@ from typing import List from monkey_island.cc.models.utils.field_encryptors.i_field_encryptor import IFieldEncryptor -from monkey_island.cc.server_utils.encryption import get_encryptor +from monkey_island.cc.server_utils.encryption import get_datastore_encryptor class StringListEncryptor(IFieldEncryptor): @staticmethod def encrypt(value: List[str]): - return [get_encryptor().enc(string) for string in value] + return [get_datastore_encryptor().enc(string) for string in value] @staticmethod def decrypt(value: List[str]): - return [get_encryptor().dec(string) for string in value] + return [get_datastore_encryptor().dec(string) for string in value] diff --git a/monkey/monkey_island/cc/server_setup.py b/monkey/monkey_island/cc/server_setup.py index 7d8bf2d9f..a4e4da485 100644 --- a/monkey/monkey_island/cc/server_setup.py +++ b/monkey/monkey_island/cc/server_setup.py @@ -27,7 +27,7 @@ from monkey_island.cc.server_utils.consts import ( # noqa: E402 GEVENT_EXCEPTION_LOG, MONGO_CONNECTION_TIMEOUT, ) -from monkey_island.cc.server_utils.encryption import initialize_encryptor # noqa: E402 +from monkey_island.cc.server_utils.encryption import initialize_datastore_encryptor # noqa: E402 from monkey_island.cc.server_utils.island_logger import reset_logger, setup_logging # noqa: E402 from monkey_island.cc.services.initialize import initialize_services # noqa: E402 from monkey_island.cc.services.reporting.exporter_init import populate_exporter_list # noqa: E402 @@ -88,7 +88,7 @@ def _configure_logging(config_options): def _initialize_globals(config_options: IslandConfigOptions, server_config_path: str): env_singleton.initialize_from_file(server_config_path) - initialize_encryptor(config_options.data_dir) + initialize_datastore_encryptor(config_options.data_dir) initialize_services(config_options.data_dir) diff --git a/monkey/monkey_island/cc/server_utils/encryption/__init__.py b/monkey/monkey_island/cc/server_utils/encryption/__init__.py index e245575eb..a41240be1 100644 --- a/monkey/monkey_island/cc/server_utils/encryption/__init__.py +++ b/monkey/monkey_island/cc/server_utils/encryption/__init__.py @@ -8,6 +8,6 @@ from monkey_island.cc.server_utils.encryption.password_based_encryption import ( ) from monkey_island.cc.server_utils.encryption.data_store_encryptor import ( DataStoreEncryptor, - get_encryptor, - initialize_encryptor, + get_datastore_encryptor, + initialize_datastore_encryptor, ) diff --git a/monkey/monkey_island/cc/server_utils/encryption/data_store_encryptor.py b/monkey/monkey_island/cc/server_utils/encryption/data_store_encryptor.py index f4125e1bf..215703c02 100644 --- a/monkey/monkey_island/cc/server_utils/encryption/data_store_encryptor.py +++ b/monkey/monkey_island/cc/server_utils/encryption/data_store_encryptor.py @@ -40,11 +40,11 @@ class DataStoreEncryptor: return self._key_base_encryptor.decrypt(enc_message) -def initialize_encryptor(key_file_dir): +def initialize_datastore_encryptor(key_file_dir): global _encryptor _encryptor = DataStoreEncryptor(key_file_dir) -def get_encryptor(): +def get_datastore_encryptor(): return _encryptor diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/technique_report_tools.py b/monkey/monkey_island/cc/services/attack/technique_reports/technique_report_tools.py index 8e8938d93..16884678b 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/technique_report_tools.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/technique_report_tools.py @@ -1,4 +1,4 @@ -from monkey_island.cc.server_utils.encryption import get_encryptor +from monkey_island.cc.server_utils.encryption import get_datastore_encryptor def parse_creds(attempt): @@ -29,7 +29,7 @@ def censor_password(password, plain_chars=3, secret_chars=5): """ if not password: return "" - password = get_encryptor().dec(password) + password = get_datastore_encryptor().dec(password) return password[0:plain_chars] + "*" * secret_chars @@ -42,5 +42,5 @@ def censor_hash(hash_, plain_chars=5): """ if not hash_: return "" - hash_ = get_encryptor().dec(hash_) + hash_ = get_datastore_encryptor().dec(hash_) return hash_[0:plain_chars] + " ..." diff --git a/monkey/monkey_island/cc/services/config.py b/monkey/monkey_island/cc/services/config.py index d5da366d6..973ca104a 100644 --- a/monkey/monkey_island/cc/services/config.py +++ b/monkey/monkey_island/cc/services/config.py @@ -19,7 +19,7 @@ from common.config_value_paths import ( USER_LIST_PATH, ) from monkey_island.cc.database import mongo -from monkey_island.cc.server_utils.encryption import get_encryptor +from monkey_island.cc.server_utils.encryption import get_datastore_encryptor from monkey_island.cc.services.config_manipulator import update_config_per_mode from monkey_island.cc.services.config_schema.config_schema import SCHEMA from monkey_island.cc.services.mode.island_mode_service import ModeNotSetError, get_mode @@ -90,9 +90,9 @@ class ConfigService: if should_decrypt: if config_key_as_arr in ENCRYPTED_CONFIG_VALUES: if isinstance(config, str): - config = get_encryptor().dec(config) + config = get_datastore_encryptor().dec(config) elif isinstance(config, list): - config = [get_encryptor().dec(x) for x in config] + config = [get_datastore_encryptor().dec(x) for x in config] return config @staticmethod @@ -130,7 +130,7 @@ class ConfigService: if item_value in items_from_config: return if should_encrypt: - item_value = get_encryptor().enc(item_value) + item_value = get_datastore_encryptor().enc(item_value) mongo.db.config.update( {"name": "newconfig"}, {"$addToSet": {item_key: item_value}}, upsert=False ) @@ -349,9 +349,11 @@ class ConfigService: ConfigService.decrypt_ssh_key_pair(item) for item in flat_config[key] ] else: - flat_config[key] = [get_encryptor().dec(item) for item in flat_config[key]] + flat_config[key] = [ + get_datastore_encryptor().dec(item) for item in flat_config[key] + ] else: - flat_config[key] = get_encryptor().dec(flat_config[key]) + flat_config[key] = get_datastore_encryptor().dec(flat_config[key]) return flat_config @staticmethod @@ -377,25 +379,25 @@ class ConfigService: ) else: config_arr[i] = ( - get_encryptor().dec(config_arr[i]) + get_datastore_encryptor().dec(config_arr[i]) if is_decrypt - else get_encryptor().enc(config_arr[i]) + else get_datastore_encryptor().enc(config_arr[i]) ) else: parent_config_arr[config_arr_as_array[-1]] = ( - get_encryptor().dec(config_arr) + get_datastore_encryptor().dec(config_arr) if is_decrypt - else get_encryptor().enc(config_arr) + else get_datastore_encryptor().enc(config_arr) ) @staticmethod def decrypt_ssh_key_pair(pair, encrypt=False): if encrypt: - pair["public_key"] = get_encryptor().enc(pair["public_key"]) - pair["private_key"] = get_encryptor().enc(pair["private_key"]) + pair["public_key"] = get_datastore_encryptor().enc(pair["public_key"]) + pair["private_key"] = get_datastore_encryptor().enc(pair["private_key"]) else: - pair["public_key"] = get_encryptor().dec(pair["public_key"]) - pair["private_key"] = get_encryptor().dec(pair["private_key"]) + pair["public_key"] = get_datastore_encryptor().dec(pair["public_key"]) + pair["private_key"] = get_datastore_encryptor().dec(pair["private_key"]) return pair @staticmethod diff --git a/monkey/monkey_island/cc/services/telemetry/processing/exploit.py b/monkey/monkey_island/cc/services/telemetry/processing/exploit.py index bd78e1fe8..7c156930a 100644 --- a/monkey/monkey_island/cc/services/telemetry/processing/exploit.py +++ b/monkey/monkey_island/cc/services/telemetry/processing/exploit.py @@ -3,7 +3,7 @@ import copy import dateutil from monkey_island.cc.models import Monkey -from monkey_island.cc.server_utils.encryption import get_encryptor +from monkey_island.cc.server_utils.encryption import get_datastore_encryptor from monkey_island.cc.services.config import ConfigService from monkey_island.cc.services.edge.displayed_edge import EdgeService from monkey_island.cc.services.node import NodeService @@ -76,4 +76,4 @@ def encrypt_exploit_creds(telemetry_json): credential = attempts[i][field] if credential: # PowerShell exploiter's telem may have `None` here if len(credential) > 0: - attempts[i][field] = get_encryptor().enc(credential) + attempts[i][field] = get_datastore_encryptor().enc(credential) diff --git a/monkey/monkey_island/cc/services/telemetry/processing/system_info.py b/monkey/monkey_island/cc/services/telemetry/processing/system_info.py index 4d54af4d8..ba72e822b 100644 --- a/monkey/monkey_island/cc/services/telemetry/processing/system_info.py +++ b/monkey/monkey_island/cc/services/telemetry/processing/system_info.py @@ -1,6 +1,6 @@ import logging -from monkey_island.cc.server_utils.encryption import get_encryptor +from monkey_island.cc.server_utils.encryption import get_datastore_encryptor from monkey_island.cc.services.config import ConfigService from monkey_island.cc.services.node import NodeService from monkey_island.cc.services.telemetry.processing.system_info_collectors.system_info_telemetry_dispatcher import ( # noqa: E501 @@ -70,7 +70,7 @@ def encrypt_system_info_ssh_keys(ssh_info): for idx, user in enumerate(ssh_info): for field in ["public_key", "private_key", "known_hosts"]: if ssh_info[idx][field]: - ssh_info[idx][field] = get_encryptor().enc(ssh_info[idx][field]) + ssh_info[idx][field] = get_datastore_encryptor().enc(ssh_info[idx][field]) def process_credential_info(telemetry_json): diff --git a/monkey/monkey_island/cc/services/zero_trust/scoutsuite/scoutsuite_auth_service.py b/monkey/monkey_island/cc/services/zero_trust/scoutsuite/scoutsuite_auth_service.py index ece015935..89aa002fa 100644 --- a/monkey/monkey_island/cc/services/zero_trust/scoutsuite/scoutsuite_auth_service.py +++ b/monkey/monkey_island/cc/services/zero_trust/scoutsuite/scoutsuite_auth_service.py @@ -5,7 +5,7 @@ from ScoutSuite.providers.base.authentication_strategy import AuthenticationExce from common.cloud.scoutsuite_consts import CloudProviders from common.config_value_paths import AWS_KEYS_PATH from common.utils.exceptions import InvalidAWSKeys -from monkey_island.cc.server_utils.encryption import get_encryptor +from monkey_island.cc.server_utils.encryption import get_datastore_encryptor from monkey_island.cc.services.config import ConfigService @@ -41,7 +41,7 @@ def set_aws_keys(access_key_id: str, secret_access_key: str, session_token: str) def _set_aws_key(key_type: str, key_value: str): path_to_keys = AWS_KEYS_PATH - encrypted_key = get_encryptor().enc(key_value) + encrypted_key = get_datastore_encryptor().enc(key_value) ConfigService.set_config_value(path_to_keys + [key_type], encrypted_key) diff --git a/monkey/tests/unit_tests/monkey_island/cc/models/utils/field_encryptors/test_string_list_encryptor.py b/monkey/tests/unit_tests/monkey_island/cc/models/utils/field_encryptors/test_string_list_encryptor.py index 9af487e24..a93397392 100644 --- a/monkey/tests/unit_tests/monkey_island/cc/models/utils/field_encryptors/test_string_list_encryptor.py +++ b/monkey/tests/unit_tests/monkey_island/cc/models/utils/field_encryptors/test_string_list_encryptor.py @@ -1,7 +1,7 @@ import pytest from monkey_island.cc.models.utils.field_encryptors.string_list_encryptor import StringListEncryptor -from monkey_island.cc.server_utils.encryption import initialize_encryptor +from monkey_island.cc.server_utils.encryption import initialize_datastore_encryptor MOCK_STRING_LIST = ["test_1", "test_2"] EMPTY_LIST = [] @@ -9,7 +9,7 @@ EMPTY_LIST = [] @pytest.fixture def uses_encryptor(data_for_tests_dir): - initialize_encryptor(data_for_tests_dir) + initialize_datastore_encryptor(data_for_tests_dir) def test_encryption_and_decryption(uses_encryptor): diff --git a/monkey/tests/unit_tests/monkey_island/cc/server_utils/encryption/test_data_store_encryptor.py b/monkey/tests/unit_tests/monkey_island/cc/server_utils/encryption/test_data_store_encryptor.py index fa135c345..bb005fbf7 100644 --- a/monkey/tests/unit_tests/monkey_island/cc/server_utils/encryption/test_data_store_encryptor.py +++ b/monkey/tests/unit_tests/monkey_island/cc/server_utils/encryption/test_data_store_encryptor.py @@ -1,6 +1,9 @@ import os -from monkey_island.cc.server_utils.encryption import get_encryptor, initialize_encryptor +from monkey_island.cc.server_utils.encryption import ( + get_datastore_encryptor, + initialize_datastore_encryptor, +) PASSWORD_FILENAME = "mongo_key.bin" @@ -9,24 +12,24 @@ CYPHERTEXT = "vKgvD6SjRyIh1dh2AM/rnTa0NI/vjfwnbZLbMocWtE4e42WJmSUz2ordtbQrH1Fq" def test_aes_cbc_encryption(data_for_tests_dir): - initialize_encryptor(data_for_tests_dir) + initialize_datastore_encryptor(data_for_tests_dir) - assert get_encryptor().enc(PLAINTEXT) != PLAINTEXT + assert get_datastore_encryptor().enc(PLAINTEXT) != PLAINTEXT def test_aes_cbc_decryption(data_for_tests_dir): - initialize_encryptor(data_for_tests_dir) + initialize_datastore_encryptor(data_for_tests_dir) - assert get_encryptor().dec(CYPHERTEXT) == PLAINTEXT + assert get_datastore_encryptor().dec(CYPHERTEXT) == PLAINTEXT def test_aes_cbc_enc_dec(data_for_tests_dir): - initialize_encryptor(data_for_tests_dir) + initialize_datastore_encryptor(data_for_tests_dir) - assert get_encryptor().dec(get_encryptor().enc(PLAINTEXT)) == PLAINTEXT + assert get_datastore_encryptor().dec(get_datastore_encryptor().enc(PLAINTEXT)) == PLAINTEXT def test_create_new_password_file(tmpdir): - initialize_encryptor(tmpdir) + initialize_datastore_encryptor(tmpdir) assert os.path.isfile(os.path.join(tmpdir, PASSWORD_FILENAME)) diff --git a/monkey/tests/unit_tests/monkey_island/cc/services/zero_trust/scoutsuite/test_scoutsuite_auth_service.py b/monkey/tests/unit_tests/monkey_island/cc/services/zero_trust/scoutsuite/test_scoutsuite_auth_service.py index 3df67330c..2e6c2fd50 100644 --- a/monkey/tests/unit_tests/monkey_island/cc/services/zero_trust/scoutsuite/test_scoutsuite_auth_service.py +++ b/monkey/tests/unit_tests/monkey_island/cc/services/zero_trust/scoutsuite/test_scoutsuite_auth_service.py @@ -5,7 +5,10 @@ import pytest from common.config_value_paths import AWS_KEYS_PATH from monkey_island.cc.database import mongo -from monkey_island.cc.server_utils.encryption import get_encryptor, initialize_encryptor +from monkey_island.cc.server_utils.encryption import ( + get_datastore_encryptor, + initialize_datastore_encryptor, +) from monkey_island.cc.services.config import ConfigService from monkey_island.cc.services.zero_trust.scoutsuite.scoutsuite_auth_service import ( is_aws_keys_setup, @@ -27,8 +30,8 @@ def test_is_aws_keys_setup(tmp_path): assert not is_aws_keys_setup() # Make sure noone changed config path and broke this function - initialize_encryptor(tmp_path) - bogus_key_value = get_encryptor().enc("bogus_aws_key") + initialize_datastore_encryptor(tmp_path) + bogus_key_value = get_datastore_encryptor().enc("bogus_aws_key") dpath.util.set( ConfigService.default_config, AWS_KEYS_PATH + ["aws_secret_access_key"], bogus_key_value )