forked from p15670423/monkey
Island: Add functions to encrypt agent events
This commit is contained in:
parent
930256f581
commit
0d959e891a
|
@ -0,0 +1,44 @@
|
||||||
|
import json
|
||||||
|
from typing import Callable, Iterable
|
||||||
|
|
||||||
|
from common.agent_event_serializers import JSONSerializable
|
||||||
|
from common.agent_events import AbstractAgentEvent
|
||||||
|
|
||||||
|
ENCRYPTED_PREFIX = "encrypted_"
|
||||||
|
|
||||||
|
|
||||||
|
def get_fields_to_encrypt(event: AbstractAgentEvent):
|
||||||
|
return set(vars(AbstractAgentEvent)["__fields__"].keys()) ^ set(event.dict().keys())
|
||||||
|
|
||||||
|
|
||||||
|
def encrypt_event(
|
||||||
|
encrypt: Callable[[bytes], bytes],
|
||||||
|
event_data: JSONSerializable,
|
||||||
|
fields: Iterable[str] = [],
|
||||||
|
) -> JSONSerializable:
|
||||||
|
if not isinstance(event_data, dict):
|
||||||
|
raise TypeError("Event encryption only supported for dict")
|
||||||
|
|
||||||
|
for field in fields:
|
||||||
|
event_data[ENCRYPTED_PREFIX + field] = str(
|
||||||
|
encrypt(json.dumps(event_data[field]).encode()), "utf-8"
|
||||||
|
)
|
||||||
|
del event_data[field]
|
||||||
|
|
||||||
|
return event_data
|
||||||
|
|
||||||
|
|
||||||
|
def decrypt_event(
|
||||||
|
decrypt: Callable[[bytes], bytes], event_data: JSONSerializable
|
||||||
|
) -> JSONSerializable:
|
||||||
|
if not isinstance(event_data, dict):
|
||||||
|
raise TypeError("Event decryption only supported for dict")
|
||||||
|
|
||||||
|
for field in event_data.keys():
|
||||||
|
if field.startswith("encrypted_"):
|
||||||
|
event_data[field[len(ENCRYPTED_PREFIX) :]] = json.loads(
|
||||||
|
str(decrypt(event_data[field].encode()), "utf-8")
|
||||||
|
)
|
||||||
|
del event_data[field]
|
||||||
|
|
||||||
|
return event_data
|
|
@ -0,0 +1,57 @@
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from common.agent_event_serializers import PydanticAgentEventSerializer
|
||||||
|
from common.agent_events import AbstractAgentEvent
|
||||||
|
from monkey_island.cc.repository.agent_event_encryption import (
|
||||||
|
decrypt_event,
|
||||||
|
encrypt_event,
|
||||||
|
get_fields_to_encrypt,
|
||||||
|
)
|
||||||
|
from monkey_island.cc.server_utils.encryption import RepositoryEncryptor
|
||||||
|
|
||||||
|
|
||||||
|
class FakeAgentEvent(AbstractAgentEvent):
|
||||||
|
data: str
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def key_file(tmp_path):
|
||||||
|
return tmp_path / "test_key.bin"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def encryptor(key_file):
|
||||||
|
encryptor = RepositoryEncryptor(key_file)
|
||||||
|
encryptor.unlock(b"password")
|
||||||
|
return encryptor
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def serializer():
|
||||||
|
return PydanticAgentEventSerializer()
|
||||||
|
|
||||||
|
|
||||||
|
def test_agent_event_encryption__encrypts(encryptor, serializer):
|
||||||
|
event = FakeAgentEvent(source=uuid.uuid4(), data="foo")
|
||||||
|
data = serializer.serialize(event)
|
||||||
|
fields = get_fields_to_encrypt(event)
|
||||||
|
encrypted_data = encrypt_event(encryptor.encrypt, data, fields)
|
||||||
|
|
||||||
|
# Encrypted fields have the "encrypted_" prefix
|
||||||
|
assert "encrypted_data" in encrypted_data
|
||||||
|
assert encrypted_data["encrypted_data"] is not event.data
|
||||||
|
|
||||||
|
|
||||||
|
def test_agent_event_encryption__decrypts(encryptor, serializer):
|
||||||
|
event = FakeAgentEvent(source=uuid.uuid4(), data="foo")
|
||||||
|
|
||||||
|
data = serializer.serialize(event)
|
||||||
|
fields = get_fields_to_encrypt(event)
|
||||||
|
encrypted_data = encrypt_event(encryptor.encrypt, data, fields)
|
||||||
|
|
||||||
|
decrypted_data = decrypt_event(encryptor.decrypt, encrypted_data)
|
||||||
|
deserialized_event = serializer.deserialize(decrypted_data)
|
||||||
|
|
||||||
|
assert deserialized_event == event
|
Loading…
Reference in New Issue