nips/59.md
2023-03-11 19:47:06 -05:00

6.4 KiB
Raw Blame History

NIP-59

Improved Direct Messages

draft optional author:davestgermain depends:4

In order to improve the security of kind=4 encrypted direct messages, we'll translate the ideas from the SimpleX Messaging Protocol to nostr. Briefly, each side of the conversation creates an ephemeral "conversation key" and negotiates a secure location to continue the conversation. This allows for minimal metadata to be revealed.

Conversation Negotiation

Alice (public key b5a448349c963a6cffbd57e6de0466bbe5584e14959e2f7aa4a8c295db52be7d) wants to have a DM conversation with Bob (public key 18d95d3b888e273c70aafd7fff2ea7f3ddc356171ded0fe5c452a6ff1848e08e).

Her client will create a request that contains pointers to a relay and event kind where she will listen to responses from Bob:

{
    "id":"33eee9317f2ccadcddd5e217212c8334b44af71268b44671c02d455a5c266a5f",
    "pubkey":"b5a448349c963a6cffbd57e6de0466bbe5584e14959e2f7aa4a8c295db52be7d",
    "created_at":1678579922,
    "kind":20004,
    "tags":[
        ["r","wss://relayalice.com"],
        ["p","18d95d3b888e273c70aafd7fff2ea7f3ddc356171ded0fe5c452a6ff1848e08e"]
    ],
    "content":"ad7aac0a2e19a7e53022a358ba4124b88260bcfc7856167878d906e980ed2315",
    ...
}

The content is a random token which will be used to create a "conversation key" as follows:

sha256(token + bob_public_key)

Next, the client will generate an ephemeral private key and create a standard kind=4 DM, with the content being the jsonified request above:

{
    "id": "c7ed1bba951da4a6cdfd8457ac94b738e3a46543a6436ec4fe65c2ee1193e14f",
    "pubkey": "fd3598ae6877ec6d03c5e87e29679c714fdbcadaefac80e8cbefacab05a0197c",
    "created_at": 1678579922,
    "kind": 4,
    "tags": [
        [
            "p",
            "18d95d3b888e273c70aafd7fff2ea7f3ddc356171ded0fe5c452a6ff1848e08e"
        ],
        [
            "expiration",
            "1678666322"
        ]
    ],
    "content": "J9iKwHsqIQwWjnRSqGYDgYp1viVn4prThldxIQKkwz8G+MqtMme5VsqaNRrCX9s30P4HWrwaWzytCIt2OdjbWl3ZvcSnxvPG/pyIz7QQnofRCHOnhXu5Z/obEOcHaPf0VAY6qRHvfLsBayTmZk1xLsBtIu5dhYMD+iwcFQBbuoR0S11frY1S6T1jiPx1CZAMm6varR1sVMk7+vF1RILAQZaL35XhM/Yb/t2hCMLoV7efWyh+PStcdE7yW8CwSXmk4Ay68eBBi3iAiCQwmKfKzlqTBvbQ1sVOmQNFa5IS3UgqB2XN8w7a1dFWwCPavE7E3IVjNtL/C/KwPdBvmUu6k+km50VEG5s/lwEbLpR4CicRI5VNTlcLWaFZrssZ1sclBNPgFnBfShnxUBLjKXW6MR++ICAH+FQRTEO9bc3QA/lYgRczvDIwuAArnos9O9KxonWMmUo/yBKYVks2PsEMhy8z31Xqwt1zJWcVkWcCPrvpp5bF4BQL3ufgRbzQm5AVw9erH/AQ8h5s7rDCEKtG48e5G2vmT8gptns1QKkUJXa0NnuKema4ZBV6kvcSW+WM41FgK7QZW7pM47xexHzmBvlCOGxaCuxxgjedxJh8o9Ggzct3ZGXhkM41C0emZcm2nFHP6Ti9PBRsr0+66JKaEosXHUcok4z7Ia+Q3giSAdM=?iv=UwzRKNdpKJLm6vG1LaN6eA==",
    ...
}

