Increasing PBKDF2 Iterations has done what?

I set my PBKDF2 Iterations to 2 million as I like to be on the safe side. No adverse effect at all.

Can anyone share which part of this diagram changes from 100,000 to 2,000,000

I thought it was the box at the top left.
This will mean the (password component of the) protected symmetric key is also hashed 2 million times and the password hash is hashed 2,100,001 times.

Just trying to understand the problem identified by WP. (He’s not addressing me here BTW) I don’t see how an attacker can test password guesses against the protected symmetric key.

Yes, it is the box in the top left. This issue was noted already in 2020, and is much better explained in the original article by Dmitry Chestnykh.

Thanks for the reply.

So Dmitry describes a method to perform password guess against the protected symmetric key and you have validated his work. I never saw that coming. Hope it’s still 2 million iterations though.

1 Like

Relax. I think Argon2 and/or Scrypt may be coming soon. [crossing fingers here]. LOL!

Only argon2. But soon indeed:


Yes I am completely relaxed about hashing algorithms and number of iterations. :relaxed:
I don’t need to worry about that because I have a 256 bit entropy password (I really went OTT I figured I wasn’t going to be able to remember this password so I may as well go full bananas).

I am really just interested in the academic question of how password guesses can be done against the protected symmetric key. I just don’t see how it’s possible but the grown ups say it is so.

I am looking forward to the addition Argon2 and am encouraged by Bitwarden’s receptivity to adding this, based on your original suggestion and work. Nicely done! Argon2 has a side channel attack risk. Are we simply exchanging one risk with another?

Did you read Dmitry’s article that I linked above? In my opinion, he explains it quite well.

The Protected Symmetric Key actually contains two separate keys: a 256-bit Encryption Key and a 256-bit MAC Key. MAC stands for “Message Authentication Code”, which is part of a tamper-proofing system that you can learn about here. Each secret stored in your vault consists of two parts: (1) the original data encrypted using the Encryption Key; (2) a hash derived from the encrypted string using the MAC Key. The idea is that by re-deriving the hash and comparing it to the hash that was transmitted along with the encrypted data, someone with access the the MAC Key (i.e., your Bitwarden client app) will be able to verify that the encrypted data has not been altered in the round trip from your Bitwarden client to Bitwarden’s servers, and back.

Thus, an attempt to decrypt the Protected Symmetric Key will yield a candidate for the Encryption Key and a candidate for the MAC Key. Using the candidate MAC Key to hash one of the encrypted secrets stored in your vault, if the resulting hash matches the hash that is stored together with the encrypted secret, then the MAC Key had to be correct. This implies that the Encryption Key is also correct, i.e., the Protected Symmetric Key has been successfully cracked.

Not sure I’d include side channel in my threat model to be honest. If someone has enough rights on the system to launch a side channel attack on the argon2 implementation, there are many other worries (keylogger f.e).

Anyways, we use argon2id, which is a good compromise between tmto resistance and side channel resistance. As far as I know the main concern about side channel in argon2 only applies to argon2d.

I set mine from 5000 to 696969 as the number is nice and it’s also slightly above the recommendations made by OWASP (600000)!

I am sorry if this is a dumb question but I am trying to learn more about argon2 and iOS devices, since that is what I usually use.

I read on the site linked up in another discussion. And found

“If the app uses a lot of RAM (e.g. due to using Argon2 with a large memory parameter), then AutoFill may not work. In this case, we recommend to use a relatively low value for the Argon2 memory parameter (64 MB or less, depending on the app and the database size) and a relatively high number of iterations.”

From information found on Keypass that tell me IOS requires low settings. If I end up using argon2 would that be safer than PBKDF2 that is being used at the moment.

I understand that the ram requirements is the upside of using argon2 compared to PBKF2, that way making it harder to crack the encryption. But doesn’t the whole point get lost if the requirements for iOS is on the 64mb plane.

I am sorry if this is not relevant. Feeling like a stupid non technical person who is trying to understand something advanced. Tried to understand Minimum Password Settings - TobTu about minimum requirements for the different but can’t seem to get it.

