Researching Confide Messenger Encryption

June 8th, 2020 by Ivan Ponurovskiy
Category: «Mobile», «Security», «Tips & Tricks»

iPhone users have access to literally hundreds of instant messaging apps. These apps range all the way from the built-in iMessage app to the highly secure Signal messengers, with all stops in between. Many of the messaging apps are marketed as ‘secure’ or ‘protected’ messengers, touting end-to-end encryption and zero retention policies. We routinely verify such claims by analyzing the security of various instant messaging apps. It turned out that the degree of protection can vary greatly, having little to do with the developers’ claims. Today we’ll check out Confide, a tool advertising unprecedented level of security.

Instant Messengers and Security

No messenger advertises “no security”. Most app developers advertise “secure encryption”, “end-to-end encryption”, or even “256-bit AES encryption” somewhere along the lines. Those claims mean very little in real life. TLS communications are encrypted by default, using “military grade” AES-256 encryption whether or not an app developer makes a concise effort. As a result, we’ve seen apps that only encrypt messages in transit, while the device itself keeps them in a plain database. We’ve also seen encrypted on-device databases with an encryption key keep in plain view or stored in the keychain with a low protection class. We’ve seen messages stored in the cloud, accessible via an easily extractable token or with a password cached somewhere on the device or kept in the keychain. In other words, the “secure messenger” moniker has been completely devalued, with each claim requiring thorough validation and verification by independent security researchers. We used Elcomsoft iOS Forensic Toolkit to extract Confide data and decrypt the relevant keychain records.

Confide

Your Confidential Messenger. Communicate digitally with the same level of privacy and security as the spoken word. With encrypted, self-destructing, and screenshot-proof messages, Confide gives you the comfort of knowing that your private communication will now truly stay that way.” Is this a marketing ploy, or is Confide a truly secure solution for confidential communications? We’ll try to find out.

When security goes overboard

Confide makes strong impression straight from the get-go. Messages are initially displayed as masked rectangles. In order to read a message, the user would have to touch the rectangle. Even then, Confide ensures that only a single line of the message is unveiled at a time. In addition, the sender’s name is not simultaneously visible when reading the message.

The messages are ephemeral. Confide claims to remove messages from the cloud and wipe them from the device immediately after they are read (or after 48 hours). Finally, Confide claims to implement a patented screenshot-proof technology (ScreenShieldKit).

Naturally, Confide uses all the familiar key words talking about encryption. Below is a quote from the company’s Web site:

Industry-Standard Cryptography

Confide utilizes industry-standard 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.

End-to-End Encryption

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.

Transport Layer Security

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.

So what does Confide do on iOS devices to encrypt and secure user data?

Keychain

All critical information is stored in the iOS keychain. Below is the full list of records stored in the keychain and their protection class, including the encryption keys.

Keychain Item Protection Class
BranchKeychainFirstBundle kSecAttrAccessibleWhenUnlockedThisDeviceOnly
BranchKeychainFirstInstall kSecAttrAccessibleWhenUnlockedThisDeviceOnly
Temp kSecAttrAccessibleWhenUnlockedThisDeviceOnly
KFKeychainUserID kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
KFKeychainUsername kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
KFKeychainAccessToken kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
KFKeychainPublicKey-<USER_ID> kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
KFKeychainRefreshToken kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
KFKeychainPasscodeData kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
KFSerializationAfterFirstUnlockEncryptionKey kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
KFKeychainPrivateKey-<USER_ID> kSecAttrAccessibleWhenUnlockedThisDeviceOnly
KFSerializationEncryptionKey kSecAttrAccessibleWhenUnlockedThisDeviceOnly

The kSecAttrAccesibleWhenUnlockedThisDeviceOnly protection class means that the record is only available once the device screen is unlocked; it is only available on that particular device (meaning that the record cannot be restored from a backup onto a different device, even of the same model). This is the highest protection class available in iOS. Records protected with kSecAttrAccesibleAfterFirstUnlockThisDeviceOnly are always accessible on that particular device after the device has been first unlocked.

Let’s have a closer look at the following records: KFKeychainUserID, KFKeychainPublicKey-<USER_ID>, KFKeychainPasscodeData, KFSerializationAfterFirstUnlockEncryptionKey, KFKeychainPrivateKey-<USER_ID>, KFSerializationEncryptionKey. These records are used for encrypting the app’s data.

