title | date |
---|---|
Direct Message Extension |
2025-01-18 |
The Direct Message Extension introduces a secure way for two users to send encrypted messages to each other within the twtxt ecosystem. Direct messages (DMs) leverage public/private key cryptography to ensure that only the intended recipient can read the message. This extension also enables metadata to specify a user's public key, ensuring compatibility with encryption protocol (Curve25519).
Direct messages are encoded and include the recipient's username and the encrypted message payload. This allows the message to remain private while adhering to the structure and principles of the twtxt format.
A typical direct message will contain the following structure:
!<nick url> <encrypted_message>
Here:
nick
is the intended recipient's nickname.url
is the public URL to the recipient's twtxt feed.<encrypted_message>
is the ciphertext encrypted using the recipient's public key.
-
Public Key Declaration: A new metadata field named
public_key
must be present in the user's twtxt feed. This field should contain a URL pointing to the user’s public key file.Example:
# nick = example # url = https://example.com/twtxt.txt # avatar = https://example.com/avatar.png # description = An example feed # public_key = https://example.com/public_key.pem
The public key must be in a valid PEM format.
-
Encryption of DMs: Direct messages must be encrypted using the recipient's public key to ensure confidentiality. Any modern cryptographic library supporting EC (Elliptic Curve) public/private key encryption can be used for this purpose.
-
DM Syntax: Direct messages must explicitly target the recipient using the
!<nick url>
syntax before the encrypted payload.Example:
2025-01-18T18:20:00Z !<joe https://example.com/twtxt.txt> 1234567890abcdef=
Here,
1234567890abcdef=
represents the Base64 encoded ciphertext.
The mandatory public_key
metadata field allows feed authors to publish their public key. Clients can use this key to encrypt messages for the feed author. The key must be accessible via a secure HTTPS link. This ensures that only the author can decrypt the message using their private key.
# public_key = https://example.com/public_key.pem
When sending a direct message:
- Retrieve the recipient's public key from their
public_key
metadata URL. - Encrypt the plaintext message using the public key.
- Encode the ciphertext (Base64).
- Add the new line to the twtxt feed with the recipient's
nick
andurl
followed by the encrypted message.
Let’s assume two users, alice
and bob
, want to communicate privately.
-
Key Generation: Alice and Bob each generate a public/private key pair using Curve25519 algorithm with
openssl
:openssl genpkey -algorithm X25519 -out alice_private_key.pem openssl pkey -pubout -in alice_private_key.pem -out alice_public_key.pem
openssl genpkey -algorithm X25519 -out bob_private_key.pem openssl pkey -pubout -in bob_private_key.pem -out bob_public_key.pem
-
Setup:
Alice declares her public key in her
twtxt.txt
metadata:# nick = alice # url = https://alice.example.com/twtxt.txt # public_key = https://alice.example.com/alice_public_key.pem
Bob does the same in his feed:
# nick = bob # url = https://bob.example.com/twtxt.txt # public_key = https://bob.example.com/bob_public_key.pem
-
Encrypting the Message:
Bob wants to send a private message to Alice. Using Alice's
public_key
, Bob encrypts his message using Openssl:- First, Bob retrieves Alice's public key:
wcurl https://alice.example.com/alice_public_key.pem > alice_public_key.pem
- Calculate the share key:
Bob use his private key and Alice's public key to calculate the shared key:
openssl pkeyutl -derive -inkey bob_private_key.pem -peerkey alice_public_key.pem -out shared_key.bin
Then, Bob encrypts the message using the shared key. The message is storage in
message.enc
:echo -n "Hi Alice, let’s meet tomorrow at 5 PM!" | openssl enc -aes-256-cbc -pbkdf2 -iter 100000 -out message.enc -pass file:shared_key.bin
- Bob encodes the encrypted message in Base64:
base64 -w 0 < message.enc > message.enc.b64
Check
message.enc.b64
for the encrypted message:U2FsdGVkX1+mVLsw62BUyjcjnAVtU/EP04gS9GuTsD8xW66BH3V+kb828lMswrDntCtKgauLDZEDRCmpAo3lcQ==
This will be the string of the direct message.
-
Sending the Message:
Bob appends the encrypted message to his feed:
2025-01-18T18:20:00Z !<alice https://alice.example.com/twtxt.txt> U2FsdGVkX1+mVLsw62BUyjcjnAVtU/EP04gS9GuTsD8xW66BH3V+kb828lMswrDntCtKgauLDZEDRCmpAo3lcQ==
-
Reading the Message: Alice’s client fetches the message from Bob’s feed and review if the message is for her. She would see
!<alice https://alice.example.com/twtxt.txt>
.Using her private key, Alice decrypts the message:
- First, Alice retrieves Bob's public key:
wcurl https://bob.example.com/bob_public_key.pem > bob_public_key.pem
- Calculate the share key:
Alice use her private key and Bob's public key to calculate the shared key:
openssl pkeyutl -derive -inkey alice_private_key.pem -peerkey bob_public_key.pem -out shared_key.bin
- Alice decodes the encrypted message from Base64:
echo 'U2FsdGVkX1+mVLsw62BUyjcjnAVtU/EP04gS9GuTsD8xW66BH3V+kb828lMswrDntCtKgauLDZEDRCmpAo3lcQ==' | base64 -d > message_from_bob.enc
- Alice decrypts the message using the shared key.
openssl enc -d -aes-256-cbc -pbkdf2 -iter 100000 -in message_from_bob.enc -out message_from_bob.txt -pass file:shared_key.bin
Check
message_from_bob.txt
for the decrypted message.cat message_from_bob.txt
Resulting in the plaintext message:
Hi Alice, let’s meet tomorrow at 5 PM!
-
Key Verification: Users should ensure public keys are genuine and match the feed owner to mitigate man-in-the-middle attacks.
-
Encrypted Payload Visibility: While the payload is encrypted, all users viewing the feed will see the recipient
nick
andurl
. This preserves openness but prevents eavesdroppers from reading the message. -
Private Key Security: Users must securely store their private keys and avoid exposing them. A compromised private key can lead to the decryption of all previously sent messages.
-
Replay Attacks: Clients should implement measures to detect and ignore duplicate messages to prevent replay attacks.
For clients to support the Direct Message Extension, they must:
- Parse metadata to retrieve the
public_key
field. - Implement encryption and decryption using public/private key cryptography.
- Render direct messages prefixed with
!<nick url>
. - If a client does not support this extension, it should ignore direct messages.
- 2025-01-18: Initial draft.