Appreciate any explanation, and again sorry for my ignorance

I’m not too familiar with the biometrics code, but i don’t think it even uses the KDF. So as long as you unlock with faceid/touchid this shouldn’t apply.

As for the 64 MB limit, from the keypass issue it seems this is a limitation on autofill only, not the regular app. So if you have to enter your bitwarden password in autofill, then it could be an issue.

Nevertheless, even at low memory settings, argon2 is more cracking resistant than pbkdf2, plus you can always increase iteration count (time) instead of just memory. So either way, it is an improvement over pbkdf2. Thee only reason that I know of, not to use argon2, is FIPS-140 compliance.

1 Like

Thanks so much for your explanation. Feeling a bit more comfortable going with argon2 now.

Going to do some more research also. Trying to keep learning.

Was a great explanation, your work is amazing :star_struck:

1 Like


Argon2id would mitigate the risk, assuming we get that option. That was my decision for my LUKS2 volumes. Argon2id is a blend between the various Argon2 “schemes”. All of my LUKS2 volume passwords reflect a Time Cost > 45!! Nobody is breaking Argon2id with > 20 character passwords and a Time Cost over 45!

1 Like

OK I’m begining to understand now.

Email & Master Password are transformed into a 512 bit Stretched Master Key (but having only 256 bits entropy)
The Stretched Master Key is split into Key1 and Key2.

ciphertext = AES_CBC_256(symmetricKey, Key1)
MAC = HMAC_SHA256(ciphertext, Key2)
client then sends to server (ciphertext + MAC)
server stores ciphertext + MAC in the database

This is the “encrypt then MAC” scheme.

So an attacker with the database can take a guess at the master password and produce a candidate Key2. They can then easily compute the MAC from the ciphertext and if it is the same then they know their guess is correct.

Therefore the 100,000 iterations of PBKDF2 on the server are bypassed.

@DoctorB I think you’ve got the broad strokes of this scheme down, but your description is inaccurate in some of its details.

First, the genesis of Key1 (account encryption key) and Key2 (MAC key): These are not derived from the Stretched Master Key, but they are produced by a random number generator that produced a 512-bit random number (the Generated Symmetric Key). The the Generated Symmetric Key is then split into Key1 and Key2, which have 256 bits of entropy each.

Second, the AES encryption scheme and the computation of the MAC digest both require a piece of data to be encrypted or hashed, as well as a secret key (which influences the computed result). Thus, as explained in Dmitry’s article, the two operations are performed as follows:

encryptedData = AES-CBC(key1, data)
MAC = HMAC(key2, encryptedData)
cipherString = encryptedData + MAC

[Edit: Either I misread your post, or you may have edited it while I was composing this response — it seems now that your description of ciphertext/MAC generation from Key1 & Key2 matches what I’ve written above, except that we use slightly different terminology.]

The role of the Stretched Master Key is to be an encryption key for AES-encryption of the Generated Symmetric Key (= Key1 + Key2). This produces the so-called Protected Symmetric Key.

Bitwarden’s cloud database contains both your vault (including all of the cipher strings that each consist of encrypted data and a corresponding MAC) and your account’s Protected Symmetric Key.

Therefore, the attack would consist of computing a candidate stretched master key based on a master password guess, and use this key as the AES decryption key to attempt to decipher the Protected Symmetric Key. This will results in 512 bits (64 bytes) of data, which can be divided down the middle to produce two keys (MaybeKey1 and MaybeKey2); these two keys may be just garbage (if the password guess was wrong), or they may be the actual Key1 and Key2 (if the password guess was correct). The attacker doesn’t know yet whether the guess was right or wrong, but now they simply take a cipher string from the vault, and compute a MAC using HMAC(MaybeKey2, encryptedData) — if the result matches the actual MAC that was stored in the cipher string, that implies that MaybeKey2 was equal to the original Key2. Therefore, it must also be true that MaybeKey1 equals the original Key1 (the account encryption key that can be used to decrypt all the encrypted data stored in the vault).