All messages and user data are stored encrypted in the following folder: /var/mobile/Containers/Shared/AppGroup/Confide/ConfideData/.

The folder contains files with 64-character names, e.g. f851aae5453dd9375317564efc84393a6cfb195a870044dfa6ae8af3960b228b.

While file names look random, they are in fact generated according to certain rules.

How file names are encrypted

  • Input: plain-text file name.
  • Serialization key obtained from the keychain: KFSerializationAfterFirstUnlockEncryptionKey (if the device is locked), or KFSerializationEncryptionKey (if unlocked). The serialization key is 32 bytes long.
  • The file name is encrypted with AES_128_CBC, the iv consists of the first 16 bytes of the serialization key, the encryption key uses the last 16 bytes.
  • The encrypted string is hashed with a single round of SHA256, producing the new file name:
enc_filename = SHA256(AES_CBC_128(filename, ser_key[0:16], ser_key[16:32]))

Why does Confide encrypt file names? The file names may give a hint to their content. The following plain-text file names are encrypted. It turns out that on different devices the file names will be different, since the names depend on the serialization key, which in turn is randomly generated when the app is installed.

Confide possible filenames
lastSentMessage-2016-07-14
blockedUsers-2016-05-12
friendsWhoAddedMe-2016-05-12
favoriteThreads-2014-06-03
recentThreads-2014-06-03
expiredMessageIds-2014-07-25
hiddenUserIds-2014-07-17
hiddenContactSuggestions-2017-03-20
friendsWhoAddedMeThreads-2016-07-05
cycledContactSuggestions-2017-03-20
organizations-2015-12-17
userInstallations
connections
extension-contacts-2016-08-17
hiddenFriendsWhoAddedMeUserIds-2016-06-21
archivedThreads-2014-06-03
safetyCodes-2017-04-01
raw_threads_json
addressBookUsers-2014-01-13
hiddenContactSuggestions-2015-05-04
cycledContactSuggestions-2015-05-04
deepLinkAction-2016-06-02

How file content is encrypted

Once the app is closed or minimized, all settings and unread messages are serialized, encrypted, and written to the folder /ConfideData as bplist. The data is encrypted with AES_128_CBC, the iv also employs the first 16 bytes of one of the serialization keys, while the encryption key consists of the last 16 bytes.

enc_content = AES_CBC_128(filename, ser_key[0:16], ser_key[16:32])

Last message sent

In the application settings, there is an option to save the history of sent messages. The “history” here refers to just a single message, the last message sent. This last message is stored in a file lastSentMessage-2016-07-14. Once decrypted, the content of the file can be deserialized (initWithCoder:) using the KFLastSentMessage class:

class KFLastSentMessage {
              NSDate               *dateSent;
              NSString             *textContent;
              BOOL    hasAttachment;
              NSInteger attachmentType;
} 

The unencrypted last sent message will be stored in the textContent variable. If the user disables the History option, the last message will not be saved.

Received messages

Received messages are stored in the file recentThreads-2014-06-03. Once decrypted, the content of the file can be deserialized with the KFThreadMessage class:

class KFThreadMessage {
              NSNumber         *messageId;
              NSInteger  formatVersion;
              NSDate               *dateSent;
              NSString             *senderPublicKey;
              NSData               *encryptedMessageKey;
              NSString             *attachmentId;
              NSNumber         *senderUserId;
              NSString             *encryptedTextContent; 
}

Received messages are encrypted and stored in the encryptedTextContent variable. The message decryption algorithm is as follows:

  1. Read encryptedTextContent and decode from base64.
  2. Read open and private recipient keys from the keychain (KFKeychainPublicKey-<USER_ID>, KFKeychainPrivateKey-<USER_ID>).
  3. Read the sender’s open key (senderPublicKey) from the decrypted recentThreads-2014-06-03.
  4. Using the three keys, generate the common secret with Diffie-Hellman algorithm. The elliptic curve is NID_X9_62_prime256v1, and the Key Derivation Function (KDF) is SHA256. The resulting 32-byte key is used to produce the encrypted message key (encryptedMessageKey). The length of the encrypted message key is 60 bytes:
