Web3.js – Encrypting and Decrypting Data on IPFS Using Ethereum Keys

encryptionethers.jsipfsprivate-keyweb3js

I would like my app to connect to a Web3 wallet, store encrypted data on IPFS, then retrieve that data and decrypt it (without the user exposing their private key to my app).

Is this possible? If not, is there any way of only allowing Read/Write access to IPFS data (or a MongoDB collection) based on the connected wallet's address? I'm guessing the window.ethereum object can be easily spoofed… I imagine a secure protocol might involve signing a verification transaction? Hopefully not – if this was required on every read/write it would be quite cumbersome for user interaction.

I'm using ethers.js but open to learning web3.js.

Best Answer

You'll need to the encrypt the data before storing on IPFS. But its not efficient to use ECIES encryption (which uses Ethrereum keys) on large data as its slow and Metamask will often hang. A good strategy would be to encrypt the data using a symmetric encryption like AES256. You can use something like CryptoJs for the same. Then you can encrypt the AES256 key using the Public Key of the recipient's Ethrereum address.

To get Public Key from Metamask, you can request it via eth_getEncryptionPublicKey (docs). Or if the recipient has at least one transaction on Ethrereum, you can recover public key from the transaction data like this.

Now that you have the recipient's public key, you encrypt the AES256 key with it using ECIES encryption. Now you can add both the encrypted data (encrypted using AES256) and the encrypted AES256 key (encrypted using ECIES) to IPFS. You can do this using various ways, like creating a text file of the encrypted key and zipping it along with the encrypted data so you get a single file. Or add it as separate files, or create a directory.

To get the data, the recipient will have to download both the data and encrypted AES256 key from IPFS. Then decrypt the encrypted AES256 key using their public key. You can do this using Metamask using eth_decrypt(docs). Now with the AES256 key, you can decrypt the data.

You can checkout this project which implemented this idea. Hope this helps :)