Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
OTRv4
otrv4_reference_design
Commits
e50e5707
Commit
e50e5707
authored
Nov 25, 2016
by
Fan Jiang
Browse files
use multiplex context instead of ratchet id
parent
0dc27c62
Changes
1
Hide whitespace changes
Inline
Side-by-side
multiplex_double_ratchet.go
0 → 100644
View file @
e50e5707
package
main
import
(
"bytes"
"fmt"
"golang.org/x/crypto/sha3"
"github.com/twstrike/ed448"
)
const
(
Q
=
iota
P1
P2
D
)
type
Msg
struct
{
mtype
int
sender
string
rid
,
mid
int
dh
pubkey
encKey
key
// this is here only to check if we can decrypt
ssid
int
}
func
(
m
Msg
)
decryptWith
(
k
key
)
{
if
!
bytes
.
Equal
(
k
,
m
.
encKey
)
{
panic
(
"failed to decrypt message."
)
}
}
var
c
=
ed448
.
NewCurve
()
type
seckey
[
144
]
byte
type
pubkey
[
56
]
byte
type
key
[]
byte
type
AuthState
int
const
(
AUTHSTATE_NONE
AuthState
=
iota
AUTHSTATE_AWAITING_DRE_AUTH
)
type
keychain
struct
{
our_dh_pub
,
their_dh
pubkey
our_dh_priv
seckey
R
[]
key
Ca
,
Cb
[]
key
rid
,
j
,
k
int
}
type
Entity
struct
{
name
string
previous
*
keychain
current
*
keychain
pending
*
keychain
ssid
int
AuthState
}
func
(
e
*
Entity
)
receive
(
m
Msg
)
{
fmt
.
Println
()
switch
m
.
mtype
{
case
D
:
e
.
receiveData
(
m
)
break
case
Q
:
e
.
receiveQ
(
m
)
break
case
P1
:
e
.
receiveP1
(
m
)
break
case
P2
:
e
.
receiveP2
(
m
)
break
}
}
func
(
e
*
Entity
)
query
()
Msg
{
toSend
:=
Msg
{
mtype
:
Q
,
sender
:
e
.
name
}
fmt
.
Printf
(
"%s
\t
sending Q
\n
"
,
e
.
name
)
return
toSend
}
func
(
e
*
Entity
)
receiveQ
(
m
Msg
)
{
fmt
.
Printf
(
"%s
\t
receive Q
\n
"
,
e
.
name
)
e
.
pending
=
&
keychain
{}
}
func
(
e
*
Entity
)
sendP1
()
Msg
{
e
.
pending
.
our_dh_priv
,
e
.
pending
.
our_dh_pub
,
_
=
c
.
GenerateKeys
()
toSend
:=
Msg
{
P1
,
e
.
name
,
-
1
,
-
1
,
e
.
pending
.
our_dh_pub
,
nil
,
e
.
ssid
+
1
}
fmt
.
Printf
(
"%s
\t
sending P1 %d
\n
"
,
e
.
name
,
toSend
.
ssid
)
e
.
AuthState
=
AUTHSTATE_AWAITING_DRE_AUTH
return
toSend
}
func
(
e
*
Entity
)
receiveP1
(
m
Msg
)
{
fmt
.
Printf
(
"%s
\t
receive P1 %d
\n
"
,
e
.
name
,
m
.
ssid
)
e
.
pending
=
&
keychain
{}
e
.
pending
.
their_dh
=
m
.
dh
}
func
(
e
*
Entity
)
sendP2
()
Msg
{
e
.
pending
.
our_dh_priv
,
e
.
pending
.
our_dh_pub
,
_
=
c
.
GenerateKeys
()
secret
:=
c
.
ComputeSecret
(
e
.
pending
.
our_dh_priv
,
e
.
pending
.
their_dh
)
e
.
pending
.
derive
(
secret
[
:
])
e
.
pending
.
j
=
0
// she will ratchet when sending next
toSend
:=
Msg
{
P2
,
e
.
name
,
-
1
,
-
1
,
e
.
pending
.
our_dh_pub
,
nil
,
e
.
ssid
+
1
}
fmt
.
Printf
(
"%s
\t
sending P2 %d
\n
"
,
e
.
name
,
toSend
.
ssid
)
e
.
AuthState
=
AUTHSTATE_NONE
return
toSend
}
func
(
e
*
Entity
)
receiveP2
(
m
Msg
)
{
fmt
.
Printf
(
"%s
\t
receive P2 %d
\n
"
,
e
.
name
,
m
.
ssid
)
e
.
pending
.
their_dh
=
m
.
dh
secret
:=
c
.
ComputeSecret
(
e
.
pending
.
our_dh_priv
,
e
.
pending
.
their_dh
)
e
.
pending
.
derive
(
secret
[
:
])
e
.
pending
.
j
=
1
// so he does not ratchet
// switch to new keychain
e
.
previous
=
e
.
current
e
.
current
=
e
.
pending
e
.
pending
=
nil
e
.
ssid
=
e
.
ssid
+
1
e
.
AuthState
=
AUTHSTATE_NONE
}
func
(
e
*
Entity
)
receiveData
(
m
Msg
)
{
fmt
.
Printf
(
"%s
\t
receive D %d %d %d
\n
"
,
e
.
name
,
m
.
ssid
,
m
.
rid
,
m
.
mid
)
ck
:=
make
([]
byte
,
64
)
var
kc
*
keychain
if
m
.
ssid
==
e
.
ssid
{
kc
=
e
.
current
}
else
if
m
.
ssid
==
e
.
ssid
+
1
{
fmt
.
Printf
(
"%s
\t
First msg ACK...
\n
"
,
e
.
name
)
// switch to new keychain
e
.
previous
=
e
.
current
e
.
current
=
e
.
pending
e
.
pending
=
nil
e
.
ssid
=
e
.
ssid
+
1
kc
=
e
.
current
}
else
if
m
.
ssid
==
e
.
ssid
-
1
{
kc
=
e
.
previous
}
if
m
.
rid
==
kc
.
rid
+
1
{
fmt
.
Printf
(
"%s
\t
Follow Ratcheting...
\n
"
,
e
.
name
)
kc
.
rid
=
m
.
rid
kc
.
their_dh
=
m
.
dh
secret
:=
c
.
ComputeSecret
(
kc
.
our_dh_priv
,
kc
.
their_dh
)
kc
.
derive
(
secret
[
:
])
kc
.
j
=
0
// need to ratchet next time when send
}
kc
.
k
=
m
.
mid
ck
=
kc
.
retriveChainkey
(
m
.
rid
,
m
.
mid
)
m
.
decryptWith
(
ck
)
}
func
(
e
*
Entity
)
sendData
()
Msg
{
if
e
.
current
==
nil
{
// switch to new keychain
e
.
current
=
e
.
pending
e
.
pending
=
nil
e
.
ssid
=
e
.
ssid
+
1
}
var
cj
key
if
e
.
current
.
j
==
0
{
fmt
.
Printf
(
"%s
\t
Ratcheting...
\n
"
,
e
.
name
)
e
.
current
.
our_dh_priv
,
e
.
current
.
our_dh_pub
,
_
=
c
.
GenerateKeys
()
secret
:=
c
.
ComputeSecret
(
e
.
current
.
our_dh_priv
,
e
.
current
.
their_dh
)
e
.
current
.
rid
+=
1
e
.
current
.
derive
(
secret
[
:
])
}
cj
=
e
.
current
.
retriveChainkey
(
e
.
current
.
rid
,
e
.
current
.
j
)
toSend
:=
Msg
{
D
,
e
.
name
,
e
.
current
.
rid
,
e
.
current
.
j
,
e
.
current
.
our_dh_pub
,
cj
,
e
.
ssid
}
e
.
current
.
j
+=
1
fmt
.
Printf
(
"%s
\t
sending D %d %d %d
\n
"
,
e
.
name
,
toSend
.
ssid
,
toSend
.
rid
,
toSend
.
mid
)
return
toSend
}
func
(
e
*
keychain
)
wasAliceAt
(
rid
int
)
bool
{
return
rid
%
2
==
1
}
func
(
e
*
keychain
)
retriveChainkey
(
rid
,
mid
int
)
key
{
var
ck
key
buf
:=
make
([]
byte
,
64
)
if
e
.
wasAliceAt
(
rid
)
{
ck
=
e
.
Ca
[
rid
]
}
else
{
ck
=
e
.
Cb
[
rid
]
}
copy
(
buf
,
ck
)
for
i
:=
mid
;
i
>
0
;
i
--
{
sha3
.
ShakeSum256
(
buf
,
buf
)
}
return
buf
}
func
(
e
*
keychain
)
derive
(
secret
[]
byte
)
{
r
:=
make
([]
byte
,
64
)
ca
:=
make
([]
byte
,
64
)
cb
:=
make
([]
byte
,
64
)
if
len
(
e
.
R
)
>
e
.
rid
{
secret
=
append
(
secret
,
e
.
R
[
e
.
rid
-
1
]
...
)
}
sha3
.
ShakeSum256
(
r
,
append
(
secret
,
0
))
sha3
.
ShakeSum256
(
ca
,
append
(
secret
,
1
))
sha3
.
ShakeSum256
(
cb
,
append
(
secret
,
2
))
e
.
R
=
append
(
e
.
R
,
r
)
e
.
Ca
=
append
(
e
.
Ca
,
ca
)
e
.
Cb
=
append
(
e
.
Cb
,
cb
)
}
func
main
()
{
var
a
,
b
*
Entity
fmt
.
Println
(
"========================="
)
fmt
.
Println
(
"Testing fresh DAKE"
)
fmt
.
Println
(
"========================="
)
runFreshDAKE
()
fmt
.
Println
(
"========================="
)
fmt
.
Println
(
"Testing sync data message"
)
fmt
.
Println
(
"========================="
)
testSyncDataMessages
(
runFreshDAKE
())
fmt
.
Println
(
"========================="
)
fmt
.
Println
(
"Testing async data message"
)
fmt
.
Println
(
"========================="
)
testAsyncDataMessages
(
runFreshDAKE
())
fmt
.
Println
(
"========================="
)
fmt
.
Println
(
"Testing new sync DAKE"
)
fmt
.
Println
(
"========================="
)
// a sends first, will start a new ratchet
testSyncDataMessages
(
runFreshDAKE
())
a
,
b
=
runFreshDAKE
()
// b sends first, meaning it should start by sending a follow up msg
testSyncDataMessages
(
b
,
a
)
fmt
.
Println
(
"========================="
)
fmt
.
Println
(
"Testing async DAKE message - Late msg is a follow up"
)
fmt
.
Println
(
"========================="
)
a
,
b
=
runFreshDAKE
()
testSyncDataMessages
(
a
,
b
)
//B will send a late msg during a new DAKE.
a
.
receive
(
b
.
sendData
())
//Make sure late msg is a follow up
testAsyncDAKE_AliceReceivesLateMsgFromPreviousDAKE
(
a
,
b
)
testSyncDataMessages
(
a
,
b
)
// Alice should ratchet because she sends first
a
,
b
=
runFreshDAKE
()
testSyncDataMessages
(
a
,
b
)
//B will send a late msg during a new DAKE.
a
.
receive
(
b
.
sendData
())
//Make sure late msg is a follow up
testAsyncDAKE_AliceReceivesLateMsgFromPreviousDAKE
(
a
,
b
)
testSyncDataMessages
(
b
,
a
)
// Bob should not ratchet because he sends first
fmt
.
Println
(
"========================="
)
fmt
.
Println
(
"Testing async DAKE message - Late msg is a new RATCHET"
)
fmt
.
Println
(
"========================="
)
a
,
b
=
runFreshDAKE
()
testSyncDataMessages
(
a
,
b
)
//B will send a late msg during a new DAKE.
b
.
receive
(
a
.
sendData
())
//Make sure late msg is a new RATCHET
testAsyncDAKE_AliceReceivesLateMsgFromPreviousDAKE
(
a
,
b
)
testSyncDataMessages
(
a
,
b
)
// Alice should ratchet because she sends first
a
,
b
=
runFreshDAKE
()
testSyncDataMessages
(
a
,
b
)
//B will send a late msg during a new DAKE.
b
.
receive
(
a
.
sendData
())
//Make sure late msg is a new RATCHET
testAsyncDAKE_AliceReceivesLateMsgFromPreviousDAKE
(
a
,
b
)
testSyncDataMessages
(
b
,
a
)
// Bob should not ratchet because he sends first
fmt
.
Println
(
"========================="
)
fmt
.
Println
(
"Testing async DAKE message - Alice receive late after she ratchet"
)
fmt
.
Println
(
"========================="
)
a
,
b
=
runFreshDAKE
()
testSyncDataMessages
(
a
,
b
)
//B will send a late msg during a new DAKE.
a
.
receive
(
b
.
sendData
())
//Make sure late msg is a follow up
testAsyncDAKE_AliceReceivesLateMsgFromPreviousDAKEAfterSheRatchetsAgain
(
a
,
b
)
testSyncDataMessages
(
a
,
b
)
// Alice should ratchet because she sends first
a
,
b
=
runFreshDAKE
()
testSyncDataMessages
(
a
,
b
)
//B will send a late msg during a new DAKE.
a
.
receive
(
b
.
sendData
())
//Make sure late msg is a new RATCHET
testAsyncDAKE_BobSendP1ButAliceNeverRecieveP1
(
a
,
b
)
testSyncDataMessages
(
a
,
b
)
// Alice should ratchet because she sends first
fmt
.
Println
(
"========================="
)
fmt
.
Println
(
"Testing async DAKE message - RATCHET over DAKE"
)
fmt
.
Println
(
"========================="
)
a
,
b
=
runFreshDAKE
()
testSyncDataMessages
(
a
,
b
)
//B will send a late msg during a new DAKE.
a
.
receive
(
b
.
sendData
())
//Make sure late msg is a follow up
testAsyncDAKE_AliceReceivesLateNewRathcetMsgFromPreviousDAKE
(
a
,
b
)
testSyncDataMessages
(
a
,
b
)
// Alice should ratchet because she sends first
a
,
b
=
runFreshDAKE
()
testSyncDataMessages
(
a
,
b
)
//B will send a late msg during a new DAKE.
a
.
receive
(
b
.
sendData
())
//Make sure late msg is a new RATCHET
testAsyncDAKE_AliceReceivesLateNewRathcetMsgFromPreviousDAKE
(
a
,
b
)
testSyncDataMessages
(
a
,
b
)
// Alice should ratchet because she sends first
//
// OLD TEST
//
a
,
b
=
initialize
()
b
.
receive
(
a
.
query
())
a
.
receive
(
b
.
sendP1
())
b
.
receive
(
a
.
sendP2
())
fmt
.
Println
(
"========================="
)
fmt
.
Println
(
"Testing sync data message"
)
fmt
.
Println
(
"========================="
)
a
.
receive
(
b
.
sendData
())
// b sends first, so no new ratchet happens.
a
.
receive
(
b
.
sendData
())
// b again: this is another follow up msg.
b
.
receive
(
a
.
sendData
())
// a sends, a new ratchet happens and bob follows.
b
.
receive
(
a
.
sendData
())
// a again: this is a follow up.
fmt
.
Println
(
"========================="
)
fmt
.
Println
(
"Testing async data message"
)
fmt
.
Println
(
"========================="
)
m1
:=
a
.
sendData
()
// a sends again: another follow up message.
m2
:=
b
.
sendData
()
// b sends now, a new ratcher happens for bob.
m3
:=
a
.
sendData
()
// a sends again: another follow up message.
b
.
receive
(
m1
)
// b receives follow up message from a previous ratchet.
b
.
receive
(
m3
)
// b receives follow up message from a previous ratchet.
a
.
receive
(
m2
)
// a receives a message from a new ratchet. She follows the ratchet.
fmt
.
Println
(
"========================="
)
fmt
.
Println
(
"Testing new sync DAKE"
)
fmt
.
Println
(
"========================="
)
b
.
receive
(
a
.
query
())
a
.
receive
(
b
.
sendP1
())
b
.
receive
(
a
.
sendP2
())
b
.
receive
(
a
.
sendData
())
// a sends, a new ratchet starts and bob follows
b
.
receive
(
a
.
sendData
())
// a sends a follow up
a
.
receive
(
b
.
sendData
())
// b sends, a new ratchet starts and alice follows
a
.
receive
(
b
.
sendData
())
// b sends a follow up
fmt
.
Println
(
"========================="
)
fmt
.
Println
(
"Testing async DAKE message"
)
fmt
.
Println
(
"========================="
)
a
.
receive
(
b
.
sendData
())
// make sure b0 is a follow up
b
.
receive
(
a
.
query
())
p1
:=
b
.
sendP1
()
b0
:=
b
.
sendData
()
// bob sends a data message during a new DAKE, is this a follow up msg?
b1
:=
b
.
sendData
()
// bob sends a data message during a new DAKE - surely a follow up msg.
//FIXME
b
.
receive
(
a
.
sendData
())
// a sends a new message before she receives p1, but after bob sends p1.
// this will be a new ratchet, and thats a problem because bob will also ratchet when sending p1.
a
.
receive
(
p1
)
// a receives p1
p2
:=
a
.
sendP2
()
// ... and immediately replies with a p2
a0
:=
a
.
sendData
()
// ... and send a new data msg
b
.
receive
(
p2
)
// bob receives a p2
b
.
receive
(
a0
)
// and the a0
a
.
receive
(
b0
)
// a receives b0 (I want to see how it works if she receives this BEFORE sending a0)
a
.
receive
(
b1
)
// a receives b1
// After delayed messages, happy path
a
.
receive
(
b
.
sendData
())
// b sends, a new ratchet starts and alice follows
a
.
receive
(
b
.
sendData
())
// b sends a follow up
b
.
receive
(
a
.
sendData
())
// a sends, a new ratchet starts and bob follows
b
.
receive
(
a
.
sendData
())
// a sends a follow up
}
func
initialize
()
(
alice
,
bob
*
Entity
)
{
alice
=
new
(
Entity
)
bob
=
new
(
Entity
)
alice
.
name
=
"Alice"
bob
.
name
=
"Bob"
return
}
func
runFreshDAKE
()
(
a
,
b
*
Entity
)
{
return
testSyncDAKE
(
initialize
())
}
func
testSyncDAKE
(
a
,
b
*
Entity
)
(
*
Entity
,
*
Entity
)
{
b
.
receive
(
a
.
query
())
a
.
receive
(
b
.
sendP1
())
b
.
receive
(
a
.
sendP2
())
return
a
,
b
}
func
testSyncDataMessages
(
a
,
b
*
Entity
)
{
a
.
receive
(
b
.
sendData
())
// b sends first, so no new ratchet happens.
a
.
receive
(
b
.
sendData
())
// b again: this is another follow up msg.
b
.
receive
(
a
.
sendData
())
// a sends, a new ratchet happens and bob follows.
b
.
receive
(
a
.
sendData
())
// a again: this is a follow up.
}
func
testAsyncDataMessages
(
a
,
b
*
Entity
)
{
b
.
receive
(
a
.
sendData
())
// enforce m1 is a follow up
m1
:=
a
.
sendData
()
// a sends again: another follow up message.
m2
:=
b
.
sendData
()
// b sends now, a new ratcher happens for bob.
m3
:=
a
.
sendData
()
// a sends again: another follow up message.
b
.
receive
(
m1
)
// b receives follow up message from a previous ratchet.
b
.
receive
(
m3
)
// b receives follow up message from a previous ratchet.
a
.
receive
(
m2
)
// a receives a message from a new ratchet. She follows the ratchet.
}
// NOTE The late message may or may not be a follow up.
// NOTE Bob does not receive any message after starting the DAKE.
// NOTE Bob does not receive any late messages after both finish the DAKE.
func
testAsyncDAKE_AliceReceivesLateMsgFromPreviousDAKE
(
a
,
b
*
Entity
)
{
b
.
receive
(
a
.
query
())
p1
:=
b
.
sendP1
()
// Bob sends a message which wiill be delivered late. It can be a follow up or not.
late
:=
b
.
sendData
()
// NOTE Bob does not receive any message after starting the DAKE.
a
.
receive
(
p1
)
// a receives p1
p2
:=
a
.
sendP2
()
// ... and immediately replies with a p2. The DAKE finishes for Alice.
// Alice receives the late message after finishing the DAKE
a
.
receive
(
late
)
// AKE finishes for Bob.
b
.
receive
(
p2
)
// NOTE Bob does not receive any late messages from Alice.
// This can only happen if she do not receive P1.
}
// NOTE The late message may or may not be a follow up.
// NOTE Bob does not receive any message after starting the DAKE.
// NOTE Bob does not receive any late messages after both finish the DAKE.
// NOTE Alice will start a NEW ratchet before reeives the late message.
func
testAsyncDAKE_AliceReceivesLateMsgFromPreviousDAKEAfterSheRatchetsAgain
(
a
,
b
*
Entity
)
{
b
.
receive
(
a
.
query
())
p1
:=
b
.
sendP1
()
// Bob sends a message which wiill be delivered late. It can be a follow up or not.
late
:=
b
.
sendData
()
b
.
receive
(
a
.
sendData
())
// Alice starts a NEW ratchet.
// NOTE Bob does not receive any message after starting the DAKE.
a
.
receive
(
p1
)
// a receives p1
p2
:=
a
.
sendP2
()
// ... and immediately replies with a p2. The DAKE finishes for Alice.
late_from_receiver
:=
a
.
sendData
()
// This should make Alice ratchet
// Alice receives the late message after finishing the DAKE
a
.
receive
(
late
)
// AKE finishes for Bob.
b
.
receive
(
p2
)
b
.
receive
(
late_from_receiver
)
// NOTE Bob does not receive any late messages from Alice.
// This can only happen if she do not receive P1.
}
//NOTE currently with the solution of not ratcheting when you are in AWAITING_DRE_AUTH
//NOTE can open a space to Malory to deny Bob to use new P1
func
testAsyncDAKE_BobSendP1ButAliceNeverRecieveP1
(
a
,
b
*
Entity
)
{
b
.
receive
(
a
.
query
())
p1
:=
b
.
sendP1
()
// Bob sends a message which will be delivered late. It can be a follow up or not.
late
:=
b
.
sendData
()
b
.
receive
(
a
.
sendData
())
// Alice starts a NEW ratchet.
// NOTE Bob does not receive any message after starting the DAKE.
a
.
receive
(
p1
)
// a receives p1
b
.
receive
(
a
.
sendP2
())
b
.
receive
(
a
.
sendData
())
a
.
receive
(
late
)
ridOfBob
:=
b
.
current
.
rid
b
.
receive
(
a
.
query
())
b
.
sendP1
()
a
.
receive
(
b
.
sendData
())
a
.
receive
(
b
.
sendData
())
b
.
receive
(
a
.
sendData
())
b
.
receive
(
a
.
sendData
())
a
.
receive
(
b
.
sendData
())
a
.
receive
(
b
.
sendData
())
if
b
.
current
.
rid
<=
ridOfBob
{
panic
(
"bob should ratchet even when alice not receiving p1"
)
}
// NOTE Bob does not receive any late messages from Alice.
// This can only happen if she do not receive P1.
}
func
testAsyncDAKE_AliceReceivesLateNewRathcetMsgFromPreviousDAKE
(
a
,
b
*
Entity
)
{
b
.
receive
(
a
.
query
())
p1
:=
b
.
sendP1
()
late
:=
b
.
sendData
()
// Bob sends late. Can be NEW ratchet or follow up.
b
.
receive
(
a
.
sendData
())
// Bob receives from Alice. If "late" is a follow up, this is a NEW ratchet. This is a follow up otherwise.
late2
:=
b
.
sendData
()
// Bob sends late2. This is always a NEW dake (he has just receive something from Alice).
b
.
receive
(
a
.
sendData
())
// Alice sends a follow up (she hasnt received anything from Bob), since her last message.
a
.
receive
(
p1
)
// a receives p1
p2
:=
a
.
sendP2
()
// ... and immediately replies with a p2. The DAKE finishes for Alice.
// AKE finishes for Bob.
b
.
receive
(
p2
)
// Alice receives the late message after finishing the DAKE
a
.
receive
(
late
)
a
.
receive
(
late2
)
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment