10
Hashing

Collision-Resistant Hash Functions

You and a friend each have a copy of a very large file. How can you be sure your files match exactly? Your friend could send their entire copy of the file to you, and you could compare both copies, but this is wasteful and impractical. Wouldn't it be easier if your friend could send some much shorter “fingerprint” of their copy of the file? You could compute the fingerprint of your copy and just compare the fingerprints.

This hypothetical fingerprint function must be deterministic, so that both of you compute the same fingerprint of the same file. Its output should be short, otherwise sending the fingerprint is no better than sending the entire file. Finally, the name “fingerprint” suggests that different files should have different fingerprints. Indeed, this interaction between you and your friend is vulnerable to false-positives: You and your friend might have different copies of the file whose fingerprints happen to be the same, leading you to conclude (wrongly) that the copies are identical. A pair of different inputs with the same fingerprint is called a collision.

In this scenario, we don't care what information the fingerprint leaks about the data (both users already know the data); we don't need the fingerprints to be pseudorandom; we don't need the two users to have any secrets. The only thing we care about is avoiding collisions. Collision resistance is a completely new cryptographic goal, and the focus of this chapter.

10.1. Defining collision resistance

A collision in a function HH is a pair (X,X)(X,X') where XXX\ne X' but H(X)=H(X)H(X) = H(X'). If HH has more inputs than possible outputs—and that is indeed the most interesting situation—then collisions are inevitable; this is a simple consequence of the pigeonhole principle. We can't hope for a total absence of collisions; the best we can hope is that collisions are hard to find. We call this property collision resistance.

A hash function usually refers to a function with long inputs and short, fixed-length outputs. When people talk about hash functions, they usually mean a function that supports inputs of arbitrary, variable length. It can also be useful to consider collision resistance of functions with fixed-length inputs (see section 10.4). The important properties are that the function has more inputs than outputs (so collisions do exist), and that the outputs are of a fixed length (often 256 or 512 bits).

A word of warning: Out of all the cryptographic primitives we study in this book, collision-resistant hash functions have the biggest mismatch between theory and practice. In this chapter, I'll try to address the gap as best I can.

First Attempt Formalizing Collision Resistance: It's difficult to formally define collision resistance, because hash functions involve no secrets. Below is a first attempt: We might say that a hash function HH is collision-resistant if the following libraries are indistinguishable:

LrealH\lib{real}^H
compare(X,X)\subname{compare}(X, X'):
return H(X)==H(X)H(X) == H(X')
\indist
LidealH\lib{ideal}^H
compare(X,X)\subname{compare}(X, X'):
return X==XX == X'

If the libraries are indistinguishable, then comparing two hash outputs (fingerprints) has the same effect as comparing the two strings in their entirety. Consider this chapter's motivating scenario, where you and a friend want to know whether you hold identical copies of a file. Lideal\lib{ideal} describes the logical comparison you would like to perform, and Lreal\lib{real} describes a much more efficient way of doing it. If the libraries are indistinguishable, then it is safe to perform the more efficient comparison to achieve the same result.

Another way to understand the libraries is to notice that they give different answers only when XXX \ne X' (so compare\subname{compare} in Lideal\lib{ideal} returns false\myfalse) but H(X)=H(X)H(X) = H(X') (so compare\subname{compare} in Lreal\lib{real} returns true\mytrue)—in other words, when compare\subname{compare} is called on a collision. A calling program that can find any collision (it doesn't matter whether XX and XX' have any particular meaning or interpretation) will have an easy strategy to distinguish the libraries. So by asking for the libraries to be indistinguishable, we are really asking for collisions to be hard to find.

Unfortunately, this definition falls short because these two libraries can in fact never be indistinguishable, except in the trivial and uninteresting case that HH has no collisions at all. The reason is due to subtle technicalities in how we define security: First, Kerckhoffs's principle allows an adversary to depend arbitrarily on the algorithms being attacked. Second, our security definitions care only about the running time of the calling program, and not the time needed to write the calling program's source code.

Suppose a candidate hash function HH is chosen, with output length nn, and consider the following precomputation attack: I evaluate HH on any 2n+12^n+1 distinct inputs and am guaranteed (by the pigeonhole principle) to find a collision (X,X)(X,X'). Then I can write down the source code of an algorithm A\A: “return compare(X,X)\subname{compare}(X,X'), where XX and XX' are constant strings, hard-coded into this source code. That is, the source code of A\A really looks like

return compare(01110,11000)\subname{compare}(\bit{01110}\cdots, \bit{11000}\cdots),

for some suitable pair of strings that required exponential time to find. Running this algorithm is fast, certainly polynomial-time. Finding this algorithm is hard, requiring exponential time. But only its running time is relevant when it comes to indistinguishability. This is a polynomial-time algorithm that distinguishes the libraries with advantage 1, so we must conclude that the libraries are not indistinguishable.

The “attack” I just described is successful against any function HH that has any collisions at all. These two libraries can never be indistinguishable.

Add a Dash of Salt: To avoid the issues with the previous definition, we modify the interface of a hash function to take an additional argument called a salt. A salt is a string sampled uniformly and used for all calls to the hash function; but, unlike a key, a salt can be made public. We can define collision resistance for a salted hash function as follows:

Definition 10.1.1 (Collision-resistant hash function)

A function HH is a collision-resistant hash function (CRHF) if the following libraries are indistinguishable:

Lcrhf-realH\lib{crhf-real}^H
S{0,1}λ\salt \gets \bits^\secpar
crhf.getsalt()\crhfgetsalt(\,):
return S\salt
crhf.compare(X,X)\crhfcmp(X, X'):
return H(S,X)==H(S,X)H(\salt,X) == H(\salt,X')
\indist
Lcrhf-idealH\lib{crhf-ideal}^H
S{0,1}λ\salt \gets \bits^\secpar
crhf.getsalt()\crhfgetsalt(\,):
return S\salt
crhf.compare(X,X)\crhfcmp(X, X'):
return X==XX == X'

The libraries sample a salt S\salt at the beginning of time, and make it available to the adversary via the crhf.getsalt\crhfgetsalt subroutine.

This security definition is not vulnerable to the kind of precomputation attack described above, thanks to the salt. In definition 10.1.1, the source code of a calling program is allowed to depend arbitrarily on the choice of the hash function HH, but it cannot depend on the choice of salt S\salt, because S\salt is chosen only after the combined program (calling program + library) starts.

I like to think of salt as a “personalization” string. We can all agree on a good hash function HH, but each of us can use our own personalized variant H(S,)H(\salt,\cdot). The adversary can't predict which personalized hash function H(S,)H(\salt,\cdot) it needs to attack until the start of the execution. Since there are exponentially many possible salts, precomputation is not helpful.

(You might wonder about an adversary program consisting of a huge, hard-coded lookup table that contains, for any salt S\salt, a precomputed collision in H(S,)H(\salt,\cdot). Of course, such a lookup table would be exponentially large. For technical reasons, you should think of the “running time” of a program as including the time needed to read/parse the program's description. Thus, this lookup-table-based attack is not considered polynomial-time, no matter how efficiently the huge table can be accessed. By the way, this issue applies to more than just hash functions: Essentially all cryptographic algorithms can be defeated by an exponentially large, precomputed lookup table.)

Brute Force Attacks: A brute-force attack against the collision resistance of a hash function HH would compute H(X1),H(X2),H(X_1), H(X_2), \ldots, for any sequence of distinct XiX_i strings until it finds H(Xi)=H(Xj)H(X_i) = H(X_j) for some iji \ne j. How long would this attack take, if HH has nn-bit outputs?

HH has the best chance of avoiding collisions is if the values H(X1),H(X_1), \ldots act like independent, uniformly sampled nn-bit strings. (Any bias away from uniform only increases the chance of a collision.) But in that case, the question becomes: How many independent samples must we take from {0,1}n\bits^n before encountering a repeat? This is exactly the birthday problem! We know that after roughly 2n/22^{n/2} samples, there is a good probability of observing a repeat. So a brute-force attack against collision resistance—usually called a birthday attack—has a good probability of success after 2n/22^{n/2} steps.

For this reason, if we want a CRHF to have λ\secpar bits of security—that is, if breaking the hash function is supposed to require roughly 2λ2^\secpar effort—then its output length should be at least n=2λn = 2\secpar. This is why you will (hopefully!) never see a 128-bit hash function in the wild; the most popular hash functions have output length 256, 384, or 512 bits.

Other Security Properties: This chapter focuses on collision resistance, but other properties of hash functions are sometimes relevant:

  • One-wayness: Given S\salt and YY, it should be hard to find an XX such that H(S,X)=YH(\salt,X) = Y. This property is especially important when hashing passwords. Pay attention to the distinction between the following problems:

    • Given S\salt and H(S,X)H(\salt,X), find XX.

    • Given S\salt and Y=H(S,X)Y = H(\salt,X), find some XX' with H(S,X)=YH(\salt,X') = Y.

    It is easy to make a function for which the first problem is hard; just define H(S,X)=0nH(\salt,X) = \bit0^n, so that H(S,X)H(\salt,X) gives no information at all about XX. The second problem is how we define one-wayness.

  • Second-preimage resistance: Given S\salt and XX, it should be hard to find XXX' \ne X such that H(S,X)=H(S,X)H(\salt,X) = H(\salt,X'). If collision-resistance is about the problem of finding any two people with the same birthday, then second-preimage resistance is about the problem of finding someone with the same birthday as yourself. As such, a brute-force attack against second-preimage resistance requires O(2n)O(2^n) steps for an nn-bit hash function.

10.2. Hash functions in the real world

10.2.1. Theory vs. practice

Unsalted Hash Functions: Hash functions that you encounter in the wild are standardized as unsalted functions. They have only a single input argument: a string to be hashed.

Definition 10.1.1 does not capture the collision resistance of an unsalted hash function, and indeed we have seen that it is difficult to place unsalted hash functions on solid footing in provable security. Since real-world hash functions accept inputs of any length, it is best practice to simply prepend salt to the input of an unsalted hash, as H(SX)H(\salt \| X). It would then be reasonable to conjecture that this method of adding salting to an unsalted HH is secure according to definition 10.1.1.

Salt neutralizes precomputation: The precomputation “attack” in section 10.1 is not just an academic technicality. It reflects an important real-world concern about precomputation attacks.

Suppose a server stores hashes of users' passwords, with an unsalted hash function. (We will have more to say about hashing passwords later in this section.) Knowing what hash function the server uses, an adversary can precompute the hash of, say, the trillion most common passwords. Later, after stealing the server's password file, the adversary will be able to instantly identify all users whose passwords are among the trillion most common. All of the hard work of a password-cracking attack can be done beforehand, and it can be shared among adversaries and reused against any server who uses the same unsalted hash. There is even a line of interesting research on specialized data structures called rainbow tables, that can compress enormous collections of precomputed hash outputs.

If the hash function is salted, and the salts are stored with the password file—that is to say, the adversary doesn't know the salts until obtaining the password file—then precomputation is useless. The adversary can't precompute any candidate password hashes before knowing what salt to use.

If the server hashes all users' passwords with the same salt (including the case of no salt), then an adversary can attack a large number of victims for the price of one. Every time the adversary tests a candidate password PP by computing H(S,P)H(S,P), there is a potential to learn that PP is the password of any user who uses salt SS. On the other hand, if the server uses a different salt for each user, then an adversary must choose which user it wants to attack; attacking two victims requires twice the effort as attacking one.

Recommendations: The most common standardized hash functions are from the Secure Hash Algorithm (SHA) family. SHA-1 is an unsalted Merkle-Damgård (section 10.4) hash with 160-bit output, but has been deprecated as a standard in 2011 and should no longer be used. Attacks against SHA-1 were discovered, which can generate collisions with roughly 2642^{64} effort. Remember, a good nn-bit hash function should require roughly 2n/22^{n/2} effort to find a collision.

SHA-2 is a family of unsalted Merkle-Damgård hashes, with a variety of output lengths, the most common of which are SHA-256 and SHA-512. SHA-3 is the leading state-of-the-art hash, standardized in 2015. Notably, it is not a Merkle-Damgård hash, but uses a methodology called the sponge construction, which we discuss later in chapter 12. SHA-3 is a family of hashes with varying output lengths from 224 to 512 bits.

10.2.2. Hashing passwords

One of the most common uses of hash functions is for password-based authentication. Here we briefly review various methods of authenticating using a password.

In the clear: The worst way to handle passwords is for the server to store them in the clear. We usually compare authentication methods by considering what happens when an adversary compromises the server's storage. If the server stores passwords in the clear, then an adversary who compromises the server immediately learns the passwords of all users, with no effort.

Encrypting passwords sounds like a better idea, but it isn't. In order to verify a user's password, the server must have a way to decrypt these encrypted passwords. Thus, the server must also store the decryption key. Encryption achieves nothing when ciphertexts are stored alongside the key. Don't encrypt passwords!

Unsalted hash: For a user with password PP, the server can store the value h=H(P)h = H(P), where HH is a hash function. When a user attempts to log in, it presents a password PP' and the server can check whether H(P)==hH(P') == h.

This method of authentication is far superior to storing passwords in the clear. An adversary who compromises the server learns only the hashed passwords, and must expend some effort to recover the actual passwords: It must compute H(P)H(P') for many password guesses PP'. However, when the hash function is unsalted, as we discussed above:

  • The adversary's effort can be precomputed, before compromising the server's storage.

  • The adversary's effort can be reused for many victims. Attacking nn users requires no more effort than attacking one.

Salted hash: For a user with password PP, the server can store both a user-specific salt SS and the value h=H(S,P)h = H(S,P). When a user attempts to log in, it presents a password PP' and the server can retrieve that user's salt SS and check whether H(S,P)==hH(S,P') == h.

Salted passwords ensure that the adversary must expend unique effort to attack each user: The effort must happen after compromising the server, and each victim/user requires separate effort. If you authenticate using passwords, always use salt!

Specialized Password-Hashing Functions: Typical collision-resistant hash functions like SHA-2 and SHA-3 are designed to be fast. But password hashing is one realm where it's better to be slow! If a server's collection of password hashes is leaked, then the only thing standing between an adversary and a victim's password is the speed at which the adversary can compute hashes of candidate passwords. Making a password hash a hundred or even a thousand times slower than SHA-3 would have minimal effect on the user experience (authentication would still require mere milliseconds ) but would make an adversary's task a thousand times more expensive.

A simple way to make a hash function slower is to iterate it many times; for example, if HH denotes a standard CRHF like SHA-3, then the server might hash its passwords using H(S,H(S,H(S,P)))H(\salt, H(\salt, \cdots H(\salt, P)\cdots )), with a few thousand HH's. However, this may not slow down an adversary as much as you might expect, because a determined adversary can build special-purpose hardware that can evaluate HH thousands or even millions of times faster than the general-purpose CPU that you and I use to evaluate HH. This is not a hypothetical prospect: Some hash functions are used in proof-of-work cryptocurrency, which incentivizes people to build special-purpose hardware for computing hashes as fast as possible (trillions per second).

A more recent trend is to favor password hashing functions that require a large amount of memory rather than just computation time. There is no obvious way to build memory that is specialized for password hashing, in the same way one can build processors specialized for hashing. When it comes to memory technology, adversaries and users are on a more equal footing. A recent competition selected Argon2 as a standard for password hashing that is designed to consume significant memory.

10.3. Composing collision-resistant functions

In this section, we develop intuition about collision resistance by exploring successful and unsuccessful methods of combining CRHFs.

Claim 10.3.1 (Composing CRHFs)

If H(S,X)H(\salt,X) is collision-resistant, then so is the function H2(S,X)=H(S,H(S,X))H^2(S,X) = H(S,H(S,X)).

(The figures in this chapter will not include the salt as argument to HH.)

Proof:

It is possible to prove this claim using the language of libraries. But collision resistance is usually much easier to think about in the contrapositive:

H is collision-resistant    H2 is collision-resistantH2 is \emphnot collision-resistant    H is \emphnot collision-resistant.\begin{aligned} H \text{ is collision-resistant} &\implies H^2 \text{ is collision-resistant} \\ H^2 \text{ is \emph{not} collision-resistant} &\implies H \text{ is \emph{not} collision-resistant.}\end{aligned}

Our reasoning will follow the latter logical structure. More precisely, we will prove the following:

Given any collision in H2(S,)H^2(\salt,\cdot), it is possible to efficiently (in polynomial time) compute a collision in H(S,)H(\salt,\cdot).

To understand why this establishes the security of H2H^2, suppose there exists an efficient calling program A\A that distinguishes Lcrhf-realH2\lib{crhf-real}^{H^2} from Lcrhf-idealH2\lib{crhf-ideal}^{H^2} with nonnegligible advantage ϵ\epsilon. In other words, A\A breaks the collision resistance of H2H^2. Then we can construct a new calling program A\A' which distinguishes Lcrhf-realH\lib{crhf-real}^H from Lcrhf-idealH\lib{crhf-ideal}^H with the same advantage. That is, it breaks the collision resistance of HH. A\A' simply runs A\A internally and acts as a wrapper around it. Whenever A\A calls crhf.compare(X,X)\crhfcmp(X,X'), the wrapper A\A' can detect whether (X,X)(X,X') is a collision. If so, A\A' can use (X,X)(X,X') to compute a collision under HH, using the steps described below, and send the HH-collision to its library. Thus, A\A and A\A' have essentially the same running time, and A\A' sends a collision under HH to its library with the same probability that A\A sends a collision under H2H^2 to its library.

So let (X,X)(X,X') be a collision in H2H^2 with salt S\salt. Then XXX \ne X' and

H2(S,X)=H(S,H(S,X))=H(S,H(S,X))=H2(S,X). H^2(S,X) = H(S, H(S, X)) = H(S, H(S, X')) = H^2(S,X').

Name the intermediate values in the computation of H2H^2, as Y=H(S,X)Y = H(S,X) and Y=H(S,X)Y' = H(S,X').

We can consider two cases:

\qquad

  • Case 1: Y=YY = Y'. Then (X,X)(X,X') is a collision in HH.

  • Case 2: YYY \ne Y'. Then (Y,Y)(Y,Y') is a collision in HH.

In both cases, we obtain a collision in HH.

Below is an erroneous way to combine CRHFs, in the style of CBC-MAC. We show the case of 2 rounds of CBC.

Claim 10.3.2 (Insecurely combining CRHFs using CBC-MAC)

Let HH be a hash function with nn output bits. The following function H2:{0,1}λ×{0,1}2n{0,1}nH^2 : \bits^\secpar \times \bits^{2n} \to \bits^n is not collision-resistant:

H2(S,X1X2)H^2(\salt, X_1 \| X_2):
// X1,X2X_1, X_2 exactly nn bits
Y:=H(S,X1)X2Y := H(\salt, X_1) \oplus X_2
Z:=H(S,Y)Z := H(\salt, Y)
\qquad
Proof:

We will describe how to easily compute a collision in H2H^2. Translating this attack into a formal calling program is trivial: Just compute the collision and use it as an argument to crhf.compare\crhfcmp.

Draw two copies of a schematic diagram for H2H^2, giving names to the intermediate values:

Our goal is to choose X1X2X1X2X_1 \| X_2 \ne X'_1 \| X'_2 such that Z=ZZ = Z'. First, observe that ZZ and ZZ' are direct outputs of HH. We are assuming that HH is collision-resistant, so the only way we can reasonably expect two calls to HH to produce the same output is if they also have the same inputs—that is, if Y=YY = Y'. (Remember, we are not attacking the collision resistance of HH, but the erroneous way that H2H^2 uses HH!)

Now our goal is to choose inputs to H2H^2 such that Y=YY=Y'. More specifically, we want:

H(S,X1)X2Y=H(S,X1)X2Y. \underbrace{H(S, X_1) \oplus X_2}_{Y} = \underbrace{H(S,X'_1) \oplus X'_2}_{Y'}.

But we can rearrange this equation to get the following:

H(S,X1)X2H(S,X1)=X2. H(S, X_1) \oplus X_2 \oplus H(S,X'_1) = X'_2.

This suggests the following method of computing a collision:

  1. Choose X1,X1,X2X_1, X'_1, X_2 arbitrarily, with X1X1X_1 \ne X'_1.

  2. Solve for X2=H(S,X1)X2H(S,X1)X'_2 = H(S,X_1) \oplus X_2 \oplus H(S,X'_1).

Then X1X2X_1 \| X_2 and X1X2X'_1 \| X'_2 both hash to the same value ZZ under H2H^2. Since X1X1X_1 \ne X'_1, these strings form a collision in H2H^2.

10.4. The Merkle-Damgård construction

If we have a collision-resistant hash function with fixed input length, can we use it to build one with variable input length? This section describes a recipe for doing so, called the Merkle-Damgård construction after its creators.

As a warm-up, let us first show how to increase the input length of a collision-resistant function from 2n2n bits to 3n3n bits.

Claim 10.4.1 (Increasing the input size of a fixed-input-length CRHF)

Let H:{0,1}λ×{0,1}2n{0,1}nH : \bits^\secpar \times \bits^{2n} \to \bits^n be a salted CRHF. Then the following function H:{0,1}λ×{0,1}3n{0,1}nH^* : \bits^\secpar \times \bits^{3n} \to \bits^n is also collision-resistant:

H(S,X1X2X3)H^*(\salt,X_1 \| X_2 \| X_3):
// each XiX_i is exactly nn bits
Y:=H(S,X1X2)Y := H(\salt, X_1 \| X_2)
Z:=H(S,YX3)Z := H(\salt, Y \| X_3 )
return ZZ
\quad
Proof:

As usual, we will prove that given any collision in HH^*, we can efficiently compute a collision in HH.

Suppose we are given a collision X1X2X3X1X2X3X_1 \| X_2 \| X_3 \ne X'_1 \| X'_2 \| X'_3 in HH^*. These three-block strings are different, but they may have blocks in common, so our analysis must be careful. Define Y,Y,Z,ZY, Y', Z, Z' as the intermediate values computed while hashing these strings under HH^*:

Since these strings are a collision, Z=ZZ = Z'. We consider two cases:

\qquad

  • Case 1: X1X2X1X2X_1 \| X_2 \ne X'_1 \| X'_2 and Y=YY = Y': Then X1X2X_1 \| X_2 and X1X2X'_1 \| X'_2 are a collision in HH.

  • Case 2: YX3YX3Y \| X_3 \ne Y' \| X'_3: Then YX3Y\| X_3 and YX3Y'\|X'_3 are a collision in HH.

In both cases, we obtain a collision in HH.

We complete the proof by observing that these two cases are exhaustive. To see why, suppose for sake of contradiction that we are in neither case. Since we are not in case 2, Y=YY=Y' and X3=X3X_3 = X'_3. Given that Y=YY=Y', the only way to avoid case 1 is then X1X2=X1X2X_1 \| X_2 = X'_1 \| X'_2. But now X1X2X3=X1X2X3X_1 \| X_2 \| X_3 = X'_1 \| X'_2 \| X'_3, which is a contradiction because we originally assumed that these strings are distinct. Therefore, the two cases listed above are exhaustive.

Claim 10.4.1 describes a valid approach to increase the input length of a collision-resistant function, which can be generalized in the natural way to increase the input length by any amount. However, the approach works only for fixed input lengths; it does not provide collision resistance for variable-length inputs. The situation is similar to that of CBC-MAC.

Claim 10.4.2 (Insecurity for variable-length inputs)

Let H:{0,1}λ×{0,1}2n{0,1}nH : \bits^\secpar \times \bits^{2n} \to \bits^n be a salted hash function. For any fixed \ell, the following function H:{0,1}λ×{0,1}n{0,1}nH^* : \bits^\secpar \times \bits^{\ell n} \to \bits^n is is a secure fixed-input-length CRHF, if HH is. However, HH^* is not a secure variable-input-length CRHF, even if HH is:

H(S,X1X2X)H^*(\salt,X_1 \| X_2 \| \cdots \| X_\ell):
// each XiX_i exactly nn bits long
Y1:=X1Y_1 := X_1
for i=2i=2 to \ell:
Yi:=H(S,Yi1Xi)Y_i := H(\salt, Y_{i-1} \| X_i)
return YY_\ell
\quad
Proof:

For the case of a fixed input length, the proof generalizes that of claim 10.4.1 in a natural way, and is left as an exercise.

For the case of variable input lengths, take an arbitrary string X1X2XX_1 \| X_2 \| \cdots \| X_\ell. The computation H(S,X1X2X)H^*(\salt, X_1 \| X_2 \| \cdots \| X_\ell) corresponds to the picture shown in the statement of claim 10.4.2. But there is another way to interpret the same picture.

Let Y=H(S,X1X2)Y = H(\salt, X_1 \| X_2), which is called Y2Y_2 in the computation of HH^*. An adversary can compute YY since the salt S\salt is public. But then H(S,YX3X)=H(S,X1X)H^*( \salt, Y \| X_3 \| \cdots \| X_\ell ) = H^*( \salt, X_1 \| \cdots \| X_\ell), a collision in HH^*.

Fortunately, the fix for claim 10.4.2 is simple. Just add an additional block, containing the length of the input (encoded in binary). This process is called Merkle-Damgård padding. We can even support inputs whose length is not a multiple of nn, by appropriately padding the input with 0\bit0s:

Construction 10.4.3 (The Merkle-Damgård construction)

Let H:{0,1}λ×{0,1}2n{0,1}nH : \bits^\secpar \times \bits^{2n} \to \bits^n be a fixed-input-length hash function. Then the Merkle-Damgård hash function H:{0,1}λ×{0,1}{0,1}nH^* : \bits^\secpar \times \bits^* \to \bits^n is defined as:

mdpad(X)\subname{mdpad}(X):
L:=XL := |X|, encoded as nn-bit integer
// pp = number of bits short of a multiple of nn
p:=(L)%np := (-L) \pct n
return X0pLX \| \bit0^p \| L
H(S,X)H^*(\salt,X):
// each XiX_i exactly nn bits:
X1X+1:=mdpad(X)X_1 \| \cdots \| X_{\ell+1} := \subname{mdpad}(X)
Y0:=0nY_0 := \bit{0}^n
for i=1i=1 to +1\ell+1:
Yi:=H(S,Yi1Xi)Y_i := H(\salt,Y_{i-1} \| X_i)
return Y+1Y_{\ell+1}

HH is called the Merkle-Damgård compression function.

This construction as written is limited to inputs of length less than 2n2^n bits, since it must write the length of the input as an nn-bit integer. This is not a serious limitation since in practice n256n \ge 256.

In this setting, “compression” doesn't have its typical meaning as in other parts of computer science (where we expect there to be a decompression algorithm). Here, it just refers to the fact that inputs are longer than outputs.

Y0Y_0 is called the Merkle-Damgård initialization vector (IV). It's a traditional feature of the construction, but not strictly necessary for our collision-resistance proof.

Claim 10.4.4 (Security of Merkle-Damgård)

The Merkle-Damgård construction (construction 10.4.3) is collision-resistant if its compression function HH is collision-resistant.

Proof:

As usual, we will prove the contrapositive: Given any collision X,XX, X' in HH^*, we can efficiently compute a collision in HH.

First, run H(S,X)H^*(\salt,X) and H(S,X)H^*(\salt,X') and name the intermediate values in the natural way: YiY_i, \ell, YiY'_i, \ell'. Suppose XX and XX' have different lengths, and focus on the last call to HH during the computation of HH^*:

H(S,X)=H(S,YX),H(S,X)=H(S,YX).\begin{aligned} H^*(\salt, X) &= H(\salt, Y_\ell \| X_{\ell}), \\ H^*(\salt, X') &= H(\salt, Y'_{\ell'} \| X'_{\ell'}).\end{aligned}

We assume that these two values are equal. But XXX_{\ell} \ne X'_{\ell'}, since these are just encodings of the lengths of XX and XX', which are different. So YXYXY_\ell \| X_\ell \ne Y'_{\ell'} \| X'_{\ell'} are a collision in HH.

On the other hand, if XX and XX' have the same length, then they are also split into the same number of blocks. The situation exactly reduces to the reasoning in claim 10.4.2. Given a collision in HH^* involving strings of the same number of blocks, it is possible to efficiently compute a collision in HH.

10.4.1. Merkle-Damgård in practice

Construction 10.4.3 and its proof are written in terms of a salted hash function, built from a salted compression function.

Until recently, the vast majority of real-world hash functions were unsalted Merkle-Damgård functions; the most popular standards include MD5 (MD here stands for message digest, not Merkle-Damgård), SHA1, SHA2 (SHA stands for secure hash algorithm). Collisions have been found in MD5 and SHA1. SHA2 is still in widespread use, but is being phased out in favor of its successor SHA3, which does not use the Merkle-Damgård paradigm (for reasons discussed in the next section).

Claim 10.4.4 can be interpreted as justification for the general design principle of Merkle-Damgård hash functions. We proved its security in a way that makes sense even for real-world unsalted hash functions: Given any collision in the hash function, it is possible to easily find a collision in its compression function.

10.5. PRFs from Merkle-Damgård: Length extension, NMAC, and HMAC

Suppose the only cryptographic algorithm you have available is an unsalted Merkle-Damgård hash function HH^* and you would like to implement a variable-length PRF. This section discusses several possible approaches, and some important pitfalls.

10.5.1. Length-extension attacks

We usually incorporate salt into an unsalted hash function by prepending it to the input, as H(SX)H(\salt \| X). For the purpose of collision resistance, the salt is allowed to be public. But it is natural to wonder what happens if we keep the salt private and interpret it as a secret key. Could the result be a secure variable-input-length PRF? Unfortunately, the answer is no when the hash function has the Merkle-Damgård structure.

Claim 10.5.1 (Length extension attack on trivial MAC)

Suppose HH^* is an unsalted Merkle-Damgård hash function. Then the function F(K,X)=H(KX)F(\key, X) = H^*(\key \| X) is not a secure variable-input-length PRF.

Proof:

The input KX\key\|X to HH^* is first padded with Merkle-Damgård padding, which we write as mdpad(KX)\subname{mdpad}(\key\|X). The problem with using HH^* as a PRF is that if you know H(KX)H^*(\key\|X), then you can compute the hash of any string that begins with mdpad(KX)\subname{mdpad}(\key\|X), even if you don't know K\key. The attack is called a length extension attack.

For example, suppose XX is a string with \ell blocks, whose length is an exact multiple of the blocklength nn, and let LL be an encoding of its length X|X| as an nn-bit integer. So mdpad(X)=XL\subname{mdpad}(X) = X \| L. Then the computations H(KX)H^*(\key\|X) and H(KXLX)H^*(\key\|X\| L \| X') compute the same intermediate values for the first +1\ell+1 calls to the compression function. The computation H(KX)H^*(\key\|X) stops at that point, but the computation of H(KXLX)H^*(\key\|X\|L\|X') continues. An adversary who has the output H(KX)H^*(\key\|X) has all the information needed complete the computation of H(KXLX)H^*(\key\|X\|L\|X'), even if it doesn't know K\key!

We now describe the attack more formally, as a calling program that can distinguish the Lprf-*\lib{prf-*} libraries for the function F(K,X)=H(KX)F(\key,X) = H^*(\key\|X). To make the attack easier to write, we assume that K\key is exactly nn bits long, and that X,XX, X' are exact multiples of the blocklength nn.

A\A
X:=X := {}arbitrary string, with length a multiple of nn
X:=X' := {}arbitrary string, with length a multiple of nn
L:=L := {}encoding of integer n+Xn+|X|, the length of KX\key\|X
:=1+X/n\ell := 1 + |X|/n // length of KX\key\|X, in blocks
:=+1+X/n\ell' := \ell + 1 + |X'|/n // length of KXLX\key\|X\|L\|X', in blocks
split XX' into blocks named X+2XX'_{\ell+2} \| \cdots \| X'_{\ell'}
X+1:=X'_{\ell'+1} := {}binary encoding of integer 2n+X+X2n+|X|+|X'|
Y+1:=prf.query(X)Y_{\ell+1} := \prfquery(X)
// resume Merkle-Damgård computation starting from block +2\ell+2
for i=+2i = \ell+2 to +1\ell'+1
Yi:=H(Yi1Xi)Y_i := H(Y_{i-1} \| X'_i)
Y:=prf.query(XLX)Y^* := \prfquery(X \| L \| X')
return Y==Y+1Y^* == Y_{\ell'+1}

The attack works by using F(K,X)F(\key,X) to predict F(K,mdpad(KX)X)F(\key, \subname{mdpad}(K\|X)\|X'). It is an attack against pseudorandomness, but not against collision-resistance. There is no reason to expect that the two inputs used in this attack (KX\key \|X and KXLX\key \|X \|L \| X') are a collision in the length-extension attack.

10.5.2. Hash-then-PRF

As a stepping stone to the next constructions, we show that a fixed-input-length PRF can be promoted into a variable-input-length PRF by first hashing its input.

Claim 10.5.2 (Hash-then-PRF)

Let HH^* be a variable-input-length salted CRHF with output length nn, and FF be a PRF with (fixed) input length nn. Then the following function FF' is a secure variable-input-length PRF:

F(K1K2,X)=F(K2,H(K1,X))F'(\key_1 \| \key_2, X) = F\bigl(\key_2, H^*(\key_1, X)\bigr)
\qquad

One interesting feature of this construction is that part of the PRF key (K1\key_1) is used as a salt for the hash function. A salt is allowed to be public for the sake of collision resistance, but in this case it remains secret since a PRF key is secret. Chapter 11 explores how this construction may be optimized by taking advantage of the fact that it keeps the salt secret.

Proof:

The proof has simple intuition: Suppose FF' is invoked on distinct inputs. Then since HH^* is collision-resistant, HH^* will produce distinct outputs. That means the inputs to FF are also distinct, and since FF is a secure PRF, it will produce pseudorandom outputs.

This intuition is formalized in the proof in the following way. The security definition for collision resistance is about equality tests: Testing equality of hash outputs is indistinguishable from directly testing equality of hash inputs. Thus, an important step in the security proof is to express the logic of a dictionary data structure (the kind that appears in the Lprf-rand\lib{prf-rand} library) explicitly in terms of equality tests, so we can apply the collision resistance of HH^*.

Hybrid Sequence:
The starting point is Lprf-real\lib{prf-real}.
Since FF is a secure PRF, we may replace it with a lazy random dictionary. The standard three-hop maneuver is not shown.
The library uses a dictionary data structure, and one way to implement a dictionary is as a simple list of pairs (Y,Z)(Y,Z). To read from the dictionary at position YY, simply scan the list to find a record with the correct YY. To modify the dictionary, append a new record to the list. This is not a very efficient way to implement a dictionary, but it is correct nonetheless. In this proof it is convenient to store not only YY and ZZ but also XX in each record.
Each record (X,Y,Z)(X,Y,Z) in D\mathcal{D} satisfies Y=H(K1,X)Y = H^*(\key_1,X). So instead of comparing YY' and YY, the library can compare H(K1,X)H^*(\key_1,X') and H(K1,X)H^*(\key_1,X) with the same effect.
Now the library implements a dictionary in terms of hash comparisons, so we can apply the CRHF security of HH^* in a three-hop maneuver.
The YY-values, and therefore K1\key_1, are no longer being used. They can be removed.
The resulting library is an (inefficient) implementation of a lazy random dictionary, but this time indexed by XX values rather than their hashes. In other words, it is Lprf-rand\lib{prf-rand}.
Lprf-real\lib{prf-real}
K1\key_1
K2{0,1}2λ\| \key_2 \gets \bits^{2\secpar}
{0,1}λ{}\gets \bits^\secpar
:=crhf.getsalt(){}:= \crhfgetsalt()
{0,1}λ{}\gets \bits^\secpar
prf.query\prfquery(XX):
// F(K1K2,X)F'(\key_1\|\key_2, X):
Y:=H(K1,X)Y := H^*(\key_1, X)
ZZ
:={}:= {}
F(K2,Y)F(\key_2, Y)
L[Y]\prftable[Y]
{0,1}n{}\gets \bits^n
return
ZZ
L[X]\prftable[X]
\link
Lcrhf-real\lib{crhf-real}
S{0,1}λ\salt \gets \bits^\secpar
crhf.getsalt\crhfgetsalt( ):
return S\salt
crhf.compare\crhfcmp(X,XX, X'):
return H(S,X)==H(S,X)H^*(\salt,X) == H^*(\salt,X')
Lcrhf-ideal\lib{crhf-ideal}
S{0,1}λ\salt \gets \bits^\secpar
crhf.getsalt\crhfgetsalt( ):
return S\salt
crhf.compare\crhfcmp(X,XX, X'):
return X==XX == X'

10.5.3. NMAC and HMAC

Recall the motivation for this section: to construct a variable-length PRF using only an implementation of an unsalted Merkle-Damgård hash function. In this section, let HH^* be the hash function, with compression function HH.

The NMAC construction uses the following recipe:

  1. Build a salted CRHF from an unsalted Merkle-Damgård hash function.

  2. Build a fixed-input-length PRF from an unsalted Merkle-Damgård hash function.

  3. Combine these two primitives using the hash-then-PRF construction (claim 10.5.2).

Recall that the Merkle-Damgård construction uses an initialization vector (IV), which we have usually just taken to be all-zeros, and which is some specific string in a standardized hash function. In step 1 of NMAC, we use the salt as the IV; thus, NMAC requires an implementation of the Merkle-Damgård function that lets the user specify a particular IV. Not all implementations may support nonstandard IVs, but we will address this issue a bit later. We write Hiv(S,X)H^*_{\textsf{iv}}(S,X) to denote the Merkle-Damgård hash of XX, using SS as the IV.

For step 2 of NMAC, we simply assume that HivH^*_{\textsf{iv}} is a fixed-input-length PRF on inputs of one block, treating the IV/salt as the PRF key. If you are nervous about treating a Merkle-Damgård hash as a PRF in light of claim 10.5.1, remember: These length-extension attacks apply only when using Merkle-Damgård as a variable-input-length PRF. It can still be reasonable to assume that a Merkle-Damgård hash is a secure PRF for a fixed input length.

Combining these steps gives us the full NMAC construction:

Construction 10.5.3 (NMAC)

Let H:{0,1}2n{0,1}nH : \bits^{2n} \to \bits^n be a compression function, then NMAC is defined as follows:

Hiv(S,X)H^*_{\textsf{iv}}(\salt,X):
X1X+1:=mdpad(X)X_1 \| \cdots \| X_{\ell+1} := \subname{mdpad}(X)
Y0:=SY_0 := \salt // treat SS as IV
for i=1i=1 to +1\ell+1:
Yi:=H(Yi1Xi)Y_i := H(Y_{i-1} \| X_i)
return Y+1Y_{\ell+1}
NMAC(K1K2,X)\textsf{NMAC}(\key_1 \| \key_2, X):
Y:=Hiv(K1,X)Y := H^*_{\textsf{iv}}(\key_1, X)
return Hiv(K2,Y)H^*_{\textsf{iv}}(\key_2, Y)

Because NMAC is an instance of the hash-then-PRF paradigm, we have the following:

Claim 10.5.4 (Security of NMAC)

If HivH^*_{\textsf{iv}} is a salted CRHF (interpreting its first argument as the salt), and is a secure PRF for 1-block inputs (interpreting its first argument as the PRF key), then NMAC is a secure variable-length-input PRF.

HMAC: What if you have an implementation of a Merkle-Damgård hash HH that does not allow you to specify a particular IV? HMAC is a variant of NMAC designed for this case.

Suppose the NMAC keys K1,K2\key_1, \key_2 are derived from a single key K\key^* in a special way:

K1=H(IV(KP1)),K2=H(IV(KP2)),\begin{aligned} \key_1 &= H\bigl(IV \| (\key^* \oplus P_1) \bigr), \\ \key_2 &= H\bigl(IV \| (\key^* \oplus P_2) \bigr),\end{aligned}

where P1P_1 and P2P_2 are some fixed constants, IVIV is the fixed IV of the standardized, unsalted Merkle-Damgård hash, and HH is its compression function. (In the HMAC standard, P1P_1 and P2P_2 are the hexadecimal strings 5c5c5c\bit{5c5c5c}\cdots and 363636\bit{363636}\cdots.)

This value of K1\key_1 is precisely what the first round of the standard-IV, unsalted hash HH^* computes, when the first block of its input is KP1\key^* \oplus P_1. In fact, we have:

Hiv(K1,X)=H((KP1)X).(but read below for a disclaimer.) H^*_{\textsf{iv}}( \key_1, X) = H^*\bigl( (\key^* \oplus P_1) \| X \bigr). \text{\quad \small (but read below for a disclaimer.)}

In other words, if NMAC keys are chosen this way, then we can evaluate NMAC using an implementation of HH^* with its standard, fixed IV. The result is HMAC:

In this picture, the highlighted parts show HMAC deriving NMAC keys K1\key_1 and K2\key_2 from a common K\key^*.

There is actually a slight difference between Hiv(K1,X)H^*_{\textsf{iv}}( \key_1, X) and H((KP1)X).H^*\bigl( (\key^* \oplus P_1) \| X \bigr). If XX has length LL, then the former computation will add Merkle-Damgård length padding LL, but the latter computation will add length padding L+nL+n — it “sees” an input that is one block longer than XX. But the details of the Merkle-Damgård padding do not seem relevant to the assumptions on HH that NMAC requires; presumably the assumptions are equally valid when an extra nn is always added to the length padding.

Thus, assuming that the following function GG is a PRG:

G(K)=H(IV(KP1))H(IV(KP2)), G(\key^*) = H\bigl(IV \| (\key^* \oplus P_1) \bigr) \,\big\|\, H\bigl(IV \| (\key^* \oplus P_2) \bigr),

then HMAC is indistinguishable from NMAC—or, at least a variant of NMAC that adds an extra nn to its length padding.

Exercises

  1. A birthday attack on collision resistance invokes the hash function 2n/22^{n/2} times. But the attack also needs to realize when it has seen a collision, and output the values that lead to the collision. How would you implement a birthday attack so that its total, overall running time is O(2n/2)O(2^{n/2}), not just the number of calls to HH it makes?

  2. Let HH be a salted hash function with nn bits of output, nn-bit salt, and variable-length input. Suppose that whenever XX is nn bits long we have H(S,X)=XSH(\salt,X) = X \oplus \salt. Thus, it is guaranteed that there are no collisions among nn-bit inputs. Show that HH cannot be collision-resistant in general.

  3. If XX and YY are strings of the same length, write XYX \sqsubseteq Y to mean that XX encodes an integer that is less than or equal to that of YY. Suppose HH is a hash function with the following property: For all mm and X,Y{0,1}mX,Y \in \bits^m, if XYX \sqsubseteq Y then H(S,X)H(S,Y)H(\salt, X) \sqsubseteq H(\salt,Y). Show that HH cannot be collision-resistant.

  4. Suppose HH is a CRHF and define the new function

    H(S,X1X2)=H(S,X1)H(S,X2). H'(\salt, X_1 \| X_2) = H(\salt,X_1) \oplus H(\salt,X_2).

    Here X1X_1 and X2X_2 are the same length. Is HH' also a CRHF? Either prove or describe an attack.

  5. Let F±F^\pm be a PRP with blocklength nn. Prove that CBC-MAC (below), using an all-zeros IV and the salt as the PRP key, is not a CRHF:

    H(S,X1X)H(\salt, X_1 \| \cdots \| X_\ell):
    // each XiX_i is exactly nn bits
    Y0:=0nY_0 := \bit0^n
    for i=1i =1 to \ell:
    Yi:=F(S,XiYi1)Y_i := F(\salt, X_i \oplus Y_{i-1})
    return YY_\ell
  6. h\star Let HH be a CRHF with nn output bits, and define the following function:

    H(S,X1X)H^*(\salt, X_1 \| \cdots \| X_\ell):
    // each XiX_i is exactly nn bits
    Y:=0nY := \bit0^n
    for i=1i =1 to \ell:
    Y:=YH(S,Xii)Y := Y \oplus H(\salt, X_i \| i)
    return YY

    The function has variable input length, so \ell can be any value. In H(S,Xii)H(\salt, X_i \| i), integer ii is encoded as a λ\secpar-bit string. Show that HH^* is not a variable-length collision-resistant hash function.

    Interpret {0,1}n\bits^n as an nn-dimensional vector space, so that each output of HH is a vector in that space. With enough such vectors, you can find nontrivial linear dependencies.

  7. Let FF be a secure PRP with blocklength and key size λ\secpar.

    1. Show how to efficiently find a collision in the (unsalted) function H(XY)=F(X,Y)H(X \| Y) = F(X,Y).

    2. Show how to efficiently find a collision in the (unsalted) function H(XY)=F(X,Y)XH(X \| Y) = F(X,Y) \oplus X.

    3. Show how to efficiently find a collision in the (unsalted) function H(XY)=F(XY,Y)XYH(X \| Y) = F(X \oplus Y,Y) \oplus X \oplus Y.

  8. Let HH be a salted hash function with nn output bits. Show how to efficiently find a collision in the following function H:{0,1}λ×{0,1}2n{0,1}nH' : \bits^\secpar \times \bits^{2n} \to \bits^n:

    H(S,XY)H'(\salt, X \| Y):
    Z:=H(S,X)YZ := H(\salt, X) \oplus Y
    return H(S,Z)XH(\salt, Z) \oplus X
  9. Prove the first half of claim 10.4.2. For any fixed \ell, the function HH^* described there is a secure CRHF for inputs of fixed length n\ell n.

  10. Let H:{0,1}λ×{0,1}2n+1{0,1}nH : \bits^\secpar \times \bits^{2n+1} \to \bits^n be a salted hash function with fixed input length. Prove that if HH is collision-resistant, then the following salted hash function HH^* is collision-resistant for variable-length inputs that are multiples of the blocklength:

    H(S,X1X)H^*(\salt, X_1 \| \cdots \| X_\ell):
    // each XiX_i exactly nn bits
    b:=0b := \bit0
    Y1:=X1Y_1 := X_1
    for i=2i=2 to \ell:
    Yi:=H(S,bYi1Xi)Y_i := H(\salt, b \| Y_{i-1} \| X_i)
    b:=1b := \bit1
    return YY_\ell
    1. In an AEAD scheme, it is convenient to compute a hash of the pair of strings (A,C)(A,\ctxt) where AA is the associated data and C\ctxt is the CPA ciphertext. Let HH be a CRHF. Show that the following function HH' is not collision-resistant for pairs of strings:

      H(S,(A,C))=H(S,AC). H'\bigl(\salt, (A,\ctxt) \bigr) = H(\salt, A \| \ctxt).

      Describe how to construct two distinct pairs (A,C)(A,C)(A,\ctxt) \ne (A',\ctxt') that collide under HH'.

    2. Propose a better method to hash pairs of strings and prove that it is collision-resistant.

  11. Construction 10.4.3 presents the Merkle-Damgård construction based on a compression function with 2n2n input bits and nn output bits. Describe how to modify the construction to support a compression function with n+tn+t input bits and nn output bits, for any t>0t>0.

  12. Let HH^* be a Merkle-Damgård hash function with compression function HH.

    1. Describe how to find (with good probability) four distinct strings of the form

      XY,XY,XY,XY, X\|Y, \quad X\|Y', \quad X'\|Y, \quad X'\|Y',

      that all hash to the same output under HH^*, using running time 22n/2\sim 2 \cdot 2^{n/2}.

    2. Describe how to find 2d2^d distinct messages that all hash to the same output under HH^*, using running time O(d2n/2)O(d 2^{n/2}).

    3. Suppose H1H^*_1 is a Merkle-Damgård hash function, and H2H^*_2 is some other hash function, not necessarily Merkle-Damgård, both with nn output bits. Define the new function

      H(S1S2,X)=H1(S1,X)H2(S2,X). H'(\salt_1 \| \salt_2,X) = H^*_1(\salt_1,X) \| H^*_2(\salt_2,X).

      Since HH' has outputs of length 2n2n, it is tempting to think that it could offer nn bits of security (i.e., that collisions in HH' require 2n2^n effort).

      Show how to find a collision in HH' in running time only O(n2n/2)O(n 2^{n/2}). Your attack should not assume anything about H2H^*_2.

  13. Let HH^* be an unsalted hash function with output length nn, and let CTR\textsf{CTR} denote CTR-mode encryption (construction 8.5.4). Show that the following scheme is not CCA-secure:

    Enc(K,M)\Enc(\key, \ptxt):
    Y:=H(M)Y := H^*(\ptxt)
    C:=CTR.Enc(K,MY)\ctxt := \textsf{CTR}.\Enc(\key, \ptxt \| Y)
    return C\ctxt
    Dec(K,C)\Dec(\key, \ctxt):
    // YY = last nn bits
    MY:=CTR.Dec(K,C)\ptxt \| Y := \textsf{CTR}.\Dec(\key,\ctxt)
    if YH(M)Y \ne H^*(\ptxt): return err\myerr
    return M\ptxt
  14. Let HH^* be an unsalted Merkle-Damgård hash, and define H(X)=H(X)H'(X) = \overline{ H^*(X) } (i.e., the bitwise complement of H(S,X)H^*(\salt,X)). Show how to modify the length-extension attack from section 10.5.1 to work against HH'.

  15. There are two natural ways to incorporate salt into an unsalted Merkle-Damgård hash function: (1) prepend it to the input; (2) use the salt as the IV, instead of the standardized IV value. NMAC uses the latter method.

    In the text we showed that method (1) does not lead to a secure variable-input-length PRF if you interpret the salt as the PRF key. Show that the same holds for method (2).

  16. Prove that HMAC is collision-resistant if we treat the key as a public salt, under the same assumptions that make HMAC a secure PRF.

Chapter Notes

Our first attempt at defining collision resistance fails because we allow adversaries to be nonuniform algorithms. In computational complexity, nonuniform means that a different algorithm may be used for each input length (security parameter in our case), and there is no limit to how much computation can be used to discover the “correct” algorithm for a given input length. Koblitz and Menezes have criticized the use of nonuniformity in cryptographic definitions [134]. We introduced salt to avoid the problems with our first collision resistance definition, although there have been some proposals to formalize collision resistance for unsalted functions; see Rogaway [192].

The first version of UNIX that used salted password hashing appears to be V7, released in early 1979 (according to my understanding of historical source code from the Unix Heritage Society [210]), where the source code indeed describes the relevant value as salt. Around the same time, Morris and Thompson [167] describe the practice of salting in a retrospective article about password security in UNIX. There seems to be no consensus on why the word “salt” was chosen to describe this technique.

The first formal definitions for collision resistance are due to Damgård [78]. Rogaway and Shrimpton later provided a more modern treatment of collision resistance and other desirable properties of hash functions [194].

The first collision in SHA-1 was found by Wang, Yin, and Yu [216].

Exercise 10.6 is due to Bellare and Micciancio [23].

The Merkle-Damgård construction was proposed independently by Merkle [161] and Damgård [79].

The weakness of Merkle-Damgård hashes explored in exercise 10.13 was first observed by Joux [128].

Length extension attacks on Merkle-Damgård hashes were first observed by Solo and Kent, as attributed by Tsudik [212]. Duong and Rizzo exploited length extension in a notable attack against the Flickr website [90].

NMAC and HMAC were proposed by Bellare, Canetti, and Krawczyk [14]. Our security treatment follows theirs, although a subsequent analysis by Bellare [12] gives an alternative security proof that does not rely on collision resistance.

  1. Previous Chapter9. Chosen-Ciphertext Attacks Against Encryption
  2. Next Chapter11. ☆ Universal Hash Functions