philcali / udp-sandbox

Simple UDP sandbox for encrypted messages

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

UDP Sandbox

This simple test bed is for testing encrypted UDP messages from client and server using python asyncio tools.

Encryption Channels

usage: udp-server [-h] [--channel-name-1 CHANNEL_NAME_1] [--channel-key-1 CHANNEL_KEY_1] [--channel-port-1 CHANNEL_PORT_1] [--channel-address-1 CHANNEL_ADDRESS_1]
                  [--channel-direction-1 CHANNEL_DIRECTION_1] [--channel-send-port-1 CHANNEL_SEND_PORT_1] [--channel-send-address-1 CHANNEL_SEND_ADDRESS_1]
                  [--channel-name-2 CHANNEL_NAME_2] [--channel-key-2 CHANNEL_KEY_2] [--channel-port-2 CHANNEL_PORT_2] [--channel-address-2 CHANNEL_ADDRESS_2]
                  [--channel-direction-2 CHANNEL_DIRECTION_2] [--channel-send-port-2 CHANNEL_SEND_PORT_2] [--channel-send-address-2 CHANNEL_SEND_ADDRESS_2]
                  [--channel-name-3 CHANNEL_NAME_3] [--channel-key-3 CHANNEL_KEY_3] [--channel-port-3 CHANNEL_PORT_3] [--channel-address-3 CHANNEL_ADDRESS_3]
                  [--channel-direction-3 CHANNEL_DIRECTION_3] [--channel-send-port-3 CHANNEL_SEND_PORT_3] [--channel-send-address-3 CHANNEL_SEND_ADDRESS_3]

Example UDP server application

options:
  -h, --help            show this help message and exit

channel-1:
  --channel-name-1 CHANNEL_NAME_1
                        name of the channel on index 1
  --channel-key-1 CHANNEL_KEY_1
                        key of the channel on index 1
  --channel-port-1 CHANNEL_PORT_1
                        port for channel on index 1
  --channel-address-1 CHANNEL_ADDRESS_1
                        address for channel on index 1
  --channel-direction-1 CHANNEL_DIRECTION_1
                        direction of channel on index 1
  --channel-send-port-1 CHANNEL_SEND_PORT_1
                        send data to port from channel on index 1
  --channel-send-address-1 CHANNEL_SEND_ADDRESS_1
                        send data to address from channel on index 1

channel-2:
  --channel-name-2 CHANNEL_NAME_2
                        name of the channel on index 2
  --channel-key-2 CHANNEL_KEY_2
                        key of the channel on index 2
  --channel-port-2 CHANNEL_PORT_2
                        port for channel on index 2
  --channel-address-2 CHANNEL_ADDRESS_2
                        address for channel on index 2
  --channel-direction-2 CHANNEL_DIRECTION_2
                        direction of channel on index 2
  --channel-send-port-2 CHANNEL_SEND_PORT_2
                        send data to port from channel on index 2
  --channel-send-address-2 CHANNEL_SEND_ADDRESS_2
                        send data to address from channel on index 2

channel-3:
  --channel-name-3 CHANNEL_NAME_3
                        name of the channel on index 3
  --channel-key-3 CHANNEL_KEY_3
                        key of the channel on index 3
  --channel-port-3 CHANNEL_PORT_3
                        port for channel on index 3
  --channel-address-3 CHANNEL_ADDRESS_3
                        address for channel on index 3
  --channel-direction-3 CHANNEL_DIRECTION_3
                        direction of channel on index 3
  --channel-send-port-3 CHANNEL_SEND_PORT_3
                        send data to port from channel on index 3
  --channel-send-address-3 CHANNEL_SEND_ADDRESS_3
                        send data to address from channel on index 3

Example:

Launch an encryption channel:

udp-server \
 --channel-name-1 SA1 \
 --channel-key-1 my-secret-key \
 --channel-direction-1 encrypt \
 --channel-address-1 127.0.0.1 \
 --channel-port-1 5005 \
 --channel-send-address-1 127.0.0.1 \
 --channel-send-port-1 5025
2024-04-02 19:40:26,423 udp.channel [INFO] Running SA1 for encrypt on 127.0.0.1:5005 -> 127.0.0.1:5025
2024-04-02 19:40:26,424 udp.channel [INFO] Channel SA1 is connected

In separate terminal, launch a receive client:

udp-client \
 --channel-name SA1 \
 --channel-key my-secret-key \
 --channel-direction encrypt \
 --channel-address 127.0.0.1 \
 --channel-port 5025 \
 --channel-function receive
2024-04-02 19:40:59,141 udp.channel [INFO] Channel SA1 is connected
2024-04-02 19:41:12,073 udp.client.__main__ [INFO] Data received from ('127.0.0.1', 5005)
2024-04-02 19:41:12,075 udp.client.__main__ [INFO] Data received was "Channel message 3ff14f5a-c663-45d4-8f84-17e54d2c4033 from SA1 on 1712101272"
2024-04-02 19:41:13,073 udp.client.__main__ [INFO] Data received from ('127.0.0.1', 5005)
2024-04-02 19:41:13,073 udp.client.__main__ [INFO] Data received was "Channel message 95ff6e3c-1bad-44af-9346-28320cd2cdbc from SA1 on 1712101273"
2024-04-02 19:41:14,075 udp.client.__main__ [INFO] Data received from ('127.0.0.1', 5005)
2024-04-02 19:41:14,076 udp.client.__main__ [INFO] Data received was "Channel message e4192b60-3049-4456-95a6-c3de69b70689 from SA1 on 1712101274"

In a separate terminal, launch a send client:

