forked from p15670423/monkey
Move all encryptor building related code to encryptor_factory.py from data_store_encryptor.py
This commit is contained in:
parent
26ba02a1d0
commit
9d6dc3b026
|
@ -8,7 +8,7 @@ from .encryptor_factory import (
|
||||||
FactoryNotInitializedError,
|
FactoryNotInitializedError,
|
||||||
remove_old_datastore_key,
|
remove_old_datastore_key,
|
||||||
get_encryptor_factory,
|
get_encryptor_factory,
|
||||||
get_secret_from_credentials,
|
_get_secret_from_credentials,
|
||||||
initialize_encryptor_factory,
|
initialize_encryptor_factory,
|
||||||
)
|
)
|
||||||
from .data_store_encryptor import initialize_datastore_encryptor, get_datastore_encryptor
|
from .data_store_encryptor import initialize_datastore_encryptor, get_datastore_encryptor
|
||||||
|
|
|
@ -1,49 +1,17 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import os
|
|
||||||
|
|
||||||
# PyCrypto is deprecated, but we use pycryptodome, which uses the exact same imports but
|
# PyCrypto is deprecated, but we use pycryptodome, which uses the exact same imports but
|
||||||
# is maintained.
|
# is maintained.
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
||||||
from Crypto import Random # noqa: DUO133 # nosec: B413
|
from monkey_island.cc.server_utils.encryption import KeyBasedEncryptor
|
||||||
|
|
||||||
from monkey_island.cc.server_utils.encryption import FactoryNotInitializedError, KeyBasedEncryptor
|
|
||||||
from monkey_island.cc.server_utils.encryption.encryptor_factory import (
|
|
||||||
get_encryptor_factory,
|
|
||||||
get_secret_from_credentials,
|
|
||||||
)
|
|
||||||
from monkey_island.cc.server_utils.encryption.password_based_bytes_encryption import (
|
|
||||||
PasswordBasedBytesEncryptor,
|
|
||||||
)
|
|
||||||
from monkey_island.cc.server_utils.file_utils import open_new_securely_permissioned_file
|
|
||||||
|
|
||||||
_encryptor: Union[None, DataStoreEncryptor] = None
|
_encryptor: Union[None, DataStoreEncryptor] = None
|
||||||
|
|
||||||
|
|
||||||
class DataStoreEncryptor:
|
class DataStoreEncryptor:
|
||||||
_BLOCK_SIZE = 32
|
def __init__(self, key_based_encryptor: KeyBasedEncryptor):
|
||||||
|
self._key_based_encryptor = key_based_encryptor
|
||||||
def __init__(self, key_file_path: str, secret: str):
|
|
||||||
if os.path.exists(key_file_path):
|
|
||||||
self._key_based_encryptor = DataStoreEncryptor._load_existing_key(key_file_path, secret)
|
|
||||||
else:
|
|
||||||
self._key_based_encryptor = DataStoreEncryptor._create_new_key(key_file_path, secret)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _load_existing_key(key_file_path: str, secret: str):
|
|
||||||
with open(key_file_path, "rb") as f:
|
|
||||||
encrypted_key = f.read()
|
|
||||||
cipher_key = PasswordBasedBytesEncryptor(secret).decrypt(encrypted_key)
|
|
||||||
return KeyBasedEncryptor(cipher_key)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _create_new_key(key_file_path: str, secret: str):
|
|
||||||
cipher_key = Random.new().read(DataStoreEncryptor._BLOCK_SIZE)
|
|
||||||
encrypted_key = PasswordBasedBytesEncryptor(secret).encrypt(cipher_key)
|
|
||||||
with open_new_securely_permissioned_file(key_file_path, "wb") as f:
|
|
||||||
f.write(encrypted_key)
|
|
||||||
return KeyBasedEncryptor(cipher_key)
|
|
||||||
|
|
||||||
def enc(self, message: str):
|
def enc(self, message: str):
|
||||||
return self._key_based_encryptor.encrypt(message)
|
return self._key_based_encryptor.encrypt(message)
|
||||||
|
@ -52,14 +20,10 @@ class DataStoreEncryptor:
|
||||||
return self._key_based_encryptor.decrypt(enc_message)
|
return self._key_based_encryptor.decrypt(enc_message)
|
||||||
|
|
||||||
|
|
||||||
def initialize_datastore_encryptor(username: str, password: str):
|
def initialize_datastore_encryptor(key_based_encryptor: KeyBasedEncryptor):
|
||||||
global _encryptor
|
global _encryptor
|
||||||
|
|
||||||
factory = get_encryptor_factory()
|
_encryptor = DataStoreEncryptor(key_based_encryptor)
|
||||||
if not factory:
|
|
||||||
raise FactoryNotInitializedError
|
|
||||||
secret = get_secret_from_credentials(username, password)
|
|
||||||
_encryptor = DataStoreEncryptor(factory.key_file_path, secret)
|
|
||||||
|
|
||||||
|
|
||||||
def get_datastore_encryptor():
|
def get_datastore_encryptor():
|
||||||
|
|
|
@ -1,38 +1,75 @@
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from ctypes import Union
|
|
||||||
|
|
||||||
_factory: Union[None, EncryptorFactory] = None
|
from Crypto import Random
|
||||||
|
|
||||||
|
from monkey_island.cc.server_utils.encryption import (
|
||||||
|
KeyBasedEncryptor,
|
||||||
|
initialize_datastore_encryptor,
|
||||||
|
)
|
||||||
|
from monkey_island.cc.server_utils.encryption.password_based_bytes_encryption import (
|
||||||
|
PasswordBasedBytesEncryptor,
|
||||||
|
)
|
||||||
|
from monkey_island.cc.server_utils.file_utils import open_new_securely_permissioned_file
|
||||||
|
|
||||||
|
_KEY_FILENAME = "mongo_key.bin"
|
||||||
|
_BLOCK_SIZE = 32
|
||||||
|
|
||||||
|
|
||||||
class EncryptorFactory:
|
class EncryptorFactory:
|
||||||
|
def __init__(self):
|
||||||
|
self.key_file_path = None
|
||||||
|
self.secret = None
|
||||||
|
|
||||||
_KEY_FILENAME = "mongo_key.bin"
|
def set_key_file_path(self, key_file_path: str):
|
||||||
|
self.key_file_path = key_file_path
|
||||||
|
|
||||||
def __init__(self, key_file_dir: str):
|
def set_secret(self, username: str, password: str):
|
||||||
self.key_file_path = os.path.join(key_file_dir, self._KEY_FILENAME)
|
self.secret = _get_secret_from_credentials(username, password)
|
||||||
|
|
||||||
|
def initialize_encryptor(self):
|
||||||
|
if os.path.exists(self.key_file_path):
|
||||||
|
key_based_encryptor = _load_existing_key(self.key_file_path, self.secret)
|
||||||
|
else:
|
||||||
|
key_based_encryptor = _create_new_key(self.key_file_path, self.secret)
|
||||||
|
initialize_datastore_encryptor(key_based_encryptor)
|
||||||
|
|
||||||
|
|
||||||
class FactoryNotInitializedError(Exception):
|
class KeyPathNotSpecifiedError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def get_secret_from_credentials(username: str, password: str) -> str:
|
def _load_existing_key(key_file_path: str, secret: str):
|
||||||
|
with open(key_file_path, "rb") as f:
|
||||||
|
encrypted_key = f.read()
|
||||||
|
cipher_key = PasswordBasedBytesEncryptor(secret).decrypt(encrypted_key)
|
||||||
|
return KeyBasedEncryptor(cipher_key)
|
||||||
|
|
||||||
|
|
||||||
|
def _create_new_key(key_file_path: str, secret: str):
|
||||||
|
cipher_key = _get_random_bytes()
|
||||||
|
encrypted_key = PasswordBasedBytesEncryptor(secret).encrypt(cipher_key)
|
||||||
|
with open_new_securely_permissioned_file(key_file_path, "wb") as f:
|
||||||
|
f.write(encrypted_key)
|
||||||
|
return KeyBasedEncryptor(cipher_key)
|
||||||
|
|
||||||
|
|
||||||
|
def _get_random_bytes() -> bytes:
|
||||||
|
return Random.new().read(_BLOCK_SIZE)
|
||||||
|
|
||||||
|
|
||||||
|
def _get_secret_from_credentials(username: str, password: str) -> str:
|
||||||
return f"{username}:{password}"
|
return f"{username}:{password}"
|
||||||
|
|
||||||
|
|
||||||
def remove_old_datastore_key():
|
def remove_old_datastore_key():
|
||||||
if _factory is None:
|
if not _factory.key_file_path:
|
||||||
raise FactoryNotInitializedError
|
raise KeyPathNotSpecifiedError
|
||||||
if os.path.isfile(_factory.key_file_path):
|
if os.path.isfile(_factory.key_file_path):
|
||||||
os.remove(_factory.key_file_path)
|
os.remove(_factory.key_file_path)
|
||||||
|
|
||||||
|
|
||||||
def initialize_encryptor_factory(key_file_dir: str):
|
|
||||||
global _factory
|
|
||||||
_factory = EncryptorFactory(key_file_dir)
|
|
||||||
|
|
||||||
|
|
||||||
def get_encryptor_factory():
|
def get_encryptor_factory():
|
||||||
return _factory
|
return _factory
|
||||||
|
|
||||||
|
|
||||||
|
_factory = EncryptorFactory()
|
||||||
|
|
|
@ -10,6 +10,7 @@ from monkey_island.cc.server_utils.encryption import (
|
||||||
initialize_encryptor_factory,
|
initialize_encryptor_factory,
|
||||||
remove_old_datastore_key,
|
remove_old_datastore_key,
|
||||||
)
|
)
|
||||||
|
from monkey_island.cc.server_utils.encryption.data_store_encryptor import DataStoreEncryptor
|
||||||
from monkey_island.cc.server_utils.encryption.encryptor_factory import EncryptorFactory
|
from monkey_island.cc.server_utils.encryption.encryptor_factory import EncryptorFactory
|
||||||
|
|
||||||
PLAINTEXT = "Hello, Monkey!"
|
PLAINTEXT = "Hello, Monkey!"
|
||||||
|
@ -37,7 +38,7 @@ def test_key_creation(initialized_key_dir):
|
||||||
assert (initialized_key_dir / EncryptorFactory._KEY_FILENAME).isfile()
|
assert (initialized_key_dir / EncryptorFactory._KEY_FILENAME).isfile()
|
||||||
|
|
||||||
|
|
||||||
def test_key_removal(initialized_key_dir, monkeypatch):
|
def test_key_removal(initialized_key_dir):
|
||||||
remove_old_datastore_key()
|
remove_old_datastore_key()
|
||||||
assert not (initialized_key_dir / EncryptorFactory._KEY_FILENAME).isfile()
|
assert not (initialized_key_dir / EncryptorFactory._KEY_FILENAME).isfile()
|
||||||
|
|
||||||
|
@ -61,3 +62,7 @@ def test_initialize_encryptor(tmpdir):
|
||||||
assert not (tmpdir / EncryptorFactory._KEY_FILENAME).isfile()
|
assert not (tmpdir / EncryptorFactory._KEY_FILENAME).isfile()
|
||||||
initialize_datastore_encryptor(MOCK_USERNAME, MOCK_PASSWORD)
|
initialize_datastore_encryptor(MOCK_USERNAME, MOCK_PASSWORD)
|
||||||
assert (tmpdir / EncryptorFactory._KEY_FILENAME).isfile()
|
assert (tmpdir / EncryptorFactory._KEY_FILENAME).isfile()
|
||||||
|
|
||||||
|
|
||||||
|
def test_key_file_encryption(tmpdir, monkeypatch):
|
||||||
|
monkeypatch(DataStoreEncryptor._)
|
||||||
|
|
Loading…
Reference in New Issue