[KEYMESSAGE] Booting secure environment...
[KEYMESSAGE] Loading cryptographic modules...
[KEYMESSAGE] RSA-2048 keys ready.
[KEYMESSAGE] AES-256-GCM engine online.
[KEYMESSAGE] WebRTC stack initialized.
[KEYMESSAGE] WebSocket relay connected.
_ __ __ __
| |/ / | \/ |
| ' / ___ _ _| \ / | ___ ___ ___ __ _ __ _ ___
| < / _ \ | | | |\/| |/ _ \/ __/ __|/ _` |/ _` |/ _ \
| . \ __/ |_| | | | | __/\__ \__ \ (_| | (_| | __/
|_|\_\___|\__, |_| |_|\___||___/___/\__,_|\__, |\___|
__/ | __/ |
|___/ |___/
Protocol Specification
$ cat protocol.md | less
1. Identity
Each device generates an RSA-2048 keypair on first launch.
Seed phrase: 12 words -- recoverable wallet-style identity.
nodeId = SHA-256(publicKey)[:40] (hex)
Identity persisted in EncryptedSharedPreferences.
2. Relay Connection
ws://13.140.155.230:3001/ws?nodeId=<nodeId>
Relay responds: {type: "peers", list: [...]}
Relay broadcasts: {type: "peer_online", nodeId: A}
Relay: km-signaling (ws://13.140.155.230:3001)
Only forwards signaling messages:
- peer_online / peer_offline (presence)
- sdp (offers/answers)
- ice (candidates)
- contact_exchange
No message storage
No chat message forwarding
WebSocket WebSocket
(signaling) (signaling)
+-----------------------+ +-----------------------+
| Device A | | Device B |
| nodeId: A | | nodeId: B |
+----------+------------+ +----------+------------+
| |
+----------- WebRTC -----------+
DataChannel
(encrypted P2P)
+------------------------------+
| coturn:3478 (STUN/TURN) |
| (fallback if NAT blocks P2P) |
+------------------------------+
3. Contact Discovery
QR code contains: Name|PublicKey
Scanner adds contact locally and sends contact_exchange via relay.
Both sides call checkContactOnline() to trigger WebRTC.
4. WebRTC Negotiation
The peer with the lower nodeId creates the Offer.
If both nodeIds are greater than the peer's, they wait for the peer to initiate.
[RTC-01] peer_online received
[RTC-02] contact found
[RTC-03] Creating PeerConnection (STUN only)
[RTC-04] PeerConnection created
[RTC-05] Creating DataChannel (offerer only)
[RTC-06] DataChannel created
[RTC-07] Creating Offer (if myNodeId < peerId)
[RTC-08] Offer created
[RTC-09] Offer sent via relay -- {type: "sdp", from:A, data:{sdp, type:"offer"}}
[RTC-10] SetRemoteDescription (offer/answer received)
[RTC-11] RemoteDescription set -- Creating Answer
[RTC-12] Answer created -- sent via relay
[RTC-13] ICE candidates generated (STUN)
[RTC-14] ICE received and added
[RTC-15] ICE state: CHECKING to CONNECTED
[RTC-16] ICE CONNECTED
[RTC-17] DataChannel OPEN
5. Message Encryption
Hybrid encryption: RSA + AES-256-GCM
1. Generate random 256-bit AES key
2. Encrypt message with AES-256-GCM (12-byte nonce)
3. Encrypt AES key with RSA-OAEP (destination public key)
4. Format: base64(aes_key).base64(iv).base64(ciphertext)
Sent via DataChannel:
{
type: "msg",
data: "<encrypted_payload>",
id: "<uuid>"
}
ACK response:
{
type: "ack",
id: "<uuid>"
}
6. Message Queue
If WebRTC is not yet connected, messages are queued with SENDING status.
When WebRTC connects, retryQueuedMessages() re-sends them.
7. Contact Exchange (fallback)
If a decrypted message starts with [CONTACT_EXCHANGE],
it is processed as a contact exchange even if the relay was unavailable.
Releases
$ ls releases/
> No releases published yet. Check back soon.
System Info
Application: KeyMessage
Developer: KemaMada
Signaling Relay: ws://13.140.155.230:3001
STUN/TURN: coturn:3478
Encryption: RSA-2048 + AES-256-GCM
Transport: WebRTC DataChannel (P2P)
Status: active
[root@keymessage ~]#