Thread

Pretty basic construction of Nostr silent DM's that break the DM graph privacy nightmare. Others probably have suggested the same thing because it's too damn simple and obvious of a solution. Still gonna put it up here, maybe someone has comments. Might become a NIP proposal if there is interest. I've coded it up and it works quite nicely.

Replies (16)

I'd be uneasy about a supposed "shared secret" being put in a public `p` tag. Indeed, AIUI, using a silent inbox as presented here completely breaks the security of any past and future regular NIP-04 DMs between the same parties, because the same "shared secret" used for encryption in regular NIP-04 DMs is being used publicly in the silent inbox. An attacker doing trial and error decryption of NIP-04 DMs would be able to decrypt all regular DMs between the two, as well as deanonymize the silent inbox.
NIP-92: Rendezvous Beacons (draft; ) enables anonymous establishment of communication between two parties, addressing the issue of receiving messages from unknown contacts. A shared secret is derived using ECDH like in NIP-04, but this shared secret is only used through *tagged hashes*, with a different tag (not to be confused with nostr tags) for each purpose. From the shared secret, a *rendezvous keypair* is established, where the sender knows the private key and the recipient knows the public key. This is done by tweaking the sender's key (an ephemeral key in the case of NIP-92) using a tweak value derived from the shared secret.
Maybe something's missing in the pictures. Note that I'm not talking about decrypting *silent inbox* DMs. Here's an example of it going wrong as I understand it: First, Alice (keypair p1, Q1) sends Bob (keypair p2, Q2) a *regular* NIP-04 DM (no silent inbox). NIP-04 uses shared secret `S = p1 * Q2 = p2 * Q1` to encrypt the message. In NIP-04, this is given in the example code as: `let sharedPoint = secp.getSharedSecret(ourPrivateKey, '02' + theirPublicKey)` Eve also picks up this DM. She sees that Alice sent Bob a DM of a certain length at a certain point in time. She can't decrypt it yet, but stores it in her collection for later. Next, they Bob decides to try using a silent inbox. This time, Bob sends a message to Alice. Silent inbox uses shared secret `S = p1 * Q2 = p2 * Q1` (from the picture titled "Shared Secrets"). Bob constructs the event using an ephemeral key `w`, encrypting to `Q1` (I presume using `w * Q1` as the NIP-04 encryption key, but this is not relevant to the attack). She puts `S` in the `p` tag of the event and signs it (from the picture titled "Send and receive flow"). Eve also picks up this DM. She doesn't yet know its sender or recipient, but she reads the `p` tag and starts trying to decrypt the DMs she's got in her collection one by one, using the contents of the `p` tag as the shared secret. One of the DMs does decrypt to a valid message, namely the first, regular, DM from Alice to Bob. Eve can now decrypt every past and future regular (not silent inbox) DM between Alice and Bob. Furthermore, while Eve can not decrypt silent inbox messages due to the use of different encryption keys here, she learns that the silent inbox in question belongs to Alice and Bob and can see the length and timing of each message going to it.
Apart from the shared secret issue, one thing not addressed here is sender authentication. Assuming the encryption key is `S' = w * Q2`, since the sender signs with the ephemeral key `w`, unless the recipient can somehow verify that `w` belongs to the intended counterparty, the recipient has no way of authenticating the sender. Anyone who correctly guesses one of the participants of the silent inbox (e.g. a relay operator would be able to trivially figure this out in many cases) can send a DM to that participant with an ephemeral private key of their own, pretending to be the other participant.