-
Notifications
You must be signed in to change notification settings - Fork 588
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add NIP-104: E2EE messaging using MLS #1427
base: master
Are you sure you want to change the base?
Conversation
|
||
### Clients | ||
|
||
The device/client pair (e.g. Primal on iOS or Coracle on web) with which a user joins the group is represented as a `LeafNode` in the tree. The terms `Client` and `Member` are interchangeable in this regard. It is not possible to share group state across multiple `Clients`. If a user joins a group from 2 separate devices, their state is separate and they will be tracked as 2 separate members of the group. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I may be misunderstanding but can't clients share keypackages with the user or other clients? Making it interoperable within the same device?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, I had been operating under the assumption that this private key couldn't/shouldn't be shared between devices but given these key packages should only be used once there is the option of encrypting the private key (to yourself) in the content field of the key package event using NIP-44 encryption. This would mean the following:
- Any client could respond to a group welcome message (the invite to a new group) provided they had access to your nostr identity private key.
- The client that responded to the welcome message would be the client that would be added to the group. Any other clients that you wanted to have access to the group would have to be added separately.
- If your identity key leaks then the private key to these key package keys also leaks. Given these events are meant to be used once and deleted, I don't think this is actually that big a deal tbh.
Would love thoughts from others on this.
|
||
If a client receives 2 or more `Commit` messages attempting to change same epoch, they MUST apply only one of the `Commit` messages they receive, determined by the following: | ||
|
||
1. Using the `created_at` timestamp on the kind `445` event. The `Commit` with the lowest value for `created_at` is the message to be applied. The other `Commit` message is discarded. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Malicious clients can chose to send lower created_at values on purpose, making sure their commits are the ones that are used?
Maybe we can use NIP-03 (timestamp attestation) to make sure these timestamps are valid?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that the time it takes to get the commit OTS attested will cause more troubles than it solves.
Fundamentally, a malicious client that is part of the group was added to the group by someone in the group. Anyone in the group can evict that malicious client as soon as they notice bad behavior. I think this is probably not something the spec can solve and rather is the domain of the applications that are implementing this spec to decide.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there someway to have an "authority" identified for these Commits? like a group admin or similar.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that the time it takes to get the commit OTS attested will cause more troubles than it solves.
Fundamentally, a malicious client that is part of the group was added to the group by someone in the group. Anyone in the group can evict that malicious client as soon as they notice bad behavior. I think this is probably not something the spec can solve and rather is the domain of the applications that are implementing this spec to decide.
Could a malicious client use a similar technique to preempt attempts to remove it?
Also consider that a client with an out of sync clock can effectively become a denial of service attack and would probably be extremely difficult to detect/mitigate unless other client software was specifically looking for such behavior.
One way to mitigate this would be to define a way to establish a quorum and push the COMMIT acknoledgement from a relay OK to a response event from N/2 + 1
of whatever constitutes that quorum to get something similar to the serialization provided by Raft or Paxos
104.md
Outdated
|
||
### Deleting KeyPackage Events | ||
|
||
Clients MUST delete the KeyPackage Event on all the listed relays any time they successfully process a group request event for a given KeyPackage Event. Clients MAY also create a new KeyPackage Event at the same time. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The RFC says1 that
In order to avoid replay attacks and provide forward secrecy for messages sent using the initial keying material, KeyPackages are intended to be used only once.
However, reliable message deletion on Nostr is not possible. Especially when using a 3rd party relay, even moreso when using a bunch of relays.
Doesn't this mean MLS on Nostr can't guarantee forward secrecy? Or am I missing something?
Footnotes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is why users or the clients implementing this should select the relays that they publish key packages to carefully based on advertised support of event deletion and (optionally) support of the -
tag to ensure that the even isn't rebroadcast to other relays.
Another mitigation strategy for this (that resides at the client/application level) is that clients could require some level of freshness for the Key Package events that they use and refuse to use Key Package events that are older than a certain time in the past.
### Goals of this NIP | ||
|
||
1. Private _and_ Confidential DMs and Group messages | ||
1. **Private** means that an observer cannot tell that Alice and Bob are talking to one another, or that Alice is part of a specific group. This necessarily requires protecting metadata. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this still the case for a malicious or compromised Delivery Service (relay)?
The RFC says that
the DS may be able to determine group membership
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is why we publish all the Group events from ephemeral keys. A sophisticated malicious relay could use IP addresses to triangulate a give user but if users are using a VPN then this is mitigated (and this is the case across all of nostr).
Is this the code implementing it? https://github.com/erskingardner/openmls_nostr_crypto I feel like this is only part of it. |
I'm working on implement this NIP for https://github.com/lumehq/coop |
@rabble yes, this is definitely only part of it. I started that library and intend for it to be complete but then got sucked into updating upstream dependencies to support Schnorr signatures over The future benefit of that library you liked above will be that nostr clients will have fewer dependencies on underlying crypto primitives, that's basically it. |
🤙 Definitely feel free to DM me if you run into anything or have questions. |
104.md
Outdated
"sig": <signed with ephemeral sender key> | ||
} | ||
``` | ||
- The `content` field is a [tls-style](https://www.rfc-editor.org/rfc/rfc9420.html#name-the-message-mls-media-type) serialized [`MLSMessage`](https://www.rfc-editor.org/rfc/rfc9420.html#section-6-4) object which is then encrypted according to [NIP-44](44.md) but using the MLS [`exporter_secret`](https://www.rfc-editor.org/rfc/rfc9420.html#section-8.5) and the group ID values to calulate the `conversation key` value. The rest of the NIP-44 encryption process is the same. The `exporter_secret` value should be generated with a 32-byte length and labeled `nostr`. This `exporter_secret` value is rotated on each new epoch in the group. Clients should generate a new 32-byte value each time they process a valid `Commit` message. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Calling out a small update here. The serialized MLSMessage
object isn't always encrypted and even when encrypted would leak header information.
To remedy this, I'm proposing that we use NIP-44 encryption for the content field, with a twist. Since all members of the group need to be able to decrypt the message content we need to use a shared secret value that they all know.
MLS provides a mechanism to export a secret key from the current state of the ratchet tree. This exporter_secret
value is labeled and can be generated to be any length. We'll generate a 32-byte value and use it along with the group ID value (also 32 bytes) to generate a value that we'll use for the conversation key
in NIP-44's encryption. This will allow all participants to encrypt and decrypt these content fields and get to the messages.
The exporter_secret
is rotated on each group epoch so the key will be rotated after each Commit
, providing forward and post-compromise security for this content field encryption. In other words, even if an attacker got the exporter_secret
value, they would only be able to decrypt group messages from a single epoch.
Farcaster implemented Signal protocol in DMs. Then they've dropped it because it was too complex to support on different devices (old / new / different libraries). It would be great to have some kind of demo app first. I suspect it'll be quite complicated. |
Nice, how can one extend the Group creation to use FROST (Maybe even have the FROST signers as group admins)? |
I've had a bit of a look at FROST but haven't really thought about how it might apply. For now, it's completely out of scope. |
@paulmillr working on it :) |
Some very initial thoughts on a potential choice of cipher suite: https://njump.me/nevent1qvzqqqqqqypzpp59a0hkv5ecm45nrckvmu7pnk0sukssvly33u3wwzquy4v037hcqyg8wumn8ghj7mn0wd68ytnddakj7qgwwaehxw309ahx7uewd3hkctcqyprq4w327fynj7wa6lha6pktmer8c0979ds0sc89cgsmh5af4pet60p3dcc @erskingardner looking forward to see your demo app, and what dependencies it pulls in. That might help inform the above. |
|
||
When a new user is added to a group via an MLS `Commit` message. The member who sends the `Commit` message to the group is responsible for sending the user being added to the group a Welcome Event. This Welcome Event is sent to the user as a [NIP-59](59.md) gift-wrapped event. The Welcome Event gives the new member the context they need to join the group and start sending messages. | ||
|
||
Clients creating the Welcome Event SHOULD wait until they have received acknowledgement from relays that their Group Event with the `Commit` has been received before publishing the Welcome Event. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does an "acknowledgement from relays" look like?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just that you get an ack from a relay when sending the event. Same as any other event that you publish.
104.md
Outdated
|
||
Application messages are the messages that are sent within the group by members. These are contained within the `MLSMessage` object. The format of these messages should be unsigned Nostr events of the appropriate kind. For example, if a user sends a text note to the group, it would be a `kind: 1` event. If the user reacts to a message, it would be a `kind: 7` event. | ||
|
||
This means that once the application message has been deserialized, clients can store those events and treat them as any other Nostr event, effectively creating a private Nostr feed of the group's activity and taking advantage of all the features of Nostr. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This "private Nostr feed" makes me think of the local relay ideas. And the various *box models that have surfaced.
This makes me wonder how Signal does group admin stuff. They have a nice features to tweak within groups. For these different MLS events, is it expected that all participants are publishing all event types for the group? |
Signal groups is just a bunch of 1-to-1 messages. Group settings are stored in the server in enclaves. |
This looks super great, I have been thinking about something like this for a while and will maybe try building a client for it. Any update on the more specific example process/app? |
I'm working on a reference client right now @github-tijlxyz I'll let everyone know here and on nostr when it's ready. :) |
This is ready for review. I've made some updates based on what I'm doing in White Noise and while I don't have fully completed libraries, I would love to start working with anyone that is interested in implementing this to help find more places where we need supporting library code. Obviously, I'd love to merge this NIP once we get some more eyes on it. @fiatjaf @staab @vitorpamplona @pablof7z @paulmillr @Sjors @v0l @hzrd149 |
@erskingardner do you have a fully working MLS over nostr implementation in place? |
Yes. https://github.com/erskingardner/whitenoise I'm still having some platform specific issues (nothing related to MLS) before it's ready for distribution but it works end to end. |
A brief description of how this is solved would be useful. I know MLS is supposed to solve it, but an ELI5 version would nonetheless be helpful. Like, what exactly happens after user's messaging key is leaked. Or if their private key is leaked. |
@paulmillr do you think it's worth having a section in the NIP about the threat model and various compromises possible? Or are you just looking for an explanation here? MLS has a specific section I can link to that goes into lots of detail on this for MLS specifically. There are some nostr specific things I could add though. |
MLS spec is hard to read. I think a simple section describing how things improve over the status-quo would be useful, including compromises. Best to keep it concise. |
Added a section on Security considerations with some basic details and links to MLS docs on the more in-depth stuff. |
is it the idea that we can try Whitenoise? i can't get it to work with the several dependencies |
Which dependencies? |
I mean if I should try to run whitenoise now, because I think there are some problems like a release tag missing for https://github.com/erskingardner/nostr-openmls which is specified here https://github.com/erskingardner/whitenoise/blob/master/src-tauri/Cargo.toml and some of the dependencies there point to local directories. |
Ah yeah, good catch. I've been making changes to those libraries locally. Let me try and get a buildable version done tomorrow. Fair warning. I've been building locally on a mac and things seem to be working well but once I try and run the app on any other platform I get a lot of strange behavior which I'm working on fixing now. |
@alexfj0 you should be able to build the app now, I've updated the dependencies to point to GH. To test out groups and messages, it's easiest to do the following:
Let me know if you have any troubles. |
Take 2!
This NIP outlines a way to do secure direct and group messaging on Nostr using the MLS protocol.
Easy to read