@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).