shared_secret = ECDH(sender_pub_key, recepient_pub_key, recepient_priv_key, NID_X9_62_prime256v1, KDF_SHA256);
  1. The message key is encrypted with the AES_GCM_256 algorithm, the key being the shared secret obtained in the previous step, and iv being the bytes 16 through 32 of the encrypted message key. In addition, the so-called Additional Authenticated Data (AAD) is used for encryption. AAD is an additional layer of encryption security that guarantees message integrity and authenticity. Four AADs are used to encrypt the key: the message format version (formatVersion), the sender ID (senderUserId), the sender’s public key (senderPublicKey), and the recipient’s public key (recepientPublicKey). All this data is fed to the AES_GCM_256 In case of successful decryption, a 32-byte message key (messageKey) is obtained.
message_key = AES_GCM_256(enc_message_key, shared_secret, enc_message_key[16:32], AAD);
  1. All that’s left is decrypting the message itself. The message is also encrypted with AES_GCM_256, the encryption key being the previously decrypted message key, the iv being the bytes 16 through 32 of the encrypted message. AAD is not used when encrypting messages.
message = AES_GSM_256(enc_message, message_key, enc_message[16:32])

If the user has several unread messages, then each message will have a unique (encrypted) message key.

The app password

The user can optionally set a password that will be prompted when the application is launched or brought foreground. Password data is stored in the keychain as KFKeychainPasscodeData, for example:

$1$50000$EJktlLyT6B3sU8uuiAtlajwal1K2QIi0FuyA/uEv8uc=$7T9aLOojzxJAQdwV5FxhIs01yYCCWP//Abx+++QCGWjrnWRfhzKoH113++KE36OClV79U9/fWoiuX/i4p7PMb90zbzOpcX38myKGmhUm7jGRVj83y+yvkfZxmE/s7nR+hROXbVq9DmFMnb+HDZiTusYOR5JOdwqAMIbVxZlpZhvHGyO3WLdvJQiTszsZ9U7G

Elements are separated with the ‘$’: version number (1), the number of iterations (50,000), the salt, and the string encrypted with the encryption key derived from the user’s password. The app password does not affect the encryption of stored or transmitted messages.

To following algorithm checks the app password:

  1. The password is turned into a key with PBKDF_SHA1; the salt and the number of iterations are read from the KFKeychainPasscodeData keychain record.

passcode_key = PBKDF_SHA1(passcode, salt, iterations);

  1. Next, the algorithm attempts to decrypt the string from the KFKeychainPasscodeData record using AES_128_CBC, the iv being the first 16 bytes of the key derived in the previous step. The encryption key is the last 16 bytes.
passcode_secret = AES_CBC_128(enc_string, passcode_key[0:16], passcode_key[16:32]);
  1. The result is compared with the following string:
beiquohnoikai9pai3afai5najoog3Tan2xahjai8gaigogeC7dahMihe6Eeke9QuohX6gah1ue3be4mah6woo3oofootab2thae3phaigai5eeghoo6suixoh7woo1v

If there is a match, the password is successfully verified.

Attachments

The user can attach audio, video and image files. Attachments are only downloaded once the user begins to interact with them (e.g. starts watching the video or listening to the audio file). Attachments are deleted immediately after the message is closed or the Confide app is minimized. Therefore, one cannot find any traces of the attachments in the file system.

iOS backups

None of the data is stored in either iCloud or iTunes backups, with or without a password. Speaking of Confide, logical acquisition is useless.

Conclusion

From what we see, Confide brought security a bit overboard. If there is a balance between convenience and security, Confide is about 110% security and negative 10% convenience. The paranoid privacy setting, the patented counter-screenshot measures, and the obscure message reading UX are complemented with by the book implementation of internal security. Confide ticks all the right marks by storing relevant information in keychain records protected with the highest protection class, and encrypting everything that can and should be encrypted. Even in worst-case scenario (an iPhone with a known or compromised passcode with jailbreak available), the examiner would only be able to access unread messages and (if the corresponding option is ticked in the app settings) the last sent message. There is no message history to speak of, and no trace of attachments.

 


REFERENCES:

Elcomsoft iOS Forensic Toolkit

Extract critical evidence from Apple iOS devices in real time. Gain access to phone secrets including passwords and encryption keys, and decrypt the file system image with or without the original passcode. Physical and logical acquisition options for all 64-bit devices running all versions of iOS.

Elcomsoft iOS Forensic Toolkit official web page & downloads »