This is a great teaching example for the “don’t roll your own crypto” proponents.
This is a great teaching example for the “don’t roll your own crypto” proponents.
(I should add: disclosure, I work there too.)
The crypto design is brittle, but the practical attacks are somewhat limited. The reason why it's so disparaged by cryptographers it because it ignores several decades of cryptographic advances -- the whole saga of attacks on SSL / TLS<=1.2 taught us that key separation and clear protocol composition boundaries are important, but Telegram fails disastrously at these. Security proofs should be made before a protocol is used, not as an afterthought.
The real reason why I would not recommend Telegram is that chats (by default) and group chats (by necessity) are not encrypted. Telegram's servers will be eventually breached by someone. A malicious actor will be hired as a software engineer, or as an intern. When this happens, all you ever wrote in Telegram will be a plaintext at their disposal -- unacceptable in 2022, and post-Snowden.
The interesting part is really just the first step - starting with a user's password, to statically derive a service-authentication key and a data-encryption key that the service provider ostensibly never sees.
At $DAYJOB we independently came up with this same zero-knowledge solution too, using slightly different primitives. Ideally there'd be some well-reviewed zero-footgun nacl.SecretBox()-style thing for this use case, but there simply isn't.
Most people face a choice between rolling their own crypto or not using it at all.
Can you provide a link? That one's hard to Google.
There is a whole hellacious amount of mechanism in this protocol that doesn't seem necessary at all. I don't know if doing it simply would involve more keys or less keys but it would certainly seem to involve fewer concepts and less ad-hoc invention --- PAKEs are a solved problem, KDFs are a solved problem, key-wrap encryption is a solved problem.
Instead they came up with unpadded RSA, ECB-encrypted key blobs, a single shared key for all the blobs, a post-back proof that is just that broken RSA piped directly back to the server. I don't know, seems pretty bad?
Backup and sync-type software has the interesting engineering requirement that it is expected for the user's device to get completely lost/stolen/wiped, so any key material must be reproducible from the user's password.
Password -> KDF(1) gives you a password-alike: used for logins, server treats this kdf output as a password and stores a bcrypt/argon hash of it, as you would normally expect from a run-of-the-mill webapp.
The client generates a random data encryption key; seals it with the password; and then submits the sealed version to be stored in the user's profile on the web server.
The web server can't unseal the original data encryption key without the original password, and it never sees that, only the KDF(1) version of it.
That's all they've really done here. There is one more level of key indirection for the blobs themselves that i think is irrelevant but maybe useful for key rotation. Totally agree that unpadded RSA and ECB suck as primitives - they were bad choices then, they are bad choices now, and AEAD is a no-brainer upgrade (EDIT: and would close the post-back oracle) - but aside from picking better primitives the mechanism really does seem okay to me. I'd love to hear more from you though,
I think if you have a download link of the form https://foo.bar/#abcdef... you can simply put a large random value there (e.g. 128 bit), use HKDF to derive an ID and an encryption key, use the ID (shared with the server) to store/fetch encrypted data on/from the server and the key (not shared with the server) to encrypt/decrypt it on the client side. This would assume that the ID transmitted to the server over a secure channel and that brute-forcing of IDs to download encrypted data is not practical. Such a scheme would not be secure though if you derived the ID and key from a user-provided password, as the server could then brute-force the password from the ID the client provides.
You'd be surprised, but I've seen designers who managed to shoot themselves in the feet with SecretBox() calls alone. Anything more complex than using a library that does the crypto for you calls for an external/crypto team review.
Further, outside of Signal, whose authors won the RWC Levchin Prize for their design work, the other modern secure messengers essentially don't roll their own: they draft off the design work Signal did. Which is a good thing for their users. The alternative course, of coming up with your own special snowflake crypto, gets you papers like the one we're commenting on.
That doesn’t mean it was a great idea for them to pseudo-‘roll their own’, but it doesn’t deserve the vehement hatred that is constantly poured over it.
https://core.telegram.org/mtproto/description_v1
I honestly haven’t looked into anything newer from Telegram because it was pretty clearly a tire-fire and Signal was already a thing.