# One way shared key encryption with NaCl - is it safe to generate a throwaway keypair for the encrypting party

So, I need users to be able to pass me information that no one else can read, so I've generated a secret key. Using NaCl I create a key pair from that secret key and I share the public key of the key pair with my users.

Now, they encrypt their information with nacl.box() which requires their message, a nonce, my public key, but also their private key? In the past I've traditionally used asymmetric encryption like AES (edit: I meant RSA) and only needed my public key... so I just generate, on the user's end, a random key pair for the user to use. I'll call this throwawayKey.

encryptedMessage = nacl.box(message = "foo",
nonce = 0,
publicKey = MY_SHARED_KEY,
secretKey = throwawayKey.secretKey());


Then they can send me back this encrypted message AND send me back the public key for the throwaway key I generated them: throwawayKey.publicKey().

Then, I can later decrypt on my end, using this:

decryptedMessage = nacl.box.open(message = encryptedMessage,
nonce = 0,
publicKey = throwawayKey.publicKey(),
secretKey = MY_SECRET_KEY);


Is this a safe way to have users send their info to my securely?

I'm not used to having to generate a throwaway key pair for generic one way asymmetric encryption. It feels wrong to just generate a random throwaway key. Am I using NACL wrong?

• FYI NaCl isn't libsodium. Libsodium is an extension to NaCl's API designed to be easier to use. doc.libsodium.org Feb 2 '21 at 4:27
• Also, AES is symmetric, not asymmetric, and doesn't have a public key. Feb 2 '21 at 4:32
• @SAIPeregrinus Ah sorry I meant to say RSA! Feb 2 '21 at 5:16

From the documentation:

The crypto_box function encrypts and authenticates a message m using the sender's secret key sk, the receiver's public key pk, and a nonce n.

So the secret key (actually a private key, but that has the same acronym) is used for authentication. If you use a ephemeral (what you call "throwaway") key pair then you forgo verification of the authentication. For authentication it is required that you trust the public key of the sender - an adversary can generate a key pair as well after all.

The good thing is that the authenticated encryption should at least prevent plaintext oracle attacks. Those kind of attacks could lead to partial or full disclosure of the plaintext without leaking the key.

• For this specific use case my only concern is that only I can read the messages, I don't necessarily care if bad data is sent, only that the good data that is sent is only readable by me. Jul 2 '21 at 22:33
• OK, but as the question is not that clear, the above is the result of using an ephemeral key pair at the sender part. For why you would always need to provide a private key and send the public key, I would recommend reading up on (EC)IES. If you regenerate the ephemeral key pair for each message a random nonce would probably not be needed. Jul 2 '21 at 22:49
• Thanks I'll check that out now Jul 2 '21 at 23:00
• Cool. Just one note, I'm not sure about the nonce, so you might as well keep it random unless there is a strong reason not to include it. Jul 2 '21 at 23:47

If you want users to be able to send you messages anonymously you can use "sealed boxes" instead of plain boxes.

• It seems internally a sealed box is doing what I've proposed above and therefore is a valid technique? As per your comments you're right I am not using libsodium, just nacl purely, so my dependency unfortunately does not have sealed_boxes built in. Feb 2 '21 at 5:20
• Although it looks like it may use a random nonce and not just a nil nonce like I did. In my system replay attacks aren't a concern but I've decided to switch to random nonce as well since I don't know enough about the internals of NaCl to just assume they can be static. Random Nonce is then publicly shared to me from client. Feb 2 '21 at 5:29

I think you are misunderstanding the way NaCl boxses work. NaCl encryption like you are doing it uses two algorithms. One symmetric one and another asymmetric. Specifically XSalsa20 (symmetric) and Curve25519 (asymmetric).

The way it works is as follows:

Curve25519 allows the generation of a shared 32 byte key given a public key and private key. So basically you can generate the same shared key if you send your public key to someone and they send theirs to you. (The same key will be generated for both sides, but an attacker will not have your private keys, so they can't generate the shared key).

This is essentially what happens when you make a box. A shared key is derived from the public key you received and your own private key, and then used for encryption using XSalsa20.

Essentially after making the box, you are using symmetric encryption to encrypt stuff using the key derived from the key pair. Also it's the same key every time given the same key pair, you aren't making throwaway keys (and you don't need to make another box object every single time, they will all use the same key anyway, you can use the encrypt method with the same object).

As a side note, you should never reuse the same nonce again when encrypting messages so it's not safe at all to use 0 for every message.

Edit: You might be wondering why this is done. The reason is because asymmetric encryption is slow, and generally not so efficient for encrypting long messages. So in most cases, asymmetric encryption is only used either to exchange a symmetric key (or to encrypt a symmetric key that is used to encrypt the actual message and then send both the message and the encrypted symmetric key) or to generate one (like in this case). Even in cases that don't deal with real-time communication, this is how it is generally done.

NaCl boxes work for continuous two-way conversation, so there is no need to make different throwaway key-pairs for every single message (you generate a single shared key and use it for conversation from that point forwards, generating a new key each time would be a waste of resources). As long as the shared key itself and the private keys (which allow the generation of the shared key) are safe and you don't reuse a nonce, you should be safe. I am not sure of your use case, but you can technically generate a random key pair each time too (however, this means you cannot determine if the message is from the same person as before obviously). If you want people to send you messages, in other words, one-way communication that is not real-time, you can technically do this too (again, this breaks the authentication).

• Thanks, also just curious, is the only reason to not use the same nonce because of a potential replay attack? Jul 2 '21 at 19:45
• @AlbertRenshaw Not exactly, in this case the message content is also leaked, while also potentially allowing a third party to forge further messages. Jul 2 '21 at 20:07
• So if the message contents, nonce, and public key are known but not the private key... new unique messages (with the same nonce) can be forged and signed, even without the private key? Do you have a source for that because if so I have a serious security flaw I need to address today. Jul 2 '21 at 21:01
• @AlbertRenshaw Yes, if the nonce is reused, it results in a drastic loss of privacy. As for a source, XSalsa20 is a stream cipher, look up stream cipher attacks (specifically reused key attack). A nonce here is essentially a way to make sure that the same streamkey is not reused. The leak is quite severe if a nonce is reused. Note that a nonce doesn't have to be private, it just shouldn't be reused. Also I thought I might elaborate a bit more on the original answer, so I added an edit, you might wanna read that too. Jul 2 '21 at 21:50
• thanks refactoring to random nonce. Edit: Well I went to refactor to use random nonce instead and it turns out I already was with the comment //Just incase hahaha Jul 2 '21 at 22:34