# StopMe - An end-to-end encrypted messaging application This application is built on the IPFS network. It allows for anyone to communicate with anyone else provided they join the conversation. No messages or data are stored in any centralized servers. The system is completely decentralized and distributed. ## How it works ### Definition of Terms Application - The program that makes this system possible. User - A person or bot that interacts with the application. Client - An instance of the application running on a specific device. Trusted Shared Devices - A list of devices that have gone through the join-account process performed and verified by the user. Contacts - A list of users (friendly names entered by the user or shared to the user from the contact's devices). The Contact object can contain a list of clients trusted by the Contact through which a contact can be reached. The application can/will hide these clients from the user and simply send messages to all clients for a given contact. ### Globally Unique Users Each client is uniquely identified by their public key. The pub/sub channel they listen on matches the IPFS address of their public key. Clients will maintain contact lists for the clients with whom they communicate. Clients can also share public addresses of other devices owned by the same user. See "Multiple Devices" below. ### Starting Conversations and Sending Messages Clients listen on a pub/sub channel based on their globally unique username. In order to start a conversation client A sends a conversation request to that user's public channel sending their username and a public key. The user of Client B can choose to accept or ignore a conversation request. If they accept the request then Client A's public key is stored and a conversation ID is generated. The conversation ID is encrypted with Client B's public key and is sent along with Client A's public key. Client B will store Client A's public key for future use. The two clients are now able to send encrypted messages to each other. Once a key exchange and conversation has been established the message sending proceeds as follows. If Client A wants to send a message to Client B, then the user of Client A will compose a message. Client A will generate a crypto-safe random password which will be a shared secret. The message is then encrypted with that password plus an initialization vector (google shared secret crypto with initialization vector for more information). The password is then itself encrypted using the public key of Client B (this way only Client B's private key will be able to decrypt the password). Lastly, a pub/sub message is composed with the encrypted password and encrypted message. A signature is generated using Client A's private key in order to provide validation and proof that the message was indeed sent from Client A. Message structure: ```proto message Message { string password = 1; // encrypted by Client B's public key string conversationID = 2; // encrypted using `password` string contents = 3; // encrypted using `password` string signature = 4; // generated using Client A's private key signing contents+conversationID+timestamp+nonce int64 timestamp = 5; // unencrypted int64 nonce = 6; // unencrypted } ``` Once a user has accepted a conversation request for a given user then the new contact will be created and their client can share a list of their trusted clients/devices (see multiple devices below). ### Multiple Devices Each client will store a list of clients and their public keys that have been verified as owned by the same user. This verification process is as follows: A user has already set up and used Client A. Now they want to add their phone as a client (we'll call it Client P). The user will turn on a special mode on Client A called "Add new device". This puts Client A into a mode where it is listening for a "join-account" message. The user will then tell Client P to "join-account". There will be a code presented on Client P's screen. The user will then enter the code on Client A. Client P will have sent the code to Client A through its pub/sub channel along with a signature. Client A compares the entered code with the one it received from Client P, also ignoring all other "join-account" messages potentially spammers. If the codes match then Client P's public address and key are stored on Client A as a trusted device. The reverse will happen as well but in this case the user will not need to set Client P into the "Add new device" mode, it will simply ask for the code displayed on Client A. That code is also passed via pub/sub channels so Client P can verify it. Client A and its public keys are then stored on Client P's trucsted client list. Shared devices will then proceed to send each other contact lists, message histories, conversation requests and other trusted devices. Since shared trusted devices will each need to receive their own encrypted versions of each message, each client will broadcast to known contacts the updated list of clients at which a given user is reachable. The application should broadcast to contacts its trusted shared devices on a periodic basis. This way those contacts will be more likely able to contact an available device and send and receive messages from different devices from the same user. ### Removing a Device (lost or stolen) Private Keys will be stored on devices using passcodes or fingerprint locks. On devices that support it the Private Keys will be stored in the TPM. Trusted client lists when shared between devices or contacts will need to be signed by these private keys. A user can remove a device from the trusted list by unlocking the private key and publishing an updated trusted device list signed by that private key. Other trusted devices will receive these messages and update their own trusted device lists accordingly.