Course: Network Security
Students: Amir Tabat (05220000102) · Selanay Akbaba (05210000248)
Repository: https://github.com/TRextabat/net_sec
Branches: week2 (HW2) · week3 (HW3)
| Branch | Contents | How to run |
|---|---|---|
week2 |
Birthday Attack + Secure UDP Chat (baseline) | git checkout week2 && docker compose up --build |
week3 |
HW3 additions: password hardening, lockout, logout/TTL | git checkout week3 && docker compose up --build |
| Problem | Report (LaTeX source) | |
|---|---|---|
| HW2 — Birthday Attack + Secure Chat | submission_docs/problem2_report.tex |
submission_docs/problem2_report.pdf |
| HW3 — Password Hardening + Session Management | submission_docs/problem3_report.tex |
submission_docs/problem3_report.pdf |
Regenerate any PDF:
python3 submission_docs/convert_to_pdf.py # compiles the .tex → .pdfBuilt on top of HW2. Three improvement areas:
| Area | Implementation |
|---|---|
| Password hardening | Policy: min 8 chars, upper+lower+digit+symbol required; Argon2id parameters increased; zxcvbn strength check |
| Brute-force / lockout | Exponential back-off + account lockout after N consecutive failures; per-IP rate limiting in Redis |
| Logout + session expiry | LOGOUT command; server-side TTL on session tokens; client-side idle timeout; SESSION_EXPIRED notification |
| Demo (dave) | 4th Mininet client tests all 3 features: policy rejection, lockout after 5 bad logins, logout with server-side token revocation |
git checkout week3
docker compose up --buildPasswords must satisfy all of:
- Minimum 8 characters
- At least one uppercase letter (A–Z)
- At least one lowercase letter (a–z)
- At least one digit (0–9)
- At least one symbol (
!@#$%^&*etc.) - zxcvbn strength score ≥ 2 (rejects common passwords / dictionary words)
# Valid: "Secure#42" "P@ssw0rd!"
# Invalid: "password", "12345678", "aaaaaaaa"python3 -c "
import sys, time; sys.path.insert(0, '.')
from client.client import SecureUDPChatClient
c = SecureUDPChatClient('127.0.0.1', 9090)
c.connect()
c.login('alice', 'Secure#42')
print('Session token:', c._token[:8], '...')
time.sleep(2)
c.disconnect()
"The client sends a LOGOUT message with its session token. The server
immediately invalidates the token in Redis. Any subsequent message using
that token receives SESSION_EXPIRED.
python3 -c "
import sys, time; sys.path.insert(0, '.')
from client.client import SecureUDPChatClient
c = SecureUDPChatClient('127.0.0.1', 9090)
c.connect()
c.login('alice', 'Secure#42')
c.logout() # sends LOGOUT, token revoked server-side
time.sleep(1)
c.disconnect()
"Set a short TTL via environment variable and observe SESSION_EXPIRED:
SESSION_TTL_SECONDS=10 docker compose up --build
# After 10 s of inactivity the server evicts the token
# Client receives SESSION_EXPIRED on next sendpython3 -c "
import sys; sys.path.insert(0, '.')
from client.client import SecureUDPChatClient
c = SecureUDPChatClient('127.0.0.1', 9090)
c.connect()
for i in range(10):
ok = c.login('alice', 'wrongpassword')
print(f'attempt {i+1}:', ok)
# After 5 consecutive failures: account locked for LOCKOUT_SECONDS
# Subsequent attempts return AUTH_LOCKED immediately
"A complete secure chat system over UDP, running inside a Mininet network topology within a single Docker container.
Security stack:
- Passwords: Argon2id (PHC format)
- Session keys: X25519 ECDH + HKDF-SHA256 → AES-256 key
- Confidentiality + Integrity: AES-256-GCM (authenticated encryption)
- Non-repudiation: ECDSA P-256 signatures stored in server audit log
- Replay protection: sequence counter + msg_id deduplication + 30-second timestamp window
- Group keys: per-group random AES-256 key, distributed encrypted per member
- Docker ≥ 24.0 and Docker Compose v2
- Linux host with OVS kernel module:
sudo modprobe openvswitch
- Privileged containers (required for Mininet network namespaces)
git checkout week2
docker compose up --buildThe demo automatically:
- Starts the secure chat server on
h_server (10.0.0.1:9090) - alice registers, logs in, creates group
#team, sends a DM to bob and a group message - bob registers, logs in, sends a DM to alice
- carol registers, logs in, joins
#team, receives the group message - Verifies ECDSA signatures, replay rejection, and delivery statuses
python3 server/server.py 9090Environment variables:
| Variable | Default | Purpose |
|---|---|---|
REDIS_HOST |
localhost |
Redis hostname |
REDIS_PORT |
6379 |
Redis port |
SESSION_TTL_SECONDS |
3600 |
Session token lifetime (HW3) |
LOCKOUT_THRESHOLD |
5 |
Failed logins before lockout (HW3) |
LOCKOUT_SECONDS |
300 |
Lockout duration in seconds (HW3) |
python3 -c "
import sys; sys.path.insert(0, '.')
from client.client import SecureUDPChatClient
c = SecureUDPChatClient('127.0.0.1', 9090)
c.connect()
ok = c.register('alice', 'Secure#42')
print('Registered:', ok)
c.disconnect()
"# alice creates the group
python3 -c "
import sys, time; sys.path.insert(0, '.')
from client.client import SecureUDPChatClient
c = SecureUDPChatClient('127.0.0.1', 9090)
c.connect(); c.login('alice', 'Secure#42')
c.create_group('team'); c.send_group('team', 'Hello team!')
time.sleep(2); c.disconnect()
"
# carol joins the group
python3 -c "
import sys, time; sys.path.insert(0, '.')
from client.client import SecureUDPChatClient
c = SecureUDPChatClient('127.0.0.1', 9090)
c.connect(); c.login('carol', 'C@rol123!')
c.join_group('team'); time.sleep(3); c.disconnect()
"python3 client/crypto_utils.py # crypto primitives self-test
python3 shared/protocol.py # protocol pack/unpack self-test
python3 birthday_attack/birthday_attack.py # BD attack + plot
docker compose up --build # full Mininet integration testnet_sec/
├── server/
│ ├── server.py # ChatServer + SecureChatServer
│ ├── auth.py # AccountManager (register, login, session, lockout, logout)
│ ├── group.py # GroupManager (create/join/leave + group keys)
│ ├── store.py # Redis-backed UserStore + MessageLog
│ └── crypto_server.py # Server-side crypto primitives
├── client/
│ ├── client.py # UDPChatClient + SecureUDPChatClient
│ ├── demo_client.py # DemoClient + SecureDemoClient
│ └── crypto_utils.py # Client-side crypto primitives (+ password policy)
├── shared/
│ └── protocol.py # Message constants + pack/unpack helpers
├── birthday_attack/
│ └── birthday_attack.py # BD attack derivation + plot
├── mininet/
│ ├── run_demo.py # Demo orchestration (week2 + week3 scenarios)
│ └── Dockerfile
├── docker-compose.yml
├── submission_docs/
│ ├── problem2_report.tex / .pdf # HW2 report
│ ├── problem3_report.tex / .pdf # HW3 report
│ ├── convert_to_pdf.py
│ └── figures/
└── problem_sets/
├── problem1.txt
├── problem2.txt
└── problem3.txt
Client Server
│── REGISTER {user, argon2_hash(pw), pub} ─►│ store user:username hash
│── LOGIN {user, pw_plaintext, ecdh_pub} ──►│ verify Argon2, run ECDH
│◄── SESSION {token, server_ecdh_pub} ──── │
│ Both sides: HKDF(X25519(priv,pub)) → session_key (AES-256)
│── LOGOUT {token} ─────────────────────►│ revoke token in Redis
│ │ (TTL-based expiry also running)
│◄── SESSION_EXPIRED ─────────────────── │ sent on any use of expired token
| Package | Version | Purpose |
|---|---|---|
cryptography |
46.0.3 | X25519, AES-GCM, ECDSA P-256 |
argon2-cffi |
23.1.0 | Argon2id password hashing |
redis |
5.x | Redis client + session TTL |
zxcvbn |
4.4.28 | Password strength estimation (HW3) |
| Issue | Cause | Fix |
|---|---|---|
user_exists error on second run |
Redis persists data between container restarts | docker compose down -v && docker compose up --build |
DEMO_PASSWORD rejected by policy |
Password lacks uppercase/lowercase/digit/symbol or is too weak | Use a strong password: DEMO_PASSWORD=Secure#42 in .env |
ModuleNotFoundError: zxcvbn |
Package not installed in local dev | pip install zxcvbn or use Docker (docker compose up --build) |
| OVS kernel module missing | Host kernel module not loaded | sudo modprobe openvswitch on the host before running Docker |
| Dave's lockout test shows "locked" warning with wrong count | LOCKOUT_THRESHOLD env var set differently |
Default is 5; override in .env or docker-compose.yml |
| Session expired mid-conversation | SESSION_TTL_SECONDS too short |
Increase in .env, default is 3600 (1 hour) |
- UDP MTU: messages > ~1300 bytes may exceed payload; fragmentation not implemented
- Group key rotation only on leave; not on periodic schedule
- No forward secrecy for stored messages (server log holds ciphertext)