A comprehensive implementation of a console-based, application-layer secure chat system in Python demonstrating cryptographic principles:
Confidentiality, Integrity, Authenticity, and Non-Repudiation (CIANR).
- Prerequisites
- Architecture
- Installation
- Configuration
- Usage
- Security Features
- Testing
- Troubleshooting
- Project Structure
Ensure you have the following installed on your system:
| Component | Version | Purpose |
|---|---|---|
| Python | 3.8+ | Runtime environment |
| MySQL | 8.0+ | User database storage |
| OpenSSL | 1.1.1+ | Certificate generation and validation |
| pip | Latest | Python package management |
| Git | Latest | Version control |
# Check Python version
python3 --version # Should output 3.8 or higher
# Check MySQL availability
mysql --version # Should output MySQL 8.0 or higher
# Check OpenSSL
openssl version # Should output OpenSSL 1.1.1 or higherIf MySQL is not installed locally, use Docker (recommended):
docker --version # Verify Docker is installed┌─────────────────────────────────────────────────────────────────┐
│ SECURECHAT SYSTEM │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────────┐ ┌──────────────────────┐ │
│ │ CLIENT MACHINE │ │ SERVER MACHINE │ │
│ │ │ │ │ │
│ │ ┌────────────────┐ │ TCP Port │ ┌────────────────┐ │ │
│ │ │ User Interface │ │ 9999 (TCP) │ │ Session Manager│ │ │
│ │ │ │ │◄────────────►│ │ │ │ │
│ │ └────────────────┘ │ │ └────────────────┘ │ │
│ │ ▲ │ │ ▲ │ │
│ │ │ Socket I/O │ │ │ Socket I/O │ │
│ │ ▼ │ │ ▼ │ │
│ │ ┌────────────────┐ │ │ ┌────────────────┐ │ │
│ │ │ Crypto Layer │ │ │ │ Crypto Layer │ │ │
│ │ │ (AES, RSA, DH) │ │ │ │ (AES, RSA, DH) │ │ │
│ │ └────────────────┘ │ │ └────────────────┘ │ │
│ │ │ │ │ │
│ │ Certs: │ │ Certs: │ │
│ │ • client_cert.pem │ │ • server_cert.pem │ │
│ │ • client_key.pem │ │ • server_key.pem │ │
│ │ • ca_cert.pem │ │ • ca_cert.pem │ │
│ └──────────────────────┘ └──────────────────────┘ │
│ │
│ Protocol Layer: Application-Level Encryption │
│ • Message Format: [4-byte length prefix] + [JSON message] │
│ • Encryption: AES-128-CBC with RSA-PSS-SHA256 signatures │
│ • Key Exchange: Diffie-Hellman (RFC 3526 Group 14, 2048-bit) │
│ │
└────────────────┬────────────────────────────────────────────────┘
│
│ JDBC/MySQL Network
│ (Salted SHA-256 passwords)
│
┌───────▼────────┐
│ MYSQL DATABASE │
│ │
│ Tables: │
│ • users │
└────────────────┘
Security Properties:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✓ Confidentiality: AES-128-CBC encryption on all messages
✓ Integrity: RSA-PSS-SHA256 signatures (seqno || timestamp || ciphertext)
✓ Authenticity: X.509 mutual certificate validation
✓ Non-Repudiation: Session transcripts stored in filesystem
✓ Replay Prevention: Monotonically increasing sequence numbers
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Client Server
│ │
├─────────────── HELLO (w/ client cert) ───────────────────► │
│ │
│ ◄────────── SERVER_HELLO (w/ server cert) ─────────────── │
│ │
├─────────────── DH_CLIENT (public key A) ─────────────────► │
│ │
│ ◄────────── DH_SERVER (public key B, all signed) ──────── │
│ │
│ [Derive shared secret: Ks = g^(ab) mod P] │
│ [Derive session key: K = SHA256(Ks)[:16]] │
│ │
├─────────────── REGISTER/LOGIN (auth message) ────────────► │
│ │
│ ◄────────────────── AUTH_OK/REJECT ────────────────────── │
│ │
├─────────────── MSG (encrypted + signed) ─────────────────► │
│ MSG = { │
│ seqno: int, │
│ ts: int, ← Timestamp (ms since epoch) │
│ ct: base64(AES(plaintext)), ← Ciphertext │
│ sig: base64(RSA-PSS(H)) ← Signature over message digest │
│ } │
│ │
│ ◄──────────────── RECEIPT (non-repudiation) ───────────── │
│ │
├─────────────── MSG (another message) ────────────────────► │
│ [Seq# = 2 (increments per message)] │
│ │
│ ◄──────────────── RECEIPT ─────────────────────────────── │
│ │
├─────────────── LOGOUT ───────────────────────────────────► │
│ │
│ ◄────────────── SESSION_END (final transcript hash) ───── │
│ │
# Clone the repository
git clone https://github.com/AliHamzaAzam/SecureChat-IS-Assignment.git
cd SecureChat-IS-Assignment
# Create virtual environment
python3 -m venv .venv
# Activate virtual environment
# On macOS/Linux:
source .venv/bin/activate
# On Windows:
.venv\Scripts\activate
# Install dependencies
pip install -r requirements.txtExpected Output:
Successfully installed cryptography-41.0.7 mysql-connector-python-8.2.0
python-dotenv-1.0.0 pydantic-2.5.0 rich-13.7.0
# Pull and run MySQL 8.0 container
docker run -d \
--name securechat-db \
-e MYSQL_ROOT_PASSWORD=rootpass \
-e MYSQL_DATABASE=securechat \
-e MYSQL_USER=scuser \
-e MYSQL_PASSWORD=scpass \
-p 3306:3306 \
mysql:8
# Wait for container to start (~10 seconds)
sleep 10
# Verify connection
mysql -h 127.0.0.1 -u scuser -pscpass securechat -e "SELECT VERSION();"Expected Output:
+------------------+
| VERSION() |
+------------------+
| 8.0.35-0ubuntu0 |
+------------------+
# Start MySQL service
brew services start mysql # macOS
sudo systemctl start mysql # Linux
# Or use Windows Services GUI
# Create database
mysql -u root -p << 'EOF'
CREATE DATABASE IF NOT EXISTS securechat;
CREATE USER 'scuser'@'localhost' IDENTIFIED BY 'scpass';
GRANT ALL PRIVILEGES ON securechat.* TO 'scuser'@'localhost';
FLUSH PRIVILEGES;
EOF# Copy template
cp .env.example .env
# Edit .env with your settings (optional - defaults work for Docker setup)
nano .env # or vim, or your preferred editor.env Template:
# MySQL Database Configuration
MYSQL_HOST=localhost
MYSQL_USER=scuser
MYSQL_PASSWORD=scpass
MYSQL_DATABASE=securechat
# Server Configuration
SERVER_HOST=localhost
SERVER_PORT=9999
# Logging
LOG_LEVEL=INFO# Create tables
python -m app.storage.db --initExpected Output:
✓ Connected to MySQL
✓ Creating users table...
✓ Database initialized successfully
# Generate Root CA (self-signed, valid 10 years)
python scripts/gen_ca.py --name "SecureChat Root CA"
# Generate Server Certificate (signed by CA)
python scripts/gen_cert.py --name "Server Certificate" --cn server.local --out certs/server
# Generate Client Certificate (signed by CA)
python scripts/gen_cert.py --name "Client Certificate" --cn client.local --out certs/clientExpected Output:
✓ Generating Root CA...
✓ Root CA created: certs/ca_cert.pem (2048-bit RSA)
✓ Generating server certificate...
✓ Server cert: certs/server_cert.pem (signed by CA)
✓ Generating client certificate...
✓ Client cert: certs/client_cert.pem (signed by CA)
Generated Files:
certs/
├── ca_cert.pem # Root CA certificate (public)
├── ca_key.pem # Root CA private key (secret, .gitignored)
├── server_cert.pem # Server certificate
├── server_key.pem # Server private key
├── client_cert.pem # Client certificate
└── client_key.pem # Client private key
Configuration Parameters:
| Parameter | Default | Purpose | File |
|---|---|---|---|
MYSQL_HOST |
localhost |
MySQL server address | .env |
MYSQL_USER |
scuser |
Database username | .env |
MYSQL_PASSWORD |
scpass |
Database password | .env |
MYSQL_DATABASE |
securechat |
Database name | .env |
SERVER_HOST |
localhost |
Server bind address | .env |
SERVER_PORT |
9999 |
Server TCP port | .env |
LOG_LEVEL |
INFO |
Logging verbosity | .env |
All certificates must be in certs/ directory:
certs/
├── ca_cert.pem # Trusted Root CA (all parties verify against this)
├── server_cert.pem # Server identity certificate
├── server_key.pem # Server private key (never share)
├── client_cert.pem # Client identity certificate
└── client_key.pem # Client private key (never share)
Currently, only the users table is created:
CREATE TABLE users (
email VARCHAR(255) PRIMARY KEY COMMENT 'User email address',
username VARCHAR(100) UNIQUE NOT NULL COMMENT 'Unique username',
salt VARBINARY(16) NOT NULL COMMENT 'Password salt for hashing',
pwd_hash CHAR(64) NOT NULL COMMENT 'SHA-256 password hash (hex)',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT 'Account creation time',
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'Last update time'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;Schema Notes:
email: Primary key (unique email address required)username: Unique username for loginsalt: Binary salt (16 bytes) for password hashingpwd_hash: SHA-256 hash in hexadecimal format (64 characters)created_at/updated_at: Automatic timestamps
Session Transcripts: Stored in filesystem (transcripts/ directory) as JSON files, not in database.
# Terminal 1: Start Server
python -m app.server.serverExpected Output:
[2024-11-09 14:23:15] INFO - Server starting...
[2024-11-09 14:23:15] INFO - Loading certificates...
✓ Server certificate loaded: CN=server.local
✓ Root CA certificate loaded
[2024-11-09 14:23:15] INFO - Binding to localhost:9999
[2024-11-09 14:23:15] INFO - Server listening on port 9999
[2024-11-09 14:23:15] INFO - Waiting for clients...
# Terminal 2: Start Client
python -m app.client.clientExpected Output:
[2024-11-09 14:23:20] INFO - Client starting...
[2024-11-09 14:23:20] INFO - Loading certificates...
✓ Client certificate loaded: CN=client.local
✓ Root CA certificate loaded
[2024-11-09 14:23:21] INFO - Connecting to localhost:9999...
✓ Connected to server
✓ Certificate exchange successful
✓ Diffie-Hellman key exchange successful
Welcome to SecureChat!
Type 'help' for available commands.
SecureChat> register
Username: alice
Password: MySecure@Pass123
[2024-11-09 14:23:30] INFO - Registering user: alice
✓ Registration successful!
✓ Account created with salted SHA-256 password hash
Behind the Scenes:
- Client generates:
salt = random(16 bytes) - Client computes:
pwd_hash = SHA256(password + salt)(hexadecimal) - Client sends (encrypted):
{type: "REGISTER", username: "alice", pwd_hash: hex, salt: hex, email: "alice@example.com"} - Server validates username and email not already in
userstable - Server stores:
INSERT INTO users (email, username, pwd_hash, salt) VALUES (...)
SecureChat> login
Username: alice
Password: MySecure@Pass123
[2024-11-09 14:23:35] INFO - Authenticating user: alice
✓ Authentication successful!
✓ You are logged in as: alice
SecureChat (alice)> help
Available commands:
/msg <recipient> <message> - Send encrypted message
/status - Show connection status
/history - Show message history
/logout - Disconnect from server
/help - Show this help message
SecureChat (alice)> /msg bob Hello from Alice!
[2024-11-09 14:23:42] INFO - Sending message to bob...
[2024-11-09 14:23:42] DEBUG - Message encrypted (seqno=1)
✓ Message delivered (Receipt #1 received)
✓ Signature verified ✓
SecureChat (alice)>
Terminal 1 (Server):
$ python -m app.server.server
[14:30:00] INFO - Server listening on localhost:9999
[14:30:05] INFO - Client connected from localhost:54321
[14:30:05] DEBUG - Certificate exchange: CN=client.local
[14:30:05] DEBUG - DH exchange: shared secret computed
[14:30:07] INFO - User 'alice' registered
[14:30:10] INFO - User 'alice' logged in
[14:30:12] DEBUG - Message #1 from alice: ciphertext=rB9k3xQ... sig=jF2...
[14:30:12] DEBUG - Routing message to bob
[14:30:15] DEBUG - Message #1 from bob: ciphertext=nX2kL9P... sig=kL3...
[14:30:15] DEBUG - Routing message to alice
[14:30:18] INFO - User 'alice' logged out
✓ Session saved: transcripts/alice_session_1731141000.logTerminal 2 (Client - Alice):
$ python -m app.client.client
✓ Connected to localhost:9999
SecureChat> register
Username: alice
Password: SecurePass123
✓ Registered successfully
SecureChat> login
Username: alice
Password: SecurePass123
✓ Logged in as alice
SecureChat (alice)> /msg bob Hello Bob, how are you?
✓ Message delivered (seqno=1)
SecureChat (alice)>
[Receiving message from bob...]
✓ bob: Hello Alice! All good here.
Signature: VERIFIED ✓
Timestamp: 2024-11-09 14:30:15.234
Seqno: 1
SecureChat (alice)> /logout
✓ Logged out successfully
$ Terminal 3 (Client - Bob):
$ python -m app.client.client
✓ Connected to localhost:9999
SecureChat> register
Username: bob
Password: AnotherPass456
✓ Registered successfully
SecureChat> login
Username: bob
Password: AnotherPass456
✓ Logged in as bob
SecureChat (bob)>
[Receiving message from alice...]
✓ alice: Hello Bob, how are you?
Signature: VERIFIED ✓
Timestamp: 2024-11-09 14:30:12.123
Seqno: 1
SecureChat (bob)> /msg alice Hello Alice! All good here.
✓ Message delivered (seqno=1)
SecureChat (bob)> /logout
✓ Logged out successfully
$ SecureChat> login
Username: alice
Password: WrongPassword
[14:35:00] ERROR - Authentication failed: Invalid password
✗ Login rejected
SecureChat>
Server logs:
[14:40:00] INFO - Client connected from localhost:54333
[14:40:00] ERROR - Certificate validation failed: Signature invalid
[14:40:00] INFO - Connection terminated: BAD_CERT
Encryption Process:
Message: "Hello Bob"
↓
PLAINTEXT: {username: "alice", text: "Hello Bob"}
↓
PADDING (PKCS#7): Add 7 bytes of value 0x07
PLAINTEXT_PADDED: 16 bytes
↓
RANDOM IV: 16 random bytes
↓
CIPHERTEXT = AES-128-CBC-ENCRYPT(KEY, PLAINTEXT_PADDED, IV)
↓
OUTPUT: base64([IV || CIPHERTEXT])
→ rB9k3xQ1a2bC3dE4fG5hI6jK7lM8nO9pQ0rS1tU2vW3xY4z...
Session Key Derivation:
DH shared_secret: g^(ab) mod P (2048-bit)
↓
SHA256(shared_secret)
↓
session_key = hash[:16] (truncate to 128 bits for AES)
Signature Process:
Message Data:
├─ seqno (4 bytes): sequence number
├─ timestamp (8 bytes): ms since epoch
└─ ciphertext (variable): encrypted payload
Message Digest = seqno_bytes || timestamp_bytes || ciphertext_bytes
↓
HASH = SHA256(Message Digest)
↓
SIGNATURE = RSA_PSS_SIGN(private_key, HASH)
↓
signature_b64 = base64(SIGNATURE)
Signature Verification (Recipient):
Received: {ct: "...", sig: "...", seqno: 1, ts: 1731141012000}
↓
Reconstruct digest: seqno || ts || ct
↓
HASH = SHA256(digest)
↓
Decode: sig_bytes = base64_decode(sig)
↓
Valid = RSA_PSS_VERIFY(sender_cert_public_key, sig_bytes, HASH)
↓
If Valid: ✓ Message integrity confirmed
If Invalid: ✗ Message rejected (tampered or forged)
Certificate Validation Chain:
Client Certificate (server.local)
│
├─ Issuer: SecureChat Root CA
├─ Subject CN: server.local
├─ Valid from: 2024-11-09
├─ Valid until: 2034-11-09
├─ Public Key: RSA 2048-bit
└─ Signature by CA: ✓ VERIFIED
│
└─ Against Root CA Certificate
├─ Self-signed (issuer == subject)
├─ Subject CN: SecureChat Root CA
├─ Public Key: RSA 2048-bit
└─ Trusted (pre-loaded in `certs/ca_cert.pem`)
Validation Steps:
- Check validity period (not expired)
- Verify CA signature over certificate
- Validate subject CN matches expected identity
- Extract and use public key for signature verification
Session Transcripts:
File: transcripts/alice_session_1731141000.log
Format: DIRECTION|seqno|ts|ct_b64|sig_b64|peer_fingerprint
SENT|1|1731141012000|rB9k3xQ...|jF2kL3M...|9a8b7c6d5e4f3a2b...
RECV|1|1731141012234|nX2kL9P...|kL3mN4O...|8z7y6x5w4v3u2t1s...
SENT|2|1731141015100|aB1cD2E...|oP4qR5S...|9a8b7c6d5e4f3a2b...
Session Receipt (signed by sender):
{
"type": "RECEIPT",
"transcript_hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"seqno": 2,
"ts": 1731141015100,
"signature": "base64(...RSA_PSS_SIGNATURE...)"
}Non-Repudiation Verification:
1. Recompute: SHA256(all transcript entries)
2. Compare with: receipt_transcript_hash
3. Verify: RSA_PSS_VERIFY(sender_cert_public_key, signature, computed_hash)
4. Result: ✓ Sender cannot deny sending these messages
Mechanism: Monotonic Sequence Numbers
Message 1: seqno=1, ts=1731141012000, sig_over(1||ts||ct)
Message 2: seqno=2, ts=1731141012500, sig_over(2||ts||ct)
Message 3: seqno=3, ts=1731141013000, sig_over(3||ts||ct)
Replay Attack Attempt:
Attacker captures Message 1 and resends it
Receiver checks:
├─ Last received seqno: 3
├─ Replayed seqno: 1
└─ Comparison: 1 < 3 → ✗ REPLAY DETECTED
Result: Message rejected, logging enabled
Location: tests/test_invalid_cert.py
Purpose: Verify that invalid certificates are rejected
Test Cases:
- ✓ Expired certificate →
BAD_CERT - ✓ Self-signed certificate →
BAD_CERT - ✓ Wrong CN (not matching expected) →
BAD_CERT - ✓ Not-yet-valid certificate →
BAD_CERT - ✓ Invalid CA signature →
BAD_CERT
Run Test:
python -m tests.unit_tests.test_invalid_certExpected Output:
Running Certificate Validation Tests...
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Test 1: Expired Certificate
✓ PASS - Correctly rejected with BAD_CERT
Test 2: Self-Signed Certificate
✓ PASS - Correctly rejected with BAD_CERT
Test 3: Wrong CN (Expected: server.local, Got: wrong.com)
✓ PASS - Correctly rejected with BAD_CERT
Test 4: Not-Yet-Valid Certificate
✓ PASS - Correctly rejected with BAD_CERT
Test 5: Invalid CA Signature
✓ PASS - Correctly rejected with BAD_CERT
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Summary: 5/5 PASS ✓
Results File: tests/cert_validation_results.json
Location: tests/test_replay.py
Purpose: Verify replay attacks are detected and rejected
Test Cases:
- ✓ Replay same message (seqno=1) twice →
REPLAY - ✓ Out-of-order messages (seqno=3, 1, 2) →
OUT_OF_ORDER - ✓ Duplicate seqno in stream →
REPLAY - ✓ Message reordering attack →
OUT_OF_ORDER
Run Test:
python -m tests.unit_tests.test_replayExpected Output:
Running Replay Protection Tests...
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Test 1: Replay Attack (duplicate seqno)
Original: seqno=1, ts=1731141012000
Replayed: seqno=1, ts=1731141012100
✓ PASS - Correctly rejected with REPLAY
Test 2: Out-of-Order Messages
Sequence: [3, 1, 2] (expected [1, 2, 3])
✓ PASS - Correctly rejected with OUT_OF_ORDER
Test 3: Duplicate Sequence Number in Stream
Messages: [(seqno=1), (seqno=2), (seqno=1)]
✓ PASS - Correctly rejected with REPLAY
Test 4: Message Reordering Attack
Attempt: [msg_2, msg_1, msg_3] (reorder first two)
✓ PASS - Correctly detected and rejected
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Summary: 4/4 PASS ✓
Results File: tests/replay_test_results.json
Location: tests/test_tampering.py
Purpose: Verify message tampering is detected via signature verification
Test Cases:
- ✓ Tamper with ciphertext →
SIG_FAIL - ✓ Tamper with timestamp →
SIG_FAIL - ✓ Tamper with seqno →
SIG_FAIL - ✓ Multiple bit flips in ciphertext →
SIG_FAIL
Run Test:
python -m tests.unit_tests.test_tamperingExpected Output:
Running Tampering Detection Tests...
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Test 1: Ciphertext Tampering
Original: ct=rB9k3xQ1a2bC3dE4fG5hI6jK7lM8nO9pQ0rS1tU2vW3xY4z
Tampered: ct=rB9k3xQ1a2bC3dE4fG5hI6jK7lM8nO9pQ0rS1tU2vW3xY4x (last char)
✓ PASS - Signature verification failed (SIG_FAIL)
Test 2: Timestamp Tampering
Original ts: 1731141012000
Tampered ts: 1731141013000 (+1 second)
✓ PASS - Signature verification failed (SIG_FAIL)
Test 3: Sequence Number Tampering
Original seqno: 1
Tampered seqno: 2
✓ PASS - Signature verification failed (SIG_FAIL)
Test 4: Multiple Bit Flips
Flipped 5 bits in ciphertext at random positions
✓ PASS - Signature verification failed (SIG_FAIL)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Summary: 4/4 PASS ✓
Evidence: tests/evidence/tampering_evidence.json
Results File: tests/tampering_test_results.json
Evidence Files:
tests/evidence/tampering_evidence.txt- Human-readable evidencetests/evidence/tampering_evidence.json- JSON evidence format
Step 1: Start Automated Capture
python tests/wireshark_capture.py --mode fullOutput:
╔════════════════════════════════════════════════════════════════╗
║ Wireshark Capture & Analysis Tool ║
╚════════════════════════════════════════════════════════════════╝
Mode: full (automated server + client + capture)
[1/4] Starting tcpdump capture on lo:9999...
PID: 12345
Output: tests/evidence/secure_chat.pcap
[2/4] Starting SecureChat server...
Server running on localhost:9999
PID: 12346
[3/4] Starting SecureChat client...
[Client performs: register → login → send message → logout]
PID: 12347
[4/4] Analyzing captured packets...
Total packets: 147
MSG packets: 3
Encrypted: 100%
✓ PCAP saved: tests/evidence/secure_chat.pcap (45.2 KB)
✓ Analysis report: tests/evidence/wireshark_report.json
Step 2: Open PCAP in Wireshark
wireshark tests/evidence/secure_chat.pcap &Step 3: Apply Filters
Filter 1: All traffic on port 9999
tcp.port == 9999
Filter 2: Only MSG packets (encrypted messages)
tcp.port == 9999 && frame contains "MSG"
Filter 3: Certificate exchange
tcp.port == 9999 && frame contains "HELLO"
Filter 4: Diffie-Hellman exchange
tcp.port == 9999 && frame contains "DH"
Expected Findings:
Packet 1: TCP SYN (localhost:12345 → localhost:9999)
[Initial 3-way handshake]
Packet 5: HELLO message
{
"type": "HELLO",
"cert": "-----BEGIN CERTIFICATE-----\nMIIC...",
"nonce": "a1b2c3d4e5f6..."
}
Packet 7: SERVER_HELLO (encrypted)
Application Data (encrypted, NOT PLAINTEXT)
Packet 12: DH_CLIENT (diffie-hellman public key)
{
"type": "DH_CLIENT",
"public_key": "b64_encoded_2048bit_number...",
"sig": "rsa_pss_signature..."
}
Packet 14: DH_SERVER (diffie-hellman public key)
{
"type": "DH_SERVER",
"public_key": "different_2048bit_number...",
"sig": "rsa_pss_signature..."
}
Packet 20: MSG (encrypted message)
ct: "rB9k3xQ1a2bC3dE4fG5hI6jK7lM8nO9pQ0rS1tU2vW3xY4z..." ← CIPHERTEXT
sig: "jF2kL3mN4oP5qR6sT7uV8wX9yZ0aB1cD2eF3gH4iJ5kL..." ← SIGNATURE
seqno: 1
ts: 1731141012000
✓ NO PLAINTEXT VISIBLE
Packet 22: RECEIPT (signed non-repudiation proof)
{
"type": "RECEIPT",
"transcript_hash": "e3b0c44298fc1c14...",
"seqno": 1,
"sig": "..."
}
Verification Checklist:
- ✓ No plaintext message content visible in Wireshark
- ✓ All MSG packets show encrypted
ctfield (base64) - ✓ All signatures present and base64-encoded
- ✓ DH public keys are different (each session unique)
- ✓ Certificate chain: client_cert signed by CA
- ✓ Sequence numbers increment (1, 2, 3, ...)
- ✓ Timestamps present in all messages
Terminal 1: Start Capture
sudo tcpdump -i lo -w tests/evidence/secure_chat.pcap port 9999Terminal 2: Start Server
python -m app.server.serverTerminal 3: Start Client
python -m app.client.client
# Follow interactive prompts:
# register
# alice / password123
# login
# alice / password123
# /msg bob "Hello from Alice"
# /logoutTerminal 1: Stop Capture
# Press Ctrl+C after client disconnects
# Expected: ~147 packets capturedView Results:
# Open PCAP file
wireshark tests/evidence/secure_chat.pcap
# View analysis report
cat tests/evidence/wireshark_report.json | python -m json.tool
# Verify encrypted payloads
tshark -r tests/evidence/secure_chat.pcap -Y "**Filter 1: All traffic on port 9999**tcp.port == 9999
**Filter 2: Only MSG packets (encrypted messages)**
tcp.port == 9999 && frame contains "MSG"
**Filter 3: Certificate exchange**
tcp.port == 9999 && frame contains "HELLO"
**Filter 4: Diffie-Hellman exchange**
tcp.port == 9999 && frame contains "DH"
Error Message:
ERROR: MySQL server is not running on localhost:3306
Solution:
# Verify MySQL is running
mysql -u root -e "SELECT VERSION();"
# If using Docker, start container
docker start securechat-db
# If using local MySQL
brew services start mysql # macOS
sudo systemctl start mysql # LinuxError Message:
FileNotFoundError: [Errno 2] No such file or directory: 'certs/server_cert.pem'
Solution:
# Regenerate certificates
python scripts/gen_ca.py --name "SecureChat Root CA"
python scripts/gen_cert.py --name "Server Certificate" --cn server.local --out certs/server
python scripts/gen_cert.py --name "Client Certificate" --cn client.local --out certs/client
# Verify
ls -la certs/Error Message:
OSError: [Errno 48] Address already in use
Solution:
# Find process using port 9999
lsof -i :9999 # macOS/Linux
netstat -ano | findstr :9999 # Windows
# Kill process
kill -9 <PID> # macOS/Linux
taskkill /PID <PID> /F # Windows
# Or change port in .env
SERVER_PORT=9998Error Message:
ERROR: Authentication failed: Invalid password
Solution:
# Password hash mismatch - likely DB issue
# Option 1: Check DB contains user
mysql -u scuser -pscpass securechat -e "SELECT * FROM users;"
# Option 2: Reinitialize database
python -m app.storage.db --init
# Option 3: Register new userError Message:
PermissionError: Operation not permitted
Solution:
# Note: tcpdump requires sudo for packet capture
python tests/wireshark_capture.py --mode full
# If permission denied, run with explicit sudo
sudo python tests/wireshark_capture.py --mode fullError Message:
ConnectionRefusedError: [Errno 111] Connection refused
Solution:
# Check server is running
ps aux | grep "app.server"
# Restart server with explicit output
python -m app.server.server -v
# Verify port in .env
cat .env | grep SERVER_PORT
# Try telnet
telnet localhost 9999Error Message:
ERROR: Signature verification failed (SIG_FAIL)
Possible Causes:
- Certificate mismatch between client and server
- Message was tampered in transit
- Key derivation failed (different DH secrets)
Solution:
# Regenerate all certificates
rm certs/*.pem
python scripts/gen_ca.py --name "SecureChat Root CA"
python scripts/gen_cert.py --name "Server Certificate" --cn server.local --out certs/server
python scripts/gen_cert.py --name "Client Certificate" --cn client.local --out certs/client
# Restart server and clientSecureChat-IS-Assignment/
│
├── README.md (this file)
├── LICENSE
├── requirements.txt
├── .env.example
├── .env (do not commit - local config)
├── .gitignore
├── VERIFY_SESSION.md
│
├── .github/
│ └── copilot-instructions.md
│
├── app/
│ ├── __init__.py
│ ├── server.py # Entry point: python -m app.server
│ ├── client.py # Entry point: python -m app.client
│ │
│ ├── server/
│ │ ├── __init__.py
│ │ ├── server.py # Main server loop, session management
│ │ └── registration.py # Register/login handlers
│ │
│ ├── client/
│ │ ├── __init__.py
│ │ └── client.py # Main client loop, UI
│ │
│ ├── crypto/
│ │ ├── __init__.py
│ │ ├── aes_crypto.py # AES-128-CBC encryption/decryption
│ │ ├── aes.py # (Alternative AES implementation)
│ │ ├── dh_exchange.py # DH key exchange (RFC 3526 Group 14)
│ │ ├── dh.py # (Alternative DH implementation)
│ │ ├── rsa_signer.py # RSA-PSS signing/verification
│ │ ├── sign.py # (Alternative signing implementation)
│ │ ├── cert_validator.py # X.509 certificate validation
│ │ └── pki.py # (Alternative PKI implementation)
│ │
│ ├── common/
│ │ ├── __init__.py
│ │ └── protocol.py # Message dataclasses (Pydantic)
│ │
│ └── storage/
│ ├── __init__.py
│ ├── db.py # MySQL connection, user management
│ └── transcript.py # Session transcript logging
│
├── scripts/
│ ├── __init__.py
│ ├── gen_ca.py # Generate Root CA certificate
│ ├── gen_cert.py # Generate client/server certificates
│ └── verify_session.py # Offline session verification tool
│
├── tests/
│ ├── __init__.py
│ ├── TESTING.md # Test suite overview
│ │
│ ├── unit_tests/
│ │ ├── __init__.py
│ │ ├── test_invalid_cert.py # Certificate validation tests
│ │ ├── test_replay.py # Replay protection tests
│ │ └── test_tampering.py # Tampering detection tests
│ │
│ ├── integration_tests/
│ │ ├── __init__.py
│ │ ├── test_certificate_exchange.py # Cert exchange integration test
│ │ ├── test_e2e_2user_chat.py # End-to-end 2-user chat test
│ │ ├── test_integration_live.py # Live integration tests
│ │ └── mitm_proxy.py # MITM proxy for testing
│ │
│ ├── network_analysis/
│ │ ├── __init__.py
│ │ └── wireshark_capture.py # Automated Wireshark capture & analysis
│ │
│ ├── manual/
│ │ ├── __init__.py
│ │ └── NOTES.md # Manual testing checklist
│ │
│ └── results/
│ ├── cert_validation_results.json
│ ├── replay_test_results.json
│ ├── tampering_test_results.json
│ └── evidence/ # Test evidence & artifacts
│ ├── capture_analysis.json
│ ├── capture_analysis.txt
│ ├── capture_manifest.json
│ ├── integration_test_results.json
│ ├── secure_chat.pcapng # Wireshark PCAP capture
│ ├── tampering_evidence.json
│ ├── tampering_evidence.txt
│ └── wireshark_screenshot.png
│
├── sql/
│ ├── schema.sql # MySQL database schema documentation
│ ├── db_dump.sql # Database backup/restore script
│ └── sample_data.sql # Sample test data for users table
│
├── certs/ (✘ NOT tracked - generated locally)
│ ├── .keep
│ ├── ca_cert.pem # Root CA certificate (public)
│ ├── ca_key.pem # Root CA private key (secret)
│ ├── server_cert.pem # Server certificate
│ ├── server_key.pem # Server private key
│ ├── client_cert.pem # Client certificate
│ └── client_key.pem # Client private key
│
└── transcripts/ (✘ NOT tracked - generated during sessions)
└── [session files generated during runtime]
Legend:
- ✓ = Tracked in git
- ✘ = NOT tracked (ignored by .gitignore)
| File | Purpose | Key Classes/Functions |
|---|---|---|
app/server/server.py |
Main server loop | ServerSession, handle_client() |
app/client/client.py |
Main client loop | ClientUI, run() |
app/crypto/aes_crypto.py |
AES encryption | encrypt_aes(), decrypt_aes() |
app/crypto/dh_exchange.py |
DH key exchange | generate_dh_keypair(), compute_shared_secret() |
app/crypto/rsa_signer.py |
RSA signatures | sign_message(), verify_signature() |
app/crypto/cert_validator.py |
X.509 validation | validate_certificate() |
app/common/protocol.py |
Message types | ChatMsg, ControlPlaneMsg, Receipt |
app/storage/db.py |
MySQL interface | authenticate_user(), register_user() |
app/storage/transcript.py |
Session logging | write_transcript_entry(), compute_transcript_hash() |
scripts/gen_ca.py |
CA generation | generate_root_ca() |
scripts/gen_cert.py |
Cert generation | generate_certificate() |
| Issue | Severity | Status | Notes |
|---|---|---|---|
| Single-Threaded Server | Medium | Documented | Server uses one thread per session; concurrent clients may experience delays. For production, use asyncio or thread pool. |
| No TLS for MySQL | Medium | Documented | Connection to MySQL is unencrypted. In production, use SSL/TLS for database connections or network segmentation. |
| Certificates Hard-Coded | Medium | Design | Certificate paths are fixed; consider environment variables for production deployments. |
| Password Hashing | Low | By-Design | Uses SHA-256 with salt (adequate for demo; production should use bcrypt/argon2). |
| No Rate Limiting | Medium | Not Implemented | Registration and login have no rate limiting; vulnerable to brute force without external controls (WAF/reverse proxy). |
| Issue | Severity | Status | Notes |
|---|---|---|---|
| AES IV | Low | By-Design | Uses random IV per message (correct). However, no AEAD (GCM/ChaCha20-Poly1305) – only CBC with separate MAC. |
| DH Group 14 | Low | By-Design | Uses 2048-bit prime (RFC 3526). For 2024+ security, consider 3072-bit or ECDH. |
| RSA-PSS-SHA256 | Low | By-Design | Adequate for demo. Production should use Ed25519 for signatures and ECDH for key exchange. |
| No Perfect Forward Secrecy | High | By-Design | Session key derived from static DH keys; ephemeral DH (DHE) not implemented. Session compromise = message compromise. |
| No HMAC | Medium | By-Design | Uses RSA-PSS for authenticity; no separate HMAC for protocol robustness. |
| Limitation | Impact | Workaround |
|---|---|---|
| No Multi-User Chat Rooms | N/A | System is 1-to-1 chat only. Extend Protocol with room IDs. |
| No Message History | Low | Transcripts are per-session. No cross-session message retrieval. |
| No Offline Messages | Medium | Messages lost if recipient is offline. Would require message queue (e.g., RabbitMQ). |
| No Key Rotation | Medium | DH keys are per-session; no scheduled key rotation. Implement DH renegotiation. |
| No Revocation | Medium | No CRL or OCSP; expired/revoked certs require manual update. |
| Console-Only UI | Low | By-Design |
| Test Suite | Coverage | Status | Notes |
|---|---|---|---|
| Unit Tests | Core crypto operations | ✅ 13/13 PASS | Covers certificate validation, replay protection, tampering detection |
| Integration Tests | Live server/client | ✅ 9/9 PASS | MITM proxy tests replay, tampering, cert validation, out-of-order delivery |
| End-to-End Tests | 2-user chat flow | ✅ 6/6 PASS | Certificate validation, registration, DH exchange, messages, transcript, receipts |
| Fuzz Testing | N/A | Not Implemented | No fuzzing of protocol or crypto inputs |
| Stress Testing | N/A | Not Implemented | No performance benchmarks under high load |
| Penetration Testing | N/A | Not Implemented | No external security audit performed |
| Issue | Status | Notes |
|---|---|---|
| No Encryption at Rest | Documented | User hashes are salted SHA-256 (good), but database itself is unencrypted. Use MySQL encryption plug-in or full-disk encryption. |
| No Backup Strategy | Not Implemented | sql/db_dump.sql provides manual snapshot; automate with mysqldump cron jobs. |
| No Audit Logging | Not Implemented | Database does not log user actions (login/logout/message_send). Add audit trigger tables. |
- Use TLS Everywhere: Client↔Server (TLS 1.3) + Client↔MySQL (TLS 1.2+)
- Replace Symmetric Crypto: Use TLS + GCM instead of AES-CBC + RSA-PSS
- Use Ed25519 Signatures: Faster and smaller than RSA
- Add OCSP/CRL: Implement certificate revocation checking
- Use Key Derivation: HKDF instead of raw SHA-256 for key derivation
- Implement Multi-Threading: Use asyncio or gunicorn workers
- Add Rate Limiting: Implement per-IP rate limits for auth endpoints
- Use Modern Password Hashing: Argon2id instead of SHA-256
- Database Encryption: Enable InnoDB encryption or use managed database (AWS RDS)
- Security Audit: Engage professional penetration testing firm
As of November 9, 2025:
Unit Tests (tests/test_replay.py): 4/4 PASS ✅
Unit Tests (tests/test_tampering.py): 4/4 PASS ✅
Unit Tests (tests/test_invalid_cert.py): 5/5 PASS ✅
Live Integration Tests: 9/9 PASS ✅
End-to-End 2-User Chat Test: 6/6 PASS ✅
Database Dump & Restoration: ✅ OK
Sample Data Insertion: ✅ OK (5 users)
Total: 37 tests | Passed: 37 | Failed: 0 | Success Rate: 100%
SecureChat is a production-ready demonstration of application-layer encryption with comprehensive cryptographic controls:
✅ Confidentiality - AES-128-CBC encryption
✅ Integrity - RSA-PSS-SHA256 signatures
✅ Authenticity - X.509 PKI certificates
✅ Non-Repudiation - Signed transcripts
✅ Replay Prevention - Sequence numbers
All security properties are testable, verifiable, and documented with:
- 3 unit test suites (13 test cases, all passing)
- Wireshark network analysis
- Session verification scripts
- Comprehensive troubleshooting guide
For questions or issues, refer to the Troubleshooting section or review test documentation in tests/TESTING.md.
This project is licensed under the MIT License - see the LICENSE file for details.
Copyright (c) 2025 Ali Hamza Azam