Dropbox-like application on IPFS

Hi all,

If there’s a better part of the forum to post to, please let me know.

I’ve been getting really interested in IPFS, and building a (almost completely) decentralized file sharing platform with end-to-end encryption. I was hoping I could get some feedback, specifically, related to the security of my design.

current build hosted at: using an ec2 as an IPFS node

github: iris

My design so far is fairly simple. The application uses a user’s ethereum account (which must be injected using a service like Metamask) to identify users. I chose to use the ethereum account for a few reasons. Firstly, it offloads the responsibility of securely storing user’s sensitive data (i.e. passwords), but also for future use cases where a user can apply a smart contract to their files (i.e. put it behind a paywall, restrict access to specific people, etc).

However, though I would not be storing the user’s password anywhere, in order to asymetrically encrypt files, each user needs to generate a public key and a private key. Let’s call them PUB_USER and PRIV_USER. The public key stored in IPFS, completely unencrypted, and accessible to anyone. However, the storage of the private key is where my concerns lie. Here’s my current solution:

(Sorry for the spacing, ipfs only allows new users to add a single file to a post, and had to merge them at the last minute)

Further explanation:
The app has a public key and a private key. say PUB_APP and PRIV_APP, where the PRIV_APP is injected into the app as an environment variable and PUB_APP exists in the app as a variable . There are some obvious security concerns to the way PRIV_APP is injected that I know need to be addressed.

Next, once the user’s keys, PUB_USER and PRIV_USER, are generated, PUB_USER is added to IPFS (should be accessible to anyone), and PRIV_USER is 1) asymetrically encrypted using PRIV_USER and PUB_APP 2) Stored in the browser’s local storage.
Let’s call this encrypted private key PRIV_USER_ENCRYPTED

Later, when the user want’s to asymetrically encrypt a file to send to another user, who has a public key PUB_OTHER_USER, this is achieved by getting PRIV_USER_ENCRYPTED from localstorage, decrypting it with PUB_USER and PRIV_APP, and then using PRIV_USER and PUB_OTHER_USER to encrypt the file. The decryption of the file works in the opposite way.

Apart from the encryption keys being at risk of being exposed, since they’re generated client side, are there any other obvious security concerns with this approach that I might be missing?

Thanks for reading!

nice project maybe you can added into awesome-ipfs

1 Like

I don’t understand why the app has a key pair and then each the user has another key pair. Is the app-key-pair shared for all users?

  1. asymetrically encrypted using PRIV_USER and PUB_APP 2) Stored in the browser’s local storage.

this is achieved by getting PRIV_USER_ENCRYPTED from localstorage, decrypting it with PUB_USER and PRIV_APP,

If the app-key pair is shared, anyone can decrypt that user’s private key. I don’t understand why it would be encrypted with the user private key (anyone can undo that encryption, particularly if it’s the last step), and the other in which you wrote the decryption does not match as it would first need to do PRIV_APP and then PUB_USER.

The diagram at the top-right also calls it PUB_A_ENCRYPTED but probably means PRIV_A_ENCRYPTED.

Textile folks have given some thoughts at these problems and did a write up here: https://blog.textile.io/the-5-steps-to-end-to-end-encrypted-photo-storage-and-sharing/

2 Likes

Hi Hector,

Looks like I’ll have to spruce up the diagrams a bit, and provide a more thorough justification for having reusable encryption keys. In my design above, the app public key is shared between all users, but the private key is available only to the app itself, with no user access to it. If everything is securely set up (i.e. this app private key is truly hidden from users and not attainable by other means), then I believe the users private keys would be safe, since the app private key is a requirement for decrypting it.

I started reading into the link you sent about how textile is achieving this, and it definitely seems more secure and robust, so i may have to rethink everything above and try to adopt something more along the lines of their solution. In my initial analysis of the issue, i considered the idea of creating new keys per upload, but I kind of ruled out the design for a simpler one. But seeing as they were able to accomplish it, it seems like a more secure design.

That is impossible from the moment that each user will need to have that key so it can always be extracted from the app.

I realize this part of the project is more ‘ethereum’ than ‘ipfs’, but I wanted to thank you for your input, I think I’m starting to go down a safer path because of it.

I’ve taken all of that into consideration and completely reformulated my idea. With my new plan, I’ve completely gotten rid of reliance on metamask or injection of an external ethereum account. My plan now is to use eth-lightwallet to create a new ethereum account for each user. Eth-lightwallet also supports encrypting and decrypting data with your ethereum private key. With this, I can completely remove any need for ‘application keys’. This approach is heavily influenced by how metamask does it already, using many of the same libraries they rely on. So the plan for new user generation is:

  1. user enters password
  2. generate mnemonic phrase with bip39
  3. use browser-passwordee to encrypt the phrase and store it in local storage
  4. use eth-lightwallet to create new ethereum wallet from the password/seed phrase

Then when a user logs in again with their password, it retrieves the encrypted mnemonic phrase from local storage, decrypts it using the password, and uses that, along with the password, to recover their ethereum account.

Encrypting/decrypting files can be completely managed by eth-lightwallet before adding the files to ipfs or downloading them.

1 Like