Threema contains a "Validation Logging" feature that makes it possible for anyone to independently confirm that messages sent via Threema are end-to-end encrypted using the NaCl Networking and Cryptography library. It works by logging the raw encrypted message as it was generated by the sender to a text log file that can be emailed from within the app. Using the sender's public key and the recipient's private key, the message can be decrypted by a very simple decryption program written in C that is supplied in source code form.
The supplied C programs have been verified to compile under Linux and FreeBSD. If you don't have access to a physical machine with one of these operating systems installed, we recommend that you install Ubuntu Desktop as a virtual machine.
Some knowledge on using a Unix-type operating system is required, and knowledge on how to operate a C compiler may be necessary. Verification of the source code of the supplied C program requires working knowledge of the C language.
The decryption program requires an installation of the NaCl library. For common operating systems, a ready-made package is available from the vendor.
If no package is available for your operating system, you can also compile NaCl from source as described on the NaCl Installation page.
Download the source code of the validation programs.
The following files are included:
Usually all that is required to compile threema_unbox and threema_getprivkey is to type make inside the directory with the files.
Your raw private key can be extracted from a Threema ID backup (a string in the format "ABCD-EFGH-IJ12-..."). Use threema_getprivkey as follows:
# ./threema_getprivkey backup: 7MUX-MA7U-MOED-JG5T-ZXNX-EMAQ-IZKE-JXXM-RT3D-K3LN-UZA7-JJWF-3OTB-YSKP-XW3I-HG6I-UKJM-75R2-2PAK-HIAD password: <enter backup password> Identity: STUVWXYZ Private key: aaebd94ed62dbbf21f557c9af485a6a27f39e7663d8024a3aba46b70bf50c670
IMPORTANT: keep the private key confidential and destroy it after use!
Message decryption also requires the public key of the message's sender (for incoming messages) or recipient (for outgoing messages). For convenience, the validation log already includes the public key. If you want to be extra sure, you can obtain it from the QR code displayed by the other person's Threema app (note that it has to be the other person's public key, not your own!).
Scan the QR code using a generic QR scanner app, e.g. NeoReader. You will get a string like the following:
The public key is the 64 hex characters at the end of the string.
The validation log will contain entries like the following (note that this is dummy data and will not decrypt):
2013-03-13 16:54:58 +0000 incoming message ID 0123456789abcdef from ABCDEFGH to STUVWXYZ: Nonce: 9ed4f34a8c97e7410f43e4286e241620331be3a14d892e9d Data: 140733c4b99d1ea6e75fc1debbe377f0455674734fdb57505be6dfde94fcf03ea80a12472 c908a37ce5efad9883701e5bd570fb588670c41b6df5f3bf37835136b0369ba6ae2835233d904d2 842716e651fd0bd401d7cb02dac232021e138688f84ec6043bfccbff7543a69077b4fcf94f77420 8a85dbc12c86556af8ba3becff05e45b24a0f851ba66f4d38a071663a276 Public key (ABCDEFGH): 9246c8107a8c3b71a9ffc845db2b463a3b3b73d4d6b133fa8673eefb0bae3f69
Choose the message that you want to decrypt. Start threema_unbox and provide the following values (all in hex):
# ./threema_unbox nonce: 9ed4f34a8c97e7410f43e4286e241620331be3a14d892e9d pubkey: 9246c8107a8c3b71a9ffc845db2b463a3b3b73d4d6b133fa8673eefb0bae3f69 privkey: aaebd94ed62dbbf21f557c9af485a6a27f39e7663d8024a3aba46b70bf50c670 data: 140733c4b99d1ea6e75fc1debbe377f0455674734fdb57505be6dfde94fcf03ea80a12472 c908da37ce5efad9883701e5bd570fb588670c41b6df5f3bf37835136b0369ba6ae2835233d904d 2842716e651fd0bd401d7cb02dac232021e138688f84ec6043bfccbff7543a69077b4fcf94f7742 08a85dbc12c86556af8ba3becff05e45b24a0f851ba66f4d38a071663a276b0664cfa Padding: 113 bytes Sample message text.
If decryption is successful, the number of padding bytes included in the message will be printed, followed by the message text (each message contains a random amount of PKCS#7 padding). The length of the encrypted data equals ([type = 1 byte] + [authenticator size = 16 bytes] + message text length + padding).
It may seem strange that outgoing messages can be decrypted by entering the sender's private key and the recipient's public key, i.e. without knowing the recipient's private key. This is because NaCl uses ECDH to derive a shared secret between the two involved parties, which is then used in conjunction with a nonce for symmetric encryption. The secret is the same no matter whether the combination of (sender private key + recipient public key) or (sender public key + recipient private key) is used. This behavior is also the reason for the repudiability property of the NaCl crypto_box model: using his own private key and the sender's public key, any recipient can forge a message that will look just like it was actually generated by the purported sender, so the recipient cannot convince a third party that the message was really generated by the sender and not forged by the recipient. However, the recipient is still protected against forgeries by third parties, since the recipient himself will know whether or not he has used his own private key for such a forgery.