udp-client \
 --channel-name SA1 \
 --channel-key my-secret-key \
 --channel-direction decrypt \
 --channel-address 127.0.0.1 \
 --channel-port 5005 \
 --channel-function send

Once the send client is activated, you will see messages propagate:

Receiver

2024-04-02 19:40:59,141 udp.channel [INFO] Channel SA1 is connected
2024-04-02 19:41:12,075 udp.client.__main__ [INFO] Data received was "Channel message 3ff14f5a-c663-45d4-8f84-17e54d2c4033 from SA1 on 1712101272"
2024-04-02 19:41:13,073 udp.client.__main__ [INFO] Data received was "Channel message 95ff6e3c-1bad-44af-9346-28320cd2cdbc from SA1 on 1712101273"
2024-04-02 19:41:14,076 udp.client.__main__ [INFO] Data received was "Channel message e4192b60-3049-4456-95a6-c3de69b70689 from SA1 on 1712101274"

Sender

2024-04-02 19:41:12,070 udp.channel [INFO] Channel SA1 is connected
2024-04-02 19:41:12,070 udp.client.__main__ [INFO] Sending Channel message 3ff14f5a-c663-45d4-8f84-17e54d2c4033 from SA1 on 1712101272 
2024-04-02 19:41:13,072 udp.client.__main__ [INFO] Sending Channel message 95ff6e3c-1bad-44af-9346-28320cd2cdbc from SA1 on 1712101273
2024-04-02 19:41:14,074 udp.client.__main__ [INFO] Sending Channel message e4192b60-3049-4456-95a6-c3de69b70689 from SA1 on 1712101274

This trivial example demonstrates a sender sending plain text data to the server, which routes encrypted data to the receiver. The receiver with knowledge of how to decrypt the data. Now change the SA on the server:

2024-04-02 19:46:48,178 udp.channel [INFO] Channel SA1 is connected
2024-04-02 19:46:51,854 udp.client.__main__ [INFO] Data received from ('127.0.0.1', 5005)
Exception in callback _SelectorDatagramTransport._read_ready()
handle: <Handle _SelectorDatagramTransport._read_ready()> 
Traceback (most recent call last):
  File "/usr/lib/python3.10/asyncio/events.py", line 80, in _run
    self._context.run(self._callback, *self._args)
  File "/usr/lib/python3.10/asyncio/selector_events.py", line 1035, in _read_ready
    self._protocol.datagram_received(data, addr)
  File "/home/philcali/code/udp-sandbox/udp/client/__main__.py", line 20, in datagram_received
    output = self.decrypt(data)
  File "/home/philcali/code/udp-sandbox/udp/channel/__init__.py", line 56, in decrypt
    plaintext = aes.decrypt_and_verify(
  File "/home/philcali/.local/lib/python3.10/site-packages/Crypto/Cipher/_mode_gcm.py", line 567, in decrypt_and_verify
    self.verify(received_mac_tag)
  File "/home/philcali/.local/lib/python3.10/site-packages/Crypto/Cipher/_mode_gcm.py", line 508, in verify
    raise ValueError("MAC check failed")
ValueError: MAC check failed

Full Example

udp-sandbox.gif

In the above video, you can see five terminal windows that represent machines doing various tasks:

  • Top left: this is a sender instance sending data. Encrypted data is sent to router
  • Bottom left: this is a router instance that forwards packets to the server. The tcpdump demonstrates that data is encoded and encrypted UDP
  • Top center: this is the server instance receiving data. Server will receive encrypted data and forward to router
  • Bottom right: this is a router instance that forwards packets to the receiver. The tcpdump demonstrates that data is plain text
  • Top right: this is a receiver instance that catches data. Receiver will output plain text data.

Prepare

In ubuntu, spin up five vm's using multipass:

for vm in sender receiver encryptor router-1 router-2; do
  multipass launch -n "$vm"
done

Receiver - Sender - Encryptor

Prepare compute instances with the udp-sandbox installation:

multipass shell $instance # where instance is sender, receiver, and encryptor
sudo apt-get install -y python3-pip
git clone https://github.com/philcali/udp-sandbox.git
cd udp-sandbox
python3 -m pip install -e .

Routers

Prepare the router instances:

Router 1

multipass shell router-1
DPORT=5005
DEST="<encryptor.ip>"

Router 2

multipass shell router-2
DPORT=5025
DEST="<receiver.ip>"

Routing Config

sudo iptables -F
sudo iptables -t nat -F
sudo iptables -X
sudo iptables -t nat -A PREROUTING -p udp --dport "$DPORT" -j DNAT --to-destination "$DEST:$DPORT"
sudo iptables-save
sudo apt-get install iptables-persistent

Execute

Receiver

multipass shell receiver
udp-client \
--channel-name SA1 \
--channel-key my-secret \
--channel-port 5025 \
--channel-address 0.0.0.0 \
--channel-direction decrypt \
--channel-function receive

Router

multipass shell router-1
sudo tcpdump -i ens3 -s 0 udp -vv -X -c 1000

Encryptor

multipass shell encryptor
udp-server \
--channel-name-1 SA1 \
--channel-key-1 my-secret \
--channel-port-1 5005 \
--channel-address-1 0.0.0.0 \
--channel-direction-1 decrypt \
--channel-send-port-1 5025 \
--channel-send-address-1 <router-2.ip>

Sender

multipass shell sender
udp-client \
--channel-name SA1 \
--channel-key my-secret \
--channel-port 5005 \
--channel-address <router-1.ip> \
--channel-function send \
--channel-direction encrypt

Once the sender begins, you should see output similar to the above video.

Teardown

multipass stop --all
multipass delete --all
multipass purge

About

Simple UDP sandbox for encrypted messages

License:Apache License 2.0


Languages

Language:Python 100.0%