I'm trying to implement a web app(lication), which allows to share data automatically with connected users. Data will be encrypted end-to-end asymmetrically on the clients.

My first plan was to share the public key through the app itself, but then I realized that users need some verification that the public key is really from that user. Now I tell them to share the public key via email addresses they already know from each other.

But there is still a security hole:

How could users be sure that my application uses the public key of the recipient? I still could encrypt the message with my own key, intercept it and forward it with the recipient's public key. To withstand tests by security experts, I could do that only on specific users or at specific times.

I'm at the point where I think that it's impossible to encrypt and share data securely in the same app. Thus users have to encrypt data in another app and copy it manually into the sharing app.

Is there a workaround or does it boil down to trust?

The small print

Question "Sharing encrypted data" is similar to this, but I cannot access user's machines and the answers don't question the security of the public key sharing mechanism.

migrated from stackoverflow.com Jun 12 '14 at 21:02

This question came from our site for professional and enthusiast programmers.


How could users be sure that my application uses the public key of the recipient? I still could encrypt the message with my own key, intercept it and forward it with the recipient's public key. To withstand tests by security experts, I could do that only on specific users or at specific times.

To some extent, users will always need to trust the people supplying any crypto software (and any libraries and OS components used by the crypto software, or running alongside it) they use.

You can somewhat mitigate this issue by publishing the source code of your client software, inviting security experts to review it, and encouraging users to compile the software from the source. You can publish SHA-2 hashes of the source code (and binaries, if you distribute any) to let users verify that the source code they downloaded is the official reviewed version, and encourage users to share and compare the hashes to ensure that you're not sending different hashes to different users.

Ultimately, none of this will entirely prevent you from hiding malicious code in your program (even if the user personally reviewed the code before compiling it, there could still be a Thompson hack in the compiler itself), but it does make it more likely that you'd get caught if you tried it.

I'm at the point where I think that it's impossible to encrypt and share data securely in the same app. Thus users have to encrypt data in another app and copy it manually into the sharing app.

Most of these trust issues will still be present even if the encryption and sharing functions are separated.

The main advantage of doing so is that, with a separate encryption app, the user could, in principle, run it in a sandbox that is not allowed to communicate with anything else, except for reading the plaintext and writing out the ciphertext (or vice versa). This would make it somewhat harder for the app to open a covert channel to transmit the data to a third party — although, without a detailed manual examination of the ciphertext, it's hard for the user to rule out the possibility of the encrypted file itself containing extra information or deliberate weaknesses to allow someone other than the intended recipient to decode it. Also, in practice, it's unlikely that most users would actually bother running the encryption software in such a sandbox.

Another advantage, of course, is that splitting the encryption and sharing code into separate applications means less security-critical code to review: if the sharing app never sees the unencrypted data, and cannot control how it's encrypted, it does not really need such detailed scrutiny. Also, if the encryption and sharing software is provided by different parties, it's somewhat less likely that they would collude to compromise the security of the combined software (although just compromising the encryption app might well be enough).

Ultimately, it does boil down to trust. You can do various things to encourage trust, and to limit your own ability to break it, but you can't eliminate it entirely.

What I would do in your position, to minimize my own ability to compromise the software, would be to:

  • Open-source your application, and publicly invite independent security reviews.

  • Encourage users to compile your application from the source.

  • Distribute SHA-2 sums of all the source code (and binaries) you release, both on your web page, within the release packages, on mailing lists and via any other channel you can think of. Encourage your users to share and compare these checksums from multiple sources, and to complain publicly if they don't seem to match.

  • Possibly provide a baseline encryption feature in the program, but clearly note that this may not be fully secure, and encourage your users to use additional encryption (of their choice) on top of that.

  • Separate any built-in encryption code, and any other security-critical parts of the code into separate programs. Even if these helper programs were automatically invoked by default, to provide an integrated user experience, it should be possible for the user to invoke each of them separately in an isolated environment.

  • Not use on-demand code distribution (e.g. in-browser JavaScript) or any kind of automatic update mechanisms: these make it very easy to deliver compromised code to specific users (e.g. in the guise of a bug-fix update). Alas, avoiding these mechanisms also makes it harder to distribute legitimate bug fixes to users, so there's a tricky security tradeoff here.

    The best you can probably do here is to either a) distribute updates through a channel the users already trust, and which preferably involves at least some external review, such as the system package manager on Linux, or b) poll for updates (over SSL), but don't download them automatically; encourage your users to verify via external channels that there really has been a legitimate update (and to do the SHA-2 sum checking described above) before installing the update.

  • Accept that, no matter what I do, there's always the possibility that the software could be compromised. Also accept that, in practice, most users will not care, and will be content to trust you, whether they should or not.


