From fd1cb9d36ddd376c8b6d112f8fc157889a28a420 Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Thu, 30 Sep 2021 12:02:43 +0300 Subject: [PATCH] Add a secret to datastore encryptor This change enables the encryption/decryption of mongo key with a custom secret --- .../encryption/data_store_encryptor.py | 30 ++++++++++------ monkey/tests/data_for_tests/mongo_key.bin | Bin 32 -> 327 bytes .../unit_tests/monkey_island/cc/conftest.py | 5 ++- .../test_string_list_encryptor.py | 8 ----- .../encryption/test_data_store_encryptor.py | 33 +++++++----------- .../test_scoutsuite_auth_service.py | 9 ++--- 6 files changed, 38 insertions(+), 47 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 215703c02..df185a1c8 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 @@ -1,3 +1,4 @@ +import io import os # PyCrypto is deprecated, but we use pycryptodome, which uses the exact same imports but @@ -5,6 +6,9 @@ import os from Crypto import Random # noqa: DUO133 # nosec: B413 from monkey_island.cc.server_utils.encryption import KeyBasedEncryptor +from monkey_island.cc.server_utils.encryption.password_based_byte_encryption import ( + PasswordBasedByteEncryptor, +) from monkey_island.cc.server_utils.file_utils import open_new_securely_permissioned_file _encryptor = None @@ -14,24 +18,30 @@ class DataStoreEncryptor: _BLOCK_SIZE = 32 _KEY_FILENAME = "mongo_key.bin" - def __init__(self, key_file_dir): + def __init__(self, key_file_dir: str, secret: str): key_file = os.path.join(key_file_dir, self._KEY_FILENAME) if os.path.exists(key_file): - self._load_existing_key(key_file) + self._load_existing_key(key_file, secret) else: - self._init_key(key_file) + self._init_key(key_file, secret) self._key_base_encryptor = KeyBasedEncryptor(self._cipher_key) - def _init_key(self, password_file_path: str): + def _init_key(self, password_file_path: str, secret: str): self._cipher_key = Random.new().read(self._BLOCK_SIZE) + encrypted_key = ( + PasswordBasedByteEncryptor(secret).encrypt(io.BytesIO(self._cipher_key)).getvalue() + ) with open_new_securely_permissioned_file(password_file_path, "wb") as f: - f.write(self._cipher_key) + f.write(encrypted_key) - def _load_existing_key(self, key_file): - with open(key_file, "rb") as f: - self._cipher_key = f.read() + def _load_existing_key(self, key_file_path: str, secret: str): + with open(key_file_path, "rb") as f: + encrypted_key = f.read() + self._cipher_key = ( + PasswordBasedByteEncryptor(secret).decrypt(io.BytesIO(encrypted_key)).getvalue() + ) def enc(self, message: str): return self._key_base_encryptor.encrypt(message) @@ -40,10 +50,10 @@ class DataStoreEncryptor: return self._key_base_encryptor.decrypt(enc_message) -def initialize_datastore_encryptor(key_file_dir): +def initialize_datastore_encryptor(key_file_dir: str, secret: str): global _encryptor - _encryptor = DataStoreEncryptor(key_file_dir) + _encryptor = DataStoreEncryptor(key_file_dir, secret) def get_datastore_encryptor(): diff --git a/monkey/tests/data_for_tests/mongo_key.bin b/monkey/tests/data_for_tests/mongo_key.bin index 6b8091efb87cf62909e0df7cb1b32a26fbbe1b13..edf082ae1b34cf2b5b99b1d7598909643aff89b3 100644 GIT binary patch literal 327 zcmZ>C4Q66skaiAobqsNJiFb-*D5!KyEp{%dEGSVh(=*UBU}#_%aA4gLUR!lWLqF{H z7WPDm&*jT!th~@Azpn1ayd?)pPMGU^Em3H&?domnOAUC*x%?JiYpsIra^0j-+g$zyQPc!dY-F28z?NHS=?+{PK z48HwJ#?F!Rvw3th&pKD->W5k~JkjPBwC>iroL6Oc;f|_YWJL42&CV?R>B^^{)yCdp G(gOfVLQz=& literal 32 qcmV+*0N?*B`K`wF4N^}E{V5abou0lKRFizfQd8~TCPNe92btmtybtgI diff --git a/monkey/tests/unit_tests/monkey_island/cc/conftest.py b/monkey/tests/unit_tests/monkey_island/cc/conftest.py index 9cca0caab..cde82e939 100644 --- a/monkey/tests/unit_tests/monkey_island/cc/conftest.py +++ b/monkey/tests/unit_tests/monkey_island/cc/conftest.py @@ -27,6 +27,9 @@ def monkey_config_json(monkey_config): return json.dumps(monkey_config) +ENCRYPTOR_SECRET = "m0nk3y_u53r:53cr3t_p455w0rd" + + @pytest.fixture def uses_encryptor(data_for_tests_dir): - initialize_datastore_encryptor(data_for_tests_dir) + initialize_datastore_encryptor(data_for_tests_dir, ENCRYPTOR_SECRET) 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 d02ad5bbb..7ea21849b 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,6 +1,3 @@ -import pytest - -from monkey_island.cc.server_utils.encryption import initialize_datastore_encryptor from monkey_island.cc.server_utils.encryption.dict_encryption.field_encryptors import ( StringListEncryptor, ) @@ -9,11 +6,6 @@ MOCK_STRING_LIST = ["test_1", "test_2"] EMPTY_LIST = [] -@pytest.fixture -def uses_encryptor(data_for_tests_dir): - initialize_datastore_encryptor(data_for_tests_dir) - - def test_encryption_and_decryption(uses_encryptor): encrypted_list = StringListEncryptor.encrypt(MOCK_STRING_LIST) assert not encrypted_list == MOCK_STRING_LIST 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 bb005fbf7..98229c6fe 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,35 +1,26 @@ import os +import pytest +from tests.unit_tests.monkey_island.cc.conftest import ENCRYPTOR_SECRET + from monkey_island.cc.server_utils.encryption import ( + DataStoreEncryptor, get_datastore_encryptor, initialize_datastore_encryptor, ) -PASSWORD_FILENAME = "mongo_key.bin" - PLAINTEXT = "Hello, Monkey!" -CYPHERTEXT = "vKgvD6SjRyIh1dh2AM/rnTa0NI/vjfwnbZLbMocWtE4e42WJmSUz2ordtbQrH1Fq" -def test_aes_cbc_encryption(data_for_tests_dir): - initialize_datastore_encryptor(data_for_tests_dir) +@pytest.mark.usefixtures("uses_encryptor") +def test_encryption(data_for_tests_dir): + encrypted_data = get_datastore_encryptor().enc(PLAINTEXT) + assert encrypted_data != PLAINTEXT - assert get_datastore_encryptor().enc(PLAINTEXT) != PLAINTEXT - - -def test_aes_cbc_decryption(data_for_tests_dir): - initialize_datastore_encryptor(data_for_tests_dir) - - assert get_datastore_encryptor().dec(CYPHERTEXT) == PLAINTEXT - - -def test_aes_cbc_enc_dec(data_for_tests_dir): - initialize_datastore_encryptor(data_for_tests_dir) - - assert get_datastore_encryptor().dec(get_datastore_encryptor().enc(PLAINTEXT)) == PLAINTEXT + decrypted_data = get_datastore_encryptor().dec(encrypted_data) + assert decrypted_data == PLAINTEXT def test_create_new_password_file(tmpdir): - initialize_datastore_encryptor(tmpdir) - - assert os.path.isfile(os.path.join(tmpdir, PASSWORD_FILENAME)) + initialize_datastore_encryptor(tmpdir, ENCRYPTOR_SECRET) + assert os.path.isfile(os.path.join(tmpdir, DataStoreEncryptor._KEY_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 2e6c2fd50..32b4f19ad 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 import ( - get_datastore_encryptor, - initialize_datastore_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.zero_trust.scoutsuite.scoutsuite_auth_service import ( is_aws_keys_setup, @@ -19,7 +16,7 @@ class MockObject: pass -@pytest.mark.usefixtures("uses_database") +@pytest.mark.usefixtures("uses_database", "uses_encryptor") def test_is_aws_keys_setup(tmp_path): # Mock default configuration ConfigService.init_default_config() @@ -29,8 +26,6 @@ def test_is_aws_keys_setup(tmp_path): mongo.db.config.find_one = MagicMock(return_value=ConfigService.default_config) assert not is_aws_keys_setup() - # Make sure noone changed config path and broke this function - 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