|
To efficiently sign messages, Alice needs to be able to compute a summary of her message in a way that makes prohibits an attacker from generating a different message that has the same summary. `Cryptographic hash functions` were designed to solve this problem. The ideal hash function is a function that returns a different number for every possible input. In practice, it is impossible to find such a function. Cryptographic hash functions are an approximation of this perfect summarization function. They compute a summary of a given message in 128, 160, 256 bits or more. They also exhibit the `avalanche effect`. This effect indicates that a small change in the message causes a large change in the hash value. Finally hash functions are very difficult to invert. Knowing a hash value, it is computationally very difficult to find the corresponding input message. Several hash functions have been proposed by cryptographers. The most popular ones are :
|
|
|
MD5, originally proposed in :rfc:`1321`. It has been used in a wide range of applications. In 2010, attacks against MD5 were published and this hash function is now deprecated.
|
|
|
SHA-1 is a cryptographic hash function that was standardized by the NIST in 1995. It outputs 160 bits results. It is now used in a variety of network protocols.
|
|
|
SHA-2 is another family of cryptographic hash functions designed by the NIST. Different variants of SHA-2 can produce has values of 224, 256, 384 or 512 bits.
|
|
|
Another important point about cryptographic algorithms is that often these algorithms require random numbers to operate correctly (e.g. to generate keys). Generating good random numbers is difficult and any implementation of cryptographic algorithms should also include a secure random number generator. :rfc:`4086` provides useful recommendations.
|
|
|
Cryptographic protocols
|
|
|
We can now combine the cryptographic operations described in the previous section to build some protocols to securely exchange information. Let us first go back to the problem of authenticating Alice on Bob's computer. We have shown earlier that using a simple password for this purpose is insecure in the presence of attackers.
|
|
|
A naive approach would be to rely on hash functions. Since hash functions are non-invertible, Alice and Bob could decide to use them to exchange Alice's password in a secure manner. Then, Alice could be authenticated by using the following exchange.
|
|
|
Since the hash function cannot be inverted, an eavesdropper cannot extract Alice's password by simply observing the data exchanged. However, Alice's real password is not the objective of an attacker. The main objective for Mallory is to be authenticated as Alice. If Mallory can capture `Hash(passwd)`, he can simply replay this data, without being able to invert the hash function. This is called a `replay attack`.
|
|
|
To counter this replay attack, we need to ensure that Alice never sends the same information twice to Bob. A possible mode of operation is shown below.
|
|
|
To authenticate herself, Alice sends her user identifier to Bob. Bob replies with a random number as a challenge to verify that Alice knows the shared secret (i.e. her password). Alice replies with the result of the computation of a hash function (e.g. SHA-1) over a string that is the concatenation between the random number chosen by Bob and Alice's password. The random number chosen by Bob is often called a `nonce` since this is a number that should only be used once. Bob performs the same computation locally and can check the message returned by Alice. This type of authentication scheme has been used in various protocols. It prevents replay attacks. If Eve captures the messages exchanged by Alice and Bob, she cannot recover Alice's password from the messages exchanged since hash functions are non-invertible. Furthermore, she cannot replay the hashed value since Bob will always send a different nonce.
|
|
|
Unfortunately, this solution forces Bob to store Alice's password in clear. Any breach in the security of Bob's computer would reveal Alice's password. Such breaches unfortunately occur and some of them have led to the dissemination of millions of passwords.
|
|
|
A better approach would be to authenticate Alice without storing her password in clear on Bob's computer. For this, Alice computes a `hash chain` as proposed by Lamport in [Lamport1981]_. A hash chain is a sequence of applications of a hash function (`H`) on an input string. If Alice's password is `P`, then her 10 steps hash chain is : :math:`H(H(H(H(H(H(H(H(H(H(P))))))))))`. The result of this hash chain will be stored on Bob's computer together with the value `10`. This number is the maximum number of remaining authentications for Alice on Bob's computer. To authenticate Alice, Bob sends the remaining number of authentications, i.e. `10` in this example. Since Alice knows her password, `P`, she can compute :math:`H^9(P)=H(H(H(H(H(H(H(H(H(P)))))))))` and send this information to Bob. Bob computes the hash of the value received from Alice (:math:`H(H^9(P))`) and verifies that this value is equal to the value stored in his database. It then decrements the number of authorized authentications and stores :math:`H^9(P)` in his database. Bob is now ready for the next authentication of Alice. When the number of authorized authentications reaches zero, the hash chain needs to be reinitialized. If Eve captures :math:`(H^n(P))`, she cannot use it to authenticate herself as Alice on Bob's computer because Bob will have decremented its number of authorized authentications. Furthermore, given that hash functions are not invertible, Eve cannot compute :math:`H^{n-1}(P)` from :math:`H^{n}(P)`.
|
|
|
The two protocols above prevent eavesdropping attacks, but not man-in-the-middle attacks. If Mallory can intercept the messages sent by Alice, he could force her to reveal :math:`H^n(P)` and then use this information to authenticate as Alice on Bob's computer. In practice, hash chains should only be used when the communicating users know that there cannot be any man-in-the-middle on their communication.
|
|
|
Public key cryptography provides another possibility to allow Alice to authenticate herself on Bob's computer. Assume again that Alice and Bob know each other from previous encounters. Alice knows Bob's public key (:math:`Bob_{pub}`) and Bob also knows Alice's key (:math:`Alice_{pub}`). To authenticate herself, Alice could send her user identifier. Bob would reply with a random number encrypted with Alice's public key : :math:`E_p(Alice_{pub},R)`. Alice can decrypt this message to recover `R` and sends :math:`E_p(Bob_{pub},R)`. Bob decrypts the nonce and confirms that Alice knows :math:`Alice_{priv}`. If an eavesdropper captures the messages exchanged, he cannot recover the value `R` which could be used as a key to encrypt the information with a secret key algorithm. This is illustrated in the time sequence diagram below.
|
|
|
A drawback of this approach is that Bob is forced to perform two public key computations : one encryption to send the random nonce to Alice and one decryption to recover the nonce encrypted by Alice. If these computations are costly from a CPU viewpoint, this creates a risk of Denial of Service Attacks were attackers could try to access Bob's computer and force it to perform such costly computations. Bob is more at risk than Alice in this situation and he should not perform complex operations before being sure that he is talking with Alice. An alternative is shown in the time sequence diagram below.
|
|
|
Here, Bob simply sends a random nonce to Alice and verifies her signature. Since the random nonce and the signature could be captured by an eavesdropper, they cannot be used as a secret key to encrypt further data. However Bob could propose a secret key and send it encrypted with Alice's public key in response to the signed nonce that he received.
|
|
|
The solution described above works provided that Bob and Alice know their respective public keys before communicating. Otherwise, the protocol is not secure against man-in-the-middle attackers. Consider Mallory sitting in the middle between Alice and Bob and assume that neither Alice nor Bob knows the other's public key.
|
|
|
In the above example, Alice sends her public key, (:math:`Alice_{pub}`), in her first message together with her identity. Mallory intercepts the message and replaces Alice's key with his own key, (:math:`Mallory_{pub}`). Bob replies with a nonce, `R`. Alice then signs the random nonce to prove that she knows :math:`Alice_{priv}`. Mallory discards the information and instead computes :math:`E_p(Mallory_{priv},R)`. Bob now thinks that he is discussing with Alice while Mallory sits in the middle.
|
|
|
There are situations where symmetric authentication is required. In this case, each user must perform some computation with his/her private key. A possible exchange is the following. Alice sends her certificate to Bob. Bob replies with a nonce, :math:`R1`, and provides his certificate. Alice encrypts :math:`R1` with her private key and generates a nonce, :math:`R2`. Bob verifies Alice's computation and encrypts :math:`R2` with his private key. Alice verifies the computation and both have been authenticated.
|
|