NIP 04 - block cipher mode, padding, shared secret
AES-CBC is kind of old tech and frowned upon nowadays, but I totally get that it fits pre existing software and libraries (if you care, you can read about a typical objection to using it, and my counterpoints, in the comment thread to the SNICKER gist).
However I feel like you should at least specify the padding scheme used, because implementations need to do it, and what's much much worse: I saw, a few years ago when I was paying attention to such things, at least 2 libraries that implemented PKCS7 wrong. The implications of that will just depend (it usually won't matter, except if two different libraries are using different algos and encrypt/decrypt just fails, but then you can easily figure that out).
Technically PKCS7 is not the only padding algo possible here, but it is by far the most used in that context I think.
A separate question is why you don't hash the pubkey? I'd have to double check whether the reason that's done is largely academic (namely: you don't have pure uniform randomness over the 32 bit range in the key, but in secp it's close enough that it doesn't matter, unless I missed something), but I'm curious if you had an actual reason to choose not to do it, as afaik standards for DH/ECDH always do that(? maybe?).
Another thing i'd like to throw in here is the fact that the raw generated shared secret is used as encryption key for AES. Why not derive a more-random key from it using HKDF (or something alike)? This makes sure there is no more structure in the secret
and yeah, why not AES-AEX or maybe even ChaCha20Poly1305 (XChaCha if you'd like to go even further)
Another thing i'd like to throw in here is the fact that the raw generated shared secret is used as encryption key for AES.
That was my last paragraph, but you were a lot more explicit, which is always good :)
And the more I think about not using a KDF, the more dangerous it feels (thinking about the fact that you're exposing the underlying homomorphism, or to put it less pretentiously, what happens if you are for some reason using related keys, in multiple sessions. I don't know but it's concerning.)
AES-CBC is kind of old tech and frowned upon nowadays
I didn't know. My brief research before writing the spec showed that it was ok and didn't have any vulnerabilities, and it seemed simple enough. But I didn't care very much because I thought NIP-06 would be just a prototype and that someone would come up with a better idea later. I am not convinced Nostr should even have direct messages yet, to be honest, I think it would work better as a way for people to discover each other's better DM methods using other protocols.
A separate question is why you don't hash the pubkey?
I didn't look at any standards when writing it, I just did what felt ok (because, again, it was supposed to be just a prototype and because Ben Arc wanted it so badly). Then later when I learned it was common to hash the point I asked Stepan Snigiriev (I mean I just casually asked, please don't hold him accountable for this) if he saw something wrong with not hashing it, I believe he said it was ok, so I didn't worry anymore.
Right, this all makes sense. (Btw did you mean NIP 6 or NIP 4 there?).
Has anyone implemented it yet? At this point I'm just curious, don't feel the need to give detailed accounting of what has or will happen here :) I ask because if not, why not just change it to a SHA2 hash of the point? It is after all much cheaper than the preceding EC mult operation.
A quick search throws up something much more sophisticated, but along the lines of my "mulling about related keys" above:
https://crypto.stackexchange.com/a/67609/14985
This kinda makes sense, if an adversary can use you as an "oracle", by pinging tons of keys at you to do ECDH with, then over time they can learn about your key, because you're doing algebraic operations and seeing the output. (see the description of "Cheon's attack" above). Hashing destroys that algebraic relationship.
Oh, it has been implemented many times in many clients, perhaps 10.
I don't want to be the guy pushing everybody to change, I don't know if it makes sense to change, it is probably better to write a new standard completely different and then people can slowly switch while supporting both.
But I was thinking of actually making a different protocol just for private encrypted messages that lived outside Nostr. Something that used the same Nostr principles of having somewhat dumb servers relaying stuff over WebSockets in an open and interoperable way -- but also such that metadata couldn't be leaked and there was forward-secrecy, good practices etc.
I am not qualified to invent this protocol, but I think a "nostr-like" model could be successful here -- and then it could integrate seamlessly in existing Nostr clients, using the same base keypairs and so on. What do you think? Can this be done?
A new protocol over Nostr (or a protocol like Nostr) just for encryption seems like a nice idea, then we aren't bound by NIPs either. But i do wonder how that's going to be implemented
AES in CBC is vulnerable to ciphertext malleability ofc, and even when one tacks on a MAC it still has problems.
Suggest a move to AES in GCM, or ChaCha20-Poly1305.
One could also consider that for a project that is focused on censorship resistance hiding the curve points during ECDH could be extremely valuable. Techniques like Elligation exist, though on Weierstrass curves (given the nod to Bitcoin) there are options too.
Finally appreciate this is a protocol specification and not an implementation, but with cryptography mistakes will be made unless explicit guidance is provided (such as using a HKDF on the x coordinate after ECDH).
In their current form encrypted DM's aren't strong enough.
@iloveyumyumshrimpnoodles @johnalanwoods do you think it is possible to design a protocol that allows users to store data (private messages) in servers without the servers actually knowing, but these servers can still identify these users somehow and can still serve the correct data (private messages) to the target user when that target users asks?
It's important for the servers to know that some specific user is using them and not others so they can charge money or restrict access as desired -- but it's not desirable that the servers learn a lot of metadata about the messages being sent and received.
How would you do this?
It shouldn't be too hard i'd imagine. Here's an example of how i'd do it:
- Alice has keypair KP1, which consist of PUBKEY1 and PRIVKEY1
- Bob has keypair KP2, which consts of PUBKEY2 and PRIVKEY1
- Alice sends Bob PUBKEY1, and Bob sends Alice PUBKEY2
- They exchange secrets (using Elliptic Curve cryptography), and then use a key derivation such as HKDF (the python cryptography module has an easy to use function for that)
- Now, they have a secret key which is used to encrypt the message, which only Alice and Bob can read
For the symmetric encryption algorithms, here's what i'd pick:
- Chacha20Poly1305 (or XChaCha)
- AES-GCM
Another thing we should look in is deniable encryption, perfect forward secrecy and metadata. As the Ex-NSA chief Michael Hayden said: they kill people based on metadata. If the ciphertext's encryption cant be broken, the metadata is still useful. For example; currently the encrypted dm's still leak data about who sent the dm and who received it. This is enough to kill a person like Edwards Snowden (say, he gets a message from a whisteblower with a known public key, they will know he got a message from that public key).
Sorry if my rants don't make much sense, i just woke up :3
i don't think Nostr (in a publish-retrieve) sense would work well with this, so we should build a new protocol over websockets aswell.
ANOTHER thing i'd like to throw in here is the fact that Nostr (or atleast the python library, haven't checked others) uses a single keypair for both signing and key exchanges which is a bad practice
@fiatjaf - definitely possible, solution would depend on the detailed requirements, but something akin to Onion routing would work.
@fiatjaf - definitely possible, solution would depend on the detailed requirements, but something akin to Onion routing would work.
Onion routing seems interesting, but how would we implement this so it can be used with Nostr?
Also interesting to check in my opinion the TextSecure protocol that Signal uses.
This was discussed many times in gh-107. I think we all have a consensus it's bad. Should there be a temporary NIP which replaces NIP4 with something better?
I don't think we should "specify padding mode" etc: nip4 should just get deprecated and that's it.
@johnalanwoods @iloveyumyumshrimpnoodles why would you pick chacha instead of xchacha? Seems like inability to use random nonce is a big deal.
Also, what do you have in mind for deniability?
why would you pick chacha instead of xchacha? Seems like inability to use random nonce is a big deal.
I was thinking python mode, since that requires an extra library just for using XChaCha20Poly1305 (the Cryptography library doesn't have support for it yet, which is the one currently in use by python-nostr)
But yeah i would definitly pick XChaCha over regular ChaCha all day, just makes me feel more secure
Also, what do you have in mind for deniability?
Perhaps we could use something like decoy messages, i am currently working on a chat app using Nostr which uses that technique. Incase somebody is forced to decrypt some messages they can pick the decoy ones which just show harmless texts or perhaps images of cats.
I still haven't fully imagined the deniable encryption yet so excuse me if i made any mistakes
@paulmillr - I'd suggest XChaCha20-Poly1305 or XSalsa20-Poly1305 for the symmetric primitive.
On deniability, just use ephemeral keys.
@iloveyumyumshrimpnoodles implementing xchacha is like a couple days of work with tests, it's very simple. So doesn't matter if some python lib doesn't support it.
I've been working on a concept for private messaging on nostr for the last few days, and I think nostr would work well for this purpose. It can't all be done in a single NIP, I plan to propose multiple NIPs that all work to construct a reasonably secure private messaging protocol on top of nostr.
Some things I think the protocol should have:
- Strictly opt-in feature, unlike NIP-04
- Replaceable pubkey, separate from main account key, available in the user's
set_metadataevent. - Hidden sender and recipient, messages are completely opaque blobs apart from the outer
created_atand approximate message length. - Recipients are all part of one anonymity set even to relays.
- Relays can identify senders and recipients by IP addresses, but are unable to link senders and recipients directly, as all messages go to all recipients. For senders who need even better anonymity and cannot use Tor, I think a separate NIP can be made to solve that.
- For symmetric encryption I'm looking at (X)ChaCha20-Poly1305.
- Deniable authentication.
- Forward secrecy (except possibly the first message in a "DM request" type of message, as this would have to be encrypted to the public reception key which the recipient might only replace periodically).
- Protection against / detection of replay, reordering or deletion of messages.
- Future secrecy as in the double ratchet algorithm.
I had not considered the concept of deniable encryption. It seems that a form of this can be easily implemented if necessary, at the cost of doubling the size of all ciphertexts.
@shafemtol why "Replaceable pubkey, separate from main account key"?
How this works "all messages go to all recipients"? are all users supposed to decrypt ALL messages?
@shafemtol why "Replaceable pubkey, separate from main account key"?
- If encrypting directly to someone's main account key, then later compromise of the account key results in compromise of the message as well.
- A separate key allows for providing e.g. only a dedicated messaging app with the private messaging key, limiting private key exposure.
How this works "all messages go to all recipients"? are all users supposed to decrypt ALL messages?
Yes, by trial decryption of a message header. Bitmessage works on the same concept. A weaker variant would be to have this only for the first message between two users, with later messages being one-to-one. In that case, only those wanting their inbox to be open to strangers need to subscribe to such broadcasts. The trade-off is that relays can then identify senders and recipients.
That's private set intersection problem. It is not scalable and can't be. Like, at all. Same reason why zcash, etc are not really scalable. They at least use diversifiers though.
Bitmessage is garbage and is not popular. We need something that could become actually useful, instead of bitmessage clone — IMO.
Other ideas of yours sound great.
Is there any trick that allows a server to perform encrypted queries on fully encrypted data?
Is there any trick that allows a server to perform encrypted queries on fully encrypted data?
There are ways to do certain kinds of queries, but I don't know of any such stuff that is not very resource intensive compared to plain queries.
Hm, so what about people use different keys for each message, but they use some form of zero-knowledge proof to prove they are allowed to use that relay?
Or maybe they can get some blind tokens from the relay -- either by buying or by any other process -- and then use those tokens every time they want to publish something?
Or maybe they can get some blind tokens from the relay -- either by buying or by any other process -- and then use those tokens every time they want to publish something?
Some sort of chaumian ecash token system would be great. In the simplest form all tokens have a single denomination. One could for example charge one token for every k bytes of storage, plus one token for every n current subscribers that an event would reach. Deleting an event could result in the tokens spent on storage being refunded.
However, I don't think one can assume that relays cannot identify most users by other means, such as by their IP address, IP TTL, TLS library, HTTP headers and client behavior. My impression is that current clients will happily connect to any relay they come across and proceed to reveal the user's pubkey. So any secure messaging system will have to be designed with this in mind.
Thoughts on using proof of work to combat spam?
@shafemtol I am not talking about Nostr or current clients, but about a separate hypothetical system that is similar to Nostr but optimized for encrypted direct communication.
@paulmillr in a system like that the relays could sell trade proof-of-work for these tokens.
Some sort of chaumian ecash token system would be great.
I am not talking about "money" tokens, just usage tokens. I don't think you should call these ecash tokens. It's just a way to control access to the relay resources without requiring users to identify themselves explicitly.