Authenticated AES 256 CBC HMAC SHA512 - What's the right way to implement in C#? I have a "Encrypt-then-Mac" C# implementation of "AE_AES_256_CBC_HMAC_SHA_512" WITHOUT associated data, only authentication. In my code, I follow these steps to encrypt strings:


Generate a crypt random salt of 32 bytes using RNGCryptoServiceProvider;
Generate an auth random salt of 32 bytes using RNGCryptoServiceProvider;
Derive a crypt key of 32 bytes using Rfc2898DeriveBytes (PBKDF2) passing as parameters password bytes, previously generated random crypt salt bytes, and the number of 100,000 iterations.
Derive an auth key of 32 bytes using Rfc2898DeriveBytes (PBKDF2) passing as parameters password bytes, previously generated random auth salt bytes, and the number of 100,000 iterations.
Encrypt plain string bytes using AES with the 256 bits/32 bytes derived crypt key, in CBC mode, with a random IV and PaddingMode.PKCS7.
Write encrypted data bytes, IV, crypt salt and auth salt to a memory stream, respectivelly.
Compute the HMACSHA512 hash from the memory stream data, using the previously derived auth key.
Truncate the output of HMACSHA512 to initial 32 bytes and append this tag bytes to the end of memory stream.
Return the output bytes as Base64 string.


To decrypt I do the reverse way, comparing the sent tag with the calc tag before decrypt data.
I've been wondering if this implementation is correct, could you please give me a direction? Am I on the right way?
I'm going to use the answer field as I think the question is about doing a full review, which is typically off topic. However, since the comments are too short, I'll give a few hints and then allow the question to be closed.

You're on the right track if you have to use a password, however:

32 bytes of salt is excessive, you only need 16 bytes / 128 bits at max.

The idea to use dual PKBDF2 is not a good one as an attacker only needs one of the keys to verify a correct guess of the password. That means that per password you'd doing twice the work as an attacker needs to do. It is better to use the output of the first PBKDF2 and either split that up (e.g. using SHA-512 for two 256 bit keys) or derive keys using a KBKDF such as HKDF from it.

CBC mode is still vulnerable to attack if you don't verify the authentication tag first. You should make sure that the correct order is preserved, or use an AEAD scheme.

The IV might as well be set as all zero or be calculated from the password &amp; salt, as the salt already provides the required randomization. You could even use the salt itself as IV.

Generally we write the IV / salt and other static information at the beginning - not the end - of the file. First of all, it's easier to find / parse that way and furthermore, you need the keys before you can start verification and / or decryption.

Base 64 encoding the entire output is fine if text is what is required. Otherwise you should just store the ciphertext and header as binary file.