Basic Authenticated DH

Last Updated: 16 December 2018

In the last episode, we've seen how a naive implementation for authenticated Diffie-Hellman allowed an attacker Susan to long-term impersonate Alice, even after the session was long over. We'll therefore modify once again the key-exchange protocol to prevent long-term impersonation through ephemeral leakage.

The story so far

Recall that Alice sends \((\mathit{I_{Alice}}, g^a, \operatorname{sig_{Alice}}(g^a))\) to Bob, where \(\mathit{I_{Alice}}\) is Alice's identity (e.g. her e-mail address), \(g^a\) is her ephemeral short-term public key, and \(\operatorname{sig_{Alice}}(g^a)\) is the signature of \(g^a\) with her long-term private key. Bob is supposed to verify that \(\operatorname{sig_{Alice}}(g^a)\) is indeed the signature of \(g^a\), using Alice's long-term public key. He is also supposed to get Alice's long-term public key from a valid certificate that a CA issued to Alice.

The purpose of signing \(g^a\) was to prevent a man in the middle attack. In unauthenticated Diffie-Hellman, Susan would simply replace \(g^a\) with \(g^s\), and Bob couldn't tell the difference. Adding identities alone wouldn't help: Susan would simply replace \((\mathit{I_{Alice}}, g^a)\) with \((\mathit{I_{Alice}}, g^s)\). Bob can't tell that \(g^s\) doesn't belong to \(\mathit{I_{Alice}}\). That's the purpose of adding \(\operatorname{sig_{Alice}}(g^a)\) to the mix. If Susan merely switched \(g^s\) for \(g^a\), Bob would get \((\mathit{I_{Alice}}, g^s, \operatorname{sig_{Alice}}(g^a))\), and since \(\operatorname{sig_{Alice}}(g^a)\) doesn't match \(g^s\), he won't be duped. But replacing \(\operatorname{sig_{Alice}}(g^a)\) with \(\operatorname{sig_{Susan}}(g^s)\) isn't an option for Susan: Bob, upon getting \((\mathit{I_{Alice}}, g^s, \operatorname{sig_{Susan}}(g^s))\) would immediately see that \(\operatorname{sig_{Susan}}(g^s)\), used with the public key in \(\mathit{I_{Alice}}\)'s certificate, doesn't verify \(g^s\).

This scheme seemed so nice, yet we've seen how Susan was still able to long-term impersonate Alice. What went wrong?

The problem was that if Susan (with the help of Neal), is able to come up with \(a\) corresponding to \(g^a\), she is able to fool Bob with a replay attack: by replaying \((\mathit{I_{Alice}}, g^a, \operatorname{sig_{Alice}}(g^a))\) to Bob sometimes in the future (long after the original Alice-Bob session was over), Bob would compute a key \(k_{AB_2}\), und Susan, with the help of \(a\) would compute \(k_{AB_2}\) as well.

The reason this attack succeeded was not so much that Alice leaked \(\operatorname{sig_{Alice}}(g^a)\) (though it helped and was necessary for the man in the middle attack to work at all), it was that \(\operatorname{sig_{Alice}}(g^a)\) lacked freshness. Susan could re-use a stale \(\operatorname{sig_{Alice}}(g^a)\) signature of \(g^a\) that Alice provided initially, to impersonate her forever (or at least until Alice's certificate expired in a couple of months, invalidating \(\operatorname{sig_{Alice}}(g^a)\) along the way). Or, to put it differently, Alice leaked a pair \((g^a, \operatorname{sig_{Alice}}(g^a))\) that was valid forever. This unlimited validity is the actual culprit.

Maybe adding freshness to \(\operatorname{sig_{Alice}}(g^a)\), such that it won't stay valid beyond the end of the session would help make this issue go away? That's what Basic Authenticated Diffie-Hellman (BADH) is all about.

Basic Authenticated Diffie-Hellman (BADH)

How do we limit the length of time that \(\operatorname{sig_{Alice}}(g^a)\) is valid? Well, by including in \(\operatorname{sig_{Alice}}(g^a)\) not only \(g^a\) but another parameter that changes from session to session! What about adding both \(g^a\) and \(g^b\) to \(\operatorname{sig_{Alice}}\), calling it now \(\operatorname{sig_{Alice}}(g^a, g^b)\)? Surely, this signature would be valid for the current session, but since Bob will present \(g^{b_2}\) in a subsequent session, Susan won't be able to replay \(\operatorname{sig_{Alice}}(g^a, g^b)\) to Bob, since he'll be expecting \(\operatorname{sig_{Alice}}(g^a, g^{b_2})\) instead... which she can't compute, since she doesn't have Alice's long-term secret key.

In other words, \(\operatorname{sig_{Alice}}(g^a, g^b)\) will always stay fresh, since it changes with each new session. Even if Susan recorded the sequence \((g^{a_1}, g^{b_1}, \operatorname{sig_{Alice}}(g^{a_1}, g^{b_1})), (g^{a_2}, g^{b_2}, \operatorname{sig_{Alice}}(g^{a_2}, g^{b_2})), \cdots, (g^{a_n}, g^{b_n}, \operatorname{sig_{Alice}}(g^{a_n}, g^{b_n}))\) of previous sessions between Alice and Bob, she still won't be able to come up with an \((g^{a_n}, g^{b_{n+1}}, \operatorname{sig_{Alice}}(g^{a_n}, g^{b_{n+1}}))\), when trying to initiate a session with Bob, who offered her \(g^{b_{n+1}}\) as the next ephemeral public key.

With the current version of the protocol, Alice doesn't yet have \(g^b\), so she can't just compute (\(g^a || g^b\) means \(g^a\) concatenated with \(g^b\)):