2
$\begingroup$

I need to choose an HMAC function for PBKDF2.

I'm using .net so I don't have the option to use SHA3. At first glance, and according to this answer by Thomas Pornin it seems like SHA512 would be best.

However, I've heard that there are some possible downsides to SHA2 compared to SHA1. One of them possibly having something to do with quantum computers. (Yes, I know they're not practical yet, but why not choose better over worse?)

So the bottom line is - should I use HMACSHA1 or HMACSHA2 (512)? Or in other words, is the abovementioned answer a recommendation to always use SHA2 or is it dependant on some factors?

[Also, I would like to verify that I understand correctly that in any case, I should only ask it for the native output (160 bits for HMACSHA1 and 512 for HMACSHA2-512 - right?). Right?]

More (possibly relevant) info

I have a requirement to use only Microsoft libraries. And I need to implement a password stretching function with feedback - how far is the function done. So I can't use Rfc2898DeriveBytes (which doesn't provide feedback), nor SHA3 (unless I write it myself. But I've already written the PBKDF2 myself, and would rather use a built in HMAC rather than write that too.).

$\endgroup$
1
  • 2
    $\begingroup$ There is essentially no reason to use SHA-1 in new protocols unless severely constrained by restrictions to use existing functionality on an already designed IC or something like that. Unless you have such exotic constraints, or you're implementing or studying an existing protocol, just forget that SHA-1 exists, and likewise MD5. $\endgroup$ Jan 21, 2018 at 23:54

2 Answers 2

6
$\begingroup$

The only downside to SHA-2 over SHA-1 is that SHA-2 is a little slower.

In this case, that is of no practical consequence whatsoever because you're trying to make something slow to compute, and it is only a matter of raising the number of iterations to make it cost a certain number of bit operations in serial.

However, please consider using the modern memory-hard password hashes scrypt or argon2 instead of PBKDF2, to limit the advantage that attackers with highly parallel low-memory GPUs, FPGAs, or ASICs can attain over the defenders using ordinary CPUs.

Of the SHA-2 family, SHA-512 is a little faster than SHA-256 on CPUs with native 64-bit integer arithmetic, which are the vast majority of personal computing devices today. So it provides a tiny advantage to the defender to use SHA-512 instead of SHA-256.

$\endgroup$
2
  • $\begingroup$ Thanks. I assume, however, that implementing scrypt or argon2 would be much more complicated (and therefore error prone) than PBKDF2 (which was, to be honest, simpler than I had anticipated) since I get to use an already implemented HMAC. $\endgroup$
    – ispiro
    Jan 21, 2018 at 21:34
  • 2
    $\begingroup$ I would be pretty surprised if nobody had implemented scrypt or argon2 for .NET already! $\endgroup$ Jan 21, 2018 at 23:55
1
$\begingroup$

You should pick the function that gives a CPU-equipped defender the most advantage against GPU-based attackers (which are the likeliest attackers). How do we find this out? First, let's benchmark the hash functions on our CPU, using OpenSSL. Here's some results on my computer (a 64-bit Intel machine, about 4 years old):

$ openssl speed sha1 sha256 sha512
To get the most accurate results, try to run this
program when this computer is idle.
Doing sha1 for 3s on 16 size blocks: 8500388 sha1's in 2.99s
Doing sha1 for 3s on 64 size blocks: 6084902 sha1's in 2.99s
Doing sha1 for 3s on 256 size blocks: 3194162 sha1's in 2.98s
Doing sha1 for 3s on 1024 size blocks: 1159960 sha1's in 2.99s
Doing sha1 for 3s on 8192 size blocks: 169801 sha1's in 3.00s
Doing sha256 for 3s on 16 size blocks: 6272034 sha256's in 2.99s
Doing sha256 for 3s on 64 size blocks: 3709199 sha256's in 2.98s
Doing sha256 for 3s on 256 size blocks: 1658154 sha256's in 2.99s
Doing sha256 for 3s on 1024 size blocks: 510230 sha256's in 2.99s
Doing sha256 for 3s on 8192 size blocks: 68516 sha256's in 2.99s
Doing sha512 for 3s on 16 size blocks: 4354579 sha512's in 2.98s
Doing sha512 for 3s on 64 size blocks: 4322349 sha512's in 2.98s
Doing sha512 for 3s on 256 size blocks: 1947058 sha512's in 2.99s
Doing sha512 for 3s on 1024 size blocks: 733465 sha512's in 2.99s
Doing sha512 for 3s on 8192 size blocks: 105135 sha512's in 2.99s
OpenSSL 0.9.8zh 14 Jan 2016
built on: Oct  5 2016
options:bn(64,64) md2(int) rc4(ptr,char) des(idx,cisc,16,int) aes(partial) blowfish(idx) 
compiler: -arch x86_64 -fmessage-length=0 -pipe -Wno-trigraphs -fpascal-strings -fasm-blocks -O3 -D_REENTRANT -DDSO_DLFCN -DHAVE_DLFCN_H -DL_ENDIAN -DMD32_REG_T=int -DOPENSSL_NO_IDEA -DOPENSSL_PIC -DOPENSSL_THREADS -DZLIB -mmacosx-version-min=10.6
available timing options: TIMEB USE_TOD HZ=100 [sysconf value]
timing function used: getrusage
The 'numbers' are in 1000s of bytes per second processed.
type             16 bytes     64 bytes    256 bytes   1024 bytes   8192 bytes
sha1             45431.10k   130461.64k   274629.59k   397354.48k   464321.06k
sha256           33573.81k    79537.34k   142061.40k   174862.56k   187880.57k
sha512           23344.35k    92714.51k   166725.04k   251069.34k   287770.18k

The exact numbers are not the most important thing here, but rather the ratios:

  • With 16-byte blocks, SHA-256 is 50% faster than SHA-512, and SHA-1 100% faster
  • With 64-byte blocks, SHA-256 is 14% slower than SHA-512, and SHA-1 40% faster

The block sizes are 20 bytes for SHA-1, 32 bytes for SHA-256 and 64 bytes for SHA-512, so this comparison doesn't exactly represent the work that the former two functions would do in PBKDF2, but in light of the numbers below it's just not going to matter.

Now, here's some numbers from a Hashcat benchmark result I found on the web, for a rather powerful password cracking rig with eight Nvidia GTX 1080 GPUs. (I just typed "hashcat benchmark" into Google and grabbed the first result.)

Hashtype: SHA1

Speed.Dev.#1.:  8538.1 MH/s (96.95ms)
Speed.Dev.#2.:  8511.0 MH/s (97.22ms)
Speed.Dev.#3.:  8625.6 MH/s (97.79ms)
Speed.Dev.#4.:  8599.6 MH/s (96.85ms)
Speed.Dev.#5.:  8617.4 MH/s (97.89ms)
Speed.Dev.#6.:  8560.9 MH/s (97.30ms)
Speed.Dev.#7.:  8640.8 MH/s (97.61ms)
Speed.Dev.#8.:  8677.5 MH/s (97.22ms)
Speed.Dev.#*.: 68771.0 MH/s

Hashtype: SHA256

Speed.Dev.#1.:  2865.2 MH/s (96.18ms)
Speed.Dev.#2.:  2839.8 MH/s (96.65ms)
Speed.Dev.#3.:  2879.5 MH/s (97.14ms)
Speed.Dev.#4.:  2870.6 MH/s (96.32ms)
Speed.Dev.#5.:  2894.2 MH/s (96.64ms)
Speed.Dev.#6.:  2857.7 MH/s (96.78ms)
Speed.Dev.#7.:  2899.3 MH/s (96.46ms)
Speed.Dev.#8.:  2905.7 MH/s (96.26ms)
Speed.Dev.#*.: 23012.1 MH/s

Hashtype: SHA512

Speed.Dev.#1.:  1071.1 MH/s (96.43ms)
Speed.Dev.#2.:  1063.9 MH/s (96.40ms)
Speed.Dev.#3.:  1084.2 MH/s (96.25ms)
Speed.Dev.#4.:  1076.9 MH/s (96.03ms)
Speed.Dev.#5.:  1080.2 MH/s (96.64ms)
Speed.Dev.#6.:  1074.1 MH/s (96.16ms)
Speed.Dev.#7.:  1086.3 MH/s (96.01ms)
Speed.Dev.#8.:  1088.1 MH/s (95.91ms)
Speed.Dev.#*.:  8624.7 MH/s

Again, we're going to focus on the ratios, not the specific numbers. On this rig:

  • SHA-256 is 167% faster than SHA-512
  • SHA-1 is 697% faster than SHA-512

This confirms Pornin's answer that you link. Assuming 64-bit CPUs, you should use SHA-512 because relative to the CPU time that you expend, it imposes the largest slowdown on a GPU-equipped attacker:

  • On CPU SHA-1 is 40-100% faster than SHA-512, but on GPU it's 697% faster
  • On CPU SHA-256 is 14% slower to 50% faster than SHA-512, but on GPU it's 167% faster.

However, I've heard that there are some possible downsides to SHA2 compared to SHA1. One of them possibly having something to do with quantum computers. (Yes, I know they're not practical yet, but why not choose better over worse?)

A quick Google doesn't show me any useful results on such a thing. I see Bitcoin-related rumor discussions that talks specifically about SHA-256.

[Also, I would like to verify that I understand correctly that in any case, I should only ask it for the native output (160 bits for HMACSHA1 and 512 for HMACSHA2-512 - right?). Right?]

You can ask for any number of output bits, but with PBKDF2 specifically it's better not to ask for more than the underlying hash function's output size; see this answer for some references (and mentally edit the statements that you shouldn't ask for 256 bits; that bit is only true for SHA-1). But note that for many applications 128-bit output is just fine; see this Q&A for an explanation.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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