cryptee / web-client

Cryptee's web client source code for all platforms.
https://crypt.ee
Other
445 stars 22 forks source link

[Question] KDF used to generate the user key from the pass-phrase? #192

Closed num0005 closed 1 year ago

num0005 commented 1 year ago

Is your feature request related to a problem? Please describe.

I was wondering how the user key is derived from the low-entropy pass-phrase. It seems that the KDF function part of the code is handled by opengpgjs?

Describe the solution you'd like

Would be nice to have some more details about the way the E2E encryption is implemented on the web page about the security.

Additional context Really love the product the team made, and I appreciate keeping the lines of communication with the community open through this repo.

johnozbay commented 1 year ago

Hi there! πŸ‘‹πŸ»

Thanks a lot for filing this thoughtful question, and thanks for tagging it correctly to help us get to this question quickly! Also thank you so much for your kind words and compliments! πŸ™πŸ» Really happy to hear you're liking Cryptee! Team and I are trying our best to make and maintain things as transparently as humanly possible.

This is an excellent question!

The KDF (key-derivation-function) is indeed handled by OpenPGPjs, as well as the encryption implementation itself. [more on this below]

First I'll start by clarifying / correcting something in your question (mostly for posterity / and for future readers), and answer everything afterwards.


Would be nice to have some more details about the way the E2E encryption is implemented...

First off β€”Β to clarify / correct : E2EE (End to End Encryption) is an encryption used for communications, and implies there's another end. (so basically you can think of it like you and your friend can communicate/message without the company/server/third parties' knowledge.)

In case of Cryptee, the correct term is client-side-encryption, since there's no other party to communicate with, and neither the server nor anyone else can see your files, only you can. And we use AES-256, which is a symmetric key encryption algorithm, used most commonly in client-side-encryption. (vs asymmetrical / public-key algorithms most commonly used in E2EE between multiple communicating parties)

For future reference, if you see a storage company / service using the incorrect terminology, dig deeper. Since E2EE is often misused for marketing purposes to describe that your communication to the server is encrypted, (so you and the server are the communicating parties) but the server (the other end of the communication) can still see your data.

Reason why I wanted to clarify this has to do with the fact that, most companies who document their E2E or other encryption implementation tend to do so, because they use custom / unique / home-brewed encryption implementations. Not that one type of encryption is easier than the other, but in the case of E2EE, there's significantly more room for error than there is in client-side-encryption. (i.e. how key exchange is handled etc)

The reason why we don't have a lot of implementation information on our security page is because we use perhaps the most industry standard encryption there is : AES-256 β€” and we do so via OpenPGPjs. Then everything that which is Cryptee is built on top of it.

So to put it differently, there's virtually no piece of code inside Cryptee that changes / handles / deals with the implementation of encryption itself, we use a single encrypt / decrypt function call to OpenPGPjs, and that handles everything. And OpenPGPjs is regularly and frequently audited. So there's little reason for us to try and re-publish a sub-par copy-pasted version of their implementation documentation.


It seems that the KDF function part of the code is handled by opengpgjs?

Yes, that is correct! OpenPGPjs uses a 'S2K' (string-to-key) function to convert passphrase strings into symmetric-key encryption/decryption keys.

So there isn't a single line in Cryptee's codebase handing the key derivation, it's all OpenPGPjs.

To further elaborate, Your original question text in the issue (which I read in the email notification) was actually much more comprehensive, asked about the speed of the KDF, and I wish you didn't edit it out, because I think it was an excellent question πŸ‘πŸ» β€”Β as, one would need to dig through OpenPGPjs documentation if they haven't read through the entire OpenPGPjs codebase like I have πŸ˜…

At the moment OpenPGPjs uses 224 iteration count bytes for S2K :

https://github.com/openpgpjs/openpgpjs/blob/c60f2e3490c83b7c5499bf0e29124b668bbae4dd/src/config/config.js#L84

For comparison, BIP39 mnemonic with 12 words commonly used by wallets will give you 16 bytes / 128 bits of security, similar to the security of AES-128. (not exactly a good direct technical comparison, but figured it would help contextualize things)

One can technically lower s2kIterationCountByte to lower protection and increase performance, or vice-versa. But instead of opening under the hood and changing the encryption implementation, we instead chose to use the existing OpenPGPjs configuration and implementation, which for the purposes of client-side-encryption is already quite strong.

(and we didn't want to roll our own custom encryption implementation / configuration, that which could/would deviate from the OpenPGP standard, and make things harder for us in the future β€”Β should we wish to enable sharing features in Cryptee some day, and enable optional E2EE features for some content on Cryptee, i.e. sharing photos or docs collaboration etc)


Hoping I could clarify some stuff, answer your question, and this helps! ✌🏻 I'll close the thread for now, but please feel free to ping me with further questions and re-open the thread, I'd be happy to elaborate further.

Once again, deeply appreciate the thoughtful question and taking the time to go through the codebase! World needs more amazing people like you! πŸ™πŸ»

All the very best,

John