Skip to content

YannLeao/secure-chat-client

Repository files navigation

Secure Chat — Android Client

A secure Android chat client with end-to-end encryption, built in Kotlin with Jetpack Compose as a project for the Information Security course at UFRPE (Computer Engineering).

This repository contains the mobile client. It connects to the Secure Chat Python server through a custom JSON-over-TCP protocol, performs a cryptographic session handshake, authenticates users with asymmetric signatures, and establishes independent end-to-end encrypted sessions per contact.

Tip

Looking for the Python server? → secure-chat-server


Author

Yann Leão — Computer Engineering, UFRPE
Advisor: Prof. Ygor Amaral


Preview

Splash / Connection Chat
Splash flow Chat screen

Table of Contents

  1. Architecture
  2. Security Stack
  3. Features
  4. Requirements
  5. Setup
  6. Running
  7. Debugging
  8. Protocol

Architecture

Android clients do not open direct sockets to each other — the server is responsible for routing. Message contents are protected with end-to-end encryption, so the server only ever sees an opaque e2e_payload.

[Android Client A] ─────────────────────── [Android Client B]
       │      logical E2E encrypted channel        │
       │                                           │
       └──────────── [Python Server] ──────────────┘
                       routes only
                  cannot read E2E content

Android Client

  • Connects to the server using a persistent TCP socket
  • Performs an ECDH-based cryptographic handshake on connect
  • Wraps all post-handshake traffic in a secure envelope (AES-256 + HMAC)
  • Authenticates via ECDSA challenge-response — no password transmitted after registration
  • Manages independent E2E encrypted sessions per contact
  • Encrypts and authenticates chat messages before routing them through the server
  • Stores conversation history encrypted at rest via Android Keystore

Python Server

  • Accepts, authenticates, and routes TCP client connections
  • Distributes public keys between contacts
  • Forwards E2E payloads without decrypting them
  • Stores offline messages until the recipient reconnects
  • Broadcasts user status and typing events

Security Stack

Layer Mechanism Purpose
Client-server key exchange Ephemeral ECDH + HKDF-SHA256 Derives unique session keys per connection
Client-server envelope AES-256-CBC + HMAC-SHA256 Protects all traffic after handshake
Session expiration Randomized time (30–60 min) and message count (50–100) Forward secrecy; hides rekeying pattern
Identity ECC key pair stored in Android Keystore Represents the user's cryptographic identity
Authentication ECDSA challenge-response Proves identity without transmitting a password
Public key distribution Server-mediated key lookup Lets contacts discover each other's identity keys
E2E key exchange Ephemeral ECDH per contact + HKDF-SHA256 Derives chat keys unknown to the server
E2E message protection AES-256-CBC + HMAC-SHA256 Encrypts and authenticates chat payloads
Local storage AES-256-GCM via Android Keystore Encrypts message history at rest

E2E Message Flow

Plaintext message
        │
        ▼
E2E encrypt (AES-256) + HMAC
        │
        ▼
{ iv, ciphertext, hmac } → e2e_payload
        │
        ▼
Wrapped in client-server secure envelope
        │
        ▼
Server routes opaque payload (cannot read content)
        │
        ▼
Recipient verifies HMAC → decrypts E2E payload → plaintext

Features

  • Registration, login, and existing-device authentication via asymmetric signature
  • New-device login with password and automatic key rotation
  • Contact list with real-time online/offline status
  • Terminal-inspired dark UI built with Jetpack Compose
  • Real-time chat with double-layer encrypted payloads
  • Offline message delivery on reconnect
  • Typing indicators
  • Local encrypted message history (Room + Android Keystore)
  • Logcat traces for protocol demonstration

Requirements

  • Android Studio (latest stable)
  • JDK 17 or the bundled JDK from Android Studio
  • Android device or emulator with API 26+
  • A running instance of the Secure Chat Python server
  • Network access between the client and the server

Project stack:

  • Kotlin + Coroutines
  • Jetpack Compose + Material 3
  • Room (local encrypted storage)
  • Kotlinx Serialization
  • Bouncy Castle
  • Android Keystore

Setup

1. Clone and Open

git clone <client-repository-url>

Open the project folder in Android Studio and let Gradle sync complete.

2. Start the Server

Start the Python server before launching the app. The client expects the server to be reachable at the configured host and port.

Important

Emulator: use Android's built-in alias 10.0.2.2 to reach localhost on the host machine.
Physical device: the phone and the server must be on the same network. Use the server machine's local IP address.

3. Configure Server Address

Locate the socket configuration in the client code and update the host and port to match your server.

4. Build and Run

Run directly from Android Studio, or build via the command line:

# macOS / Linux
./gradlew :app:assembleDebug

# Windows
.\gradlew.bat :app:assembleDebug

Running

Recommended demo flow:

  1. Start the Python server.
  2. Launch the app on two clients — for example, one emulator and one physical device.
  3. Register two different users (or authenticate with pre-existing accounts).
  4. Open a conversation from the contact list — the E2E handshake happens automatically.
  5. Exchange messages while both users are online.
  6. Send a message with one user offline, then reconnect to demonstrate offline delivery.

Debugging

Useful Logcat filters for following the cryptographic protocol live:

E2EProtocol
Crypto
LOGOUT

The E2EProtocol tag is especially useful for demonstrations. It shows:

  • Plaintext before E2E encryption
  • Generated E2E payloads (iv, ciphertext, hmac)
  • Received E2E payloads before decryption
  • Decrypted plaintext after HMAC verification
  • E2E session fingerprints (aesFp, hmacFp) for comparing both clients

Tip

If E2E decryption fails, compare the aesFp and hmacFp values on both clients — they must match for the same conversation. Mismatched fingerprints indicate a handshake or key derivation issue.


Protocol

The app communicates with the server using newline-delimited JSON over TCP:

{"type": "message_type"}\n

After the initial cryptographic handshake, all messages are wrapped in a secure envelope:

{
  "type": "secure_envelope",
  "iv": "HEX_STRING",
  "ciphertext": "HEX_STRING",
  "hmac": "HEX_STRING"
}

Chat messages carry a second encryption layer inside the envelope:

{
  "type": "message",
  "from": "alice",
  "to": "bob",
  "e2e_payload": {
    "iv": "HEX",
    "ciphertext": "HEX",
    "hmac": "HEX"
  }
}

The server decrypts only the outer envelope to route the message. The e2e_payload remains opaque.

For the full specification — all message types, cryptographic flows, and E2E protocol — see PROTOCOLS.md.

About

Android chat client with DHE+HKDF session encryption, ECDSA authentication, and end-to-end encrypted messaging over a custom TCP protocol

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages