Logo

Introduction

TorX is a C library enabling user interface developers to interface with Tor to create and manage hidden services for the purpose of transferring data peer to peer, primarily in the form of text, files, and data streams.

Key Points:

Distinguishing Points from all other Tor chats:

History:

The developer was tired of having to manage dozens of anonymous email, XMPP accounts, and associated keys, on top of having to maintain anonymity. We all are.

The developer's friend's family member ended up on Interpol's "Red List" and the developer watched their friend struggle to maintain constant communication with their family member, sometimes going for weeks without communication, as their family member travelled the world using a combination of illicitly obtained passports and unlawful border crossings. When they were in contact, one day they would use a Korean instant messenger, the next day one from Pakistan, and on. It was tedious and unreliable.

The developer was inspired to solve this problem not just for the technically competent (like the developer), but also for the technically illiterate (like the developer's friend and their family member).

Threat Model

Primary Goals:

Screenshots

Desktop Client (torx-gtk4)

Screenshot Screenshot Screenshot Screenshot Screenshot Screenshot Screenshot

Mobile Client (torx-flutter)

Screenshot Screenshot Screenshot Screenshot

How It Works

WARNING: Diagrams can be inaccurate, outdated, and unclear. With the exception of the "Message Diagram", these diagrams ARE incomplete and REQUIRE updating.

Handshake with V3Key / V3Auth Diagram:
________________________________________________________________________________
|	SING <---VV[2]+PeerOnion[56]+PeerV3KeyB64.pub[52]--- Peer		|
|	||		(down)							|
|	\/									|
|	Gen_CTRL								|
|	+ PeerV3Key ---VV[2]+CtrlOnion[56]+V3KeyB64.pub[52]---> Peer		|
|				(up)			   ||			|
|							   \/			|
|					(Brings up PeerOnion with V3Key)	|
|_______________________________________________________________________________|
		
Private Group Handshake with Signed Messaging Diagram:
(Note: Group_Ctrl is passed in Group_offer when PeerCount == 0, and is signed in GROUP_OFFER_ACCEPT(_FIRST)
_________________________________________________________________________________________________________________________
|	GROUP_OFFER(_FIRST) ---GroupID[32]+PeerCount[4]+InviteRequired[1](+Group_Ctrl[56]+ed25519_pk[32])---> Invitee	|
|												||			|
|												\/			|
|									(Accepts invitation(+Signs creator Group_Ctrl))	|
|										(Generate Group_CTRL+Keypair)		|
|	Inviter	<---GroupID[32]+Group_Ctrl[56]+ed25519_pk[32](+InvitationSignature[64])--- GROUP_OFFER_ACCEPT(_FIRST)	|
|	||														|
|	if(peercount > 0) ---PEERLIST---> Invitee, who trusts it if !peerlist && group[g].n > 0				|
|	||														|
|	\/														|
|	(Sign Invitee's Group_Ctrl)					(Sign invitee + Provide invitor invitation)	|
|	GROUP_OFFER_ACCEPT_REPLY ---GroupID[32]+Group_Ctrl[56]+ed25519_pk[32]+InviteeSignature[64]			|
|	||									+InvitorSignature[64]---> Invitee	|
|	||												||		|
|	\/												\/		|
|	(group_add_peer --> Connect/Chat)					(group_add_peer --> Connect/Chat)	|
|_______________________________________________________________________________________________________________________|
		
Public Group Handshake with Signed Messaging Diagram:
_________________________________________________________________________________________________________________________
|	(Someone scans the Public Group ID off a QR code)								|
|	(Generate Group_CTRL+Keypair)											|
|	GROUP_BROADCAST ---> All online peers ---> All their online peers (promulgates through network)			|
|															|
|	(Someone in Group) ---> (decrypts GROUP_BROADCAST) ---> GROUP_PUBLIC_ENTRY_REQUEST --->	New peer		|
|										(group_add_peer --> Connect/Chat)	|
|												||			|
|												\/			|
|	(Someone in Group)							<--- GROUP_PUBLIC_ENTRY_REQUEST		|
|		||													|
|		\/													|
|	(group_add_peer --> Connect/Chat)										|
|_______________________________________________________________________________________________________________________|
		
Connecting to other peers after joining a private group (this message is in-group): TODO
_________________________________________________________________________________________________________________________
|															|
|								GROUP_REQUEST_PEERLIST ---[0]---> Group_Peer		|
|												||			|
|												||			|
|	Group_Ctrl <---(Signature[64])(Timestamp[4+4])+Peercount[4]+Onions[56*peercount]	\/			|
|	||		+Ed25519_pk(s)[32*peercount]+InvitationSignature(s)[64*peercount]--- GROUP_PEERLIST		|
|	||														|
|	\/														|
|	(add new peers)													|
|	GROUP_ENTRY_REQUEST ---GroupID[32]+Group_Ctrl[56]+ed25519_pk[32]+InvitationSignature[64]---> (new) Group_Peer(s)|
|														||	|
|														\/	|
|								Group_Ctrl <---[0]-- GROUP_ENTRY_REQUEST_REPLY_OK	|
|							(update status)				(add new peer)		|
|							(Connect/Chat)				(Connect/Chat)		|
|_______________________________________________________________________________________________________________________|
		
Message Diagram (2024/05/31 version, current). Applies to all protocols except ENUM_PROTOCOL_FILE_PIECE. Integers are in network-order.
_________________________________________________________________________________________________________________________________________________________________
|	Packet Len		[2] uint16_t		Unsigned, every packet. Not included in .message_len							|
|	Protocol		[2] uint16_t		Signed, every packet. Not included in .message_len							|
|	Message Len		[4] uint32_t		Signed, only in first packet. Not included in .message_len						|
|	Message			[.message_len]		Included in .message_len										|
|	{ '\0'	}		{ [1] }			Only where message is expected to a string, included in .message_len (therefore signed if applicable)	|
|	{ Time }		{ [4] uint32_t }	Only on dated messages, included in .message_len (therefore signed if applicable)			|
|	{ NSTime }		{ [4] uint32_t }	Only on dated messages, included in .message_len (therefore signed if applicable)			|
|	{ Signature }		{ [crypto_sign_BYTES] }	Only on signed messages, included in .message_len (NOT ITSELF SIGNED)					|
|_______________________________________________________________________________________________________________________________________________________________|
		
Base protocols Diagrams (2024/05/31 version, current). Describes content of "Message" from the "Message Diagram". [Numbers] are byte counts. 1-8 bytes are unsigned int in network order (Big endian).
_________________________________________________________________________________________________________________________________________________________________________________
|	ENUM_PROTOCOL_FILE_OFFER			CHECKSUM[64] + SIZE[8] + MODIFIED[4] + FILENAME (no null termination)							|
|	ENUM_PROTOCOL_FILE_OFFER_PRIVATE		CHECKSUM[64] + SIZE[8] + MODIFIED[4] + FILENAME (no null termination)							|
|	ENUM_PROTOCOL_FILE_PAUSE			CHECKSUM[64]														|
|	ENUM_PROTOCOL_FILE_CANCEL			CHECKSUM[64]														|
|	ENUM_PROTOCOL_FILE_OFFER_GROUP			HashOfHashes + Splits[1] + CHECKSUM_BIN_LEN *(splits + 1)) + SIZE[8] + MODIFIED[4] + FILENAME (no null termination)	|
|	ENUM_PROTOCOL_FILE_OFFER_GROUP_DATE_SIGNED	HashOfHashes + Splits[1] + CHECKSUM_BIN_LEN *(splits + 1)) + SIZE[8] + MODIFIED[4] + FILENAME (no null termination)	|
|	ENUM_PROTOCOL_FILE_OFFER_PARTIAL		HashOfHashes + Splits[1] + CHECKSUM_BIN_LEN *(splits + 1)) + SIZE[8] + split_progress[section][8] *(splits + 1)		|
|	ENUM_PROTOCOL_FILE_REQUEST			CHECKSUM[64] + START[8] + END[8]											|
|	ENUM_PROTOCOL_GROUP_BROADCAST			crypto_box_SEALBYTES[48] + ( Salt[16] + Onion[56] + ed25519_pk[32] ) 							|
|	ENUM_PROTOCOL_GROUP_PUBLIC_ENTRY_REQUEST	crypto_box_SEALBYTES[48] + ( Salt[16] + Onion[56] + ed25519_pk[32] ) 							|
|	ENUM_PROTOCOL_GROUP_PRIVATE_ENTRY_REQUEST	Onion[56] + ed25519_pk[32] + Invitation[64] (invitation is signature of onion + pk by some invitor from group)		|
|	ENUM_PROTOCOL_GROUP_REQUEST_PEERLIST		Peercount[4]														|
|	ENUM_PROTOCOL_GROUP_PEERLIST			Peercount[4] + onions[56*peercount] + ed25519_pk[56*peercount] { + invitations[64*peercount] }				|
|	ENUM_PROTOCOL_GROUP_OFFER			GROUP_ID[32] + Peercount[4] + invite_required[1]									|
|	ENUM_PROTOCOL_GROUP_OFFER_FIRST			GROUP_ID[32] + Peercount[4] + invite_required[1] + Onion[56] + ed25519_pk[32] (to be signed by invitee)			|
|	ENUM_PROTOCOL_GROUP_OFFER_ACCEPT		GROUP_ID[32] + Onion[56] + ed25519_pk[32] (to be signed by invitor)							|
|	ENUM_PROTOCOL_GROUP_OFFER_ACCEPT_FIRST		GROUP_ID[32] + Onion[56] + ed25519_pk[32] + Invitation[64] (we sign invitor/group-creator's onion + pk)			|
|	ENUM_PROTOCOL_GROUP_OFFER_ACCEPT_REPLY		GROUP_ID[32] + Onion[56] + ed25519_pk[32] + Invitation[64] + Invitation[64] (1st: new invite for them; 2nd: our invite)	|
|	ENUM_PROTOCOL_PIPE_AUTH				Onion[56]														|
|	ENUM_PROTOCOL_PROPOSE_UPGRADE			protocol_version[2]													|
|	ENUM_PROTOCOL_KILL_CODE				User generated explanation ('My house got raided!' etc)									|
|	ENUM_PROTOCOL_UTF8_TEXT				User generated data ('hey how are you?' etc)										|
|	ENUM_PROTOCOL_UTF8_TEXT_DATE_SIGNED		User generated data ('hey how are you?' etc)										|
|	ENUM_PROTOCOL_UTF8_TEXT_PRIVATE			User generated data ('hey how are you?' etc)										|
|	"other"						UI developers can register their own text/binary/stream protocols with the protocol_registration function		|
|_______________________________________________________________________________________________________________________________________________________________________________|
		
ENUM_PROTOCOL_FILE_PIECE Diagram (2024/05/31 version, current)
_________________________________________________________________________________________________________________________________________________________________
|	Packet Len		[2] uint16_t		Unsigned, every packet.											|
|	Protocol		[2] uint16_t		Unsigned, every packet.											|
|	Truncated File Checksum	[4] unsigned char	Unsigned, every packet. To distingush between data from multiple files sent on the same connection.	|
|	Start position		[8] uint64_t		Unsigned, every packet. Offset from the start of the file.						|
|	Data			(up to packet size)	Unsigned, every packet.	Up to PACKET_SIZE_MAX - 16 (sum of above bytes) of data				|
|_______________________________________________________________________________________________________________________________________________________________|
		
Data stored in plaintext on disk (2025/01/10 version, current)
________________________________________________________________________________________________
|	.split Files	CHECKSUM_BIN_LEN + Splits[1] + split_progress[section][8] *(splits + 1)	|
|	Anything intentionally stored in plaintext to any of the databases.			|
|_______________________________________________________________________________________________|
		

Safety

As of intial pre-release (November 2024), this is absolute bleeding-edge alpha software. It's not ready to be used with untrusted peers at this time.

DO:

DO NOT:

Download

Two proof-of-concept TorX UI clients are currently available for Android, Windows, and Linux. It will soon be available for Mac/OSX. Later we intend for it to be available on iOS.

For Android users, please install F-Droid, then click "Settings" --> "Repositories" --> "+" --> "Scan QR Code" (or "Enter repository URL manually" --> https://torx-chat.github.io/)

Alternatively (unsafe), download the TorX.apk file directly, but then you will not get automatic updates.

Current Repository QR Code

For Linux users and others, we're intending to put together some packages but currently you should get it from source and contact us for build support.

Contact / Support

At the present time, due to the alpha status of the software, the preferred method of obtaining support is on IRC. The following channels exist, in order of preference:

The lead developer's IRC nick is "TorX" and their client supports OTR (Off The Record) encryption. Please do not do anything in the channels that violates the respective network's Terms of Service. If you need help connecting to IRC, ask ChatGPT.

If absolutely necessary, the developer can be contacted by email:

Contribute

Click here to see our unified schedule and TODO lists.

We need experienced contributors for the following key technical roles:

You are also welcome to offer contribution of other services:

Contributors are expected to:

Contributions can be provided publically or privately. Contributors are welcome to provide their contributions anonymously.

Contributors' private lives are not our concern. If your public or private life actions cause harm to the image of the project, we may ban your pseudonym, which could require you to evade the ban in order to continue providing your much valued contributions to the project.

If you are interested, join one of our IRC channels