0

I'm creating a pastebin-style application which stores notes and has the following options:

  • Ephemeral, where it is deleted as soon as it is read
  • Encrypted, where the content is encrypted before being sent to the server (used to determine if a client should be prompted for a password)
  • Expiration, a TTL

During the flow of the application, when you navigate to the endpoint: example.com/ABCD1234, it first loads metadata about the note with ID ABCD1234. Even if the note is ephemeral, reading the metadata should not remove the note. Once any necessary parameters are provided, it will reddirect to example.com/ABCD1234/read which pulls the content and removes it from the server if the note is ephemeral.

enter image description here

My trouble is from prompting the password. There are a few options that I can see.

  1. Send the password as part of the request to retrieve the note and check if the password is correct on the server side. Personally, I would like to avoid the plaintext password ever being sent over the network or being seen by the server in any capacity, so this is ideally not going to be used.

  2. When creating an encrypted note, the client would generate a hash of the password and send it along with the encrypted content to be stored on the server's backend datastore. When retrieving the metadata, provide the password hash back to the client so it can be easily checked in the browser to determine if the password is correct. Of course this option opens up the possibility of password brute forcing by cracking the hash, but a sufficiently complex password shouldn't be particularly vulnerable.

  3. When creating an encrypted note, use a piece of randomly generated (on the client side) but known plaintext and, using the same password, some ciphertext as well of that known plaintext which is completely unrelated to the actual content e.g. "This is a challenge". Both the plaintext and ciphertext of this challenge would be provided via the metadata, and if the password entered can decrypt the ciphertext into the known plaintext "This is a challenge", then the redirect on the client side will occur.

  4. Some kind of non-interactive zero knowledge proof, but this is currently difficult to implement.

Note that this is not about authorizing access to the content itself or I would integrate with some identity provider and have account-based reading. It's simply about providing an easier experience to the user so that if they type in the wrong password, it won't pull the content, delete the note, and decrypt the data to garbled nonsense thus preventing them from ever being able to re-enter the correct password. I just want the browser to confirm it knows the right password before deleting ephemeral notes.

4
  • 1
    I'm not sure if I don't understand your question or if what you write does not match. You say initially, that the data are encrypted at the server - which then would mean that it is easy for the server to check if the correct password was provided before deleting the data (providing your encryption also ensures integrity). Yet your description of variant 2 suggests that the data is encrypted at the client: "the client would generate a hash of the password and send it along with the encrypted content to be stored on the server's backend datastore". So, I'm confused about your design. Aug 4, 2023 at 4:56
  • @SteffenUllrich negative, the note would be encrypted on the client side before it is sent to the server. The server is told whether or not it is encrypted just so it knows whether or not to present the password prompt to the client who reads it, but it nevre sees the plaintext of the content nor the password itself. The generated URL would look something like example.com/ABC123#xxyyzz where ABC123 is the note ID (transmitted to the server in a GET request) and xxyyzz is the password which is a hash parameter in the URL which is not sent to the server.
    – Goodies
    Aug 4, 2023 at 6:39
  • @SteffenUllrich I do see the mistake in my wording, though. I meant that the data which exists on the server side is encrypted, not that it is actively encrypted on the server side. My mistake.
    – Goodies
    Aug 4, 2023 at 6:40
  • OP, What you are trying to build seems very similar to the (now defunct) Firefox Send service for sending encrypted files. All encryption is done on the client side; and the server only sees the ciphertext of the file, and never sees the plaintext of the encryption keys. See wired.com/story/firefox-send-encrypted-large-files for more info.
    – mti2935
    Jan 2 at 8:32

1 Answer 1

0

This is possible using password based encryption, which you could pair with password based authentication to retrieve a specific note. However, it is probably a better idea to use a single password for a user; I don't think any user is going to want to manage let alone remember a password per note. Regardless of the function used, the password should be relatively complex if any kind of security can be maintained.

The idea is that you derive one or more secrets using a Password Based Key Derivation Function or PBKDF. Well known ones are PBKDF2 and Argon2. There are also other options such as bcrypt or scrypt. The PBKDF can be run in the client / browser. The parameters such as salt and the work factor (iteration count) required for the operation need to be retrieved first, but they can be public to the server (and possible other parties).

After you've created the secrets you can use the key to protect the note (the message in cryptographic terms). Nowadays we try and use an authenticated cipher such as GCM or ChaCha20/Poly1305 for these kind of operations. Authenticated ciphers offer confidentiality but also authentication / integrity of the message. If a single password is used then it is possible to derive message specific keys, e.g. by storing a random with the message and using that as parameter to a Key Based Key Derivation Function such as HKDF-Extract.

You can use another secret to authenticate to the server. Of course, that secret needs to first be shared with the server once it has been created. After that it can be verified with the server. It is possible to do this using a simple compare if (e.g. HTTP basic authentication) if a secure connection has been established, but there are other options as well (challenge response protocol, Secure Remote Password (SRP) protocol).

Passwords are relatively dangerous to use for encryption as they are often too simple. I would suggest that you offer some options here, such as having an option to use generated passwords (e.g. by a browser, or pasted from a password manager). It would also be a good idea to have an indicator of the estimated strength of the given password. During use I would recommend adding counter measures after a wrong password has been used (adding delays during authentication, or deleting the (local) ciphertext after a few bad attempts). Beware though that decryption of ciphertext can take place in an offline setting, using fast, easily parallelizable operations.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .