Security of the encrypted notes #1

Closed
opened 2023-03-05 15:37:04 +00:00 by sofia · 5 comments
Owner

Currently, notes are encrypted using pwbox which is a crate that enables password-based encryption and decryption.

This is fine, but I have a few things that I want to answer/resolve:

  1. The decryption is quite fast. Are the notes prone to a brute-force attack?
    Yes, but this is prevented using a KDF on newer databases.
  2. What should be considered a "safe" password (length, entropy, etc)?
    Using a basic entropy function (E = L * log2(R), where E is the entropy, L is the password length and R is the quantity of unique characters), seems like a good entropy value is higher than 60. But this function under-represents the importance of dictionary-based attacks, which are more valuable after the implementation of a KDF.
  3. Should the use of a "safe" password be enforced?
    Yes, partially (see #issuecomment-14).
  4. Should values like entropy be shown to the user when creating a password?
    Yes, it is a good idea to show that to the user, and has been already implemented (b051b923fd)

Another alternative would be to salt/hash the password: that way dictionary-based attacks could be made more difficult.

Currently, notes are encrypted using [pwbox](https://docs.rs/pwbox/0.5.0/pwbox/) which is a crate that enables password-based encryption and decryption. This is fine, but I have a few things that I want to answer/resolve: 1. The decryption is quite fast. **Are the notes prone to a brute-force attack?** Yes, but **this is prevented using a [KDF](https://en.wikipedia.org/wiki/Key_derivation_function)** on newer databases. 2. **What should be considered a "safe" password (length, entropy, etc)?** Using a basic entropy function (`E = L * log2(R)`, where `E` is the entropy, `L` is the password length and `R` is the quantity of unique characters), seems like **a good entropy value is higher than 60**. But this function under-represents the importance of dictionary-based attacks, which are more valuable after the implementation of a KDF. 3. **Should the use of a "safe" password be enforced?** Yes, partially (see [#issuecomment-14](https://git.sofiaritz.com/sofia/note-taking/issues/1#issuecomment-14)). 4. **Should values like entropy be shown to the user when creating a password?** **Yes, it is a good idea** to show that to the user, and has been already implemented (b051b923fdd6cb5009d8155c34e0e03944c2e13c) Another alternative would be to salt/hash the password: that way dictionary-based attacks could be made more difficult.
Author
Owner

Related information:

This comment showcases case studies, example implementations, or things related to the issue.

**Related information:** This comment showcases case studies, example implementations, or things related to the issue. - [KeePass Help Center article about security](https://keepass.info/help/base/security.html) - [Argon2 Crate](https://docs.rs/argon2/latest/argon2/) - Could be useful for hashing the password before encrypting the notes (KDF) - Entropy calculation formula: `E = L * log2(R)`, where `E` is the entropy, `L` is the password length, and `R` is quantity of unique characters.
sofia self-assigned this 2023-03-05 15:43:24 +00:00
sofia started working 2023-03-05 15:47:28 +00:00
sofia canceled time tracking 2023-03-05 15:47:32 +00:00
sofia started working 2023-03-05 15:48:54 +00:00
sofia closed this issue 2023-03-05 16:35:07 +00:00
sofia stopped working 2023-03-05 16:35:07 +00:00
46 minutes 13 seconds
Author
Owner

Chosen solution (modified from f4b5a0541d):

The password is hashed using Argon2, with the salt being SHA256(password). The output hash is then encoded using hex.

The password-checking function checks if the "note database" is encrypted using the plain password (and returns it) or if it is encrypted using the hashed+salted password (and returns the hashed+salted password). This allows older databases to work properly.

A migration path may be added in the future.

Chosen solution (modified from f4b5a0541d425a2505aecbd9135ba66ef329db9f): >The password is hashed using Argon2, with the salt being `SHA256(password)`. The output hash is then encoded using hex. > >The password-checking function checks if the "note database" is encrypted using the plain password (and returns it) or if it is encrypted using the hashed+salted password (and returns the hashed+salted password). This allows older databases to work properly. > >A migration path may be added in the future.
Author
Owner

Reopening due to unsolved questions.

Reopening due to unsolved questions.
sofia reopened this issue 2023-03-05 16:38:27 +00:00
Author
Owner

Chosen solution (modified from b051b923fd):

Seems like according to the formula used (E = L * log2(R), where E is the entropy, L is the password length and R is the quantity of unique characters), a good value is a entropy higher than 60.

This is shown by using two distinct colors when rendering the entropy (dark orange when is lower than 60, and light green when is higher than 60).

Even though entropy is quite important, it would be more useful to take into account dictionaries when calculating the entropy, because raw bruteforce attacks are somewhat mitigated with the usage of a KDF.

Chosen solution (modified from b051b923fdd6cb5009d8155c34e0e03944c2e13c): >Seems like according to the formula used (`E = L * log2(R)`, where `E` is the entropy, `L` is the password length and `R` is the quantity of unique characters), a good value is a entropy higher than 60. > >This is shown by using two distinct colors when rendering the entropy (dark orange when is lower than 60, and light green when is higher than 60). > >Even though entropy is quite important, it would be more useful to take into account dictionaries when calculating the entropy, because _raw_ bruteforce attacks are somewhat mitigated with the usage of a KDF.
Author
Owner

The remaining thing to answer is: "Should the usage of a "good" password be enforced?".

This is quite difficult to answer, because there are many things to take into account:

  1. What should be considered a "good" password?
  2. Is there a way to ensure that the "good" password algorithm doesn't have any flaws that prevent the usage of actually good password?
  3. Is it actually useful to enforce a "good" password? Or does it only create burden on the user and encourages bad practices (writing the password on a .txt, etc)?
  4. How would we handle compatibility with old databases?

The past has shown that arbitrary limitations (requirement of lowercase and uppercase characters and the like) actually helps attackers to create better brute-force attacks. On contrast, the enforcement of basic limitations (minimum of 12 characters and the like) does actually help to protect the password.

The thing with any limitation is that it puts more burden on the people, which means that bad practice could be encouraged as a side effect (for example, saving the password on a .txt, saving the password on a piece of paper, etc).

We have to find the sweet spot between enforcing security and reducing the burden on people.

We could enforce just basic security practices (12 character passwords) and give the people the tools to assess the security of the given password (entropy values with a color indicator, etc). Because that's actually what arbitrary limitations tried, but failed to do so.

Another thing to consider is the possibility of password-less keys: pairing the password with technology like certificated, hardware keys, OTP, and things like that. That way there is a great protection against brute-force attacks because of the requirement of 2FA, but the user is able to "forget" the password if law enforcement or any bad actor asks the user to hand it over. (Which is also another thing of its own: defining the attack vectors that this app protects against and designing it to be zero-trust in future iterations).


To summarize, the answer to those questions would be:

  1. Entropy + "dictionary-probability"
  2. No, because it's difficult to cover all of the edge-cases
  3. It isn't useful to establish arbitrary password requirements, but basic ones are actually useful in the real world.
  4. Seems like at this early stage (me as a user, project hosted on a random Forgejo instance without federation, etc), we're able to make breaking changes (at least until a versioning system is actually used)
The remaining thing to answer is: "**Should the usage of a "good" password be enforced?**". This is quite difficult to answer, because there are many things to take into account: 1. What should be considered a "good" password? 2. Is there a way to ensure that the _"good" password algorithm_ doesn't have any flaws that prevent the usage of _actually good_ password? 3. Is it actually useful to enforce a "good" password? Or does it only create burden on the user and encourages bad practices (writing the password on a .txt, etc)? 4. How would we handle compatibility with old databases? --- The past has shown that arbitrary limitations (requirement of lowercase and uppercase characters and the like) actually _helps_ attackers to create better brute-force attacks. On contrast, the enforcement of basic limitations (minimum of 12 characters and the like) does actually help to protect the password. The thing with any limitation is that it puts more burden on the people, which means that bad practice could be encouraged as a side effect (for example, saving the password on a .txt, saving the password on a piece of paper, etc). **We have to find the _sweet spot_ between enforcing security and reducing the burden on people.** We could enforce just basic security practices (12 character passwords) and give the people the tools to assess the security of the given password (entropy values with a color indicator, etc). Because that's actually what _arbitrary limitations_ tried, but failed to do so. Another thing to consider is the possibility of password-less keys: pairing the password with technology like certificated, hardware keys, OTP, and things like that. That way there is a _great_ protection against brute-force attacks because of the requirement of 2FA, but the user is able to "_forget_" the password if law enforcement or any bad actor asks the user to hand it over. (Which is also another thing of its own: defining the attack vectors that this app protects against and designing it to be zero-trust in future iterations). --- To summarize, the answer to those questions would be: 1. Entropy + "_dictionary-probability_" 2. No, because it's difficult to cover _all_ of the edge-cases 3. It isn't useful to establish _arbitrary_ password requirements, but basic ones are actually useful in the real world. 4. Seems like at this early stage (me as a user, project hosted on a random Forgejo instance without federation, etc), we're able to make breaking changes (at least until a versioning system is actually used)
sofia closed this issue 2023-03-05 23:30:53 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Total time spent: 46 minutes 13 seconds
sofia
46 minutes 13 seconds
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: sofia/note-taking#1
No description provided.