-
Notifications
You must be signed in to change notification settings - Fork 88
Security design
To provide its security properties, TFC's hardware and software designs differ from currently existing messaging systems. As the design choices may at times appear inconvenient or overly complicated, this document explains the rationale behind them in detail and compares TFC's protocol against the current state-of-the-art protocols such as the Signal protocol.
All programs, from secure messaging apps to operating systems, are written by imperfect humans. As writing a formal proof of correctness for even the simplest application is a practical impossibility, all programs should be assumed to contain bugs. These bugs can sometimes compromise the security of the system passively (due to eventual erroneous behavior), or they can introduce vulnerabilities that can be exploited by attackers with malicious inputs.
All proper end-to-end encrypted (E2EE) messaging systems store private key(s) exclusively on the user's device (endpoint). The holy grail of attacks against E2EE systems is called exfiltration where the sensitive data, namely the private keys or plaintext messages, are stolen from the endpoint. The attack is directed against the target system's trusted computing base (TCB), which is defined as the set of all parts that are critical to the security of that system. The overwhelming majority of TCBs are connected to the network and compromising them with polished malware that exploits a zero-day vulnerability, is trivial and undetectable.
Depending on the protocol design of the messaging system, the exfiltrated private key can be leveraged in a number of passive and active attacks that allow decryption of messages in transit.
A messaging program cannot protect the user by itself. Even if it was somehow perfectly written, it is only a small part of the entire software stack: by compromising, for example, a more trusted part of the operating system, all security the messaging tool can provide is lost. The only way to ensure sensitive data cannot be stolen from the endpoint is to patch all vulnerabilities in all the programs that the networked TCB consists of. Since this is a practical impossibility, it is usually mitigated with personal security products (PSPs). However, nation-state actors have been found to test their malware is not detected by such utilities.
The requirement list of the [CIA's] Automated Implant Branch (AIB) for Grasshopper puts special attention on PSP avoidance, so that any Personal Security Products like 'MS Security Essentials', 'Rising', 'Symantec Endpoint' or 'Kaspersky IS' on target machines do not detect Grasshopper elements. Source
As software has its limitations, hardware-based systems have been designed to provide more robust security.
One attempt to provide security against exfiltration is to generate and store keys, and handle cryptographic operations on a secure cryptoprocessor of a smart card or a hardware security module (HSM). These systems have rigorous security design that reduces the number of vulnerabilities significantly. For example, Google has introduced a prototype for secure messaging with micro-SD card shaped smart card called Project Vault. This is great in the sense that sensitive keys stay protected and in that cryptographic operations can be trusted during runtime. However, despite best efforts by companies, it is practically impossible to verify there are no vulnerabilities, that governments have not coerced the company to insert backdoors or that government agencies do not replace products shipped to customers. The major issue is, even if the design of the smart card is perfect in every aspect, it does not guarantee the confidentiality of communication:
Plaintext messages are still written using a keyboard connected to the insecure host computer. Thus, if an attacker has compromised the operating system and planted, e.g., a kernel or API-based keylogger and screenlogger, plaintext messages can be accessed before encryption and after decryption. Malware can exfiltrate messages in real time, or cache them for later exfiltration. So, while smart cards and HSMs are excellent, e.g., when creating digital signatures, they are not the solution for secure messaging.
For high-security communication, the general recommendation is to use something like PGP on an air-gapped system, which is a significant improvement over smart cards, as the entire TCB, including plaintext i/o, is moved to a computer that can not be reached from the network directly.
The main issue in this approach is, however, the window of opportunity for malware to jump over the air-gap never closes.
The rough overview of the attack is as follows: The attacker first exploits the networked computer with sophisticated malware. Then, the first time an encrypted message is received from a contact, the malware spreads to the air-gapped computer via the ciphertext transmission media, e.g., a thumb drive. The next time a message is sent to the contact, the malware covertly exfiltrates the private key and all captured keystrokes (including the password that protects the private key) using the transmission media to the networked computer, from where they are forwarded to the attacker in the network.
The primary tool for air-gapped messaging has always been PGP which is problematic as it lacks forward secrecy: Once the private RSA key has been exfiltrated, all past and future messages protected by the key can be decrypted passively. While no examples of malware specifically targeting PGP have yet been found, some malware such as Stuxnet have already demonstrated the capability to jump over air-gaps and the NSA's modular payload UNITEDRAKE has plugins called SALVAGERABBIT and GROK that enable the attacker to exfiltrate files and log keystrokes. The NSA has also devised implants for jumping over air-gaps.
A simple air-gap is clearly not enough. However, by carefully evaluating each step of the previous example in isolation, a way to secure the endpoint becomes apparent:
-
The TCB on the air-gapped computer of the sender remains clean (which is not the same as invulnerable -- it simply means "not infected") as long as ciphertexts are only exported, and a clean (=separate, never before used) removable media is used every time, and the old media is destroyed immediately after use.
-
If the air-gapped computer of the recipient only receives ciphertexts from the network, an arbitrary number of ciphertexts can be imported to the air-gapped computer. As long as the used removable media is immediately destroyed after the ciphertext has been imported, no malware that propagates to the air-gapped receiver computer has a return channel it can use to exfiltrate keys or plaintexts.
Exfiltration secure communication in single direction
The problem of this two computers per endpoint -approach is however that messages can be only sent in one direction. However, by nature, human communication is bidirectional. The significant discovery and core idea of TFC is the realization that a separate set of computers can be added for replies...
Bidirectional exfiltration secure communication
...and that since the networked computers of the return channel can also be assumed to be compromised, a duplicate networked computer is not needed. The solution, therefore, is for each endpoint to have three separate computers: A split TCB where one computer only outputs ciphertexts, and another only receives ciphertexts. The third computer acts as a protocol converter that relays ciphertexts between the user's unidirectionally connected computers, and the network.
Unified Networked Computers for endpoint
To make the split TCB suitable for real-time instant messaging, removable media must be replaced with a unidirectional data transmission link that relies on asynchronous data transmission over protocols such as the UDP or UART. However, how is the unidirectionality guaranteed? Running only a listener program on the receiver computer is not high assurance: malware that propagates to that system can trivially add sender functionality to establish a return channel. The answer is to remove the return channel on the hardware level. However, features such as auto MDI-X make it impossible to enforce unidirectional UDP transmission over Ethernet. A simpler transmission protocol is required, and for that, UART with TTL or RS232 level voltages fits perfectly.
Unlike bit-banged serial communication over GPIO, UART chips most likely have more than just rule-based limitations on Tx and Rx pin assignment. However, more assurance should be sought. Unidirectionality of communication can be guaranteed with a simple hardware device called data diode that is placed in-between the sending and receiving UART interfaces. Data diode is a device that takes advantage of the fundamental laws of physics to define the direction of data flow. The data diode used in TFC is a slight modification to the design by the pseudonym Sancho P. (Earlier data diode designs are based on the paper by Douglas W. Jones and Tom C. Bowersox on RS232 data diodes.)
This data diode makes use of two optocouplers, each with two transducers that form a unidirectional gateway. On the sender side, depending on whether the output bit is one or zero, the high or low signal from the FT232R UART interface's Tx-pin turns the LED inside the HCPL-7723 optocoupler on or off. The state of the LED is detected by the optocoupler's photodiode, and the reproduced signal is then amplified by the optocoupler's TIA and the signal is finally fed into the Rx-pin of the receiving UART interface.
This optical gap is guaranteed to be one way because while LEDs show a weak photoelectric effect, photodiodes (excluding Ternary and quaternary GaAsP photodiodes) do not emit light when current passes through them.
The hardware configuration that combines the data diodes with split TCB has impressive security guarantees. It sets a one-time price tag on endpoint security. As long as the Source Computer (transmitter) doesn't output sensitive data (due to programming error or pre-existing malware), the entire system remains secure against remote key and plaintext exfiltration with malware. The malware cannot propagate from Networked Computer to Source Computer, and malware that propagates from Networked Computer to Destination Computer (receiver) is unable to exfiltrate data back to Networked Computer.
The data diodes in the illustration above are denoted with the standard diode symbol: Data can flow through them in the forward direction (indicated by the triangle-shaped arrowhead), but not in the reverse direction. The puzzled invader represents malware/attacker unable to achieve its goal, that is, propagate further and/or access sensitive content.
Source Computer runs the TFC Transmitter Program that reads input from the user and based on that, encrypts, signs and outputs messages/files/commands. By design, Source Computer requires the capability to output data to the network. As malware could use the same channel to output sensitive keys and plaintexts covertly, the computer has an absolute requirement of remaining clean.
During TFC setup, Source Computer has the same amount of security against infection as all standard end-to-end encrypted messaging systems have throughout their use. Setup of TFC on Source Computer, therefore, introduces a race hazard that ends after the installer has downloaded all dependencies and programs, and disconnected the Source Computer from the network. If the Source Computer was not infected at this point, the security properties of Source Computer's alternative data diode model
take effect: The data diode prevents all inbound traffic and permanently protects the Source Computer from remote compromise. Source Computer is the only device to have such property, and therefore, it is the only device trusted to generate private keys for communication (and to give trustworthy advice to the user during operation).
All devices that are bidirectionally connected to the Source Computer need to form their own, closed ecosystem. The devices must never be connected to less secure computers. For example, a journalist who wishes to send photos to the newsroom, should only connect the memory card of the camera to their Source Computer. Any physical documents to be sent should be scanned with a scanner dedicated to the Source Computer.
Destination Computer runs the TFC Receiver Program that authenticates, decrypts and processes messages, files and commands it receives through its serial interface and the data diode. Destination computer makes use of the security properties of the classical data diode model
that ensures any infiltrating malware is unable to exfiltrate sensitive keys/plaintexts from the computer. All received packets are encrypted and signed with XChaCha20-Poly1305, thus the adversary is unable to inject packets even if they compromise the Networked Computer. Because Destination Computer must by design receive data from the network, and because serial interface's software stack (including the driver and the PySerial library) is with overwhelming probability not invulnerable, a determined attacker can with high probability (i.e., they are assumed to be able to) execute arbitrary code on Destination Computer. Because of this, the Receiver Program is not trusted to contribute to TFC's communication key generation: the private key or the entropy used to produce it might have been sent in by the attacker, and that would completely break the security of the system.
Destination Computer and any devices connected to it should also form a closed ecosystem. Data received by, e.g., a newsroom can be copied across computers with same security level using (wired) local network. The computers in the LAN must take same precautions regarding connectivity and covert exfiltration channels as the Destination Computer. The surface area of key exfiltration attacks can be reduced if all received documents are exported from the Destination Computer directly using a dedicated printer before they are re-scanned to less secure systems.
TFC is designed with the assumption the Networked Computer is compromised by an attacker immediately. The Relay Program running on the Networked Computer only relays contact requests, X448 public keys, group management messages, and signed ciphertexts. Compromise of this system is not different from a compromised email-server routing PGP-ciphertexts: Networked Computer is not part of the TCB, it is part of the ciphertext routing network.
There is, however, a lot more to security than just confidentiality of content. Networked Computer is problematic in terms of anonymity and metadata: If the device is compromised, any files, hardware IDs, public IP addresses and data collected by sensors such as webcams, microphones and Wi-Fi interfaces that can be attributed to the user, can reveal the user's real-life identity to the attacker.
TFC uses 256-bit XChaCha20-Poly1305 authenticated encryption to protect all communication and persistent data. Symmetric keys are either pre-shared, or exchanged using X448, the base-10 fingerprints of which are verified via out-of-band channel. TFC provides per-message forward secrecy with Blake2b based hash ratchet. Except for transmitted files, all variable length data is padded before encryption to hide plaintext length. All persistent TFC data is encrypted locally using XChaCha20-Poly1305, the key of which is derived from password and a 256-bit salt using Argon2id. Keys and nonces are generated with Linux kernel's getrandom() syscall that draws entropy from its ChaCha20 based CSPRNG.
Each algorithm listed above is state-of-the-art (read: best possible choice) as per modern standards. Below is a more detailed dissection of each primitive.
X448
X448 is the Diffie-Hellman function for Curve448-Goldilocks, a state-of-the-art elliptical curve published by Mike Hamburg in 2014.
For more details, see
- https://eprint.iacr.org/2015/625.pdf
- http://ed448goldilocks.sourceforge.net/
- https://en.wikipedia.org/wiki/Curve448
The reasons for using X448 in TFC include
-
Curve448 meets the criterion for a SafeCurve:
-
Parameters
-
Use of large prime field (p = 2448 - 2224 - 1).
-
The Edwards curve (x2+y2 = 1-39081x2y2) is complete.
-
The base point (x1,y1) is on the curve.
-
-
ECDLP security
-
222.8-bit security against the Pollard's rho method. This is important as the security of hash ratchet depends on the security of the root key. Curve25519 is thus less feasible choice. Curve448 is also likely to resist quantum computers and mathematical breakthroughs against ECC for a longer time.
-
Safe against additive and multiplicative transfer.
-
The complex-multiplication field discriminant is 2447.5, which is much larger than the required minimum (2100).
-
The curve-generation process is fully rigid, i.e. it has been completely explained. In comparison, NIST P-curves use coefficients generated by hashing unexplained seeds.
-
-
ECC security
-
Use of Montgomery ladder that protects from side channel attacks by doing constant-time single-scalar multiplication.
-
221.8-bit security against twist attacks (small-subgroup attack combined with invalid-curve attack).
-
Support for complete single-scalar and multi-scalar multiplication formulas.
-
Points on Curve448 (e.g. public keys) are indistinguishable from uniform random strings.
-
-
-
Safer curves (M-511 and E-521) do not have robust implementations.
-
NIST has announced X448 will be included in the SP 800-186.
-
Its public keys do not require validation as long as the resulting shared secret is not zero:
[X448] is actually two curves, where any patterns of bits will be interpreted as a point on one of the curves or on the other. [Source]
-
Its public keys are reasonably short (84 chars when WIF-encoded) to be manually typed from Networked Computer to Source Computer.
The X448 implementation used is the OpenSSL implementation (that is based on the original work by Mike Hamburg), and its Python bindings in the pyca/cryptography library.
The correctness of the X448 implementation is tested by TFC unit tests. The testing is done in limited scope by using the official test vectors.
XChaCha20-Poly1305
ChaCha20 is a stream cipher published by Daniel J. Bernstein (djb) in 2008. The algorithm is an improved version of Salsa20 -- another stream cipher by djb -- selected by ECRYPT into the eSTREAM portfolio in 2008. The improvement in question is, ChaCha20 increases the per-round diffusion compared to Salsa20 while maintaining or increasing speed.
For more details, see
- https://cr.yp.to/chacha.html
- https://cr.yp.to/snuffle.html
- https://cr.yp.to/snuffle/security.pdf
- https://en.wikipedia.org/wiki/Salsa20#ChaCha_variant
The Poly1305 is a Wegman-Carter message authentication code (MAC) also designed by djb. The MAC is provably secure if ChaCha20 is secure. The 128-bit tag space ensures the attacker's advantage to create an existential forgery is negligible.
For more details, see
The version used in TFC is the XChaCha20-Poly1305-IETF, a variant of the ChaCha20-Poly1305-IETF (RFC 8439). Quoting libsodium, the XChaCha20 (=eXtended-nonce ChaCha20) variant allows encryption of ~264 bytes per message, encryption of practically unlimited number of messages, and safe use of random nonces due to the 192-bit nonce space.
The reasons for using XChaCha20-Poly1305 in TFC include
-
Conservative 256-bit key size that matches the 222.8-bit security of X448, and BLAKE2b (with truncated, 256-bit hashes).
-
The Salsa20 algorithm has 14 years of cryptanalysis behind it and ChaCha20 has resisted cryptanalysis as well [1, 2]. Currently, the best public attack breaks ChaCha7 in 2233 operations.
-
Security against differential and linear cryptanalysis [1, 2].
-
Security against cache-timing attacks on all CPUs (unlike AES on CPUs without AES-NI).[p. 2]
-
The increased diffusion over the well-received Salsa20.
-
The algorithm is much faster compared to AES (in cases where the CPU and/or implementation does not support AES-NI).
The XChaCha20-Poly1305 IETF implementation used is the libsodium implementation and its Python bindings in the pyca/PyNaCl library.
The correctness of the implementation is tested by TFC unit tests. The testing is done in limited scope by using the libsodium and official IETF test vectors.
BLAKE2b
BLAKE2 is the successor of SHA3-finalist BLAKE*, designed by Jean-Philippe Aumasson, Samuel Neves, Zooko Wilcox-O'Hearn, and Christian Winnerlein. The hash function is based on the ChaCha stream cipher, designed by djb.
*BLAKE was designed by Jean-Philippe Aumasson, Luca Henzen, Willi Meier, and Raphael C.-W. Phan.
For more details, see
- https://blake2.net/
- https://tools.ietf.org/html/rfc7693.html
- https://docs.python.org/3.7/library/hashlib.html#blake2
The reasons for using BLAKE2b in TFC include
-
According to NIST [p. 13] BLAKE received more in-depth cryptanalysis than Keccak (SHA3):
Keccak received a significant amount of cryptanalysis, although not quite the depth of analysis applied to BLAKE, Grøstl, or Skein.
-
BLAKE shares design elements with SHA-2 that has 11 years of cryptanalysis behind it.
-
128-bit collision/preimage/second-preimage resistance against Grover's algorithm running on a quantum Turing machine.
-
The implementation of the algorithm is bundled in Python3.7's hashlib.
-
Compared to SHA3-256, the algorithm runs faster on CPUs which means better hash ratchet performance.
The ARX-based algorithms, BLAKE and Skein, perform extremely well in software. [p. 13]
-
Compared to SHA3-256, the algorithm runs slower on ASICs which means attacks by high-budget adversaries are slower.
Keccak has a clear advantage in throughput/area performance in hardware implementations. [p. 13]
Note that while the default digest length of BLAKE2b (the implementation optimized for AMD64 systems) is 512 bits, the digest length is truncated to 256 bits for the use in TFC.
The correctness of the BLAKE2b implementation [1, 2] is tested by TFC unit tests. The testing is done with the complete suite of BLAKE2b known answer tests (KATs).
Argon2
Argon2 is a password hashing function designed by Alex Biryukov, Daniel Dinu, and Dmitry Khovratovich from the University of Luxembourg. The algorithm is the winner of the 2015 Password Hashing Competition (PHC).
For more details, see
- https://password-hashing.net/
- https://github.com/P-H-C/phc-winner-argon2/blob/master/argon2-specs.pdf
- https://en.wikipedia.org/wiki/Argon2
The reasons for using Argon2 in TFC include
-
PBKDF2 and bcrypt are not memory-hard, thus they are weak against massively parallel computing attacks with FPGAs/GPUs/ASICs [p. 2].
-
scrypt is very complex as it "combines two independent cryptographic primitives (the SHA256 hash function, and the Salsa20/8 core operation), and four generic operations (HMAC, PBKDF2, Block-Mix, and ROMix)." [p. 10] Furthermore, scrypt is "vulnerable to trivial time-memory trade-off (TMTO) attacks that allows compact implementations with the same energy cost." [p. 2]
-
Of all the PHC finalists, only Catena and Argon2i offer complete cache-timing resistance by using data-independent memory access. Catena does not support parallelism [p. 49], thus if it later turns out TFC needs stronger protection from cache-timing attacks, the selection of Argon2 (that always supports parallelism) is ideal, as switching from Argon2id to Argon2i is trivial.
-
More secure algorithms such as the Balloon hash function do not have robust implementations.
The purpose of Argon2 is to stretch a password into a 256-bit key. Argon2 features a slow, memory-hard hash function that consumes computational resources of an attacker that attempts a dictionary or a brute force attack.
The function also takes a salt (256-bit random value in this case) that prevents rainbow-table attacks, and forces each attack to take place against an individual (physically compromised) TFC-endpoint, or PSK transmission media.
The Argon2 version used is the Argon2id, that is the current recommendation of the draft RFC. Argon2id uses data-independent memory access for the first half of the first iteration, and data-dependent memory access for the rest. This provides a lot of protection against TMTO attacks which is great because most of the expected attacks are against physically compromised data storage devices where the encrypted data is at rest. Argon2id also adds some security against side-channel attacks that malicious code injected to the Destination Computer might perform. Considering these two attacks, Argon2id is the most secure choice.
The implementation of Argon2 used in TFC is the argon2_cffi that provides C-bindings for the algorithm's reference C implementation.
The correctness of the implementation is tested by TFC unit tests. The testing is done by comparing the output of the argon2_cffi
library with the output of the Argon2 reference command-line utility under randomized input parameters.
Strong random numbers: Linux-RNG
The default key length is 32 bytes (256 bits).
The key is generated by the Linux kernel's modern, ChaCha20-based cryptographically secure pseudo-random number generator (CSPRNG), also known as the Linux-RNG, or LRNG.
The LRNG is currently receiving a lot of love from Jason Donenfeld, and no documentation, not even the one maintained by the German BSI, is keeping up with the overhaul.
The best resource to study the RNG functionality is for now, the source code itself:
This segment will be expanded later once the overhaul settles on a more modern design.
The output of getrandom()
is further compressed with BLAKE2b. The preimage resistance of the hash function protects the internal state of the entropy pool just in case some user decides to modify the source to accept pre-4.8 Linux kernel that has no backtracking resistance. Another reason for the hashing is, it's recommended by djb.
Since BLAKE2b only produces 1..64 byte digests, its use limits the size of the generated keys to 64 bytes. This is not a problem for TFC because again, the largest key it generates is the 56-byte X448 private key.
Forward secrecy is the process of using ephemeral keys to prevent retrospective decryption of intercepted ciphertexts with keys that are compromised from the endpoint at some point. TFC provides per-packet forward secrecy with what's called a hash ratchet.
In hash ratchet, the message key (denoted with KM) is passed through a key derivation function (KDF) after every encryption or decryption operation. The pre-image resistance of the hash function used in the KDF prevents deriving previous key(s) from the current key. Since hash function maintains the entropy of the initial key, no salt or slow hash functions are necessary for the KDF. The KDF used in TFC is the BLAKE2b hash function.
In the situation where one or more packets have dropped, the encryption key determined by the hash ratchet state of the Transmitter Program will have advanced further, than what the decryption key of the Receiver Program's hash ratchet state would expect. To determine the unknown offset, the Receiver Program needs to know how many times the Transmitter Program had at that point passed the initial message key through the KDF. This information is delivered using a value called the hash ratchet counter (harac for short).
The harac is a 64-bit zero-padded bit string. The counter space might sound small (when compared to key space), but even at a fictitious rate of 5 billion packets per second, it would last for more than 100 years.
The harac is delivered next to the forward secret assembly packet. It is encrypted with a static key called the header key (denoted with KH). The header key is generated independently (when PSK is used), or it is domain-separated from the X448 shared key using the KDF. The static nature of the header key is not a problem as the nonce space is massive (192 bits). The primary function of harac encryption is to provide authenticity with the Poly1305 MAC, as maliciously altered harac value would DoS the Receiver Program as it would try to catch up with a purported ratchet state that claims to be, e.g., a hundred million derivations ahead of the Receiver Program's ratchet state. The secondary function is to provide confidentiality to the number of sent packets the harac value reveals.
The harac also has a secondary purpose: it serves as a deterministic, never repeating counter that is mixed together with the previous message key when deriving the next one. This ensures that the message keys will never fall into a short cycle.
When the Receiver Program receives a packet, it will first decrypt the harac using the header key. If the decrypted harac indicates packets have dropped, Receiver Program will display a notification about the missed packets. It will then catch up with the purported ratchet state. If decryption of the assembly packet with the derived message key is successful, Receiver Program will store the next unused message key and harac value to the key database.
One thing to consider is, frenemies (malicious contacts) are always able to perform the DoS attack (described above) against user's Receiver Program. Receiver Program will prompt the user to verify whether they would like to catch up with the ratchet state, but preventing the attack is a hard problem because the contact could send multiple packets that are just below the set warning threshold (100,000 missed packets). Such attacks can, however, be detected by multiple notifications of Receiver Program, e.g. Warning, 99999 messages from contact Chuck were missed
, and it should be dealt by removing the contact from TFC.
TFC does not use Signal-style double-ratchet (hash-ratchet + Diffie-Hellman ratchet) because it would require the user to manually type a new public key from Receiver Program to Transmitter Program after every received message; Such a protocol would be unusable. TFC does, however, allow users to switch to new keys by re-adding the contact and re-exchanging keys. This procedure does not mix in entropy from the previous ratchet, as due to the risk of dropped packets, user and contact might end up in inconsistent state by deriving different keys. This would create a lot of hassle, from which TFC could not recover without creating completely new keys.
Due to lack of Diffie-Hellman ratchet, TFC is unable to provide a property called future secrecy. What it means is, if TFC's private keys are compromised at any point, the adversary can decrypt all messages until the users exchange new keys. While Signal avoids this problem by continually mixing in new entropy, the effectiveness of future secrecy can be questioned: If private keys of Signal are stolen at any point, it is highly likely that the endpoint is infected with malware that can exfiltrate all future keys and plaintexts to the adversary.
Future secrecy is effective in cases where the adversary compromises only a limited set of keys, if decryption attack with keys is only passive, or if MITM attack that leverages the keys seizes at some point. It should be emphasized that weak endpoint security of networked TCBs is not the fault of messaging tools. Future secrecy is by no means a bad thing and having it on applications that run on networked TCB is excellent. TFC is unable to provide it, but in turn, it can provide what networked TCBs cannot -- security against remote data exfiltration.
The future secrecy property in Signal also avoids the issue of using weak keys for extended periods, because new entropy is continuously mixed into kernel CSPRNG and from there into DH key pairs. TFC is unable to mix in new entropy and is thus dependent on the security of the initial key. All keys are generated using getrandom() syscall that on modern Linux kernels (3.17 and newer) blocks when the internal state of the CSPRNG has less than 256 bits of entropy. Generated keys can, therefore, be assumed to be secure even if the Transmitter Program is run on a live distro. Instead of mandating minimum kernel version of 3.17, TFC expects 4.17 or later; This ensures not just that getrandom() syscall is available, but that the kernel also utilizes the newer ChaCha20-based CSPRNG (a.k.a LRNG).
Since ciphertexts are signed with symmetric Poly1305 MACs (as opposed to digital signatures in, e.g., PGP and iMessage), messages in TFC do not include cryptographic proofs about message's authorship. The conversing parties -- Alice and Bob -- are both in possession of the symmetric keys they use to sign and verify messages they send each other. The shared key means Alice can be sure Bob was the sender of the message (because she knows it was not her), but also, that Alice cannot show the message to a third party and prove Bob wrote it because Alice could also have created the message and the MAC.
OTR-protocol has an interesting feature: it publishes expired MAC keys after the session ends. The publishing allows any third party to forge conversations afterwards. TFC is unable to do this because hash ratchets are deterministic; Even if the Poly1305 MAC keys were domain separated from the hash ratchet's message keys, Receiver Program of Alice could not notify Transmitter Program of Bob which messages it has received. Because in TFC the session lasts until the users perform the next key exchange, the only way to publish MAC keys would be at some point in a trailing message.
Were MITM attacker Mallory to prevent the flow of messages to Alice, a trailing message from Bob would contain the MAC key of the first message. As stream ciphers are malleable, this would allow Mallory to create an undetectable existential forgery in cases where she knows the plaintext content of the first message for whatever reason (e.g., high priori probability).
Sender-based control is an unreliable security feature that is advertised as a way to protect the sender from the recipient, by removing messages delivered to the said recipient. This feature is mostly snake oil because it requires the software to be proprietary and to limit the rights of the recipient. TFC is free and open source software (FOSS) for a very good reason: It is much harder for nation states to coerce backdoors into FOSS tools. Because TFC is FOSS, it means any user can trivially edit their Receiver Program not to remove the messages asked by the sender (this would probably require commenting out 1..3 lines of code). Secondly, even if TFC was proprietary software, no magical crypto dust makes the recipient unable to take a screenshot, or use an external camera to record incoming messages.
TFC does, however, provide sender based control over partially transmitted data. What this means is, messages longer than 254 bytes (when compressed) are sent over multiple assembly packets. The content is encrypted with an inner layer of XChaCha20-Poly1305, the key of which is concatenated to the ciphertext. As long as the packet delivery is canceled before the 1..2 last assembly packets that contain the inner key are delivered to sender's Relay Program the recipient is unable to decrypt the long transmission. Unfortunately, the inner layer of encryption makes partial transmissions impossible in cases where for example, a dissident must quickly upload as much of the data as possible before their door gets busted down. Such situations are however likely to be much rarer than those where the user realizes they have been sending a large message or file to a wrong contact.
TFC's command /whisper
allows the user to send a message to the recipient and request it not to be logged. The request is accepted as long as the recipient does not change the behavior of their Receiver Program. It is meant to be used by conversing parties as a mean to choose what messages are logged, and what to keep off-the-record. Providing the feature might appear hypocritical, but at no point is the feature advertised as means to protect the user from the recipient, it only protects the user and the recipient from third parties in cases where the recipient has not disabled the feature from the source code.
During the initial launch, Transmitter and Receiver Programs first generate a 256-bit salt, and then prompt the user to enter and confirm a master password, that is fed together with the salt into the password based key derivation function Argon2id to derive the 256-bit master key, that will be used to encrypt data at rest.
As the key derivation time is limited by user's tolerance to wait, TFC optimizes security by scaling threads to match the CPU, and by tweaking the time_cost
and memory_cost
according to best practices, until key derivation takes between three and four seconds. The three-second minimum is the recommendation for key derivation for hard-drive encryption defined in the Argon2 RFC draft.
The implementation first uses as much memory as possible. It then increases time_cost
until the key derivation takes between three and four seconds. Once time_cost
that exceeds three second limit has been determined, if key derivation then takes over four seconds (value we consider too long for decent user experience), memory_cost
is tweaked by doing a binary search for a value that leads to key derivation time between three and four seconds.
While this configuration is as good as password based key derivation gets, it is a truism no KDF configuration is strong enough if the user has chosen a weak password (i.e. a short one or one that's in the attacker's password dictionary).
The 32-byte BLAKE2b digest of the master key is stored together with salt
, time_cost
, memory_cost
and parallelism
parameters into database {tx,rx}_login_data
. The master key will be derived from the password (entered into TFC's login screen) and salt every time Transmitter and Receiver Programs are launched, and it is only accepted if its hash matches the one in the database. Forgetting the password or tampering/deleting the login data file renders all user-data inaccessible. Under the assumption password remains unbreakable by the adversary, encrypted databases help against following threats:
Wear leveling
All data is encrypted before it touches the hard drive: These are increasingly becoming SSDs that don't overwrite data the way magnetic drives do.
Physical data exfiltration
In the case where the adversary has not remotely exploited Destination Computer with a keylogger that copies TFC master password, physical access where encrypted data is merely exfiltrated means attacker is unable to access sensitive data. Similar protection can also be obtained with Full Disk Encryption (FDE) and by ensuring the encrypted disk is not mounted during off-hours. TFC keeps data secure even when FDE drive is mounted, but TFC is not running.
Physical data tampering
Since databases use authenticated encryption (XChaCha20-Poly1305), any tampering of TFC databases results in MAC error when the user enters the correct password. If however the hash, salt, or key derivation parameters in login data have been tampered with, the user only gets a warning that the entered password was incorrect.
Impersonation
In situations where the Source Computer or the Destination Computer is left powered on (something the user should never do), but TFC master password has not been entered, encryption of data prevents communication to contacts while impersonating as the user.
Database metadata leak
TFC databases are padded so that regardless of content, as long as the user has 50 or fewer contacts, that form 50 or fewer groups, each with 50 or fewer members, databases do not leak any metadata about the user's TFC configuration. The user can increase contact and group database limits from settings with /set
command (values need to be multiples of 10), which will cause the application to expand the padded database size. Different types of data in databases are stored in constant length format:
-
Logged assembly packets are stored as 256-byte strings
-
UNIX timestamps for logged messages are stored as 4-byte strings
-
Unicode string variables like group names and nicks are stored as PKCS #7 padded, UTF-32 encoded strings (length of 1024 bytes)
-
Integers are stored as (big-endian) unsigned long long (length of 8 bytes)
-
Floats are stored as binary64 (length of 8 bytes)
-
Booleans are stored as single bytes (
\x00
or\x01
) -
Symmetric keys, public key fingerprints, and TFC accounts (=Tor Onion service Ed25519 public keys) are stored as 32-byte strings.
Based on the padding formats above
-
Contact and key databases will be padded with dummy contacts with dummy data (until not necessary, i.e. when the database has 50 contacts and is full).
-
Groups in group database will be padded with dummy members (until not necessary)
-
Group database will be padded with dummy groups with dummy members (until not necessary)
Unfortunately, the message log database cannot be effectively padded, so it leaks metadata about the total number of sent and received messages. Because of this, logging of messages is disabled by default. If the setting logfile_masking
is enabled, Transmitter and Receiver Program of the user will during traffic masking (explained later) log each output assembly packet to prevent an attacker who correlates what Source Computer outputs with the logfile size, from deducing how large portion of the packets were, e.g., whispered messages.
Messaging applications have practically always consisted of two parts: the input box and the conversation window. In TFC, the Transmitter Program is essentially the input box (with visible input history and key/contact management interfaces), and the Receiver Program is the conversation window. To decrypt messages from Bob, the Receiver Program of Alice must have a copy of the symmetric message key used by the Transmitter Program of Bob. To make conversation easy to follow on one screen, messages sent by Bob must also be displayed by his Receiver Program. This means Bob's Receiver Program must also have a copy of the message key. Again, as the Receiver Program is not trusted to generate keys for communication purposes, a way to deliver them from his Source Computer is needed. Furthermore, the Transmitter and Receiver Program of each user need to share a synchronized state (e.g., settings and active conversation window). To maintain that, instead of entering commands into two computers every time, the Receiver Program should be managed via the Transmitter Program to the furthest extent with commands. But how should the commands and symmetric message keys be delivered from the Source Computer to the Destination Computer?
Removable media is slow, introduces a running cost and risks data remanence that endangers forward secrecy. Separate direct data diode enforced channel from Source to Destination Computer is problematic as serial name (e.g. /dev/ttyUSB0
) mapping is not persistent. Even with UIDs and dedicated interfaces, users could still misconfigure data diode wiring: Source Computer might, therefore, output sensitive data intended for Destination Computer to Networked Computer. In such case infected Networked Computer and Destination Computer might fool the user into thinking data was correctly sent: Source Computer cannot tell to what device it is outputting data. Destination Computer, on the other hand, might accept volatile commands from the Networked Computer (that appear to come from the Source Computer over the trusted channel), and for example remove log files or worse, PSKs that might have been exchanged over meetings that required expensive travel.
Commands and message keys need to be encrypted before delivery, and in such case, users might as well route them via the Networked Computer: This simplifies the hardware layout significantly and reduces cost. The symmetric encryption key for this purpose is called the local key
, and it needs to be delivered from Source Computer to Destination Computer somehow. The key should definitely not be derived from a password, because users choose on average 40-bit passwords and brute forcing such key space would be trivial. As stated above, public key cryptography is a bad idea as the Destination Computer might have been compromised with a magic packet received via the Networked Computer. Were the Receiver Program generate a key pair determined by Mallory, she could undetectably derive the shared key by combining the known Receiver Program's private key with the Transmitter Program's public key (as it transits through the Networked Computer). Delivering the key via removable media or trusted serial interface has the same problems as in the cases described above regarding message key or command delivery.
The following image describes how the local key is delivered from the Source Computer to the Destination Computer.
-
The Transmitter Program generates three 256-bit symmetric keys: local key KL, local header key KLH, and local key encryption key KKE. It also generates a one byte long confirmation code cc.
-
The Transmitter Program encrypts KL, KLH and cc using KKE (|| denotes concatenation).
-
The Transmitter Program outputs the ciphertext CT to the Destination Computer via the Networked Computer.
-
The Transmitter Program displays KKE on Source Computer screen. The format is the same as Bitcoin's WIF: Base58 with integrated 4-byte checksum, sliced into even length chunks to help with typing.
-
The user enters KKE on the Receiver Program using the Destination Computer's keyboard.
-
The Receiver Program decrypts CT using KKE.
-
If decryption was successful, the Receiver Program stores KL and KLH to key database and reveals cc to the user.
-
The user types cc to Transmitter Program to verify KL and KLH have been delivered to Receiver Program.
If cc was correct, Transmitter Program stores KL and KLH to key database and allows the user to add the first contact.
After a contact has been added, a new local key can be created with Transmitter Program's command /localkey
.
Confirmation codes are used in TFC to ensure important data like keys were successfully delivered, before the program allows the user to continue. The confirmation code is designed to be as short as possible to type, but complex enough (256 choices), so the user does not attempt to brute force it. If due to a loose connection or transmission error data (like the CT above) was not delivered to Destination Computer, the packet can be resent by simply pressing Enter.
Before user's TFC setup can exchange encrypted messages, files or public keys (TFC DATA in the image below), it needs to connect to the recipient.
TFC connection establishment over V3 Onion Services
NOTE: In the explanation below, a single quote '
is used to denote data from the contact.
NOTE: Although local key delivery was explained in the previous chapter, some of the following steps take place automatically in the background even before the local key delivery.
-
The Relay Program generates an ephemeral X448 private key KS for the session and derives a public key KP from that.
-
The Transmitter Program generates a long-term ed25519 private key KOS for the Onion Service, and an ephemeral confirmation code cc, and sends them to the Relay Program.
-
The Relay Program uses KOS to set up a v3 Tor Onion Service (aka Tor Hidden Service).
-
The Relay Program displays the confirmation code cc to the user.
-
The user types the cc to their Transmitter Program so the program knows the Onion Service private key was successfully delivered (and that if necessary, the local key delivery can begin).
NOTE: The local key setup takes place at this point during the first run.
-
Transmitter and Relay Program display the user's TFC account (derived from KOS) to them.
-
Alice and Bob obtain each other's TFC account over an authenticated channel.
-
Alice and Bob type each other's TFC account, nick and preferred key exchange method into their Transmitter Program.
-
The Transmitter Program stores the contact's TFC-account and forwards it to the user's Relay Program on Networked Computer. (Transmitter Program will deliver the Onion Addresses of existing contacts to the Relay Program along with the Onion Service ed25519 private key every time it starts).
-
The TFC account is the v3 Onion Service URL without
http://
and.onion
. (Note that despite the protocol claiming to be HTTP, all connections to.onion
servers are encrypted using TLS (HTTPS)-equivalent encryption.) For example- Let TFC account of Bob be
bobpkjrwo7i3xtryurt4ab4nmo376as7axju5lzimmecrehhzlga56qd
and - Let TFC account of Alice be
alicew6wvfxqjqknntxrt6rw3ngwt6hqeqrcgldu47miq2xfzfqhqsid
When Relay Program of Bob receives Alice's TFC account, it connects to Alice via URL
http://alicew6wvfxqjqknntxrt6rw3ngwt6hqeqrcgldu47miq2xfzfqhqsid.onion
To ensure contacts can request TFC DATA intended only for them, the Relay Program's server requires the requester to provide a URL token known only by the two participants. The URL token is agreed using X448:
The Relay Program's server publishes KP under the root domain:
-
http://alicew6wvfxqjqknntxrt6rw3ngwt6hqeqrcgldu47miq2xfzfqhqsid.onion
for Alice -
http://bobpkjrwo7i3xtryurt4ab4nmo376as7axju5lzimmecrehhzlga56qd.onion
for Bob
Since the Onion Address authenticates the Tor Onion Service, KP obtained from the server can be assumed to be authentic.
- Let TFC account of Bob be
-
Once the public key of the contact's Relay Program is obtained, the user's Relay Program combines its private key with the contact's public key to derive the X448 shared key SSK:
SSK = BLAKE2b(X448(KS, KP')) = BLAKE2b(X448(KS', KP))
-
The Relay Program of Bob uses SSK as the URL token to request TFC DATA from Alice with GET method to URLs
-
http://alicew6wvfxqjqknntxrt6rw3ngwt6hqeqrcgldu47miq2xfzfqhqsid.onion/
SSK/messages
-
http://alicew6wvfxqjqknntxrt6rw3ngwt6hqeqrcgldu47miq2xfzfqhqsid.onion/
SSK/files
and Alice respectively does the same by using URLs
-
http://bobpkjrwo7i3xtryurt4ab4nmo376as7axju5lzimmecrehhzlga56qd.onion/
SSK/messages
-
http://bobpkjrwo7i3xtryurt4ab4nmo376as7axju5lzimmecrehhzlga56qd.onion/
SSK/files
The path can be observed e.g. with Tor Browser. The upper window shows the URL token related X448 public key in hexadecimal format, and in the lower one, entering the correct URL token allows requesting the ciphertext.
Data exchanged by Relay Programs is available by knowing the Onion URL and URL token
Security is provided by the following properties:
- The address of the Onion Service that belongs to Bob is pinned to Alice's Transmitter and Relay Programs: Malicious contact Chuck is, therefore, unable to change the URL Alice's Relay Program connects to, so they are unable to change the URL token public key KP.
- The private key KOS never leaves the Networked Computer, and deriving the private key from the Onion address is as hard as ECDLP for Curve25519. Chuck is, therefore, unable to create an Onion Service with an identical Onion-address.
- Upon connection, the purported path is validated in constant time to prevent side-channel attacks from leaking the SSK. Chuck is, therefore, unable to obtain the path to request packets it is not authorized to receive. Deriving the SSK from the public key is as hard as ECDLP for Curve448.
The key exchange used to derive URL token is not authenticated via any means other than by the v3 Onion address in the TFC account. The reason for this is Mallory who has compromised the Networked Computer has access to private keys related to the Onion Service in any case. However, while in such situation the outer layer of encryption and possibly the anonymity Tor provides is lost, the situation is similar to that when the outer layer of Signal's encryption (TLS) is broken: There still exists an inner layer of end-to-end encryption that protects the content. The key exchanges related to the inner layer are explained right after the next chapter.
One aspect not mentioned above is, only one party needs to obtain the authentic TFC account of another user. When Transmitter Program sends details about contact(s) to Relay Program, the contacts -- with whom the user has not exchanged keys yet -- are marked as pending pending contacts. E.g., when Alice adds Bob as a new contact, her Relay Program will learn that Bob is a pending contact. This in turn causes the Relay Program of Alice to repeatedly send a contact request to Bob by connecting to
http://bobpkjrwo7i3xtryurt4ab4nmo376as7axju5lzimmecrehhzlga56qd.onion/contact_request/alicew6wvfxqjqknntxrt6rw3ngwt6hqeqrcgldu47miq2xfzfqhqsid
until Bob's Onion Service acknowledges it has received the contact request. The Relay Program of Alice will then load Bob's URL-token related public key from his Onion Service, and derive the URL-token. Finally, Alice's Relay Program starts polling the <address>.onion/<SSK>/messages
and <address>.onion/<SSK>/files
paths for incoming TFC data.
The Onion Service of Bob will keep returning empty responses, until Bob accepts the contact request by adding Alice's TFC-account. This causes Bob's Relay Program to connect to Alice's Onion Service, and request the URL-token related public key. Bob's Relay Program will then derive the URL-token, and offer TFC data (Transmitter Program's X448 public key, or the first PSK-message) via the <address>.onion/<SSK>/messages
path.
Thus, until Bob accepts Alice's contact request, there is no way for Alice to know if Bob has seen and/or accepted the contact request.
While TFC by default only shows each contact request once per session, there is no computational overhead* to generate valid Onion Addresses. The abuse potential of the anonymous contact request is an unfortunate side effect: Since contact requests can't require authentication, attackers can spam random contact requests anonymously to a known Onion URL. It is therefore recommended the user keeps their TFC account secret. Keeping the TFC account secret is also the only mitigation available to hide when the user's TFC endpoint is running. This is because the prop224 basic_auth
functionality hasn't been implemented yet for v3 Onion Services.
Such a spam attack is not expected to be a major issue, as it is based on the fact it's noisy, and it would alert the user someone has ill intentions towards them. If the spam turned out to be a problem, contact requests can optionally be turned off with the command /set accept_contact_requests False
. Disabling the contact requests is not visible to the attacker in any way: the server will still report it has acknowledged the contact request. Disabling the contact requests does not block adding contacts completely, as the built-in mechanism to isn't the only way to exchange Onion Addresses.
*One possibility to mitigate this issue, would be to only display vanity Onion Addresses that have their first n
characters fixed to some value. For example, by accepting only requests from unique Onion Service accounts that start with e.g. tfc
, it would force the attacker to generate on average 32^3 = 32,768
keys for every spam request. Setting such limits can however hurt the users on slower hardware, and in some situations such as having hard copies of TFC accounts, would reveal the purpose of the Onion Addresses to a third party, who finds the list.
The X448 key exchange is described in the following image:
NOTE: In the explanation below, a single quote '
is used to denote data from the contact.
-
The Transmitter Program generates an X448 private key KS and derives a public key KP from that.
-
The public key KP is sent to the contact as TFC DATA via the Tor Onion Service (explained above).
-
The Relay Program of the user displays the contact's public key KP' once the Relay Programs have connected to each other. Bitcoin's Wallet Import Format (Base58 with checksum) is again used here. However, whereas the local key decryption key uses the Mainnet header, X448 public keys use the Testnet headers. This way the user is unable to accidentally enter the wrong type of key to the wrong field.
-
The user manually types the contact's public key KP' to their Transmitter Program.
-
The Transmitter Program derives the X448 shared secret from the private key KS of user and the public key KP' of contact. Because the raw bits of the X448 shared secret might not be uniformly distributed in the keyspace (i.e. bits might have bias towards 0 or 1), Transmitter Program passes the raw shared secret through a computational extractor (BLAKE2b CSPRF in this case) to ensure uniformly random shared key. The Transmitter Program uses this shared key as a source key, and feeds it together with a public key (counter) and the type of the key (context variable), into a KDF (BLAKE2b) to derive unidirectional message and header subkeys and fingerprints:
sender_message_key = blake2b(message=receiver_public_key, key=x448_shared_key, person=b'message_key') receiver_message_key = blake2b(message=sender_public_key, key=x448_shared_key, person=b'message_key') sender_header_key = blake2b(message=receiver_public_key, key=x448_shared_key, person=b'header_key') receiver_header_key = blake2b(message=sender_public_key, key=x448_shared_key, person=b'header_key') sender_fingerprint = blake2b(message=sender_public_key, key=x448_shared_key, person=b'fingerprint') receiver_fingerprint = blake2b(message=receiver_public_key, key=x448_shared_key, person=b'fingerprint')
-
The Transmitter Program prompts the user to establish an end-to-end encrypted call with Signal by Open Whisper Systems and to verify the TFC public key fingerprints F and F'.
-
The Transmitter Program encrypts contact's TFC account, nick, message keys KM and KM', and header keys KH and KH' with the local key KL.
-
The Transmitter Program outputs the ciphertext CT to the Receiver Program via the Networked Computer.
-
The Receiver Program decrypts the ciphertext using KL and stores the contact's TFC account, nick, KM, KM', KH and KH' to its key and contact databases.
-
The Receiver Program displays a confirmation code cc to the user. The cc is a deterministic, truncated BLAKE2b hash of the Onion Service public key of the contact.
-
The user types the cc to the Transmitter Program which completes the key exchange.
Any messages received from the participant who completed the key exchange first, are cached by the slower participant's Receiver Program until that participant has also derived the keys.
Fingerprints are human-readable values intended to verify the key exchange was not under a Man-in-The-Middle attack (MITM). MITM attacks can not be solved by cryptography itself, thus it is paramount that the users check their fingerprints match.
The fingerprints verified in step 6 above are presented in the decimal format to make pronunciation fast and easy in any language. We believe the proper balance between convenience and security is to always display the fingerprints and ask the user to verify them, but not force them to do so. Transmitter Program stores the public key fingerprint pair into the contact database. Fingerprint verification can be skipped by pressing Ctrl + C in the "Did the fingerprints match" y/n
prompt. This sets the fingerprint verification status as (Unverified)
. The fingerprints can be verified at later point with the command /verify
.
If a MITM attack is detected during the fingerprint comparison, users should select No (=keys did not match)
which aborts the key exchange. In such a scenario there are few options.
- They should try again later (which results in different Tor circuit)
- If the users know each other in real life and are able to, they should meet and exchange PSKs.
- Only if the users have no other contacts, they could also try deleting the
$HOME/tfc/user_data
directory and starting fresh with completely new Onion Service addresses. This will destroy all user data, keys, and logs, and should be done only as a last resort.
TFC uses well-thought-out design for fingerprints: Instead of just using hashes of public keys, fingerprints are domain separated, derived keys: they cannot be correlated with public keys without knowing the X448 shared key. To understand the security benefit, assume a scenario where the fingerprints users compare are regular hashes of public keys. In a situation where the Networked Computer running Tails has been compromised to the point the adversary can monitor public keys the Source Computer outputs via the serial link, the adversary can associate the public key with a particular endpoint but isn't able to tell to whom the endpoint belongs.
Now, suppose the adversary is also eavesdropping and transcribing ( 1, 2, 3, 4 ) calls: They can record the spoken fingerprints and associate them with the person to whom the phone is registered. Since fingerprints are hashes, the adversary can generate an endpoint-to-public-key lookup table and by hashing the public keys, add fingerprint for each endpoint. To deanonymize the endpoint, all the adversary needs to do is perform a reverse-lookup.
To prevent this attack, fingerprints in TFC are not hashes, but domain separated subkeys, in other words, keyed hashes of public keys. As the adversary does not know either participants' X448 private key ( KS or KS'), they do not know the X448 shared key. Without the shared key, the attacker is unable to derive the fingerprint from the public key, and so, correlate endpoints with real-life identities of callers.
X448 is not future-proof because quantum computers are making their way (albeit slowly). In future, a 4060-qubit universal quantum computer will be able to break the key exchange with Shor's algorithm, which makes retrospective decryption of conversations, the symmetric keys of which were agreed with X448 trivial to break. The currently available post-quantum key exchange algorithms use much longer keys when compared to ECC. They are fine with applications that run on networked TCBs, but such keys are infeasibly long to type by hand in systems such as TFC. Until trustworthy post-quantum algorithms with short keys are found, TFC users looking for post-quantum security are stuck with pre-shared symmetric keys.
While PSKs are not practical in all cases (especially if the contact lives across the world), the people who would use TFC are assumed to be close to one another and to have at least occasional face-to-face meetings during which PSKs can be exchanged. PSKs have effectively indefinite lifetime, so even an expensive trip to perform the key exchange might be worth it. The last thing to consider is the key authenticity: The highest assurance against MITM attacks is obtained in physical meetings, and exchange of removable media containing pre-shared keys is even easier than verifying public keys aloud or comparing QR-codes.
The PSK exchange protocol is as follows.
NOTE: In the explanation below, a single quote '
is used to denote data from the contact.
-
The Transmitter Program generates message key KM, header key KH and salt S.
-
The Transmitter Program prompts the user to enter and confirm a PSK encryption password Pwd that will be told to the contact.
-
The Transmitter Program derives key encryption key KKE from Pwd and salt S with Argon2id. The Argon2's
memory_cost
is fixed to 512 mebibytes to allow interoperability with low-end hardware (such as netbooks) the contact might be using. To ensure long key derivation times,time_cost
is fixed to 25 to make derivation slow, but not unbearably so. -
The Transmitter Program encrypts KM and KH using KKE to create ciphertext CTPSK. It then prompts the user to insert a
clean
never before used removable media into the Source Computer, into which the Transmitter Program then stores CTPSK || S under file name such asu5oeq.psk - Give this to s7tcr
where
u5oeq
is the first five characters of the user's TFC-account ands7tcr
is the first five characters of the recipient's TFC-account. -
The Transmitter Program encrypts contact's TFC-account, nick, KM and KH using the local key KL to create CTTx.
-
The Transmitter Program outputs CTTx to the Receiver Program via the Networked Computer.
-
The Receiver Program decrypts CTTx using KL and stores contact's TFC caccount, nick, KM and KH to contact and key databases.
-
The users exchange removable media in a physical meeting. The passwords Pwd and Pwd' protecting CTPSK and CTPSK' should also be exchanged somehow. For example
-
Verbal exchange during the meeting where the keyfiles are exchanged.
-
Verbal exchange over an end-to-end encrypted call (e.g., Signal, the security QR-code of which was scanned during the key exchange meeting).
-
Delivery on a separate security device (e.g., a Yubikey).
-
Passwords should not be included on PSK delivery media itself. This prevents a single point of failure for PSK delivery. Furthermore, the PSK already contains the 256-bit salt that is essentially the same thing.
-
-
The user places the removable media of the contact to their Destination Computer and issues the command
/psk
to their Transmitter Program. The program forwards the command to the Receiver Program that then opens the PSK selection prompt. The user selects the PSK file from the removable media.WARNING! If the user connects the contact's PSK transmission media into their Source Computer instead of their Destination Computer, all security of the user's TFC endpoint must be assumed to have been lost permanently. This is because the Source Computer might now have been infected, and it might export private keys to the Networked Computer when the user is not looking.
WARNING! If the PSK is exchanged with an untrustworthy contact whose device contains malware and a covert wireless exfiltration channel, all security is again, lost. PSKs must never be exchanged with people the user does not know well. A wise precaution is to copy the PSK file from the thumb drive to the Destination Computer's disk and to remove the thumb drive before even starting TFC's Receiver Program. Another way to add security is to use dedicated buffer computer (e.g. a netbook) running Tails to copy the PSK file to a thumb drive the user has bought themselves. While this doesn't prevent software implants, it does reduce the risk of covert transmitters in PSK delivery hardware exfiltrating TFC databases.
-
The user enters the password Pwd' as told by their contact into their Receiver Program, using the keyboard of the Destination Computer.
-
The Receiver Program derives the key decryption key KKE' from the contact's password Pwd' and salt S'.
-
The Receiver Program decrypts CTPSK' using KKE' and stores contact's KM' and KH' to its key database.
-
The Receiver Program displays a confirmation code cc to the user. The cc is a deterministic, truncated BLAKE2b hash of the Onion Service public key of the contact.
-
The user types the cc to the Transmitter Program which completes the key exchange.
Once the keyfile is imported from removable media, it is overwritten with the tool shred, and the user is advised to physically destroy the PSK transmission media to ensure forward secrecy of keys, and that no data leaves the Destination Computer.
The user must always assume the contact's removable media/Yubikey etc. contained malware that exfiltrated sensitive keys and logs of the user on the device. Thus, the device(s) must never be returned to the contact, and they must be destroyed physically. It is the responsibility of the contact to know they can not have their device(s) back.
In TFC, a group conversation is nothing but an agreement between multiple users to make their Transmitter Program multicast messages and files to each member of the group and to create a new window to their Receiver Program, into which the members are allowed to redirect their private messages. Redirection is requested by prepending the message with a group message header and the group's 4-byte ID. The prepending happens automatically when the group is active. Window creation, management, and selection also happen automatically with encrypted commands, whenever the user edits the members of the group or selects the group.
When the user selects a group, all message and file packets sent to the members of that group are encrypted with the message key that would be used to encrypt private messages to that member. Regardless of to how many packets a message had to be split, it will be delivered to one group member at a time. The design means some members will receive the message sooner than others. However, having the ability to send the message successfully to as many users as possible takes priority over keeping the conversation synchronized. For example, would the serial interface disconnect from the optocoupler for a moment, multiple group members would lose the ability to decrypt the long message, as one or more assembly packets would be dropped for each of them.
TFC allows the user to choose whether the members of the group are notified about the user adding/removing contacts to/from their side of the group. Removed members by design never get a notification about them being removed. If the user adds a removed contact back to the group and notifies them about it, only an invitation to join the group is displayed to that contact.
Messages about leaving the group are gentlemen's agreements. For example, in a group of three members, Alice, Bob, and Charlie, say Bob leaves the group and sends a notification about it to the two other members. The Relay Programs of Alice and Charlie will, in that case, display a message that Bob has left the group, but the program will also warn them that unless they remove Bob from their side of the group, any message they send to the group should be assumed to be still readable by Bob. Bob does not even have to modify his Receiver Program to do that. All he needs to do is join back to the group and not send a notification about it to the contacts; Since by design, groups use the same keys used in private conversations with the contacts, preventing this kind of 'eavesdropping' would require proprietary software clients which is again a horrible idea, and still not safe from a skilled reverse-engineer.
Below is a dissection of different types attacks to obtain metadata about user activity. These attacks are performed by two different types of attackers: Eve is an eavesdropper who is monitoring traffic at ISP level. Mallory is a malicious active attacker who has compromised the Networked Computer and is observing what inputs the computer receives from the network, Source Computer, and local peripherals, and what it outputs to the Networked Computer's screen and to Destination Computer.
The amount of metadata TFC leaks depends on whether traffic masking is enabled. When it is enabled, Transmitter Program will output a constant stream of noise messages to Receiver Program of the selected contact or members of the selected group.
In the dissection below, if traffic masking setting affects the end-result, the implications of both setting values are discussed.
Real-life identity of the user
Since Relay Program reveals nothing about the identity of the user or their contacts, the identity of the user is not revealed even to Mallory. However, as any personal files on Networked Computer can reveal the identity of the user, use of Tails live USB (that does not store personal files) is highly recommended. Registration details of Networked Computer's hardware can also deanonymize the user, so the use of commercial off-the-shelf (COTS) hardware paid with cash is highly recommended.
Geolocation of the user
Networked Computer is a normal computer, that comes with an ever-increasing number of sensors from Wireless interfaces to GPS antennas, microphones, web cameras and so on, that can deanonymize the user or reveal their location to Mallory. Stripping all sensors is highly recommended. An additional layer of anonymity can be obtained by connecting to a random public Wi-Fi access point using a long-range parabolic or Yagi antenna.
IP address of the user
Debian based Networked Computer does not force all connections via Tor by default, so it can trivially reveal the user's IP-address to Mallory. Use of Tails OS (that enforces Tor routing) on Networked Computer is highly recommended. This is because on Tails, special care has been put to whitelist applications' rights to request e.g. the public IP address of the endpoint.
Type of data transmitted
When traffic masking is disabled, sent files appear to Eve as large bursts of Tor cells. The burst will indicate a file transmission, but it requires a traffic confirmation attack. Mallory on the other hand, can see when the user outputs files.
When traffic masking is enabled, the Source Computer will output messages and files inside assembly packets, amidst noise packets. As all these packets look identical to Mallory, the type of transferred data is hidden from both Eve, and Mallory.
Traffic masking makes an exception to packet output order: when a long message or file is sent to the group, each contact will receive multi-packet transmission roughly at the same time. The reason for this is to hide the length of the message, each member of the group must receive one packet at a time. One way to see this is, it would be pointless to send a noise message to all other members while one contact receives the long transmission.
Social graph of the user
Regardless of traffic masking setting, Eve learns nothing about the social graph of the user. However, Mallory can see to which call signs (Onion Services) the user talks to, as well as what kind of groups the user has formed from them, and when the user talks to the group. Mallory will not be able to learn whether an incoming message from a contact is a private message or a group message, unless she has also compromised the Networked Computer of the sender. However, as long as Mallory is unable to determine the real-life identity of users, their social graph remains hidden.
Quantity and schedule of communication
When traffic masking is disabled, Eve only sees that a burst of Tor cells was uploaded to the network. However, Mallory can see when and how many messages the user sends to each contact.
When traffic masking is enabled, Source Computer will output a constant stream of noise messages to Networked Computer. To prevent the user from accidentally revealing interaction with contacts, changing the active recipient of messages is disallowed. That way TFC hides quantity and schedule of output messages from both Eve and Mallory. It should be noted, however, that the use of Networked Computer reveals to Mallory that the user is present. It does not indicate TFC is being used, unless the user interacts with the TFC's Relay Program (e.g., if the user closes and reopens the application).
Message length
When traffic masking is disabled, Eve can only see Tor traffic, but Mallory can see how many packets Source Computer outputs to each contact. However, since TFC applies compression and padding to round the length of the compressed message to the next 255 bytes before encryption, Mallory does not learn the exact length of message or file.
When traffic masking is enabled, even Mallory will be unable to tell when message or file transmissions start or stop. The moment the transmission of a message or a file completes, the next packet will again be a noise packet.
Existence of Onion Server and the fact TFC is used
Assuming Eve does not know the full TFC account, she is unable to decrypt the blinded Introduction Points in the Onion Service descriptor to establish a connection to the server.
Since Mallory is assumed to have control over the Networked Computer, she both knows the Onion Service's address and that it represents a TFC endpoint. However, since each TFC user looks like a typical Tor user, it is difficult for her to know which computers she should compromise in the first place. The fact it's hard to even figure out who is using TFC (and where they are physically located) makes proximity attacks very difficult.
Under the hood, the Transmitter Program handles traffic masking with five processes: input process, sender process, two instances of noise packet generator processes and a logging process. The input process adds headers and padding to message, file, and command assembly packets, and places them into either message, file or command queue. The noise processes fill noise queues with noise packets. Both the input process and noise packet generator processes place identical tuples of data into the queue.
The sender process is an infinite loop that loads a boolean value for message, file and noise queues' status, and based on the result, picks the highest priority queue that has a 255-byte long block of plaintext data waiting. Selecting the queue is done by list indexing which is constant time (Python is a high-level language, so guarantees are hard to make). The queues are loaded under a ConstantTime context manager to reduce the attack surface further: The actual runtime of the function is much shorter on platforms that meet the minimum system requirements of Ubuntu 20.04 (Dual Core 2GHz, 4GB RAM).
Once a file or message packet is loaded from a queue, it will be sent to the selected recipient or members of the selected group. The recipient is selected (and locked) when traffic masking mode is enabled, or when the Transmitter Program is started (assuming traffic masking setting is enabled). The delivery of the packet is again done under the ConstantTime context manager that obfuscates slight variations in timing (XChaCha20-Poly1305 is a constant time cipher, but Python code around it might not be). To add even more security, the constant time context managers delay value is altered with a random amount specified by the kernel CSPRNG. Between each sent packet, the sender process checks under separate constant time context manager if a command is available, and based on that information either outputs the awaiting command, or a noise command.
All output packets are forwarded via multiprocessing queue to the logging process that will determine whether the packet will be added to the log file. Using separate processes prevents issues with i/o blocking that might affect the sender process, and reveal when TFC is being used. If logging for contact is enabled during traffic masking, only sent messages are logged. If the setting logfile_masking
is also enabled, user's Transmitter and Receiver Programs will log all the other sent and received packets (excluding commands) as placeholder data. This includes both whispered messages, and file/noise packets. The purpose of logging whispered messages as placeholder data is to hide the fact whisper messages have been sent: it's impossible for the physical attacker to determine from the ciphertext that it message wasn't in fact a noise packet.
The Receiver Program handles noise packets from all contacts without any alterations to settings. To maintain the per-packet forward secrecy, the Transmitter Program will have to re-derive keys between each message, which is troublesome. If the Networked Computer or the Destination Computer of any recipient goes offline for extended periods, catching up with the hash ratchet state after coming back online might take quite some time. The only existing solution for this is to ensure client uptime. The problem can be mitigated by ensuring Destination Computer has a fast CPU. A future consideration for better efficiency in hash ratchet performance is switching to BLAKE3, which is even faster than BLAKE2 currently used.
TFC sends files differently depending on whether the traffic masking is enabled or disabled.
When traffic masking is not enabled, the Transmitter Program compresses and encrypts the file, and outputs the ciphertext to the Networked Computer together with a list of all the TFC accounts that should receive a copy of the file. Transmitter Program will then send each recipient a file key delivery message
that contains the 32-byte BLAKE2b digest of the nonce, file ciphertext, and the related tag. The message also contains the file decryption key. This format allows multicasting the file with Relay Program. The decryption key for each contact is identical, but existential forgeries are not possible, as any alteration to the plaintext will produce a different ciphertext, the hash of which will not be found on the recipient's hash : file_decryption_key
dictionary. As the Receiver Program will discard the file key from the dictionary immediately after file decryption, replay attacks with file packets are not possible.
There is another reason to use same the symmetric key for each recipient: Mallory who has compromised the Networked Computer can with high probability link the encrypted files together. The reason she can do that is no efficient padding scheme can hide the exact file size. Thus, all ciphertexts of the same file the Source Computer outputs will be of the same size. Multicasting different looking, roughly equal length ciphertexts sequentially would not fool Mallory -- it would only slow down file transmission and increase the duration the file transmission reserves the serial interface.
When traffic masking is enabled, the Transmitter Program compresses the file, concatenates decryption key to enable sender based control over partially delivered data, splits the ciphertext into assembly packets and delivers them to the recipient(s). This process is identical to transmission of long messages, but the content is different as are the packet headers. Files are usually large, thus outputting them can take a very long time. During traffic masking messages have higher priority than files, so the sender process outputs packets from the message queue first. This makes it possible to send messages while the file transmission takes place on the background (i.e., when no message is being transmitted).
Compromise of the Source Computer completely undermines the security of TFC. To protect the user, the installer install.sh
is authenticated with a 4096-bit RSA signature, the verification key of which is imported only if the SHA256 digest of the public key file matches the digest embedded to the installer one-liner. The installer configuration for Relay, and local testing look identical to the installer configuration of the TCB configuration, until the point where the TCB configuration automatically cuts all network connections. This happens as soon as all dependencies have been downloaded to minimize the window of opportunity to compromise the system. The idea here is to hide the purpose of the device that would otherwise be revealed by the traffic shape, until it's too late to compromise the TCB. Hopefully this forces the attacker to attempt compromise of all three computers in order to compromise the Source Computer, and hopefully, such louder attack would also be easier to detect by a careful user.
If the user is targeted by a nation-state actor during the setup and Source Computer is undetectably compromised, no security can be achieved. The attack applies to all secure communication tools that are obtained from the network. The compromise can, however, be detected to a limited extent: If a packet analyzer such as Wireshark is used to monitor traffic during installation, the amount of data in the .pcap file to audit will be finite. Additionally, as the Source Computer is unable to determine what’s on the receiving side of the data diode, the receiving end can be plugged into a spectrum analyzer. These devices can see hidden signals because no information is missed: the displayed output is the result of FFT calculations. Since optocouplers are not analog, analyzing the output of optocoupler's Rx-side should trivially reveal covert channels, as any signal that turns the Tx-side LED on enough to activate Rx-side photodiode, will raise the Rx-side V_OUT to Vcc (5V).
Even though the Receiver Program does its best to drop invalid packets and authenticate all ciphertexts before decryption and handling, a constant window of opportunity remains to exploit the Destination Computer with a carefully crafted packet that might exploit, e.g., a buffer overflow vulnerability in the serial interface's driver, CPython, or PySerial library. The malware delivered as payload might then show arbitrary messages in the TFC program. These messages are however very likely out of context, as there is no way for the adversary to obtain knowledge about the content of plaintexts. This is again, because the Source Computer (the adversary can't send malware to) only outputs ciphertexts the adversary on Networked Computer has no decryption keys for, and because neither keys nor plaintexts can be exfiltrated from the Destination Computer. Additionally, if Bob's Receiver Program showed forged messages and logging is enabled by both parties, the attack can be detected by cross-comparing Source Computer side log of Alice with Destination Computer side log of Bob and vice versa. To detect malware that displays different messages than it logs, an extensive audit stage -- where messages are either videotaped or observed in real time -- is needed.
Unaddressed covert channels could be used to exfiltrate data from the split TCB:
-
The user might reuse removable media used to deliver PSKs. In such case the Destination Computer could infect the Source Computer that could then exfiltrate sensitive data. The PSK transmission media from an untrustworthy contact might also contain a covert transmitter, that an accompanied malware might use to exfiltrate key material.
-
The user might forget to remove wireless interfaces such as Wi-Fi, LTE, Bluetooth, and NFC from Source or Destination Computer. The interface could then be used to infiltrate malware and exfiltrate keys with the malware.
-
In addition to these channels, multiple covert ones -- that could leak or be used to exfiltrate keys from Source or Destination Computer -- have been found:
- Malware could exfiltrate data from the Destination Computer with emissions
- Electromagnetic channels (eavesdropped by the antenna of a nearby smartphone/implant)
- Thermal channel (eavesdropped by a nearby temperature sensor / thermal camera)
- Artificial workload (BitWhisper, HOTSPOT)
- HVAC systems connected to TCB-side network (HVACKer)
- Power lines (eavesdropped by tapping into the main electrical service panel of the building)
- Controlled power consumption (PowerHammer)
- Acoustic channel (eavesdropped by a nearby microphone or laser microphone that has line-of-sight)
- Fan pitch changes (Fansmitter, AiR-ViBeR)
- Mechanical drive (ROM, HDD etc) sounds (DiskFiltration)
- Inaudibly high sounds from speakers to mics (O`Malley, Choo, Hanspach, Goetz)
- Inaudibly high sound from speakers to speakers (MOSQUITO)
- Motherboard capacitor squeal (Genkin, Shamir, Tromer)
- Optical channel (eavesdropped by a camera in the space / outside the window)
- ROM drive tray position (CDitter)
- Invisibly fast blinking of screen (VisiSploit)
- The light of scanner (Nassi, Shamir, Elovici)
- Lights in USB keyboard (Veres-Szentkirályi)
- Monitor's LED indicator (Sepetnitsky, Guri, Elovici)
- HDD LEDs (LED-it-GO)
- Router lights if connected to TCB-side network (xLED)
- Security camera IR LEDs if connected to TCB-side network (aIR-Jumper)
- Source or Destination Computer might unintentionally leak sensitive data to nearby smartphone, device or implant
- Acoustic leak of messages/keys typed with the keyboard
- Smartphone accelerometer ((sp)iPhone)
- Networked Computer speakers/headphones (SPEAKE(a)R)
- Electromagnetic leaks
- Display / keyboard cables (van Eck phreaking / TEMPEST)
- CPU Cores (ODINI)
- Acoustic leak of messages/keys typed with the keyboard
- Malware could exfiltrate data from the Destination Computer with emissions
There exists a possibility, where an attacker could compromise the Destination Computer in a way that makes the device display some message based on key data. The user's reaction to that message on the Source Computer that is visible either to Networked Computer (i.e., when traffic masking is disabled) or to the recipient (i.e., when the attacker is also a contact), can leak key data to the adversary. The only way to prevent this is to use traffic masking and to vet contacts carefully.
TFC mitigates against the different variations of this attack to the furthest extent:
-
The first variant is a timing attack, where malware on the Destination Computer delays the display of received public key by, e.g., an hour. If the first bit of the key to be exfiltrated is 1, the attacker who monitors the Networked Computer can determine that bit by reasonable confidence if the user (re-)initializes the key exchange and outputs a public key to the Networked Computer after one hour. This attack is prevented by displaying received public keys on Relay Program only.
-
The second variant is a timing attack, where malware displays or delays messages from a friendly contact, and looks for effect on the user's replies to the contact. This attack is mitigated by having the Relay Program determine the timestamp when the message packet was received, and deliver that information to the Destination Computer, where the Receiver Program will display it next to the message content. The timestamp is displayed with 10ms resolution. The user can detect this variation of the attack if
- Receiver Program displays the message with identical timestamp much later than the Relay Program, or
- no packet with the exact same timestamp exists on the Relay Program's ephemeral packet log.
-
The third variation is oblivious exfiltration of key data to an adversary on the Networked Computer. If the malware on the Destination Computer makes the Receiver Program display a message such as
Hey Bob, add my friend David: davidw6wvfxqjqknntxrt6rw3ngwt6hqeqrcgldu47miq2xfzfqhqsid
what could happen is, such contact does not exist at all. Instead, the displayed account is the onion-URL encoding of a sensitive key such as the root-state of the local key (or the local key decryption key) the malware on the Destination Computer is trying to exfiltrate. If the user adds this account as a contact with the Transmitter Program, the Relay Program cannot tell the difference when it tries to connect to the purported Onion Service. However, the attacker on the Networked Computer can try to decrypt commands with the account and its hash ratchet states. Due to the possibility of such an attack, the user should never add contacts displayed only by the Receiver Program.
Instead, the user should always receive the account (also) through some other way, such as the Relay Program, Ricochet, Signal conversation, or a phone call. In other words, the account must be received via at least one source other than the Destination Computer. The additional source proves the account is not a sensitive key. The same also applies to theoretical group management messages malware on Destination Computer could spoof. The bundled unknown accounts might represent sensitive keys. Another related matter is the user should never join groups the group ID of which did not (also) originate from Relay Program's group invitation message. I.e., if the user sees a message from a contact like
Hey Bob, join our group "cypherpunks" under group id "2de6sbn1tCH4R" with David and Eric
the group ID might contain part of sensitive key data. If the user adds the group and sends a group management message about it to each contact, Mallory can see that key data from the Networked Computer of the user. Thus, like TFC accounts, the group ID must come from the Relay Program. (While the group ID could be delivered to the Destination Computer inside an encrypted message, it would provide an effective exfiltration channel for frenemies that have compromised user's Networked Computer and Destination Computer.)
Group IDs are random and unlike in, e.g., Signal, they are not secret, because on Networked Computer, Mallory can see the user output a message to a bunch of contacts, and determine they form a group. Knowing the group ID does not give any privileges to anyone, not even to a contact of the user unless the user has added the contact to members of the group.
TFC allows the user to quickly clear all screens with command space, space, enter. Messages can then be re-displayed with the command /msg <nick>
. If the user wishes to clear the ephemeral message log, they can issue the command /reset
. The user can also enable the setting double_space_exits
on Transmitter Program to enable panic exit functionality that resets all screens and closes TFC. This preventing, e.g., impersonation and log file access without the master password. With the setting on, the command /clear
can still be used to clear TFC screens. The highest protection against physical threats is achieved with /wipe
command that requires the user to confirm the erasure. The command overwrites all user data on all three computers and powers them down. With full disk encryption and DDR3 memory, this should offer sufficient protection against cold boot attacks.
Clearing or resetting the Relay Program display on Networked Computer is disabled during traffic masking to prevent an adversary who has compromised Networked Computer from figuring out commands are being issued. During traffic masking, the clear-command actuation speed depends on command packet queue length. Also depending on delay settings, it might take a while before the screen clearing command is delivered to the Destination Computer.
File reception in TFC is disabled by default for all contacts, and it must be manually enabled. Receiver Program does its best to show the user what kind of file is being received, but this information is gentlemen's agreement and can trivially be spoofed by the sender. GNU/Linux offers robust security and requires the user to add the execution permission to received binaries and to execute them manually. However, zero days might still cause problems: Malware sent by frenemies can again, cause data loss or make Receiver Program show arbitrary messages.
Some defense against malware running with user level privileges comes from the side channel resistance of X448, XChaCha20-Poly1305 and Argon2id. To ensure the malware is not able to eavesdrop on e.g. keyboard inputs, users should use the Wayland display server instead of X11.
TFC's default setting max_decompress_size
limits the size of received data (after decompression). The default max value is 100 megabytes. The limitation protects the user against zip bombs in received files (as well as in messages).
The computational security of 256-bit XChaCha20 protects messages against brute force attacks.
The computational security of 128-bit Poly1305 MAC protects against existential forgeries.
The Receiver Program stores the value followed by the most recent accepted hash ratchet counter value to the key database and raises a replay-attack warning if a previous hash ratchet counter value ever repeats. Additionally, as a new MAC key is derived for every message, the older authentication and decryption key no-longer exists: Even if the counter could be bypassed, the MAC verification would still fail as the message key that works has already been overwritten.
Both Transmitter and Relay Programs add adjustable Reed-Solomon erasure code to all datagrams sent over the serial interface. The erasure code allows reconstruction of packet even in the cases of significant errors during the transmission.
Whereas short transmissions can be trivially resent, long transmissions have to be canceled first. The recipient should notify the sender if errors occur between their Networked and Destination Computer so that the sender can cancel and restart the transmission; Unfortunately the physical architecture of TFC makes automatic requests for packet re-transmission impossible.
Since Reed-Solomon introduces computational overhead, users who experience no errors with their hardware can disable it by setting error correction to 0. This will switch TFC to use BLAKE2b-based error detection checksums with truncated 16-byte digests.
TFC is type checked with mypy static type checker to improve code quality.
Currently running the checker with --strict --ignore-missing-imports
flags yields no warnings.
TFC uses Travis CI with unittest coverage report to improve stability and security of the software. Cryptographic functions and the TFC API are tested with official test vectors. The links to the official sources of test vectors are listed in the docstrings of related unittests.
TFC's code has 100% coverage with 0 skips. The tests are however still a work in progress in terms of readability and meaningfulness.
Code quality is checked with pylama that combines among other things
- pycodestyle PEP8 style guide checker. Style is a personal preference and TFC aims for readability instead of following rules.
- PyFlakes error checker
- Mccabe cyclomatic complexty checker
- Pylint style and error checker
- Radon metrics tool
Online code quality is further checked with following tools:
For error handling, TFC uses EAFP where race conditions are a significant issue and LBYL where readability counts more. In any unrecoverable situation, TFC raises CriticalError, which terminates processes and gracefully exits the program.
TFC's installer install.sh
contains a list of pinned SHA512 hashes for TFC source files. These include the PIP requirements*.txt
files that contain pinned SHA512* hashes for dependencies. The dependencies downloaded over APT are verified only with associated certificates. Exfiltration security of private keys of third parties are unfortunately unfixable by us, but TFC downloads APT dependencies first to minimize the attackers' reaction time for MOTS or MITM attacks.
*Note: SHA512 is used over SHA256 only because it's faster due to its larger block size: every millisecond counts during the installation routine for Source Computer.
TFC installer is signed with PGP using a 4096-bit RSA key. The private key is generated, and the code is signed with a permanently air-gapped system to ensure exfiltration security of PGP private key. The SHA256 fingerprint of this public key file is the root of trust for the installation. The signature verification key is automatically authenticated with the digest by the one-liner used to install TFC.
All subprocess.Popen()
function calls with variable data use pipes.quote()
to prevent shell injection from user's Transmitter Program. Functions used in processing received packets from contacts never contain Popen calls.
All SQL-queries use the database API's parameter substitution to prevent SQL-injections. Furthermore, every SQL-query comes from a trusted source, and processing of received packets from contacts never contain SQL-queries.
Files accessed with open(<filename>, <permissions>)
have minimum write/overwrite permissions.