-
Notifications
You must be signed in to change notification settings - Fork 721
NIP-103: Onion Routed Direct Messages #499
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
Changes from 7 commits
b0dbdde
4bc43f4
3fdc2bc
7e4c30b
282f3c1
2ce12d6
2a0f346
43a396e
ca86eab
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| NIP-103 | ||
| ======= | ||
|
|
||
| Onion Routed Direct Messages | ||
| ---------------------------- | ||
|
|
||
| `draft` `optional` `author:threeseries` `author:giszmo` | ||
|
|
||
| This NIP defines event kinds 174 and 20174 which are events whose RSA-encrypted content is either a kind 4, (see [NIP-04](04.md), kind 174, or kind 20174 event. A kind 20174 event is nothing more than an ephemeral kind 174 event (kind 20174 can be substituted anywhere kind 174 appears in what follows). These events are intended as direct messages that can be routed through a network of bots or ordinary users to obscure sender and receiver. | ||
|
|
||
| # Motivation and usage | ||
|
|
||
| Despite being encrypted direct messages on nostr have very poor privacy properties since anyone can see who is messaging whom and when. One solution to this problem is for the entire event including its metadata to be encrypted before being sent, and for the final recipient to be further obfuscated by adding additional hops between sender and receiver. In order to provide additional privacy for users RSA keys are used for encryption since these messages can be decrypted without knowledge of the encrypting user's nostr pubkey. | ||
|
|
||
| The flow works as follows: when Bob wishes to send Alice an onion-routed DM he must first identify a set of intermediate pubkeys that can be used for routing and obtain their corresponding RSA public keys. Once done Bob creates a kind 4 event addressed to Alice using his nsec and then encrypts the whole event JSON using Alice's public RSA key. This becomes the content for the outer kind 174 event. The sender of this outer event is not Bob in general, but is rather the pubkey immediately before Alice in the chain. Events are then iterately wrapped in kind 174, working back up the chain until finally reaching Bob. | ||
|
|
||
| When Bob sends this kind 174 event to the first hop in the chain, the user or bot decrypts the content using their private RSA key. The decrypted content will be either kind 174 or kind 4, and the message is forwarded to the recipient pubkey. In order to provide additional privacy time delays can be added, or messages not forwarded until enough are in a queue. | ||
|
|
||
| # Intermediate hops | ||
|
|
||
| Intermediate nodes can be one of two types: always-online bots that exist solely to perform onion-routing, or ordinary users who have opted into forwarding messages for others (this also provides plausible deniability to the users themselves who are participating in forwarding). In the former case it may be desirable to use kind 20174 to make tracing more difficult, however there needs to be a way for bots to signal that they're online to ensure that such a message will be received. Hence it may be useful to have an ephemeral "heartbeat" event for sending these types of signals. | ||
|
||
|
|
||
| # RSA keys | ||
|
|
||
| RSA keys should be derived deterministically from the user's nsec. They should also be advertised in the metadata of a pubkey for any account that can perform onion routing. | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm afraid you have to be more prescriptive of how this should work. While profiles must expose the public RSA key, clients must know how to independently derive it from the Schnorr key. Some but you'd have to research this yourself for some real-world code example. Also you have to prescribe how and where to store the RSA pubkey. In the profile? In a new replaceable event?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This might take me some time as I'm not a cryptographer, but I'll give it a shot. Could PGP also work for this? I'm thinking the easiest way to advertise would probably be to put the public key in a kind 0 metadata event. However the key derviation works, it'd be nice if it enabled a way of verifying whether an RSA or PGP public key actually corresponded to the user's npub (i.e., the private key was derived from the associated nsec).
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nah, the key derivation is not compatible in a sense that an RSA pub key wouldn't have anything to do with the Schnorr pubkey. The determinism is in my opinion only important, so a user doesn't have to backup yet another key. As the event is signed with the Schnorr key though, you can be certain that the RSA key was approved.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Apparently for RSA it's recommended to have 2048 bit keys based on the prime numbers Here's some Python code for doing the first part, although it is extremely slow due to the primality test: from math import sqrt
import hashlib
def is_prime(n: int) -> bool:
if n <= 1:
return False
test = 2
sqrt_n = sqrt(n)
while test <= sqrt_n:
if n % test == 0:
return False
test += 1
return True
result = ""
hex_string = "0487a6b310c7bc874c075001e0aaf492d5d1aae1bfa12cae40fb18497a079027"
for _ in range(8):
result += hex_string
m = hashlib.sha256()
m.update(bytearray.fromhex(hex_string))
m.digest()
hex_string = m.hexdigest()
p = int(result[:256], 16)
q = int(result[256:], 16)
while not is_prime(p):
p += 1
while not is_prime(q):
q += 1
print(f"p: {p}, q: {q}")Do you think this might work? Again I don't know much about cryptography and would want to have it reviewed by someone who does.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not a cryptographer. If RSA is done by brute-forcing a prime number in the right range, yes, this could work and should not make things slower than any other tool that would work with RSA. Now if we should store the RSA private key in a nip-4 DM style enrypted event I don't know. That would take away the requirement for it to be deterministic. |
||
Uh oh!
There was an error while loading. Please reload this page.