3
$\begingroup$

I want to implement authenticated encryption using C#. There is a dot net class called encryptAndAuthenticate, but it is only supported on windows 8 or later, and I need the code to also work on windows 7. In other words, there is no built-in dot net library to do AES in GMC mode that works on windows 7 or earlier. So it looks like I have to use separate calls to the C# aes and hmac routines. Here is the pseudocode in my head. Am I planning this correctly?

Encryption:

  1. User supplies plaintext.
  2. User supplies password.
  3. CSPRNG generates 256-bit salt.
  4. Slow key derivation function on password and salt produces 640-bit output.
  5. First 256 bits of output becomes AES key.
  6. Next 128 bits of output becomes AES IV.
  7. Last 256 bits of output becomes HMAC-256 key.
  8. AES encrypt CBC mode using (plaintext, AES key, AES IV) to produce ciphertext.
  9. HMAC-SHA256 on IV||ciphertext (using HMAC-256 key) to produce MAC.
  10. Publicly store salt, ciphertext, and MAC.

Decryption:

  1. User retrieves salt, ciphertext, and MAC.
  2. Step 2 from above.
  3. Steps 4-7 from above.
  4. Step 9 from above.
  5. Compare calculated MAC to retrieved MAC.
  6. If different, abort and tell user decryption failed.
  7. If valid, AES decrypt CBC mode using (ciphertext, AES key, AES IV) to produce plaintext.
  8. Display plaintext to user.
$\endgroup$
  • $\begingroup$ Make sure you're also doing the HMAC over the salt and IV. $\endgroup$ – user13741 Apr 8 '16 at 16:36
  • 3
    $\begingroup$ A 640 bit salt is seriously overkill. 128 bits should be enough, 256 if you want to be generous. $\endgroup$ – CodesInChaos Apr 8 '16 at 17:07
  • $\begingroup$ Yeah, I wasn't sure of appropriate salt size. I will change to 256 bit. $\endgroup$ – Ralph P Apr 8 '16 at 17:30
  • $\begingroup$ I posted my code for review over at code review if anyone is interested in reviewing it. I decided to go with the built-in C# functionality instead of an external library for reasons of familiarity and decreased dependencies when distributing. $\endgroup$ – Ralph P Apr 9 '16 at 16:39
3
$\begingroup$

PBKDF2 alone would be bad for step 4, since the blocks of its output can
trivially be computed independently. ​ If the PBKDF you use can't directly
produce enough output, then you should compose with a fast key-based KDF.


Make sure that

the IV is part of step 9's ciphertext
and
step 5 of decryption is constant-time

.

$\endgroup$
  • $\begingroup$ Thanks. I would have screwed that up (forgetting to include IV in HMAC input). Question on the timing attack: In my application, all decryption will be done in the client app as a result of manual user actions. No server process will handle any encryption / decryption (the server will just retrieve and store encrypted data in the database on request of the client app). Does this mitigate the timing attack risk? $\endgroup$ – Ralph P Apr 8 '16 at 16:50
  • $\begingroup$ Yes. ​ I think the main possibility for leakage in that case is via some other process being paused/slowed during decryption. ​ ​ ​ ​ $\endgroup$ – user991 Apr 8 '16 at 16:56
  • $\begingroup$ I just edited my answer after noticing another potential problem. ​ ​ $\endgroup$ – user991 Apr 8 '16 at 17:04
  • $\begingroup$ Ricky, regarding your new point...is your concern that an adversary with great computing power could run PBKDF2 many times faster than the client PCs and thus have an effective brute-force attack on the user passwords? $\endgroup$ – Ralph P Apr 8 '16 at 18:01
  • 1
    $\begingroup$ @RalphP The attacker doesn't need the full 640 bits to confirm the password. Either the MAC or the encryption key is enough. So if you're using PBKDF2-HMAC-SHA-256 they can run the derivation once whereas the defender has to run it thrice. $\endgroup$ – CodesInChaos Apr 8 '16 at 19:35
0
$\begingroup$

You might want to call out to libsodium instead. It provides password hashing and authenticated encryption built-in, with a very clean API that is easy to use correctly, as long as you remember to choose a fresh nonce every time you encrypt. It will also be faster than AES+HMAC, and uses Argon2 for password hashing, the winner of the Password Hashing Competition.

The API is C, but you can easily P/Invoke, or use the existing bindings. Be warned that the bindings do not throw on auth failure.

$\endgroup$
  • 1
    $\begingroup$ But is it C# (and portably so?). I think that would matter to the OP. $\endgroup$ – Henno Brandsma Apr 9 '16 at 5:10
  • $\begingroup$ Libsodium.net is not pure c#, it is a wrapper around unmanaged libsodium C code. $\endgroup$ – rmalayter Apr 11 '16 at 4:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.