122 lines
3.4 KiB
Plaintext
122 lines
3.4 KiB
Plaintext
// Violation of forward secrecy without prekey signing
|
|
// closely follows: https://gitlab.matrix.org/matrix-org/olm/blob/master/docs/olm.md
|
|
// signage is discussed here: https://gitlab.matrix.org/matrix-org/olm/-/blob/master/docs/signing.md
|
|
attacker[active]
|
|
|
|
principal Bob[
|
|
// initialize private key, ot key
|
|
generates bob_private, bob_ot_private
|
|
bob_ot_public = G^bob_ot_private
|
|
bob_public = G^bob_private
|
|
]
|
|
|
|
Bob -> Alice: [bob_public], bob_ot_public
|
|
|
|
principal Alice[
|
|
// initialize private key, ot key
|
|
generates alice_private, alice_ot_private
|
|
alice_ot_public = G^alice_ot_private
|
|
alice_public = G^alice_private
|
|
|
|
knows public c0, c1, c2, c3, c4
|
|
|
|
k1a = bob_public^alice_private
|
|
k2a = bob_ot_public^alice_private
|
|
k3a = bob_public^alice_ot_private
|
|
|
|
// derive the master secret
|
|
sa = HASH(k1a, k2a, k3a, bob_public, alice_public)
|
|
|
|
// create the root and chain key from the 3DH'ed secret
|
|
ra1, ca1 = HKDF(sa, c1, c2)
|
|
|
|
// create ratchet key
|
|
generates ta1_private
|
|
ta1_public = G^ta1_private
|
|
ta1_sig = SIGN(alice_private, ta1_public)
|
|
|
|
// computing the first message key
|
|
mak1 = MAC(ca1, c3)
|
|
|
|
// ciphertext
|
|
generates ma1
|
|
xa1 = AEAD_ENC(mak1, ma1, CONCAT(alice_public, bob_public))
|
|
|
|
// signage not specified
|
|
xa1_sig = SIGN(alice_private, xa1)
|
|
]
|
|
|
|
// in the implementation we'd include a chain index, but since this is a model we do not
|
|
Alice -> Bob: [alice_public], alice_ot_public, ta1_public, ta1_sig, xa1, xa1_sig
|
|
|
|
principal Bob[
|
|
_ = SIGNVERIF(alice_public, xa1, xa1_sig)
|
|
_ = SIGNVERIF(alice_public, ta1_public, ta1_sig)?
|
|
|
|
k1b = alice_public^bob_private
|
|
k2b = alice_public^bob_ot_private
|
|
k3b = alice_ot_public^bob_private
|
|
|
|
// derive master
|
|
knows public c0, c1, c2, c3, c4
|
|
sb = HASH(k1b, k2b, k3b, bob_public, alice_public)
|
|
|
|
// derive root and chain
|
|
rb1, cb1 = HKDF(sb, c1, c2)
|
|
|
|
// create bob's initial message key
|
|
mbk1 = MAC(cb1, c3)
|
|
|
|
// decrypt
|
|
mb1 = AEAD_DEC(mbk1, xa1, CONCAT(alice_public, bob_public))
|
|
|
|
// now, bob wants to send a message back and advances the ratchet
|
|
|
|
// generate new ratchet key
|
|
generates tb2_private
|
|
tb2_public = G^tb2_private
|
|
tb2_sig = SIGN(bob_private, tb2_public)
|
|
|
|
// advance the ratchet using prev root key, other ratchet stuff
|
|
rb2, cb2 = HKDF(MAC(rb1, c3), ta1_public^tb2_private, c3)
|
|
|
|
// create message key
|
|
mbk2 = MAC(cb2, c3)
|
|
|
|
// ciphertext
|
|
generates mb2
|
|
xb2 = AEAD_ENC(mbk2, mb2, CONCAT(alice_public, bob_public))
|
|
|
|
// signage not specified
|
|
xb2_sig = SIGN(bob_private, xb2)
|
|
]
|
|
|
|
Bob -> Alice: xb2, xb2_sig, tb2_public, tb2_sig
|
|
|
|
principal Alice[
|
|
_ = SIGNVERIF(bob_public, xb2, xb2_sig)?
|
|
_ = SIGNVERIF(bob_public, tb2_public, tb2_sig)?
|
|
// derive new root key
|
|
ra2, ca2 = HKDF(MAC(ra1, c3), tb2_public^ta1_private, c3)
|
|
|
|
// derive new message key from the chain key
|
|
mak2 = MAC(ca2, c3)
|
|
|
|
// decrypt
|
|
ma2 = AEAD_DEC(mak2, xb2, CONCAT(alice_public, bob_public))
|
|
]
|
|
|
|
// phase[1]
|
|
principal Bob[leaks bob_private]
|
|
// principal Alice[leaks alice_private]
|
|
|
|
// first two queries violate, while the second two do not
|
|
// first two queries take a few seconds to violate, while the second two
|
|
// take a full exploration to confirm
|
|
queries[
|
|
// confidentiality? ma1
|
|
// authentication? Alice -> Bob: xa1
|
|
confidentiality? ma2
|
|
// authentication? Bob -> Alice: xb2
|
|
]
|