Don’t Use Session (Signal Fork)
Last year, I outlined the specific requirements that an app needs to have in order for me to consider it a Signal competitor. Afterwards, I had several people ask me what I think of a Signal fork called Session. My answer then is the same thing I'll say today: Don't use Session. The main reason I said to avoid Session, all those months ago, was simply due to…
@soatok@furry.engineer on the note of the cost of the attack from the shattered paper: i did some back-of-napkin math based on the cost of renting more modern GPUs than the ones used in the attack (those were GTX 970s) on a service i presently use to inexpensively rent GPUs, which i use for testing prime number hunting software.
the cost of the attack today, based on my quick math, would be almost exactly $619, if you assume that no time was wasted in setting things up, and you are renting RTX 4090 GPUs.
last time i checked this was, i think, in late 2020. i had a reason to attempt that exact attack, if it was feasible. it was not, i would've still needed closer to $10,000-20,000 at the time (i don't remember the exact figure)
@linear Oh neat!
I wonder if I could convince a cryptography-related company to offer up that much compute for a collaboration on a paper.
@Brett_E_Carlock Haven't looked, but I've been told it hasn't diverged from Signal in terms of cryptography protocols, so that's probably ok
@soatok ooo smarter question: how does signal prevent KCI?
@risottobias See also, https://github.com/soatok/rawr-x3dh :P
@soatok but how would that prevent e.g. the federated key exchange starting point of your implementation?
Like they start with a first key no?
@risottobias The key thing I'm building is for signing keypairs.
Those keypairs sign an ephemeral public key. There is no long-term x25519 public key in my design.
@soatok they took a state of the art design and broke it. if this isn't a honeypot then i don't know what is
@soatok WTAF!?🤯
Your #3 security issue (Session uses the public key as a symmetric key) should be an immediate disqualifier *RIGHT THERE*.
I don't really care if someone fixes that one. The fact that something like that *EVER* passed muster in an application which is supposedly about *privacy* should be an IMMEDIATE DISQUALIFIER.
The public key is public. I don't care if it looks like randomness. It's *public*, FFS.
That "[Tor but] with a few key differences" is pulling a crapton of weight.
The main reason I said to avoid Session, all those months ago, was simply due to their decision to remove forward secrecy
that’s all I need to know really dear god (I will read the rest tho cause it looks interesting :p)
@soatok so...
is the entire security based on the onion routing
@entronid The onion routing is a middleware between "swarms" that allegedly only persist ciphertext for a short term. So, not the "entire" security but a lot of it.
@soatok Session messenger also has connections to the alt-right scene. That should already be enough reason not to use it:
https://web.archive.org/web/20210914000446/https://twitter.com/WPalant/status/1281540005190672384
Using public keys as symmetric encryption key
(Scream into void and void screams back after reading the article 😱😱😱😱😱)
@soatok I treasure my ignorance of cryptography because I believe that there are two safe amounts of crypto-knowledge:
Between them is a dangerous middle ground of thinking you know enough to do something sensible. Hypothetically, there may be a safe middle ground where you don't know much but do know how little you know. I'm not confident of being able to do that.
Your post made me worry, because even I know least why some of those things are a bad idea.
@david_chisnall The problem isn't knowledge, it's confidence.
You can know a lot about cryptography, but unless you've convinced yourself that you know "enough" to do it "safely", you're not at risk of pulling a dangerous move.
@soatok
I have a less technological argument against Session. It's apparently such a haven for distributing CSAM that even websites specifically catering to loli artwork treat sharing a Session chat ID as an instantly bannable offense. Citations intentionally omitted as I don't want to link illicit content.
@KinkyKobolds Thank you for your restraint.
But, yes, I've heard the same. I also heard it was originally spread via 8chan, which is also known for... a lot of the same thing.
@KinkyKobolds @soatok considering that people are thinking it's an honeypot, we can hope that it's that rather than shitty crypto
@Devourer_ITA @KinkyKobolds That would be a huge relief (and also lol when the hammer finally drops on those bastards)
@shiri I get that, but in terms of cryptographic security, it's the best we have currently.
@Septem9er @soatok If I understand things correctly, Session is no longer using Lokinet, so there is no connection to this guy anymore. But I might be wrong.
@bohwaz @Septem9er According to https://oxen.io/session-lokinet and https://github.com/search?q=repo%3Asession-foundation%2Fsession-android%20oxen&type=code it's still pretty baked-in.
@soatok curious how it stacks up in relation to Matrix's protocol defaults
I think a single company in control is itself a security problem, especially with a single client (because poisoning the well is absolutely a thing when they control the stack).
Additionally, comfort of use is a real security concern because most people will trade at least some security for comfort (I've got a tongue in cheek phrase I use: "The opposite of secure is convenient").
I don't really trust something for end to end unless the whole client stack can be fully personally custom and have full freedom of client choice, and platforms I don't trust really until you can run your own custom federated instance of them... until then I consider most security a bit dubious.
@shiri Hmm. I do have an index page listing my criticisms of Matrix and other apps, which might shed some light on the issues I've identified over the years.
I'm also separately working on bringing end-to-end encryption to the Fediverse (with an emphasis on solving key management first).
Some of this work might result in useful building blocks for competing apps. Projects like MIMI might also make a decentralized but secure app ecosystem viable.
@shiri Well, they use the Signal protocol for key transport.
The bigger issue is you can turn encryption off at all.
@soatok hi! I was wondering for a long time: why is it important for a messenger to have PFS? I’ve read the post about KCI, but it seems like it wouldn’t apply if they didn’t screw up their message signing (because identity would be validated via Ed25519 anyway)?
it’s hard to imagine a scenario where my private key would be compromised, but my message history wouldn’t. are there any posts / papers / etc about possible attacks on messengers with no PFS (but proper message signing)?
why is it important for a messenger to have PFS?
A protocol with PFS looks something like this:
If you intercept the encrypted traffic now, and then hacked the server later, you wouldn't have a secret key to retrieve.
Conversely, if everything was encrypted against the long-term public key provided by the server, once you've popped the box you can decrypt all previous handshakes.
That's in the TLS use case, anyway.
E2EE is a bit more sensitive, since it's used for actual comms between people (and there isn't as much bot traffic to filter out). Higher signal/noise ratio.
I’ve read the post about KCI, but it seems like it wouldn’t apply if they didn’t screw up their message signing (because identity would be validated via Ed25519 anyway)?
The KCI problem has more to do with, if I manage to guess a single key at random (e.g., the Debian weak keys bug or something like that happened), I can only intercept one handshake, not all past and future handshakes.
The Ed25519 thing is totally separate, and just shows a poor understanding of cryptography protocols on the part of the Session devs.
@soatok I legitimately can't differentiate between "hanlon" and "nation-state" given the sheer level of incompetence displayed here... Especially "crossing the streams" by using asymmetric key material as a symmetric key. (and that's before considering that they use the public portion of said key material. Just crossing the streams at all is bad enough to warrant "kill it with fire" in my book...)
@becomethewaifu I think this is the right intuition.
If it turns out to be some government's backdoor, it was cleverly written enough to have enough other incompetence to gain plausible deniability.
If it turns out to just be mistakes, it's dangerously bad.
@goldstein This ephemerality (each key, if broken, has a limited blast radius) is talked about in technical terms and bickered about by people that write proofs a lot, but what it comes down to is reducing the value of a single key compromise and having a mechanism for the protocol to recover from compromise.
@shiri @charlotte also confirmed some more vulnerabilities related to groups, but they're not public yet.
@soatok Doesn't it also rely on some weird cryptocurrency to route messages? Can't someone destroy its routing by buying more of that cryptocurrency than anyone else for their node & then refuse to route any messages they get? That seems almost worse than the broken encryption. "Fuck you, I payed one million dollars to make sure you can never send messages with this again."
@soatok Very nice post!
I had issues with Session for longer time (I actually was it’s user for quite some time too lol)
Tho mostly they were due to its pretty bad UX
It’s good to know it also has pretty bad cryptography
@soatok Also question: Do you have any thoughts about SimpleX? I’ve been interested in it for a while, and while I don’t think it’s yet ready to be seen as Signal competitor, I still like the thought of it not requiring phone number which is like my main issue with Signal
@markasspandi https://soatok.blog/encrypted-messaging-apps/ if it's not on the list, I haven't opined about it yet
@soatok @david_chisnall Personally I've always seen it as three levels:
1- Knowing enough to do it safely
2- Knowing enough to know you can't trust yourself doing safe crypto, use only well established patterns and only doing exactly what they've been designed to do
3- Knowing enough to fuck it up
I think I'm at 2 now, yet I now know I wasn't really at 2 in the past when I thought I was, so I think you also can't trust yourself knowing which level you're at!
@dermoth @soatok @david_chisnall yeah, I'm definitely at level 3 there. 😱
@sophieschmieg @soatok @david_chisnall Ouch, that hurts.... 🤣
@sophieschmieg @soatok @david_chisnall Yet at least it proves my last point...
@dermoth @soatok @david_chisnall I mean, you need to know how to mess it up badly if you want a chance at doing it safely.
There is of course also the approach of not knowing enough and messing it up badly, but that is a lot less fun
I amended the post to add a section here in response to a Twitter blue user, scriptjunkie, who thought I didn't understand how asymmetric cryptography works.
Comparing their usage of Ed25519 to an extremely inefficient CRC32 is the only way to adequately describe how YOLO their protocol design is.
@soatok "If an attacker can arbitrarily substitute public keys in chosen plaintexts, the Ed25519 signature doesn’t really prove anything beyond “this wasn’t tampered with in-transit”."
isn't this not even proving that it wasn't tampered with, just that it wasn't non-maliciously corrupted?
@bonzoesc Yeah it's weaker than HMAC because you can just swap the public key with whatever one you want, and then you can generate an Ed25519 signature for which that signature is valid.
@soatok trying to understand scriptjunkies point here, and (even though they make some very questionable claims like a signature automatically proving identity) don't they have a somewhat valid point?
as you mentioned:
In a secure protocol, you first establish the public key for your recipient out-of-band. This is generally what handshake protocols are for, in messaging apps. In TLS contexts, we use certificates for the same reason.
Then, once you have a trusted public key, you use that to validate a signature on the message. Because you have a separate mechanism and process for figuring out which public key is correct, a valid signature is proof that the message is authentic.
so we a) establish OOB that A's public key belongs to A and b) establish that A's message was signed with A's public key to make the conclusion that A signed A's message.
and if it understood scriptjunkie's post correctly and the assumption below holds true, session does this, but just the other way around: it b) establishes that X's message was signed by X's public key (where X is unknown), and a) has already established OOB that A's public key belongs to A, and only if X's public key is A's public key X's message gets authenticated as A's message, which seems like they're doing the same two steps, but just in... reverse order?
like, that bit of code alone is definitely not enough, but this assumes that session does a separate check somewhere that only inserts messages in A's conversation if the OOB-established public key matches the one in the message packet (which has to have been confirmed to have a valid signature from the public key before), but if that assumption holds true, it'd be a very weird but still secure way to do it, or not?
there was zero evidence provided for that claim, so unless that is given this aspect shouldn't be trusted either, but it thinks there is an actually valid point in there
@lexi If the recipient had the Ed25519 public key for the sender, OOB, they wouldn't need to embed it in plaintextWithMetadata
.
In fact, it never does anything further to validate senderEd25519PublicKey
.
You can check yourself: https://github.com/session-foundation/session-android/blob/75e2b87278cc378e21b77b27fa1a2aa773d25520/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageDecrypter.kt#L44-L56
Instead, it returns a Pair<plaintext, x25519publickey>
.
This is then returned to the UI: https://github.com/session-foundation/session-android/blob/75e2b87278cc378e21b77b27fa1a2aa773d25520/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageReceiver.kt#L81-L88
Then this public key is parsed out as `sender in https://github.com/session-foundation/session-android/blob/75e2b87278cc378e21b77b27fa1a2aa773d25520/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageDecrypter.kt#L44-L56
And the only check in isValid()
is that it's non-empty: https://github.com/session-foundation/session-android/blob/75e2b87278cc378e21b77b27fa1a2aa773d25520/libsession/src/main/java/org/session/libsession/messaging/messages/visible/VisibleMessage.kt#L32-L34
@soatok ok yeah what the fuck that is stupid. it had a tiny bit of hope that they didn't fuck up the most basic parts but yeah that is bad lmao
@Mae @soatok
Choices of imputed reasoning include
- naivety & ego acting outside their competence;
and
- intentional malice intending to lure vulnerable naifs to their platform knowing its crackable by every secret service more technical than the Spanish Inquisition.
Not having checked if the principals of Session are even known, let alone what their announced principles might be, I can't guess which.
OTOH check all that apply and presume hostile unless proven friendly are good watch words.
@lexi The burden is placed upon the UI, or on the user if the UI fails to catch it, rather than the signature algorithm itself.
It's not a reasonable protocol design, and it's not a sane way to build a security product.
@soatok This post says that there is an attack of complexity 2⁶⁴ that can recover an Ed25519 private key generated by Session from a public key. I believe that this is incorrect.
Such an attack could be possible if a 128-bit value were used directly as an exponent. But the value is actually hashed first, and the hash is taken modulo a 253-bit value. This combination of functions (hash + exponentiation) doesn't allow the same quadratic speedup for finding a preimage as a pure exponentiation. If the hash function were replaced with a random oracle, it would be possible to prove that an attacker would have to check a substantial fraction of the 2¹²⁸ possible hash inputs to find a preimage. With an actual hash function, the attack complexity is probably the same (2¹²⁸).
@abacabadabacaba You may be correct. I'm planning to write a PoC this weekend to confirm if the rho variant I have in mind succeeds on a much smaller scale.
@soatok Thank you, that's a deep and very clear article!
Has anyone from Session reacted yet?
@sortedetruc Not yet. I imagine the response will consist of:
Happy to be proven wrong on that, of course.
@soatok I think a demo, say for an even smaller seed or a elliptic curve on a smaller prime field like GF(2**127-1) with a 64bit seed would go a long to quell doubts about your claim here.
Because, sad to say, I have problems imagining how the "modified version of Pollard’s rho" in your blog post is supposed to operate.
@zeri I've added a note to the blog to make this question apparent to readers, and to publicly commit to writing a PoC: https://soatok.blog/2025/01/14/dont-use-session-signal-fork/#edit-2025-01-16
@BarbossHack I saw it. I'm already planning a PoC this weekend, and will post a follow-up blog once I have results (even negative ones).
@soatok @BarbossHack i love how they never explained why they chose to generate keys this way and just deflected it with “oh but it’s hashed”
@soatok @BarbossHack like this aberration from how you are meant to use it should come with an explanation for why it is actually okay to do this — the correct way would have been easier too
@charlotte @BarbossHack At the core of their confusion, John Pollard is to blame, because he failed to tackle one of the hardest problems in computer science; naming things.
This should be a fun learning experience.
@charlotte @soatok @BarbossHack No they did
“It’s so that Session can use 13-word mnemonic seed phrases instead of 25 word mnemonic seed phrases”
lol
@markasspandi @soatok @BarbossHack if they used a 64 bit random secret, session can use a 7 word secret, they should look into that
@soatok Yeah but in case of an instant messenger, you are supposed to be able to browse the chat history, so you either can't shred the keys, or the plain-text messages (and I believe that's what Signal does), right? And if anyone hacks the server (the other party in case of E2EE, since the actual server only holds on to cipher-text), wouldn't they also get all of the chat history for free?
@feedable That's a design decision and there are trade-offs you can make.
My preference is to re-encrypt the plaintexts under a different key, for local storage and cross-device synchronization. This lets you shred the ephemeral keys and only need a local storage and backup key, which is unrelated to your communication keys.
@soatok but that's even weirder, since the key is not only global but is also stored alongside the messages (since you don't need to type in a password from which you can derive the key), rendering that encryption useless