forked from p15670423/monkey
Add a secret to datastore encryptor
This change enables the encryption/decryption of mongo key with a custom secret
This commit is contained in:
parent
191fbea665
commit
fd1cb9d36d
|
@ -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():
|
||||
|
|
Binary file not shown.
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue