desmos-labs / mooncake

The first decentralized social app based on Desmos
MIT License
47 stars 14 forks source link

Encrypt content before sending transactions #32

Open kwunyeung opened 4 years ago

kwunyeung commented 4 years ago
## Feature description

Currently all content in the transactions are not encrypted and public. Although the system is censorship resistance, it still enable trace of content delivery which link back to a certain user. As Mooncake holds the private key of the user, the content can be first encrypted and then put inside the tx message before broadcasting. The user sign the encrypted message rather than the original content. The content in the tx can be decrypted by Mooncake using the corresponding users's public key when the users load the data. The content being encrypted should be a salted string instead of the plain content so that other users can't decrypt it using users public key as they don't know the secret salt.

One scenario this feature can benefit is as below.

  1. User posted a post
  2. User regrets and deletes it
  3. User's post and deletion are all hidden in the txs where you can't trace from the Mooncake or on chain.

Implementation proposal

  1. Mooncake holds a secret salt. This can be the original value of the hashed subspace or another piece of random string. It acts like the app_id and secret of a Facebook app.
  2. Every time a user posts a content, the content is salted with the secret and encrypted. Then the post message holds this encryptedSaltedContent and broadcast.
    saltedContent = secret + content
    encryptedSaltedContent = encrypt(saltedContent, privKey)
  3. djuno should still store the encryptedSaltedContent to keep itself as the chain parser.
  4. When Mooncake displays the content, it decrypts with poster's pubkey and remove the secret
    content = remove( secret, decrypt( encryptedSaltedContent, pubkey ) )

The secret should only be available in the binary build of the Mooncake, it should not be stored on GitHub. This should be purely done during build time.

RiccardoM commented 4 years ago

Comments about the feature description

Although the system is censorship resistance, it still enable trace of content delivery which link back to a certain user.

What do you mean by that? All accounts are public, so what does "trace of content delivery" mean here?

Comments about the implementation proposal

I think the implementation you proposed is not fully correct.

If we only used asymmetric encryption, the sailt wouldn't do much about the privacy:

let saltedContent = secret + content
let encryptedContent = encrypt(saltedContent, privKey)

If we only do this, then everyone would be able to access the saltedContent by doing:

let saltedContent = decrypt(encryptedContent, pubKey)

Then, since this would be a plain text, they could simply remove the secret by guessing which value it has (this can be done easily by comparing different unencrypted post contents).

The best way would be to use both a symmetric and asymmetric encryption methods:

// When sending
let aesEncrypted = AES256.Encrypt(postContent, secret)
let pubEncrypted = RSA.Encrypt(aesEncrypted, privKey) 

// When receiving 
let pubDecrypted = RSA.Decrypt(pubEncrypted, pubKey) 
let aesDecrypted = AES256.Decrypt(pubDecrypted, secret)

At this point tho, the RSA encryption would just be a useless overhead, since all the Mooncake installations would already know the secret value. So, this can be easily simplified as:

// When sending
let aesEncrypted = AES256.Encrypt(postContent, secret)

// When receiving  
let aesDecrypted = AES256.Decrypt(pubDecrypted, secret)

Problems with this feature

As far as I see it, implementing this feature would lead to some problems:

  1. If the secret present inside Mooncake gets lost, then all the content would become unreadable.
  2. If an attacker decompiles the application and reads the secret leaking it, it would make the whole system useless.
  3. The length of the post should definitely be lower than 500 characters, since encrypting it with a salt results in a cyphertext being longer than the input.

Conclusions

I personally don't think this feature is necessary, also because I do not understand what it achieves more than we have right now.

Implementing it would only mean making Mooncake slower (encryption and decryption on mobile devices is a computationally intensive task). I think the advantages/disadvantages trade-off is too low.

kwunyeung commented 4 years ago

The goal is to hide the content in the transactions so that only Mooncake can reveal content inside the state where other public users can't trace back by only accessing the transactions.

I believe in performance-wise it won't be an issue. There are packages utilizing the smartphone hardware for encryption/decryption.

https://pub.dev/packages/cryptography https://pub.dev/packages/kms

From the Apple's iOS Security Guide, the process of AES processes should be pretty fast (I couldn't related information on Android though.). https://www.apple.com/in/business/docs/site/iOS_Security_Guide.pdf

Possibility of losing the key and reverse engineering of the app are at a high risk. After some studies, I agree the trade-off is not worth taking at this stage. Let's put this aside first. We keep Mooncake as fully open for now as it should be. We can come back to this issue after we gather more feedback in the future.