For a user to be able to trust the system, she must be able to verify that the plaintext is handled securely on the client, i.e. that any data shared with another user is encrypted with that user's public key before being sent to the server, that no information about the plaintext is somehow leaked, etc. This depends on the user (or someone she trusts) being able to inspect the source code of the client, and to be sure that the inspected version of the source code actually corresponds to the client that is running.

Whether a single program or multiple programs by different authors are involved doesn't affect the security in any significant way (a collusion between multiple parties is quite possible). However, if the source code cannot be inspected, or the plaintext is sent to the server, all bets are off. Even if the author did not maliciously intend to make the program insecure, there may well be bugs that make the program insecure.

A standard "web application" involves a user's browser running Javascript code downloaded automatically from the server. While Javascript can perform cryptographic operations directly on the client, thereby avoiding the need to send the plaintext to the server, inspecting the source code is problematic. The user would need to first download the HTML and Javascript and save it locally, inspect the code, and then run the local version, which is fairly inconvenient. If the user runs the code directly from the web server (presumably using HTTPS), she must trust not only the operator of the web server, but also the operators of the hundreds of CAs stored in her browser.


This indeed has nothing to do with end-to-end encryption between two peers. It's the classical model of an “all-knowing server” which makes data available to the clients. Your users need to fully trust you, because the security of the model depends entirely on your honesty and abilities.

The whole asymmetric encryption doesn't really do much in your scenario. If your server is compromised, the attacker may very well fetch the plain text data as it comes in. The only advantage is that it's difficult to read the data after it has been encrypted and sits on your server.

End-to-end encryption and the “all-knowing server” are two mutually exclusive models. You can't have both at the same time. If you want to manage the user data, then it's no end-to-end encryption. And if you want end-to-end encryption, you can't manage the user data. Your service would basically be limited to classical file hosting and distribution of keys (which have to be personally verified by the users like with any other key server).

  • What's about encrypted cloud storage? I could only trust them, that it's encrypted, but I can't be sure? – Christian Strempfer May 21 '14 at 21:32
  • Just to make it clear: the data is encrypted on the client, so the client must be compromised. – Christian Strempfer May 21 '14 at 21:48
  • If the client does the encryption, then the only job of the server is to host a bunch of files. It doesn't have to be some fancy cloud service. A primitive FTP server could do the same thing. – Fleche May 21 '14 at 22:38

How could users be sure that my application uses the public key of the recipient?

If you want to trust a user's public key, you need to either have confidence you are receiving it directly, or obtain third party assurance. You can have the user's public key signed by a CA or you could have a key signed by other keys you trust (web of trust).

If your server just provided me a public key or cert which is not signed, I would have no reason to trust or believe it. You need to either get it directly or rely upon third party trust.

I still could encrypt the message with my own key, intercept it and forward it with the recipient's public key.

You could be a man in the middle if the encryption happens on your server, you could also just intercept it in plain text since the user requires to trust your server before your server does the encryption.

If you are doing this client side, and want to ensure that the sender is legit, you would use the sender's private key to digitally sign the message.

If you are doing all the signing and encryption on the client side, with signed/validated certificates then your server will just have an upload of the encrypted and signed document. Doing all of this is a browser app would be a pain, some apps require a plugin/add-on to make this easier. And, the user has to trust that your not running JavaScript to intercept their commands in the browser (the same would be true about trusting a desktop app)

At any rate, if everything is done on the client side before upload, you will not be able to decrypt it if you do not have the private key of the recipient. If you send your public key instead of the recipient's public key, the end user should be able to detect this because the key won't be validly confirmed as belonging to the recipient.

  • Thanks. Signing is a good point. It wouldn't prevent additional falsely encrypted transfers, but doubling the traffic could make the user more aware about problems. – Christian Strempfer May 28 '14 at 16:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.