Skip to content

Commit c94143c

Browse files
committed
Add more pieces of the DAKE
1 parent 9bd027b commit c94143c

13 files changed

+568
-34
lines changed

Gopkg.lock

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

constants.go

+2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ const (
66

77
const (
88
messageTypeIdentityMessage = uint8(0x35)
9+
messageTypeAuthRMessage = uint8(0x36)
10+
messageTypeAuthIMessage = uint8(0x37)
911
)
1012

1113
const (

conversation.go

+108-7
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package gotra
22

33
import (
44
"bytes"
5+
"fmt"
56
"io"
67

78
"github.com/coyim/gotrax"
@@ -11,6 +12,14 @@ type conversation struct {
1112
r io.Reader
1213
longTerm *gotrax.Keypair
1314
otherInstanceTag uint32
15+
16+
im *identityMessage
17+
imp *identityMessagePrivate
18+
ar *authRMessage
19+
arp *authRMessagePrivate
20+
ai *authIMessage
21+
22+
state convState
1423
}
1524

1625
// TODO: for all these functions, if we're currently in OTRv3 we should fall back to an otr3 conversation
@@ -41,12 +50,21 @@ func isIdentityMessage(m ValidMessage) bool {
4150
return bytes.HasPrefix(m, append(gotrax.AppendShort(nil, version), messageTypeIdentityMessage))
4251
}
4352

53+
func isAuthRMessage(m ValidMessage) bool {
54+
// TODO: make this work correctly
55+
return bytes.HasPrefix(m, append(gotrax.AppendShort(nil, version), messageTypeAuthRMessage))
56+
}
57+
58+
func isAuthIMessage(m ValidMessage) bool {
59+
// TODO: make this work correctly
60+
return bytes.HasPrefix(m, append(gotrax.AppendShort(nil, version), messageTypeAuthIMessage))
61+
}
62+
4463
func (c *conversation) processQueryMessage(m ValidMessage) (plain MessagePlaintext, toSend []ValidMessage, err error) {
4564
// TODO:
4665
// if the message is 4 and we allow 4
47-
// transition to waitingAuthR
48-
// return an identity message
4966

67+
c.state = stateWaitingAuthR{}
5068
return nil, []ValidMessage{c.createIdentityMessage()}, nil
5169
}
5270

@@ -74,9 +92,85 @@ func (c *conversation) processIdentityMessage(m ValidMessage) (plain MessagePlai
7492

7593
c.fixInstanceTag(im.senderInstanceTag)
7694

77-
// Transition to the WAITING_AUTH_I state.
95+
c.im = im
96+
97+
c.state = stateWaitingAuthI{}
7898

79-
return nil, []ValidMessage{c.createAuthRMessage(im)}, nil
99+
return nil, []ValidMessage{c.createAuthRMessage()}, nil
100+
}
101+
102+
func (c *conversation) processAuthRMessage(m ValidMessage) (plain MessagePlaintext, toSend []ValidMessage, err error) {
103+
// TODO:
104+
// - If the state is WAITING_AUTH_R:
105+
// - If the receiver's instance tag in the message is not the sender's instance tag you are currently using, ignore the message.
106+
// - Validate the Auth-R message.
107+
// - If validation fails:
108+
// - Ignore the message.
109+
// - Stay in state WAITING_AUTH_R.
110+
// - If validation succeeds:
111+
// - Reply with an Auth-I message, as defined in Sending an Auth-I Message section.
112+
// - If the state is ENCRYPTED_MESSAGES:
113+
// - If this Auth-R message is the same one you received earlier:
114+
// - Retransmit your Auth-I Message.
115+
// - Otherwise:
116+
// - Ignore the message.
117+
// - If the state is not WAITING_AUTH_R:
118+
// - Ignore this message.
119+
120+
arm := &authRMessage{}
121+
_, ok := arm.deserialize(m)
122+
if !ok {
123+
// Ignore the message
124+
return nil, nil, nil
125+
}
126+
127+
verr := arm.validate(c.getInstanceTag())
128+
if verr != nil {
129+
// Ignore the message
130+
return nil, nil, nil
131+
}
132+
133+
c.ar = arm
134+
c.state = stateWaitingDakeDataMessage{}
135+
136+
return nil, []ValidMessage{c.createAuthIMessage()}, nil
137+
}
138+
139+
func (c *conversation) processAuthIMessage(m ValidMessage) (plain MessagePlaintext, toSend []ValidMessage, err error) {
140+
// TODO:
141+
// If the state is WAITING_AUTH_I:
142+
// If the receiver's instance tag in the message is not the sender's instance tag you are currently using, ignore this message.
143+
// Validate the Auth-I message.
144+
// If validation fails:
145+
// Ignore the message.
146+
// Stay in state WAITING_AUTH_I.
147+
// If validation succeeds:
148+
// Transition to state ENCRYPTED_MESSAGES.
149+
// Initialize the double ratcheting, as defined in the Interactive DAKE Overview section.
150+
// Send a regular Data Message. If a plaintext message is waiting to be sent, this can be used. Otherwise an empty heartbeat message should be sent. This data message is called "DAKE Data Message".
151+
// If there are stored Data Messages, remove them from storage - there is no way these messages can be valid for the current DAKE.
152+
// If the state is not WAITING_AUTH_I:
153+
// - Ignore this message.
154+
155+
aim := &authIMessage{}
156+
_, ok := aim.deserialize(m)
157+
if !ok {
158+
// Ignore the message
159+
return nil, nil, nil
160+
}
161+
162+
verr := aim.validate(c.getInstanceTag())
163+
if verr != nil {
164+
// Ignore the message
165+
return nil, nil, nil
166+
}
167+
168+
c.ai = aim
169+
170+
// TODO: initialize double ratchet here
171+
c.state = stateEncrypted{}
172+
173+
return nil, []ValidMessage{c.createHeartbeatDataMessage()}, nil
80174
}
81175

82176
func (c *conversation) Receive(m ValidMessage) (plain MessagePlaintext, toSend []ValidMessage, err error) {
@@ -90,12 +184,19 @@ func (c *conversation) Receive(m ValidMessage) (plain MessagePlaintext, toSend [
90184
return c.processIdentityMessage(m)
91185
}
92186

187+
if isAuthRMessage(m) {
188+
return c.processAuthRMessage(m)
189+
}
190+
191+
if isAuthIMessage(m) {
192+
return c.processAuthIMessage(m)
193+
}
194+
195+
fmt.Printf("TODO: hit a place where we need to continue...\n")
196+
93197
// - plaintext without tag
94198
// - plaintext with tag
95199
// - error message
96-
// - identity message
97-
// - auth-r message
98-
// - auth-i message
99200
// - non-interactive auth message
100201
// - dake data message
101202
// - data message

dake.go

+107-5
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,40 @@ package gotra
22

33
import (
44
"github.com/coyim/gotrax"
5+
"github.com/otrv4/ed448"
56
)
67

78
type identityMessage struct {
89
senderInstanceTag uint32
910
receiverInstanceTag uint32
1011
clientProfile *gotrax.ClientProfile
11-
y *gotrax.PublicKey
12+
y ed448.Point
1213
b *dhPublicKey
1314
}
1415

16+
type identityMessagePrivate struct {
17+
y *gotrax.Keypair
18+
b *dhKeypair
19+
}
20+
1521
type authRMessage struct {
1622
senderInstanceTag uint32
1723
receiverInstanceTag uint32
1824
clientProfile *gotrax.ClientProfile
19-
x *gotrax.PublicKey
25+
x ed448.Point
2026
a *dhPublicKey
21-
// sigma
27+
sigma *gotrax.RingSignature
28+
}
29+
30+
type authRMessagePrivate struct {
31+
x *gotrax.Keypair
32+
a *dhKeypair
33+
}
34+
35+
type authIMessage struct {
36+
senderInstanceTag uint32
37+
receiverInstanceTag uint32
38+
sigma *gotrax.RingSignature
2239
}
2340

2441
func (c *conversation) createIdentityMessage() ValidMessage {
@@ -31,10 +48,12 @@ func (c *conversation) createIdentityMessage() ValidMessage {
3148
senderInstanceTag: itag,
3249
receiverInstanceTag: uint32(0x00),
3350
clientProfile: cp,
34-
y: ykp.Pub,
51+
y: ykp.Pub.K(),
3552
b: bkp.pub,
3653
}
3754

55+
c.im = im
56+
c.imp = &identityMessagePrivate{y: ykp, b: bkp}
3857
return ValidMessage(im.serialize())
3958
}
4059

@@ -47,6 +66,89 @@ func (m *identityMessage) validate(tag uint32) error {
4766
return nil
4867
}
4968

50-
func (c *conversation) createAuthRMessage(im *identityMessage) ValidMessage {
69+
func (c *conversation) createAuthRMessage() ValidMessage {
70+
cp := c.getValidClientProfile()
71+
itag := c.getInstanceTag()
72+
xkp := gotrax.GenerateKeypair(c)
73+
akp, _ := generateDHKeypair(c)
74+
75+
ar := &authRMessage{
76+
senderInstanceTag: itag,
77+
receiverInstanceTag: c.im.senderInstanceTag,
78+
clientProfile: cp,
79+
x: xkp.Pub.K(),
80+
a: akp.pub,
81+
}
82+
83+
// TODO: figure out a real phi
84+
phi := []byte{}
85+
86+
t := []byte{0x00}
87+
t = append(t, gotrax.Kdf(usageAuthRBobClientProfile, 64, c.im.clientProfile.Serialize())...)
88+
t = append(t, gotrax.Kdf(usageAuthRAliceClientProfile, 64, cp.Serialize())...)
89+
t = append(t, gotrax.SerializePoint(c.im.y)...)
90+
t = append(t, xkp.Pub.Serialize()...)
91+
t = append(t, c.im.b.serialize()...)
92+
t = append(t, akp.pub.serialize()...)
93+
t = append(t, gotrax.Kdf(usageAuthRPhi, 64, phi)...)
94+
95+
longTerm := c.getKeypair()
96+
yk := gotrax.CreatePublicKey(c.im.y, gotrax.Ed448Key)
97+
98+
// TODO: don't ignore this error
99+
ar.sigma, _ = gotrax.GenerateSignature(c, longTerm.Priv, longTerm.Pub, c.im.clientProfile.PublicKey, longTerm.Pub, yk, t, gotrax.Kdf, usageAuth)
100+
101+
c.ar = ar
102+
c.arp = &authRMessagePrivate{x: xkp, a: akp}
103+
return ValidMessage(ar.serialize())
104+
}
105+
106+
func (m *authRMessage) validate(tag uint32) error {
107+
// TODO: implement
108+
// Check that the receiver's instance tag matches your sender's instance tag.
109+
// Validate the Client Profile as defined in Validating a Client Profile section. Extract H_a from it.
110+
// Verify that the point X received is on curve Ed448. See Verifying that a point is on the curve section for details.
111+
// Verify that the DH public key A is from the correct group. See Verifying that an integer is in the DH group section for details.
112+
// Compute t = 0x0 || KDF_1(usageAuthRBobClientProfile || Bob_Client_Profile, 64) || KDF_1(usageAuthRAliceClientProfile || Alice_Client_Profile, 64) || Y || X || B || A || KDF_1(usageAuthRPhi || phi, 64). phi is the shared session state as mention in its section.
113+
// Verify the sigma as defined in Ring Signature Authentication.
114+
115+
return nil
116+
}
117+
118+
func (c *conversation) createAuthIMessage() ValidMessage {
119+
cp := c.getValidClientProfile()
120+
itag := c.getInstanceTag()
121+
122+
ai := &authIMessage{
123+
senderInstanceTag: itag,
124+
receiverInstanceTag: c.ar.senderInstanceTag,
125+
}
126+
127+
// TODO: figure out a real phi
128+
phi := []byte{}
129+
130+
t := []byte{0x01}
131+
t = append(t, gotrax.Kdf(usageAuthIBobClientProfile, 64, cp.Serialize())...)
132+
t = append(t, gotrax.Kdf(usageAuthIAliceClientProfile, 64, c.ar.clientProfile.Serialize())...)
133+
t = append(t, gotrax.SerializePoint(c.im.y)...)
134+
t = append(t, gotrax.SerializePoint(c.ar.x)...)
135+
t = append(t, c.im.b.serialize()...)
136+
t = append(t, c.ar.a.serialize()...)
137+
t = append(t, gotrax.Kdf(usageAuthIPhi, 64, phi)...)
138+
139+
longTerm := c.getKeypair()
140+
141+
// TODO: don't ignore this error
142+
ai.sigma, _ = gotrax.GenerateSignature(c, longTerm.Priv, longTerm.Pub, longTerm.Pub, c.ar.clientProfile.PublicKey, gotrax.CreatePublicKey(c.ar.x, gotrax.Ed448Key), t, gotrax.Kdf, usageAuth)
143+
144+
c.ai = ai
145+
return ValidMessage(ai.serialize())
146+
}
147+
148+
func (m *authIMessage) validate(tag uint32) error {
149+
// TODO: implement
150+
// Check that the receiver's instance tag matches your sender's instance tag.
151+
// Compute t = 0x1 || KDF_1(usageAuthIBobClientProfile || Bobs_Client_Profile, 64) || KDF_1(usageAuthIAliceClientProfile || Alices_Client_Profile, 64) || Y || X || B || A || KDF_1(usageAuthIPhi || phi, 64). phi is the shared session state as mention in its section.
152+
// Verify the sigma as defined in Ring Signature Authentication.
51153
return nil
52154
}

0 commit comments

Comments
 (0)