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.

1 Answer 1


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 :)

  • Thank you, that's a great answer. So I can just use AES256 to encrypt the data with the public key, and ECIES to securely encrypt/decrypt the AES256 key using Metamask. pbsh, how might I get into contact with you regarding a potential employment opportunity? Commented Feb 4, 2022 at 9:02
  • 1
    Glad it helped. You can email me at [email protected]
    – pbsh
    Commented Feb 4, 2022 at 9:09
  • There is a typo in the answer, AES256 is a symmetric encryption algorithm. Commented Feb 1, 2023 at 5:34
  • If you use AES, best to use a MAC - like AES-CTR with HMAC github.com/samuel-lucas6/Cryptography-Guidelines#use-in-order-1
    – Duke
    Commented Nov 18, 2023 at 16:39
  • Hm I might have read it wrong, but looks like the encryption in unstoppable shop isn't secure. ` const ephemeralKeyPair = { publicKey: Buffer.from(process.env.EPH_PUBLIC_KEY as string, 'base64'), secretKey: Buffer.from(process.env.EPH_SECRET_KEY as string, 'base64') }` -- it's pulling the decryption key from the env vars
    – Duke
    Commented Nov 18, 2023 at 17:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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