2

I have a website where a registered user can exchange any number of offline messages with a guest. The guest only has to enter his e-mail address and should not have to create an account. The messages should be stored encrypted on the server. If there is a new message for the guest, he should only receive a one-time link by e-mail, with which he can decrypt the messages.

The requirement should only be that a hacker who steals the database cannot decrypt the messages. I thought I'd use a public/private key method and attach the private key as a GET parameter to the https link. It is never stored anywhere at any time and is only in RAM. The problem is that the private key is very long and of course I don't feel good about transferring the private key to the server.

Is there another (better) way, without any password input, or client software, just with a link via email?

4
  • Can the user and guest share some password preemptively through a separate trusted channel?
    – Luke Park
    Commented Nov 21, 2019 at 21:12
  • No, the guest initiates the conversation via the website and it should be avoided that the effort becomes too high for him. Therefore no registration. The communication is also not particularly worth protecting. It is only privacy by design.
    – root66
    Commented Nov 21, 2019 at 22:10
  • 1
    You could generate the link on the client-side (so the private key never reaches your server) and allow them to communicate this link to the client however they see fit (their own email account, slack etc.)
    – Luke Park
    Commented Nov 21, 2019 at 22:13
  • How can I decrypt the messages if the private key is not transferred to the server? GET parameters are the only way to get data from the e-mail program into the browser. POST does not work reliably. Even if a Javascript decrypts the data in the browser, the GET request would send the private key to the server.
    – root66
    Commented Nov 21, 2019 at 22:23

5 Answers 5

0

If you want that only the user can read the message, and that a hacker cannot read it in the database, this means you (your application) should also have no possibility to read the messages. And if you cannot read them, what sens it make to keep them in the database? I'd suggest that as soon as you get a new message for user you encrypt it and send. May be one reason could be that if user has lost this email, you can resend it. This is OK. Keeping encrypted Email is not a problem.

But i you want that your server can read all the user messages at any time, then you cannot of course keep the messages encrypted with users key. You have then use a separate key that is known to server only. Server encrypts and decrypts all messages in database with this key. When a message needs to be sent to user, server decrypts it with its, then encrypts with user's public key and sends it to user. If an attacker obtains your database, he will need also a password that server is using for encryption/decryption. You can use HSM to mitigate it.

To encryption: The most reliable solution would be to use PKIs. You can provide a web application, that during user registration generates key pair in browser and sends public key to your server. Your server uses later on this key to encrypt messages to this user.

0

Each registered user should have a Public Key stored on the server and a cryptosystem which cobines public and symmetric encryption should be used.

Then, anyone would be able to exchange any number of offline messages with any registered user. Each registered user would be able to answer those messages if you use ElGamal Cryptosystem which combines Public and Symmetric Encryption. Elgamal is very easy and amazing - https://en.wikipedia.org/wiki/ElGamal_encryption.

Each public key is generated in the following way: Take a secret x from a ciclic group and compute the public key $X = g^x$. All information about the ciclic group is also public (i.e. saved on the server).

Each sender (guest or not) generates an ephemeral secret key y from the ciclic group and computes a correspondig ephemeral public key $Y = g^x$.

The encryption key can only be generated by sender ($K = X^y$) and receiver ($K = Y^x$). Y should be attached to the message.

Notice ElGamal uses the concept of Diffie-Hellman without the Man-in-the-middle flaw - even the server, which acts as the intermediate channel to share the messages, is not able to get K.

0

The fundamental issues as I see it are:

  1. The guest only has to enter his e-mail address and should not have to create an account

This suggests the guest is unregistered (hence guest) so no attributable encryption keys.

  1. a hacker who steals the database cannot decrypt the messages

This is fairly vague and begs the question of what exactly is in the potentially stolen database or are you actually referring to the entire system theft?

If the concern is just the database then keeping the keys elsewhere meets the criteria. This could be as simple as a fixed key in an external process, or an external key process based upon the guest email.

If the concern is actually whole system theft and not just the database, then a similar approach is possible with the requirement that any keys are loaded and maintained only in memory from an external source that is removed upon start up.

If the concern is complete run time compromise with full memory access by the attacker, then I have no idea!

0

End-to-end encryption is hard, even without the guest account requirement!

