Developing properly end-to-end communication systems is complex. As we have seen in the past with iMessage , even if cryptographic primitives are correctly implemented and encryption keys are correctly generated and protected, the design is critical to forbid the service operator from being able to eavesdrop messages.

The encryption protocol will be particularly detailed because it is tagged as battle tested, military grade cryptography. We already knew about military grade cryptography, which seems to be a synonym of put AES-256 somewhere, no matter how you use it in many applications, but we had never heard of battle tested cryptography. This article is an opportunity to present this technology.

In recent weeks, Confide, a secure instant messaging application, has gained popularity in some circles. This article presents a quick assessment of the security of this application. The official website boasts the confidentiality provided by the product through three qualifiers: encrypted, ephemeral and screenshot protected. Each of these aspects will be studied.

TL;DR: Confide server can read your messages by performing a man-in-the-middle attack. Other security features (screenshot prevention, message deletion) can be defeated and will be detailed in a future article.

This can be circumvented by simply removing the check or by replacing the logical or by a logical and . The communications are now correctly captured and decrypted by Fiddler, and the application is fully functional. Let us now detail the protocol.

The server public key is pinned: the SHA-256 of the public key of the certificate returned by the server is compared to a hash hardcoded in the application:

The TLS connection now succeeds. However, Confide refuses to start and displays an error message, as can be seen in the following screenshot:

The strictSSL parameter can be replaced in the Confide code. It is initially set to !0 (true), and can be modified to !1 (false). Thus, connections with self-signed certificates will be accepted.

Communications are then intercepted by Fiddler, but the TLS handshake between Confide and Fiddler fails. This is because Confide tells the request module to allow only valid TLS certificates. This behavior can be changed using the strictSSL parameter:

Fiddler registers as a system proxy when it is started, and thus intercepts all communications. Confide connections are made using the node request module, which does not respect the system proxy settings under Windows. However, it is possible to specify a proxy using environment variables, as indicated in the module documentation:

All the communications exchanged between two clients pass through the Confide server ( https://confideapi.com ). Communications are protected by TLS. The first step required to analyze the traffic is to retrieve plaintext communications. A web proxy such as Fiddler can be used.

The application code is located in an asar archive. This archive contains the client, written in JavaScript, as well as node.js modules in JavaScript and native code. The client code is minified but remains very understandable.

Confide was developed with the Electron framework. This is a node.js framework for developing desktop applications with web technologies. The article presents the results of the study of Confide 1.4.2 and 1.4.3 under Windows. The code for the macOS application is probably very close. The one from iOS and Android was not analyzed.

This first part presents quickly the modifications made to the client to analyze the Confide protocol. It allows the reader to reproduce the attacks described in this article.

These messages can be encrypted or not: in fact, the demo message sent by Confide after registration is not encrypted. All other messages (at least all the messages we have sent) are encrypted. The encryption mechanism is now detailed.

When a message is sent to a client, it is notified through a WebSocket which is opened when logging on. The client then retrieves the list of unread threads with a GET request on /v1/threads?v=2 . Each thread consists of a list of "participants" and a list of unread messages.

After authentication, fixed identifiers are no longer used: in all other types of queries made by the client, the authorization field contains the token returned by the server.

The value of this field is actually fixed: the user name and the password of the Basic authorization field are stored in a slightly obfuscated and encrypted form in the cc proprietary node module. This mechanism is probably aimed at preventing an alternative client from communicating with the Confide server.

The most surprising part of the authentication request is the presence of an authorization HTTP header although no secret has been exchanged so far:

The data sent by the client has the following form:

After the account is created, the user must authenticate to the server. The user email and password are transmitted to the server through a POST request. The server returns some JSON data containing an authentication token.

A POST request to /installations/set sends to the server a UUID corresponding to the device on which Confide is installed. The server then returns the UserId , its public key and an InstallationId . This InstallationId , as we will see later, is used by Confide for synchronization on several devices.

The user authenticates (see below), and generates an ECDH key for the P-256 curve. It transmits the public part to the server in an unconventional way: it is sent in an HTTP header named Public-Key with all the requests of the user.

An e-mail or SMS containing a link to follow to activate the account is then sent to the user.

The server returns JSON data containing the profile of the created account: one may find in particular the last name and first name of the user, a UserId and a random alphanumeric username , probably used internally. This profile can then be retrieved with a GET request on /users/me once authenticated.

These pieces of information are sent to the server using a POST request on /users/create :

A user account must be created to use Confide. A valid phone number or e-mail is required. The user is then prompted to enter his / her last name, first name and password.

The protocol is not fully described here: only the steps that seemed necessary to us to analyze the end-to-end encryption are detailed.

End-to-end Encryption

The Encryption paragraph on the application website stipulates that:

Confide uses battle tested, military grade cryptography to keep your messages safe and secure. We combine this with a simple and intuitive user experience to provide superior security, with no configuration required.

All messages between Confide users are end-to-end encrypted. Encryption keys are generated locally on each device and the private key never leaves the device, ensuring that only the intended recipients can read your messages.

All communication goes through Transport Layer Security (TLS), preventing any possible man-in-the-middle attack and providing yet another layer of security, privacy and data integrity.

In this section, we show that the protection provided by Confide heavily relies on TLS and the security provided by this end-to-end encryption is very low. In particular, Confide can read user messages.

Each contact has a public key, which is included in the contact profile (recall that the public key is an ECDH key on P-256). The profile of each contact can be retrieved by searching the server. This search can be made by phone number, e-mail address or "username". We did not manage to make the "Search by username" work during our tests. It might be disabled.

Sending a Message When sending a message to one or more recipients, the client: Generates an AES-128 encryption key K and a 128-bit initialization vector IV.

Creates an empty array conversationKeys .

. For each recipient i: Computes a shared secret Si with ECDH using the sender private key and the recipient public key. Generates a 128-bit initialization vector IVi. Generates an AES-128 key Ki = SHA1(Si). Only the first 128 bits are retained. Encrypt K with Ki and IVi using AES-128-CBC and add the result to conversationKeys .

The client gets a conversationKeys array containing the key K encrypted for each of the recipients. The content of the message is then processed. The client: Encrypts each attachment (picture, video...) of the message with K and IV using AES-128-CBC.

Transmits each encrypted file to the server, which returns a unique file identifier for each file.

Encrypts the text of the message with K and IV using AES-128-CBC.

Sends the encrypted message, attachment IDs, and conversationKeys to the server. The text and attachments are therefore encrypted with the same pair (K, IV). No cryptographic integrity mechanism is present. The cryptographic protocol does not involve authentication, which hence relies on the Confide server.

Receiving a Message When a client is notified that a new message is being received, it requests the list of its unread threads. The server sends the threads, which include the list of the participants as well as the encrypted message addressed to the recipients and the sender public key: "Threads" : [{ "Participants" : [{ "UserId" : 828258 , "Username" : "bkqb5bq9" , "FirstName" : "Nadine" , "LastName" : "Alcover" , "LastMessageSent" : { "DateSent" : "2017-03-01T15:39:34Z" }, "LastMessageReceived" : { "DateRead" : "2017-03-01T15:13:50Z" } }, { "UserId" : 828569 , "Username" : "rk727f79" , "FirstName" : "Lou" , "LastName" : "Tausk" , "LastMessageSent" : { "MessageId" : 97795492 , "DateSent" : "2017-03-01T15:13:36Z" } } ], "UnreadMessages" : [{ "MessageId" : 97800395 , "DateSent" : "2017-03-01T15:39:34Z" , "SenderPublicKey" : "0324274E88A29962D48DAC6916C49BA0EA51466738F90015420CFA54AD94D0B13A" , "EncryptedMessageKey" : "BpOjb8KZfaQR/qHEWW66ZddUsZR/qKQiIbkVfDRy1ZYJqNcFG4VWtRQRoieexTR/17DQREIgQAegaPj2+TRSog==" , "TextContent" : "j2RDcxLYPRVyB/OSKWJknA==" , "SenderUserId" : 828258 , "FormatVersion" : 1 } ] } ] The recipient has no way to verify the origin of the message. It cannot check the sender's public key authenticity either. It decrypts the message encryption key with its private key and the SenderPublicKey field, and then decrypts the message content. The message integrity, again, cannot be verified.

Man-in-the-middle from the server The most obvious problem is not the reuse of the IV or the lack of integrity mechanism, it is linked to the fact that the encrypted message origin and the authenticity of the public encryption key transmitted by the server can in no way be verified by the client. Thus, the Confide server could generate its own key pair and transmit the public part to a client when the latter requests the public key of a recipient (we only note that Confide is able to do so, not that it does so). This client then unknowingly encrypts a message that can be decrypted by the server. Finally, when the server sends the message to the recipient, it is able to re-encrypt the message with its own key for the actual recipient. This is a classic man-in-the-middle attack against Diffie-Hellman based protocols, which works by design of the Confide protocol. Confidentiality of the communications is in fact provided by TLS, and not by the end-to-end encryption mechanism provided by Confide. This limits the possibilities of MitM to the Confide server, which acts here as a trusted third party. We will now see that an even more important problem is present in the protocol.