2024.06 Vol.2

// End to end encryption #Encryption

Considered Harmful

Cryptography schemes involve layers of cryptographic patterns in order to provide a valuable tool to end users. The lower level patterns, such as hashing or signatures, generally have a straight forward interface and super strong guarantees backed by the maths. It is tempting to take a few of these patterns, describe a protocol involving them, and think to yourself “Dang, I just made a super secure X!”. Whatever X may be, it is built on these battle tested crypto patterns, so it just inherits the properties! This is a trap though, leading to the often typed advice “Do not roll your own crypto.” While the patterns do in fact have these guarantees (maths), it is all to easy to describe a protocol which completely undermines them on accident. A scheme which does this is “considered harmful” since users will shoot themselves in the foot trying to use it.

I think Nostr’s NIP-04 is an interesting example. If I was to hack out an encrypted chat protocol over Nostr, I think it would look something like NIP-04! Which is not the greatest sign for NIP-04. But the Nostr context is a complicated one and does a good job exposing why these schemes are difficult to create, so let’s start there. The goal of Nostr is censorship-resistance. In the simplest Nostr use case, users post signed messages (a.k.a. events) to any number of untrusted (!) relay servers. Any user can read these messages and verify the signature attributing the message to the author. For a user to be censored, an adversary would need to stamp out all relays hosting the user’s messages. One can view all the Nostr relay’s as a public, censorship-resistant file system. And when you make it sound like that, you can start to imagine all sorts of use cases to build on top of this shared file system. So what about sending a message to just one person instead of the default public broadcast? A private message of sorts.

Nostr already has public/private key cryptography built-in, that is how any message is signed by its author. If we know a user’s public key on Nostr, can we just encrypt a message with that, so only the user could decrypt it with their private key? Sure could, a quick pit stop on why that is not the most efficient scheme though.

Hybrid Cryptography

Asymmetric cryptography (public key cryptography) is almost never used to encrypt a message directly. It is far less efficient to encrypt and decrypt data than symmetric cryptography schemes. However, it is much easier to establish a symmetric key over an open channel using asymmetric cryptography. So higher level protocols generally use a bit of asymmetric to get things started and then symmetric after that, in other words, hybrid cryptography.

NIP-04

Ok, so we won’t encrypt the whole private message with the receiver’s public key. Instead, the sender generates a random symmetric key, encrypts the message with that, and then encrypts the symmetric key with the receiver’s public key. The sender can then post the Nostr event to the “public file system” by just concatenating those two ciphertexts, delimited by some symbol. How would a receiver know the message is for them though? Maybe the sender just tacks on the receiver’s public key in plaintext, so the receiver can easily scan for their messages.

This is pretty close to NIP-04. There are some in-the-math-weeds things I am glossing over. However, the only major difference is the symmetric key is generated with a Diffie-Hellman exchange (instead of the transport pattern), but the same goal is accomplished. So what are some weaknesses of this scheme? Going back to the “Nostr relays are a public file system” analogy, these encrypted messages are going to be sitting around forever for anyone to read. If someone is able to at any point steal a receiver’s private key, they can decrypt all the NIP-04 messages to the receiver. There is no forward secrecy (a.k.a. backtracking resistance). This is a downside to performing the key exchange over the public channel.

More weaknesses become apparent when we drop the “public file system” analogy. The issue with this analogy is that it covers up that not all relays are trustworthy. If all we care about is getting a message out to the world, this isn’t a big deal since we just need one relay to work. But does that still apply to the private message use case? When the sender posts their private message to the receiver on relay X, the sender is revealing all sorts of metadata to the relay. Since Nostr is based on WebSockets (an extension of HTTP) the sender’s IP address, and any other network-level metadata, is revealed to the relay. The relay now knows that the owner of this IP is communicating with the owner of the receiver’s public key. It is similar to a side-channel attack, the cryptography scheme isn’t being attack directly, but data is leaking due to the underlying infrastructure the scheme is running on. The relay can’t decrypt the ciphertext, but the metadata can still be used to triangulate users. For example, a relay might also have information on when an IP address is communicating with a Bitcoin node and could start to deduce the subject of the ciphertext.

So NIP-04 leaves a bit to be desired from a privacy perspective. Are there possible improvements?

NIP-17

NIP-17 is the followup to NIP-04. It composes two other NIPs, NIP-44 and NIP-59. NIP-44 defines a hardened encryption scheme, things like key exchange and ciphers, which is nice, but doesn’t address the privacy issues of NIP-04. NIP-59 is where things get a little weird trying to plug some of the metadata leaks. The technique used is called a gift wrap. The gift wrapping makes it much more difficult for users to analyze the public message metadata in the future and to try and connect the dots between sender and receiver. However, the wrapping does not address the side-channel-esque leak that relays see when the messages are first posted. NIP-17 addresses this by suggesting that private messages should only be posted to trusted relays, and those relays shouldn’t propagate the messages to other non-trusted relays. So to fully mitigate side-channel attacks the channel needs to be trusted.

NIP-104

NIP-104 is another proposal for private messages based on Signal’s Double Ratchet scheme. It is pretty complicated, but one of the main takeaways is better forward secrecy at the expense of not being able to read message on different clients (which is kinda weird in Nostr-land where that is a common feature). However, the scheme still does not address the metadata leaks when a sender first posts to a relay.

Store and Forward

So initially, Nostr’s “forever public file system” seems like a great medium for any sort of store-and-forward communication. It allows clients to be dead-simple since they don’t have to be online to communicate with peers and the storage protocol is set and ready to go. As we see with NIP-04, NIP-17, and NIP-104 though, layering in privacy at this point is easier said than done. Are we able to accomplish extreme privacy for the use cases which require it?

The main leak which none of the current proposals address is the side-channel-esque network metadata relays receive when a client posts an event. It is very difficult to hide “this IP is talking to this public key owner” while still making it possible for the public key owner to know someone is trying to reach them! One popular suggestion for users is to use a private relay which they trust. At that point, maybe there is other tech better suited for the use case?

Oblivious HTTP

Oblivious HTTP (OHTTP) is a very simple protocol to separate the client metadata from a request. A Nostr relay gets the client metadata and any part of the event that is in plaintext. An OHTTP relay only gets the client metadata, the entire request is encrypted. The tradeoff is that the client is trusting the OHTTP relay to forward along the request to its destination. And obviously not collude with the destination by sharing the client metadata associated with the request. There is a layer of overhead here since both the client and the destination need to understand the OHTTP protocol, but similar to Nostr, it is simple.

The economics of running OHTTP relays may be better in certain scenarios than private and/or public Nostr relays. It is an apples to oranges comparison, but maybe there is an incentive for Nostr relay runners to integrate with an OHTTP layer?