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.
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.
“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.
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?
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.
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 |
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])
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 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:
shared_secret = ECDH(sender_pub_key, recepient_pub_key, recepient_priv_key, NID_X9_62_prime256v1, KDF_SHA256);
message_key = AES_GCM_256(enc_message_key, shared_secret, enc_message_key[16:32], AAD);
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 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:
passcode_key = PBKDF_SHA1(passcode, salt, iterations);
passcode_secret = AES_CBC_128(enc_string, passcode_key[0:16], passcode_key[16:32]);
beiquohnoikai9pai3afai5najoog3Tan2xahjai8gaigogeC7dahMihe6Eeke9QuohX6gah1ue3be4mah6woo3oofootab2thae3phaigai5eeghoo6suixoh7woo1v
If there is a match, the password is successfully verified.
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.
None of the data is stored in either iCloud or iTunes backups, with or without a password. Speaking of Confide, logical acquisition is useless.
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.
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 »