as in for the same reason as in Scrypt KDF Support , I decided to add Argon2 support. More specifically Argon2id. On the typescript-based platforms, argon2-browser with WASM is used. On the cli, argon2 bindings are used (though WASM is also available). On mobile, I just looked for the C# argon2 implementation with the most stars on Github, which was GitHub - mheyman/Isopoh.Cryptography.Argon2: Fully managed .Net Core implementation of Argon2. One advantage here is that it is pure C#.
I have validated support on: web (firefox,chrome), desktop, browser extension (manifest v2, v3 on chrome), cli, Android.
Current limitations: Since we only store the kdfIterations int, only the memory is configurable by the user. To make the other argon2 options configurable by the user, a change in backend storage and API are needed, where we provide a “kdfOptions” object (f.e as JSON) instead of the kdfIterations int.
Some minor clean ups and a rebase to the latest master are needed, after that I will create the pull-request, but I’m happy to get some input in this thread.
There are 3 variants of argon2. One very crack resistent. One very side channel resistent. One which is a combination of both. For now, I have only enabled argon2id which is the hybrid mode (and generally recommended for most users, see here: argon2i vs argon2d vs argon2id), but it would be trivial to add support for the other 2 modes as well if your primary threat is side-channel but not cracking.
Argon2 is the winner of the 2015 Password Hashing Competition. There are three different versions of the algorithm, and the Argon2id variant should be used, as it provides a balanced approach to resisting both side-channel and GPU-based attacks.
I heard on Security Now that Dashlane now uses Argon2. Not sure which version. I support the addition of these features as long as (1) an end-user can’t introduce security risk by choosing a setting which is below industry best practices (see LastPass interations set at 1); (2) it’s dead clear why a user should choose one over the other; (3) it’s sustainable (again, see LastPass breach as spreading themselves to thin), and (4) it can be easily audited.
One of the pros of LastPass was it was feature-rich. I miss some of those features on Bitwarden like paper grid 2FA and locking out Tor and other country connections. One of the risks of LastPass was that it was feature-rich, making it an unsustainable, in my view. Trying to do everything for everyone.
For this reason, I would prefer that Bitwarden integrate what it views as the best modern KDF option, which I understand is no longer PBKDF2, rather than a number of them. But, to be clear, I fully support what you are developing; it keeps best practices in security at the centre of the conversation. I would fully support this implementation if there is consensus that it’s the most appropriate KDF option. It’s also pretty exciting that you are doing this and the Scrypt KDF support.
IMO there is really no reason to use PBKDF2 anymore. Use argon2 unless you, for some reason, do not have WASM support (very old browsers), in that case use scrypt. Happy to hear other opinions about this, but this is my stance.
To back this up, here is what OWASP says on the topic:
Use Argon2id with a minimum configuration of 15 MiB of memory, an iteration count of 2, and 1 degree of parallelism.
If Argon2id is not available, use scrypt with a minimum CPU/memory cost parameter of (2^16), a minimum block size of 8 (1024 bytes), and a parallelization parameter of 1.
For legacy systems using bcrypt, use a work factor of 10 or more and with a password limit of 72 bytes.
If FIPS-140 compliance is required, use PBKDF2 with a work factor of 310,000 or more and set with an internal hash function of HMAC-SHA-256.
Speaking of which, I might do another pull request to raise the default PBKDF2 iterations to 310000. Anyways, be assured the minimums for scrypt (and argon2) are such that a user cannot pick an insecure configuration.
Dashlane uses Argon2d which is a bit more cracking resistent but weak to side channel.
Would very much support a minimum increase of of PBKDF2 to 310,000 as per OWASP minimum recommendations. Would be curious to see how it can be implemented as a minimum requirement with existing users. There is so little penalty at 310,000 or even 1,000,000+. Would be excellent for Bitwarden’s reputation to implement this immediately after the LastPass breach and publicize that all existing users will automatically benefit from it, as well, without a need to opt in.
Separately, do you know if there is a server-side scalability issue re: memory when implementing Argon2 for a service like Bitwarden which has millions of customers? I assume all the work is done on client side but am not sure and don’t know if there is a budgeting/cost implication on server side for Bitwarden.
Keep in mind that increasing your iterations by 10x, only increases the time to crack your password by 10x, while also increasing your unlock time by 10x (even if unnoticable). Adding just one letler from a-z,A-Z to your password increases the time to crack your password by 56x (if chosen at random) at no time cost. So that is much more effective under PBKDF2.
Of course switching to argon2 (or scrypt) increases the time to crack your password by several orders of magnitude (against GPU based attacks) while at the same time taking less time to unlock in practice, and without changing your password, so that is the ideal option.
How about just giving the user the option to pick which one they want to use. If a user has a device that does not work well with Argon2 they can use PBKDF2. As for me I only use Bitwardon on my desktop and laptop so Argon2id is no issue. I also use Keepass which gives you the option to choose the one you want.
A small summary of the current state of the pull requests: Desktop/Web: Mostly done, still needs qa testing for all platforms. Mobile: The C implementation of argon2 was held up due to troubles building for iOS. Kyle managed to get the iOS build working now, so at last the argon2 part should be mostly done. I also still need to add support for the new parameters from the API (memory, parallelism). Server: Needs work on the database migration part.