Vault Encryption

Encryption

Bitwarden uses AES-CBC 256-bit encryption for your Vault data, and PBKDF2 SHA-256 to derive your encryption key.


AES-GCM vs. AES-CBC

Just use AES-GCM. No contest.

AES-GCM is an authenticated encryption mode. It doesn’t just provide confidentiality by encrypting your message, it also provides integrity (which guarantees that nobody tampered with the encrypted message over the wire).

If you select AES-CBC instead of AES-GCM, you’re opening your systems to a type of attack called a padding oracle (which lets attackers decrypt messages without the key, by replaying altered ciphertexts and studying the behavior of your application).

If you must use AES-CBC, then you must also MAC your ciphertext (and the initialization vector–IV for short). You should also devise some sort of key-separation mechanism so you’re not using the same key for two different algorithms. Even something like this is fine:

encKey := HmacSha256(“encryption-cbc-hmac”, key)
macKey := HmacSha256(“authentication-cbc-hmac”, key)
iv := RandomBytes(16)
ciphertext := AesCbc(plaintext, iv, encKey)
tag := HmacSha256(iv + ciphertext, macKey)

For decryption you need a secure compare function. If one is not available to you, or you cannot guarantee it will run in constant time, a second HMAC call with a random per-comparison key will suffice.

There is no possible world in which case unauthenticated AES-CBC is a safer choice than AES-GCM.

AES-CBC + HMAC-SHA256 (encrypt then MAC) is message-committing and therefore can be safely used with algorithms like OPAQUE.

The Signal Protocol uses AES-CBC + HMAC-SHA2 for message encryption.

I think you should consider changing your encryption method. Maybe to XSalsa20/XChaChaCha