Only the recipient metadata (Bob's pubkey) is revealed to the public, in this first message of the negotiation.

Bob's client will see a DM from an unknown contact, will decrypt and validate that the request is addressed to him (the "p" tag is his public key).

The client should present Bob with a prompt, displaying the Alice's information, the requested relay and kind. If the requested kind is an ephemeral event (as shown in this example), the client can indicate that the chat with Alice would (may?) not be saved on the relay.

If Bob accepts the request, his client would first create another ephemeral private key and repeat the process described above, with his own conversation request to Alice, pointed to a relay of his choosing:

{
    "id":"d114e1153a24d630553e9b4ff072885bca9c825720620cf63c528e404c6527b6",
    "pubkey":"18d95d3b888e273c70aafd7fff2ea7f3ddc356171ded0fe5c452a6ff1848e08e",
    "created_at":1678580292,
    "kind":20044,
    "tags":[
        ["r","wss://relaybob.com"],
        ["p","b5a448349c963a6cffbd57e6de0466bbe5584e14959e2f7aa4a8c295db52be7d"]
    ],
    "content":"9a97e6513003ebe9c8050b0000012137f3cf8a100c87d6f21bddac8e48895118",
    ...
}

This event will be jsonified and addressed to the conversation key defined in Alice's first request:

{
    "id": "2637d2f047439d9c2e101f873b1b60eaf445ac1da19eab2d4ecc64dc15348f8d",
    "pubkey": "0d4684b3d8ecd52a2c276e505e872059f5bc98bf79ca28cff0d1e4a625a9c8f7",
    "created_at": 1678580443,
    "kind": 20004,
    "tags": [
        [
            "expiration",
            "1678666843"
        ]
    ],
    "content": "5YgtDICQSjv+pFsoLaiy/z7h98h9SBrzkzW2tBV8rdSRK1weXxRnnY00OB7pdiSgucQeKb38cbW8A2JXV3gtAkxe/cx71BitAB3anrNNkK8MdPZgCQ3jO7L79bxwfoRZs8ZQCsPkK0K2dxrysDQU3F9xNsvstXUCmR0nllTXIxq2+Pw//7hKd1m8caOMHri2kfToGPM+GGMHRzx/OEYZIqbgyOkX1vYepolz1gnyn9SfhDH3NdjtBoC14fArQecFRIyWmtjEGQm1FYXvdGUHB4Llt9I+5GURfSGT/upnueB+SmncGCxEYwhVE4bK5yQc32ahOGiTJtRel+kSgOqtKbCZqVJuCiOuR8ECtbLzFeI8n9iud36w+Y2wVRNMxfvczM+qkOn8uYNXdXfMNx1CHbKFAHzpNmtj15H70lmaxU4lGHbg2y74n6MJC/8gnXkt4erlzYW4ojnXiql21gdBx7DCsXLrUFCCuHzERUXlIwpgulrZPnhAgw6tPN1aOTpX4PTwGp6ZvrVy9+qmwj/U/phtB9aPqIHrcWR2gd5GSDloNajufWJ5dc5/9i347gv/2aCeSNg0gP1CONNTll7wf74XQ/ETVkVVbJlMixBk4PEgw2lw9k+7IF6oMCOqwy1mCES50sgCUu1RWLy3/2v/knGkd7jd/qT1MBAcf7pP7uM=?iv=dZEsPTXaTCAppUxjQ/rWKA==",
    ...
}

His client will send this event to wss://relayalice.com, where Alice's client will already be subscribed to events addressed to {"authors": ["0d4684b3d8ecd52a2c276e505e872059f5bc98bf79ca28cff0d1e4a625a9c8f7"], "kinds": [20004]}.

After Alice's client validates the request and connects to wss://relaybob.com, the conversation can continue between the two conversation keys, with Bob sending events as pubkey 0d4684b3d8ecd52a2c276e505e872059f5bc98bf79ca28cff0d1e4a625a9c8f7 to wss://relayalice.com, and Alice sending replies as a2ab458e92c7c2434062cf94036168fce5ca4236294b48b4911ee765e1448f1b to wss://relaybob.com.

An example message from Alice to Bob (with content Hello Bob! looks like this:

{
    "id":"441d5493d227ebe2ed98a4564226e28c8ee99b35c678bf4930837c01ef82dec0",
    "pubkey":"a2ab458e92c7c2434062cf94036168fce5ca4236294b48b4911ee765e1448f1b",
    "created_at": 1678581213,
    "kind": 20044,
    "tags":[
        ["expiration","1678667613"]
    ],
    "content":"seceIcxeEPIiYrEP9IdG4w==?iv=7SEISW2DyH7PQYj/rwnoFw==",
    ...
}

Clients SHOULD connect to at least two relays since the sender and recipient channels should be on separate connections.

The conversation kind MAY be any ephemeral event, or kind=4. As long as the clients agree to the requested destination, the conversation should proceed as normal.