Is Telegram Secure? Or How I Searched for a Backdoor in MTProto
An analysis of Telegram's MTProto protocol reveals a suspicious modification to the Diffie-Hellman key exchange that could theoretically allow the server to perform undetectable MITM attacks on secret chats.
Telegram is a smartphone messenger that positions itself as secure, protecting not only against malicious actors but also against government agencies like the NSA. To achieve this security, Telegram uses its own development — the MTProto cryptographic protocol, whose reliability many people doubt, and so do I.
After the announcement of a reward for decrypting messages, I attempted to dig into MTProto. The fact that decrypting some set of bytes is impossible (or at least very difficult) is immediately obvious, but eavesdropping on messenger traffic isn't the only type of attack.
My first thought was the possibility of a MITM attack (man-in-the-middle), and I went to read the protocol API. There I found that the protection here is fairly solid: at the time of the first client launch, an authorization key is created directly on the client device using the Diffie-Hellman key exchange protocol, but with a small difference — the Telegram server's public key is already hardcoded into the client code, which prevents third-party substitution.
After that, I installed the client, entered my phone number, and what surprised me the most was that I didn't need to enter any passwords — instead, an SMS arrives with a one-time five-digit confirmation code. I took a second phone, installed the client, entered the same number as the first time, another five-digit number arrived, which I entered on phone #2 and successfully authenticated. So there's the first vulnerability. Telegram implemented a multitude of algorithms, eliminated the possibility of traffic interception and substitution, but forgot about a basic password. An attacker doesn't need to listen to the messenger's traffic — they just need to intercept an SMS and access is obtained without any problems.
Let's move on. Telegram has chats with end-to-end encryption, where the key is known only to the conversants, and messages are encrypted with it. This key is obtained using the same Diffie-Hellman algorithm. Many messenger users demand the ability to exchange public keys via NFC and QR codes to 100% eliminate the possibility of MITM attacks, including those from the Telegram server side. Digital Fortress employees (the company that developed the messenger) claim that such functionality is unnecessary (which is already suspicious), and you can verify that nobody has substituted the public keys generated by your conversant by comparing the key visualization (as an image).
And there are a couple of buts:
After one of the conversants logs out, the chat key will be regenerated, and I can only verify that I have the same key as my conversant by looking at their phone with my own eyes. Why do I need an encrypted chat if my conversant is a meter away from me?
I looked into the API of secure chats. And my eye caught this pseudocode:
key = (pow(g_b, a) mod dh_prime) xor nonce
This is the code for obtaining a shared key using the DH algorithm, almost. Let me remind you that the original DH algorithm looks like:
key = pow(g_b, a) mod dh_prime
Variables in the expressions:
- key — the secret key used for encrypting traffic,
- g_b — the conversant's public key,
- a — your private key,
- dh_prime — a public prime number,
- nonce — a "random" sequence obtained from the Telegram server for computing the key.
The question! Why such a modification to the algorithm? If nonce is the same sequence for both clients, it simply turns the key inside out without making it any more secure. But if it's different, then the Telegram server can select a nonce that would make the users' keys match even during a MITM attack, and nobody would know they're being listened to. And even if the nonce matches for both conversants today, there's no guarantee that the nonce will match tomorrow, when the NSA / FSB / some other unpleasant organization shows up at the Digital Fortress office.
For clarification, let's turn to Alice and Bob. The attack could proceed as follows:
Alice initiates a secret chat with Bob and informs the Telegram server about this. The server gives Alice a public prime number (p) and a primitive root modulo p (g). Alice generates her private key (a) and based on it, a public key (A) which she sends to the server.
The server generates its own keys (t and T) and sends T to Bob, disguised as Alice's public key. Along with T, it sends g, p, and a random sequence (b_nonce).
Bob similarly generates keys (b, B) and computes the secret key (s). He sends his public key (B) back to the server.
The server computes s, and based on it, a not-at-all-random sequence (a_nonce), then sends T disguised as Bob's public key and a_nonce disguised as a random sequence.
Alice computes the secret key, which equals both Bob's key and the server's key.
Bob looks at the key visualization on Alice's phone and, seeing the same key as his own, uses the service without suspicion. Meanwhile, Telegram accumulates long logs without any obstacles.
So should you use it? If you need a simple, fast chat, Telegram is an excellent app. If you're paranoid, you definitely should not use it. Because even if I'm wrong and wrote complete heresy, Telegram knows everything about you: your phone number, contacts, SMS messages, location, who you communicate with and when. Pay attention to the permissions list for the app. My opinion is that Telegram is a fast, convenient, but not at all private chat.
UPDATE: The story ended well. The vulnerability was fixed, documentation and applications were updated, bug bounty hunters were motivated, which has already borne fruit. Credit must be given to the Telegram developers, who instantly responded to the article.