Skip to content

Commit

Permalink
Add nips for shared keys and closed communities
Browse files Browse the repository at this point in the history
  • Loading branch information
Jon Staab committed Nov 10, 2023
1 parent e7777c3 commit 11b226f
Show file tree
Hide file tree
Showing 3 changed files with 137 additions and 0 deletions.
3 changes: 3 additions & 0 deletions 72.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ The goal of this NIP is to create moderator-approved public communities around a

`Kind:34550` SHOULD include any field that helps define the community and the set of moderators. `relay` tags MAY be used to describe the preferred relay to download requests and approvals.

An `access` field MAY be provided to indicate whether the community is private or semi-private so that members know to request access (see [./87.md](NIP 87) for more details).

```json
{
"id": "<32-bytes lowercase hex-encoded SHA-256 of the the serialized event data>",
Expand All @@ -22,6 +24,7 @@ The goal of this NIP is to create moderator-approved public communities around a
["d", "<Community name>"],
["description", "<Community description>"],
["image", "<Community image url>", "<Width>x<Height>"],
["access", "open|closed|hybrid"],

//.. other tags relevant to defining the community

Expand Down
51 changes: 51 additions & 0 deletions 86.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
NIP-86
=======

Shared Keys
-----------

`draft` `optional` `author:staab` `author:earonesty` `author:vitorpamplona` `author:water783`

A shared key allows key holders to encrypt and decrypt messages to all other key holders. A shared key is issued by a single pubkey (the `admin`) who has sole authority to issue invitations and key rotations.

This NIP relies on [NIP 59](./59.md) for event wrapping.

## Key Sharing

Keys are shared via a `kind 24` rumor sealed by the `admin` key, wrapped using the shared key, and addressed to each recipient individually. The rumor MUST have a single `shared_key` tag containing the shared private key.

```json
{
"kind": 24,
"content": "Just a regular key rotation",
"tags": [["shared_key", "<new shared key>"]],
}
```

## Key Rotation

To rotate the shared key, the `admin` must publish a new `kind 24` rumor as described above. A `grace_period` tag MAY be included on the rumor indicating how many seconds after the new event's `created_at` timestamp previous keys are valid. This invalidates previous keys and replaces them with a new shared key.

An `expiration` tag (defined by NIP-40) MAY be included on the wrapper to support a weak form of forward secrecy (weak, since it relies on relays to delete the event). This can reduce the impact of a member's private key being leaked, which could otherwise expose old shared keys and messages addressed to those keys.

## Using the Shared Key

Any group member may post a wrapped event to the group sealed by their own key, signed by the shared key, and addressed to the shared key.

# Other Notes

## Admin key vulnerabilities

Since ultimate control of the group lies with the holder of the admin key, the security of this key is paramount. Leakage of this key would result in complete compromise of the group, as well as the doxxing of all members who have posted to the group. Management of this key is up to the group admin, but should be taken seriously.

An ideal solution would be to use an air-gapped signing mechanism to publish events, viable since the group admin need not publish often except to rotate shared keys. Also viable would be to manage key access using an nsec bunker.

## Shared key vulnerabilities

Any member of the group can implicitly invite new members to the group, since they have the private key (although this would have to happen out-of-band, since the private key is stored in a `rumor`). Any member of a group can dox other members by publishing their wrapped messages. Any member of the group can spam the group, or otherwise DOS the group. Any member can post anonymously to the group by sealing their messages with an alternative or ephemeral key.

If any single member leaks the shared secret, all messages can then be decrypted by others until the next key rotation. The use of optional frequent forward secrecy rotation events can mitigate these attacks, provided the server is compliant with the expiration times.

## Replaceable events

Wrapped replaceable events can't be de-duplicated by relays. Clients SHOULD perform this deduplication manually, keeping the most recent version.
83 changes: 83 additions & 0 deletions 87.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
NIP-87
=======

Closed Communities
------------------

`draft` `optional` `author:staab` `author:earonesty`

Some online communities may want a measure of privacy. While nostr's architecture isn't conducive to high levels of privacy due to metadata leakage and the difficulty of implementing ratchets for key rotation, it can provide basic encrypted channels appropriate for use with large groups with dynamic member lists.

This is a different trade-off from NIP 24's encrypted chat, which is simpler and provides more privacy, but is inflexible and doesn't scale as well.

This NIP relies on the following NIPs:

- [86.md](NIP 86) for key sharing
- [51.md](NIP 51) for member lists
- [72.md](NIP 72) for community definition

# Protocol Description

## Community Definition

Following NIP 72, communities are identified by the address of a replaceable `kind 34550` event. This may be wrapped using the shared key to support privately-defined communities.

## Admin Key

The key used to publish the community's `kind 34550` definition event MUST be used for performing privileged actions, such as publishing member lists and key rotations. Non-administrative events MAY be published to the community by the admin.

Because the admin key is used for managing key rotation, it's recommended that a dedicated key be used for community administration instead of the community admin's personal key.

## Key Sharing

Key sharing and rotation is accomplished as described in [85.md](NIP 85).

## Member Lists

Admins MAY publish member lists using a kind `30000` event with the community's address as the `d` tag, as described in NIP 51. These events MAY be wrapped using NIP 59 to support private member lists.

When rotating the shared key, the admin SHOULD publish an up-to-date member list. If private, the new list SHOULD be addressed to both the old key and the new one individually so clients can update member lists.

## Access Requests

Anyone may request access to a community using a `kind 25` rumor wrapped with an ephemeral key and addressed to the admin's key. The rumor's `content` MAY include a message, and its `tags` MUST include an `a` tag pointing to the community definition event's address.

On receipt, an admin MAY choose to admit the member either by rotating keys or sharing the most recent shared key.

```json
{
"kind": 25,
"content": "Pleeease let me in",
"tags": [["a", "34550:<admin pubkey>:<group name>"]]
}
```

## Exit Requests

Any member may request to be removed from a community using a `kind 25` rumor wrapped with an ephemeral key and addressed to the admin's key. The rumor's `content` MAY include a message, and its `tags` MUST include an `a` tag pointing to the community definition event's address.

On receipt, an admin MAY choose to remove the member either by rotating keys or simply by publishing a new member list.

```json
{
"kind": 26,
"content": "I'm outta here",
"tags": [["a", "34550:<admin pubkey>:<group name>"]]
}
```

## Messages

Any community member may post an event to the community either publicly following NIP 72, or privately. Private events MUST be sealed by the user's own key, signed by the shared key, and addressed to the shared key. Anyone with the shared key may decrypt these messages.

All messages MUST include an `a` tag pointing to the community definition event's address. Events of any kind MAY be published to the community either publicly or privately.

# Other Notes

## Anonymous membership

To post to a group, you must reveal your public key, doxxing yourself to all other members of a group, all of whom are able in turn to reveal your identity outside the group. To avoid this, users may join groups anonymously by generating a new keypair separate from their primary key. They may then publish an alternative kind0 to the group to maintain a different identity. Clients should help users to manage their alternative key using an appropriate strategy.

## Always-on admin key

There is no need for an admin to be always online, since key rotation requests do not expire. However, for larger groups timely key rotation might be desired. Because an admin key is distinct from that of the group owner(s), it would be easy to create an always-on service that can automate key rotations.

0 comments on commit 11b226f

Please sign in to comment.