init
This commit is contained in:
4
verifpal/README.md
Normal file
4
verifpal/README.md
Normal file
@@ -0,0 +1,4 @@
|
||||
Models in this folder:
|
||||
- `olm-fs-violation.vp`: demonstrating an explicit attack trace for Olm pre-key message secrecy violation in the case pre-keys remain unsigned by the responder
|
||||
- `olm-fs`: demonstrating Olm with pre-key signing retains secrecy, authentication, and perfect forward secrecy
|
||||
- `signal.vp`: A reference model from the original [Verifpal paper](https://eprint.iacr.org/2019/971.pdf). Attribution is at the header of the model.
|
||||
121
verifpal/olm-fs-violation.vp
Normal file
121
verifpal/olm-fs-violation.vp
Normal file
@@ -0,0 +1,121 @@
|
||||
// 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
|
||||
]
|
||||
116
verifpal/olm-fs.vp
Normal file
116
verifpal/olm-fs.vp
Normal file
@@ -0,0 +1,116 @@
|
||||
// proving authentication, confidentiality, and forward secrecy of Olm.
|
||||
// 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_ot_sig = SIGN(bob_private, bob_ot_public) // OPTIONAL
|
||||
]
|
||||
|
||||
Bob -> Alice: [bob_public], bob_ot_public, bob_ot_sig
|
||||
|
||||
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
|
||||
alice_ot_sig = SIGN(alice_private, alice_ot_public) // OPTIONAL
|
||||
|
||||
knows public c0, c1, c2, c3, c4
|
||||
_ = SIGNVERIF(bob_public, bob_ot_public, bob_ot_sig)?
|
||||
|
||||
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, alice_ot_sig, ta1_public, ta1_sig, xa1, xa1_sig
|
||||
|
||||
principal Bob[
|
||||
_ = SIGNVERIF(alice_public, xa1, xa1_sig)
|
||||
_ = SIGNVERIF(alice_public, alice_ot_public, alice_ot_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(rb1, 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))
|
||||
]
|
||||
|
||||
Bob -> Alice: xb2, tb2_public
|
||||
|
||||
principal Alice[
|
||||
// derive new root key
|
||||
ra2, ca2 = HKDF(ra1, 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))
|
||||
]
|
||||
|
||||
principal Bob[leaks bob_private]
|
||||
|
||||
// all four queries verify
|
||||
queries[
|
||||
confidentiality? ma1
|
||||
authentication? Alice -> Bob: xa1
|
||||
confidentiality? ma2
|
||||
authentication? Bob -> Alice: xb2
|
||||
]
|
||||
102
verifpal/signal.vp
Normal file
102
verifpal/signal.vp
Normal file
@@ -0,0 +1,102 @@
|
||||
// SPDX-FileCopyrightText: © 2019-2022 Nadim Kobeissi <nadim@symbolic.software>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
// (included in our artifact as a reference model)
|
||||
|
||||
attacker[active]
|
||||
|
||||
principal Alice[
|
||||
knows private alongterm
|
||||
galongterm = G^alongterm
|
||||
]
|
||||
|
||||
principal Bob[
|
||||
knows private blongterm, bs
|
||||
generates bo
|
||||
gblongterm = G^blongterm
|
||||
gbs = G^bs
|
||||
gbo = G^bo
|
||||
gbssig = SIGN(blongterm, gbs)
|
||||
]
|
||||
|
||||
Bob -> Alice: [gblongterm], gbssig, gbs, gbo
|
||||
|
||||
principal Alice[
|
||||
generates ae1
|
||||
gae1 = G^ae1
|
||||
amaster = HASH(gbs^alongterm, gblongterm^ae1, gbs^ae1, gbo^ae1)
|
||||
arkba1, ackba1 = HKDF(amaster, nil, nil)
|
||||
]
|
||||
|
||||
principal Alice[
|
||||
generates m1, ae2
|
||||
gae2 = G^ae2
|
||||
_ = SIGNVERIF(gblongterm, gbs, gbssig)?
|
||||
akshared1 = gbs^ae2
|
||||
arkab1, ackab1 = HKDF(akshared1, arkba1, nil)
|
||||
akenc1, _ = HKDF(MAC(ackab1, nil), nil, nil)
|
||||
e1 = AEAD_ENC(akenc1, m1, HASH(galongterm, gblongterm, gae2))
|
||||
]
|
||||
|
||||
Alice -> Bob: [galongterm], gae1, gae2, e1
|
||||
|
||||
principal Bob[
|
||||
bmaster = HASH(galongterm^bs, gae1^blongterm, gae1^bs, gae1^bo)
|
||||
brkba1, bckba1 = HKDF(bmaster, nil, nil)
|
||||
]
|
||||
|
||||
principal Bob[
|
||||
bkshared1 = gae2^bs
|
||||
brkab1, bckab1 = HKDF(bkshared1, brkba1, nil)
|
||||
bkenc1, bkenc2 = HKDF(MAC(bckab1, nil), nil, nil)
|
||||
m1_d = AEAD_DEC(bkenc1, e1, HASH(galongterm, gblongterm, gae2))
|
||||
]
|
||||
|
||||
principal Bob[
|
||||
generates m2, be
|
||||
gbe = G^be
|
||||
bkshared2 = gae2^be
|
||||
brkba2, bckba2 = HKDF(bkshared2, brkab1, nil)
|
||||
bkenc3, bkenc4 = HKDF(MAC(bckba2, nil), nil, nil)
|
||||
e2 = AEAD_ENC(bkenc3, m2, HASH(gblongterm, galongterm, gbe))
|
||||
]
|
||||
|
||||
Bob -> Alice: gbe, e2
|
||||
|
||||
principal Alice[
|
||||
akshared2 = gbe^ae2
|
||||
arkba2, ackba2 = HKDF(akshared2, arkab1, nil)
|
||||
akenc3, akenc4 = HKDF(MAC(ackba2, nil), nil, nil)
|
||||
m2_d = AEAD_DEC(akenc3, e2, HASH(gblongterm, galongterm, gbe))
|
||||
]
|
||||
|
||||
// principal Alice[
|
||||
// generates m3, ae3
|
||||
// gae3 = G^ae3
|
||||
// akshared3 = gbe^ae3
|
||||
// arkab3, ackab3 = HKDF(akshared3, arkba2, nil)
|
||||
// akenc5, akenc6 = HKDF(MAC(ackab3, nil), nil, nil)
|
||||
// e3 = AEAD_ENC(akenc5, m3, HASH(gblongterm, galongterm, gae3))
|
||||
// ]
|
||||
|
||||
// Alice -> Bob: gae3, e3
|
||||
|
||||
// principal Bob[
|
||||
// bkshared3 = gae3^be
|
||||
// brkab3, bckab3 = HKDF(bkshared3, brkba2, nil)
|
||||
// bkenc5, bkenc6 = HKDF(MAC(bckab3, nil), nil, nil)
|
||||
// m3_d = AEAD_DEC(bkenc5, e3, HASH(gblongterm, galongterm, gae3))
|
||||
// ]
|
||||
|
||||
phase[1]
|
||||
|
||||
principal Alice[leaks alongterm]
|
||||
principal Bob[leaks blongterm]
|
||||
|
||||
queries[
|
||||
confidentiality? m1
|
||||
authentication? Alice -> Bob: e1
|
||||
confidentiality? m2
|
||||
authentication? Bob -> Alice: e2
|
||||
// confidentiality? m3
|
||||
// authentication? Alice -> Bob: e3
|
||||
]
|
||||
Reference in New Issue
Block a user