6.7 Using a Cryptographic Hash

6.7.1 Problem

You need to use a cryptographic hash function outside the context of a MAC, and you want to avoid length-extension attacks, which are quite often possible.

6.7.2 Solution

A good way to thwart length-extension attacks is to run the hash function twice, once over the message, and once over the output of the first hash. This does not protect against birthday attacks, which probably aren't a major problem in most situations. If you need to protect against those attacks as well, use the advice in Recipe 6.8 on the first hash operation.

6.7.3 Discussion

Hash functions are not secure by themselves?not for a password system, not for message authentication, not for anything!

Because all of the commonly used cryptographic hash functions break a message into blocks that get processed in an iterative fashion, it's often possible to extend the message and at the same time extend the associated hash, even if some sort of "secret" data was processed at the start of a message.

It's easy to get rid of this kind of problem at the application level. When you need a cryptographic hash, don't use SHA1 or something similar directly. Instead, write a wrapper that hashes the message with your cryptographic hash function, then takes that output and hashes it as well, returning the result.

For example, here's a wrapper for the all-in-one SHA1 interface discussed in Recipe 6.6:

#define SPC_SHA1_DGST_LEN (20)
/* Include anything else you need. */
void spc_extended_sha1(unsigned char *message, unsigned long n,unsigned char *md) {
  unsigned char tmp[SPC_SHA1_DGST_LEN];
  SHA1(message, n, tmp);
  SHA1(tmp,  sizeof(tmp), md);

Note that this solution does not protect against birthday attacks. When using SHA1, birthday attacks are generally considered totally impractical. However, to be conservative, you can use a nonce to protect against such attacks, as discussed in Recipe 6.8.

6.7.4 See Also

Recipe 6.6, Recipe 6.8