Remember when you were a kid?
You might have had one of those crazy rings that let you send secret messages to your friends.
Secret messages that you would write to your friends weren’t truly secret, but it was novelty and just fun knowing that other people didn’t know what you were talking about.
These rings are called decoder rings and use simple Caesar cipher substitutions. Secret characters were achieved by rotating the alphabet, assigning each letter a new value. Your message in the hands of someone with 30 minutes of free time could be easily cracked, giving them the ability to read all of your messages.
This feeling of nostalgia is what gave me the urge to build a chrome extension that encrypts your Facebook messages from end-to-end. Not only would it be fun, but also secure.
End-to-end encryption means that your messages are fully encrypted before they leave your computer. This makes it so that people can’t steal your messages while they are being delivered to the server. This also means that the messaging platform you’re using can’t read your messages. I like to think that anytime something leaves your computer it’s like leaving your house. You wouldn’t go outside naked right? Put some clothes on your messages!
Encrypting your message will turn it into a string of gobbledygook:
Original Message:This is a secret!
Encrypted Message:MyjDqDUIATABEiEFwoMPwqvChMKkV3gUL8KKYsKKcDXDq2zDhsOUcsKuw7/CvhYmw4wdGkzDmiDCk0QaIQXCvsOMOkARwoJrEWDDrFkCYwfCnx7DrS8zwoPDkcOwLxQCFMOuw6fCnsOSw6MBIlIzCiEFF8OhwoNQeQEkw74CwqbCiiDDjnoHwpYgTMKwwrtvwofCqA42w4/DqWI7QikNEAAYACIgwrMXwp0/w7DDusOHTMOXwp3Co0XDr8K1KcO5wpROwr7DhsKUU8ONwr4jw4wiwptSDzXDs1vDssKOwr42H8Kawo0=
Great! I doubt anyone would be able to read that!
However… your friend needs to be able to read that 😝
If you want your friend to be able to unlock your message they will need the key to the lock. If it was our lock, we could just send them our key! Butttt…. we don’t want to just send them the key right? Because then someone can steal the key and unlock our message 😵 So what do we do?
We can get around this problem by using “asymmetric encryption”.
Think of it like this… When you want to send your message, ask them for a lock. They should be the only ones with the key to this lock. Now when you lock and send it, only your friend can open it and you don’t have to exchange any keys.
With asymmetric encryption you are dealing with pairs of public and private keys. Public keys can be thought of as the unlocked lock and can be freely distributed to all your friends. Private keys are the actual key and are to be kept top secret in a safe place.
In order to send encrypted messages we need to figure out how to send regular messages. This is the core information needed to send a message through Facebook:
RECIPIENT_ID
)MESSAGE_ID
)fb_dtsg
token (TOKEN
)C_USER
+ XS
)The recipient ID, fb_dtsg
token, and cookie can be easily grabbed from inspecting Facebook Messenger’s network activity.
Note: You have to send a message after you open the network panel.
Message IDs, on the other hand, have to be unique. If message IDs clash then the message will never appear.
How does Facebook generate its IDs?
message_id: 6306169721153220898timestamp: 1503508024490
I found that dividing the message_id by the timestamp equals ~4,194,304. This happens to be a power of 2 or 2²² to be exact. Facebook shifts the timestamp to the left by 22 bits and fills in the empty bits with a random number.
Here is an example cURL command for sending a message:
curl 'https://www.messenger.com/messaging/send/' \-H "cookie: \c_user=C_USER; \xs=XS;" \-d "action_type=0\& body=My message.\& has_attachment=false\& message_id=MESSAGE_ID& offline_threading_id=MESSAGE_ID& other_user_fbid=RECIPIENT_ID& source=0\& timestamp=0\& fb_dtsg=TOKEN"
Note: Be sure to replace C_USER
, XS
, MESSAGE_ID
, RECIPIENT_ID
, and TOKEN
with your own values. (For testing purposes, it is safe to just add 1 to the last sent _MESSAGE_ID_
)
Now that we can send messages, we need an actual interface. Chrome extensions give you a tremendous amount of power. You have complete control over any website. You can restructure html, manipulate css, and even inject scripts. If the user is on Facebook Messenger you can steal their cookies and determine which user they are talking to. This is exactly what we need.
Building an extension is easy to do if you have some experience with web programming. It’s just like building a website, on top of a website. If not, have no fear, Google has a very thorough walkthrough for building extensions, along with some helpful sample projects.
Since I don’t want to turn this into a tutorial for chrome extensions, I will just leave you with the source code for the project. (Don’t hesitate to contact me if you need some additional help)
To run your extension, follow these steps:
chrome://extensions
in your browserAs noted earlier, we need to use some form of asymmetric encryption. It’s a good idea to use a battle tested library when dealing with security. From what I’ve found, WhisperSystems’ Signal Protocol is the go-to encryption for messaging. It leaves a lot of room for implementation freedom, because Signal is just a protocol. This freedom lets us deal with a few tradeoffs.
When encrypting a message for your recipient, it’s encrypted in such a way that only the other person’s private keys can decrypt your message. Not even YOU can decrypt the message.
If you want to be able read your own messages there are a few approaches. One way is to encrypt it twice, once for you and once for the recipient. This is a bit slower because we have to encrypt everything twice. It’s also a tad less safe. The recommended approach is to store the decrypted message locally on the client.
The protocol recommends using a unique public key for every message you send. This preserves the secrecy of older messages. If your private key gets leaked only one message will be compromised, not your entire conversation. However, this means that you can only decrypt a message once.
This gives rise to the need of storing a lot of keys on the server. If a user runs out of public keys they can’t receive messages. Meaning, if somebody goes offline and they only have 100 keys, we can only send them 100 messages until they’re back online.
A possible middle ground could be generating a new key every x hours. This way users can always send messages, decrypt them multiple times, and we only need to store one key on the server at a time.
This project has been a wild roller coaster and is far from finished. If you are interested in the code behind the project, you can grab it here and check out the actual extension here. Have fun, be creative and keep on hacking!
Thanks for reading! If you have any questions, feel free to reach out at [email protected], connect with me on LinkedIn, or follow me on Medium and Twitter.
If you found this article helpful, it would mean a lot if you gave me some claps👏 and shared with friends.