With that said, fundamentally, your need isn't that complicated. Some user wants to send a message to a guest. The user's client (browser-side script, if it's a webapp) generates a symmetric encryption key (no reason to use public keys here) and encrypts the message(s) that the user sends. The encrypted messages are stored on the server, along with some identification (potentially the email address of the intended recipient, though that requires storing some plain-text PII so maybe you use an opaque identifier). The client also generates a URL, containing the key as part of the URL fragment (and, if relevant, the opaque identifier as a path or query parameter). This URL can be used to retrieve the encrypted messages and (via the fragment, which is not sent to the server) decrypt them.

The URL gets sent to the recipient (guest). You have a choice to make here: how to get that link from the user's client to the guest recipient's inbox? There are broadly speaking three ways:

  • Send the URL to the server, and the server sends the email. This violates the zero-trust property, as it requires trusting that the server does not store the URL (or even just the key portion), or use it while it's transiently passing through the system, or keep it in a "sent messages" log on the mail server, or whatever.
  • Tell the user to send the link themselves (that is, copy it to the clipboard and paste it into their own email client, or chat program, or even write it on a letter and send it via snail-mail). Not a great user experience, but hey, it (mostly) preserves zero trust... as long as you aren't using a webapp, which is basically incompatible with zero-trust (the user and recipient always need to trust that the server isn't sending them malicious script that steals the plaintext; in theory you could manually validate this every time since even minified client JS is technically readable, but in practice, ha, no).
  • Have the client app send the message with minimal user interaction but without relaying off the server. For a webapp, the closest you can probably get to that is to have the user click a mailto: URI, and hope that the user's browser is configured to open those in the right email program or webapp and that the email client (web or otherwise) parses it as expected (and that the user then clicks "Send"). For a desktop/mobile app, you could in theory have the app connect to an SMTP server directly (probably the user's server that they have to supply credentials to, which is likely a non-starter) but in reality you'd probably use a "share contract" to send the URL to a messaging app of some sort via OS-provided functionality for passing data and intent between apps.

I'm leaving out a ton of detail here, mind you. You want integrity protection, not just encryption, on the ciphertext; this should probably be done using authenticated encryption. You can also sign messages if you want them to provably come from that specific user, but sometimes sender privacy / message repudiation is a desirable property instead. You want some way to expire the links, used or unused, and probably expire them sooner if used... but you probably do not want them to expire immediately upon first use, otherwise any program that pre-fetches URLs (e.g. to check them through a security scanner, display a preview image of the resulting page, or cache them for faster loading later) might expire the link prematurely. The system as described only handles sending to guests, not guests starting a conversation or replying to a message; both are possible but it gets more complicated. This also is primarily intended for a single recipient; if you want to send the same message to multiple people, without duplicating the same plaintext across a bunch of ciphertexts, then you potentially do want to use a hybrid cryptosystem where you send the guest a private key; elliptic curve keys are short enough that this is viable but it's still adding complexity again.

Perhaps most importantly, you need to think about your threat model here. The whole question of what you're really trying to achieve, security-wise, against whom. End-to-end encryption without zero trust means little, but as mentioned above, zero trust in webapps is basically unfeasible. You'd also run into problems when encrypting to other registered users, unless you have some way to verify - in the client - that the key (probably public key) you're encrypting to belongs to that user and nobody else (like the server) has its private key, and more complexity still if you want forward secrecy.

These are all solvable problems. Take a look at Signal and its ratcheting key exchange if you want to see an open source example of a widely-used zero-trust end-to-end encrypted messaging platform with support for asynchronous transmission of large messages, complete with forward secrecy. It's a beautiful design. But it's not something a novice should try to implement, and frankly, most people don't have a good reason to do so.

0

There seems to be a flaw in the design of this system.

If you want to guarantee (to a reasonable extent) that the only person who reads the message is the user who enters their e-mail address, then the user must provide their public key and your server should encrypt the message using that key. It will be responsibility of users to decrypt the messages.

Otherwise something else needs to decrypt messages for users and therefore needs to have access to private keys. If your threat model includes the risk of the database being stolen then the same way that other system that will be decrypting messages could also be stolen, including the keys.

Is there another (better) way, without any password input, or client software, just with a link via email?

In this case the e-mail becomes "the key" because it is the only information that is required to obtain the cleartext message. Therefore you system becomes as (in)secure as the e-mail message and its delivery.

You must log in to answer this question.