Andrew Lee
Dec 10 2017
Latest Revision: Jul 6 2018 (v5.4)
Suppose all keys have been compromised, or there is no trusted channel to establish public keys. I show that it is possible to force a MITM attacker to commit a corrupted message for each legitimate message they decrypt. The goal is to make it difficult for the attacker to learn anything new from the conversation that they could not have learned by conversing with the participants individually. Additionally, the continuous corrupting of messages endangers the stealthiness of the attacker.
The main idea is to commit to a key and message before revealing the message. This forces the attacker to change both the key and message contents if they want to exploit and maintain their MITM position.
Note that the protocol described here is intended as an extra layer of security on top of a more traditional protocol for securing communications. This protocol is only useful in case the other protocol is compromised.
Another use for the protocol is to make an easy-to-use interface to set up secure communications that is strictly more secure than applying a trust-on-first-use policy and does not require manual effort in verifying public keys. Requiring new users to manually trade public keys over a secure out-of-band channel can decrease usability.
senc
denotes symmetric authenticated encryption (AEAD). senc(k, m)
means
that the message m
is encrypted and authenticated under key k
. pk
denotes
a public key, sk
denotes a secret (private) key, k
denotes a symmetric key.
The generic function h
denotes a secure hash function.
The steps are:
-
Alice and Bob generate new Diffie-Hellman keys, public
pk_a
,pk_b
, and privatesk_a
,sk_b
. They also generate symmetric keysk_a
andk_b
. These symmetric keys are not used directly but are first passed through a secure hash functionh
. This will be explained later. -
Alice sends
(HMAC(kdf(senc(h(k_a), m_a)), pk_a), pk_a)
. Then Bob sends(HMAC(kdf(senc(h(k_b), m_b)), pk_b), pk_b)
. -
Alice and Bob obtain a Diffie-Hellman shared secret,
k_ab
, from their private keys and each other's public keys. -
Alice sends
senc(k_ab, senc(h(k_a), m_a))
. Bob sendssenc(k_ab, senc(h(k_b), m_b))
. -
Alice checks
HMAC(kdf(senc(h(k_b), m_b)), pk_b)
, with the value received in step 2, and Bob similarily checksHMAC(kdf(senc(h(k_a), m_a)), pk_a)
. If the checks fail, they abort the conversation. -
Alice sends
senc(k_ab, k_a)
. Bob decrypts and readsm_a
. Then Bob sendssenc(k_ab, k_b)
. Alice decrypts and readsm_b
.
If the messages are not received in the expected order, or the authentication tags fail to verify, the conversation is aborted. Otherwise, the conversation will continue using the new shared secret.
The reason for the hash in step 2 is in case the following attack can be
achieved. At step 2, knowing pk_a
, the MITM attacker generates
and sends some ciphertext c_m
, an authentication tag t_m
, and
Diffie-Hellman public key pk_m
. At step 5, after learning k_a
and m_a
,
the MITM attacker generates a key k_m
such that m_a = sdec(k_m, c_m)
and
pk_m
and t_m
verify under k_m
. By hashing the symmetric keys, even if
the attacker could produce a key that can decrypt their ciphertext to Alice's
message m_a
, they would still need to achieve a preimage attack on the hash
function to complete the attack.
From Alice's perspective, if there is an attacker Mallory on the network, then
she does not know if she actually received pk_b
or pk_m
in step 2.
Similarly, she does not know if she received m_b
or m_m
. Let us denote the
unknown public key she received pk_x
and the message m_x
, and similarly for
others. The HMAC check at step 5 implies to Alice that the sender of pk_x
in
step 2 also knew senc(h(k_x), m_x)
in step 2. She trusts that Bob will only
reveal k_b
and therefore m_b
in step 6. Therefore when Alice reads m_x
at
step 6, she knows that if the sender of m_x
is really Bob (i.e. m_x = m_b
),
then Bob must have sent the authentication tag for pk_x = pk_b
in step 2, and
that she now has a shared secret with Bob. If the sender of m_x
is actually
Mallory, i.e. m_x = m_m
, Alice can still be sure that Mallory had committed
to m_m
without having seen m_b
, or that Mallory has reached step 6 with Bob
before initiating step 2 with Alice, so that m_m = m_b
. This effectively means
m_b
is from a previous "conversation" with Bob.
In order to eavesdrop on the conversation, Mallory needs to either make up her own responses, or to be able to impersonate one side of the conversation. If she is already able to impersonate one side of the conversation, then she does not need to execute a MITM attack in the first place.
Consider that Alice and Bob's communications have been compromised by Mallory. For simplicity, this is essentially the same as considering that all messages are in the clear and that Mallory is the only other person on the network.
In order to maintain their ability to decrypt future communications, Mallory
needs to substitute their own key for pk_b
and pk_a
. Furthermore, if
Mallory wants to pass checks on authentication tags, she needs to commit her
own messages before having read Alice's or Bob's messages.
-
Alice, Bob, and Mallory generate new asymmetric keys, public
pk_a
,pk_b
,pk_m
, and privatesk_a
,sk_b
,sk_m
. They also generate symmetric keysk_a
,k_b
, andk_m
. -
Alice sends
(HMAC(kdf(senc(h(k_a), m_a)), pk_a), pk_a)
to Mallory, and Mallory sends(HMAC(kdf(senc(h(k_m), m_ma)), pk_m), pk_m)
to Bob. Then Bob sends(HMAC(kdf(senc(h(k_b), m_b)), pk_b), pk_b)
to Mallory, and Mallory sends(HMAC(kdf(senc(h(k_m), m_mb)), pk_m), pk_m)
to Alice. -
Alice and Mallory arrive at the shared secret
k_am
. Bob and Mallory obtain the shared secretk_bm
. -
Alice sends
senc(k_am, senc(h(k_a), m_a))
to Mallory, and Mallory sendssenc(k_am, senc(h(k_m), m_mb))
to Alice. Mallory sendssenc(k_bm, senc(h(k_m), m_ma))
to Bob. Bob sendssenc(k_bm, senc(h(k_b), m_b))
to Mallory. -
Alice checks
HMAC(kdf(senc(h(k_m), m_mb)), pk_m)
with the value received in step 2, and Bob similarily checksHMAC(kdf(senc(h(k_m), m_ma)), pk_m)
. If the checks fail, they abort the conversation. -
Alice sends
senc(k_am, k_a)
. Mallory decrypts and readsm_a
. Mallory sendssenc(k_bm, k_m)
to Bob. Bob decrypts and readsm_ma
. Bob sends Mallorysenc(k_bm, k_b)
. Mallory decrypts and readsm_b
Mallory sends Alicesenc(k_am, k_m)
. Alice decrypts and readsm_mb
.Note that if Bob insists on obtaining
k_m
before sendingk_b
, then if he senses something is wrong when he readsm_ma
, he can refuse to sendk_b
.
In this attack, Mallory decrypts m_a
and m_b
, but Alice and Bob do not read
each other's messages. Instead they read Mallory's messages. If Mallory does
not know how to react appropriately in order to impersonate Alice and Bob, she
risks detection. As noted previously, if Mallory already knows how either Alice
or Bob would react to any situation, she does not need to perform a MITM attack
in the first place, and could directly impersonate one side of the conversation
to gather the information she wants from the other side. Therefore it is
exactly the situations in which the MITM attack would be useful to Mallory that
the risk of detection is highest.
This method can be used in a client-server scenario. This use case will be developed in another document.
This method can be used in a video conference context, by having each side commit a speakable nonce, then revealing the nonce only after the call has started, and reading out loud the nonces. (To the user this would be similar to the old speakable nonces in Signal.)
June-October 2017: Andy Lee uses symmetric authenticated encryption to perform the pre-commit. In this version, the MITM attacker can read the initial message once the keys are exchanged, even if they did not tamper with anything.
October 2017: Ryan Hileman clean-rooms a similar protocol starting from the security goals. He uses an HMAC to perform the pre-commit, which means that the MITM attacker can no longer obtain the plaintext after the key exchange, if they did not tamper with the key exchange and substitute their own key.
November 2017: In order to resist preimage attacks on the HMAC for low-entropy, Andy Lee uses another set of symmetric keys to encrypt the plaintext. The pre-commit now happens on ciphertexts. In this scheme the legitimate users can authenticate the HMACs before deciding expose their plaintext message contents. Furthermore, the HMAC is done with the hash of the message as the key, in order to be consistent with the specification of HMAC.
December 2017: First public gist.
July 2018: Revision with extra precautions. Instead of directly using symmetric keys, they are passed through a secure hash function first.
Could be a good use for VRF. Also, a digital signature could be used in place of HMACs. Whether or not this is advantageous will explored further.
This protocol is placed in the public domain (CC0).