Actually implementing correct signature construction

This commit is contained in:
Sarah Jamie Lewis 2018-06-22 11:11:23 -07:00
parent 1ea1521fee
commit 22aebae0e5
14 changed files with 98 additions and 92 deletions

View File

@ -80,13 +80,13 @@ func (g *Group) Invite() ([]byte, error) {
} }
// AddMessage takes a DecryptedGroupMessage and adds it to the Groups Timeline // AddMessage takes a DecryptedGroupMessage and adds it to the Groups Timeline
func (g *Group) AddMessage(message *protocol.DecryptedGroupMessage, verified bool) *Message { func (g *Group) AddMessage(message *protocol.DecryptedGroupMessage, sig []byte, verified bool) *Message {
g.lock.Lock() g.lock.Lock()
timelineMessage := &Message{ timelineMessage := &Message{
Message: message.GetText(), Message: message.GetText(),
Timestamp: time.Unix(int64(message.GetTimestamp()), 0), Timestamp: time.Unix(int64(message.GetTimestamp()), 0),
Received: time.Now(), Received: time.Now(),
Signature: message.GetSignature(), Signature: sig,
Verified: verified, Verified: verified,
PeerID: message.GetOnion(), PeerID: message.GetOnion(),
PreviousMessageSig: message.GetPreviousMessageSig(), PreviousMessageSig: message.GetPreviousMessageSig(),

View File

@ -14,7 +14,6 @@ func TestGroup(t *testing.T) {
Text: proto.String("Hello World!"), Text: proto.String("Hello World!"),
Timestamp: proto.Int32(int32(time.Now().Unix())), Timestamp: proto.Int32(int32(time.Now().Unix())),
SignedGroupId: []byte{}, SignedGroupId: []byte{},
Signature: []byte{},
PreviousMessageSig: []byte{}, PreviousMessageSig: []byte{},
Padding: []byte{}, Padding: []byte{},
} }

View File

@ -23,21 +23,21 @@ func TestMessagePadding(t *testing.T) {
group := alice.GetGroupByGroupID(gid) group := alice.GetGroupByGroupID(gid)
c1, _ := sarah.EncryptMessageToGroup("Hello World 1", group.GroupID) c1, s1, _ := sarah.EncryptMessageToGroup("Hello World 1", group.GroupID)
t.Logf("Length of Encrypted Message: %v", len(c1)) t.Logf("Length of Encrypted Message: %v", len(c1))
alice.AttemptDecryption(c1) alice.AttemptDecryption(c1, s1)
c2, _ := alice.EncryptMessageToGroup("Hello World 2", group.GroupID) c2, s2, _ := alice.EncryptMessageToGroup("Hello World 2", group.GroupID)
t.Logf("Length of Encrypted Message: %v", len(c2)) t.Logf("Length of Encrypted Message: %v", len(c2))
alice.AttemptDecryption(c2) alice.AttemptDecryption(c2, s2)
c3, _ := alice.EncryptMessageToGroup("Hello World 3", group.GroupID) c3, s3, _ := alice.EncryptMessageToGroup("Hello World 3", group.GroupID)
t.Logf("Length of Encrypted Message: %v", len(c3)) t.Logf("Length of Encrypted Message: %v", len(c3))
alice.AttemptDecryption(c3) alice.AttemptDecryption(c3, s3)
c4, _ := alice.EncryptMessageToGroup("Hello World this is a much longer message 3", group.GroupID) c4, s4, _ := alice.EncryptMessageToGroup("Hello World this is a much longer message 3", group.GroupID)
t.Logf("Length of Encrypted Message: %v", len(c4)) t.Logf("Length of Encrypted Message: %v", len(c4))
alice.AttemptDecryption(c4) alice.AttemptDecryption(c4, s4)
} }
@ -59,33 +59,33 @@ func TestTranscriptConsistency(t *testing.T) {
t.Logf("group: %v, sarah %v", group, sarah) t.Logf("group: %v, sarah %v", group, sarah)
c1, _ := alice.EncryptMessageToGroup("Hello World 1", group.GroupID) c1, s1, _ := alice.EncryptMessageToGroup("Hello World 1", group.GroupID)
t.Logf("Length of Encrypted Message: %v", len(c1)) t.Logf("Length of Encrypted Message: %v", len(c1))
alice.AttemptDecryption(c1) alice.AttemptDecryption(c1, s1)
c2, _ := alice.EncryptMessageToGroup("Hello World 2", group.GroupID) c2, s2, _ := alice.EncryptMessageToGroup("Hello World 2", group.GroupID)
t.Logf("Length of Encrypted Message: %v", len(c2)) t.Logf("Length of Encrypted Message: %v", len(c2))
alice.AttemptDecryption(c2) alice.AttemptDecryption(c2, s2)
c3, _ := alice.EncryptMessageToGroup("Hello World 3", group.GroupID) c3, s3, _ := alice.EncryptMessageToGroup("Hello World 3", group.GroupID)
t.Logf("Length of Encrypted Message: %v", len(c3)) t.Logf("Length of Encrypted Message: %v", len(c3))
alice.AttemptDecryption(c3) alice.AttemptDecryption(c3, s3)
time.Sleep(time.Second * 1) time.Sleep(time.Second * 1)
c4, _ := alice.EncryptMessageToGroup("Hello World 4", group.GroupID) c4, s4, _ := alice.EncryptMessageToGroup("Hello World 4", group.GroupID)
t.Logf("Length of Encrypted Message: %v", len(c4)) t.Logf("Length of Encrypted Message: %v", len(c4))
alice.AttemptDecryption(c4) alice.AttemptDecryption(c4, s4)
c5, _ := alice.EncryptMessageToGroup("Hello World 5", group.GroupID) c5, s5, _ := alice.EncryptMessageToGroup("Hello World 5", group.GroupID)
t.Logf("Length of Encrypted Message: %v", len(c5)) t.Logf("Length of Encrypted Message: %v", len(c5))
_, m1 := sarah.AttemptDecryption(c1) _, m1 := sarah.AttemptDecryption(c1, s1)
sarah.AttemptDecryption(c1) // Try a duplicate sarah.AttemptDecryption(c1, s1) // Try a duplicate
_, m2 := sarah.AttemptDecryption(c2) _, m2 := sarah.AttemptDecryption(c2, s2)
_, m3 := sarah.AttemptDecryption(c3) _, m3 := sarah.AttemptDecryption(c3, s3)
_, m4 := sarah.AttemptDecryption(c4) _, m4 := sarah.AttemptDecryption(c4, s4)
_, m5 := sarah.AttemptDecryption(c5) _, m5 := sarah.AttemptDecryption(c5, s5)
// Now we simulate a client receiving these messages completely out of order // Now we simulate a client receiving these messages completely out of order
timeline.Insert(m1) timeline.Insert(m1)

View File

@ -10,7 +10,6 @@ import (
"git.openprivacy.ca/openprivacy/libricochet-go/utils" "git.openprivacy.ca/openprivacy/libricochet-go/utils"
"golang.org/x/crypto/ed25519" "golang.org/x/crypto/ed25519"
"io" "io"
"strconv"
"sync" "sync"
"time" "time"
) )
@ -171,16 +170,21 @@ func (p *Profile) GetContact(onion string) (*PublicProfile, bool) {
} }
// VerifyGroupMessage confirms the authenticity of a message given an onion, message and signature. // VerifyGroupMessage confirms the authenticity of a message given an onion, message and signature.
func (p *Profile) VerifyGroupMessage(onion string, groupID string, message string, timestamp int32, signature []byte) bool { func (p *Profile) VerifyGroupMessage(onion string, groupID string, message string, timestamp int32, ciphertext []byte, signature []byte) bool {
group := p.GetGroupByGroupID(groupID)
if group == nil {
return false
}
if onion == p.Onion { if onion == p.Onion {
m := message + groupID + strconv.Itoa(int(timestamp)) m := groupID + group.GroupServer + string(ciphertext)
return ed25519.Verify(p.Ed25519PublicKey, []byte(m), signature) return ed25519.Verify(p.Ed25519PublicKey, []byte(m), signature)
} }
contact, found := p.GetContact(onion) contact, found := p.GetContact(onion)
if found { if found {
m := message + groupID + strconv.Itoa(int(timestamp)) m := groupID + group.GroupServer + string(ciphertext)
return ed25519.Verify(contact.Ed25519PublicKey, []byte(m), signature) return ed25519.Verify(contact.Ed25519PublicKey, []byte(m), signature)
} }
return false return false
@ -250,7 +254,7 @@ func (p *Profile) AddGroup(group *Group) {
} }
// AttemptDecryption takes a ciphertext and signature and attempts to decrypt it under known groups. // AttemptDecryption takes a ciphertext and signature and attempts to decrypt it under known groups.
func (p *Profile) AttemptDecryption(ciphertext []byte) (bool, *Message) { func (p *Profile) AttemptDecryption(ciphertext []byte, signature []byte) (bool, *Message) {
for _, group := range p.Groups { for _, group := range p.Groups {
success, dgm := group.DecryptMessage(ciphertext) success, dgm := group.DecryptMessage(ciphertext)
if success { if success {
@ -269,8 +273,8 @@ func (p *Profile) AttemptDecryption(ciphertext []byte) (bool, *Message) {
} }
} }
verified := p.VerifyGroupMessage(dgm.GetOnion(), group.GroupID, dgm.GetText(), dgm.GetTimestamp(), dgm.GetSignature()) verified := p.VerifyGroupMessage(dgm.GetOnion(), group.GroupID, dgm.GetText(), dgm.GetTimestamp(), ciphertext, signature)
return true, group.AddMessage(dgm, verified) return true, group.AddMessage(dgm, signature, verified)
} }
} }
return false, nil return false, nil
@ -284,11 +288,11 @@ func getRandomness(arr *[]byte) {
// EncryptMessageToGroup when given a message and a group, encrypts and signs the message under the group and // EncryptMessageToGroup when given a message and a group, encrypts and signs the message under the group and
// profile // profile
func (p *Profile) EncryptMessageToGroup(message string, groupID string) ([]byte, error) { func (p *Profile) EncryptMessageToGroup(message string, groupID string) ([]byte, []byte, error) {
group := p.GetGroupByGroupID(groupID) group := p.GetGroupByGroupID(groupID)
if group != nil { if group != nil {
timestamp := time.Now().Unix() timestamp := time.Now().Unix()
signature := p.SignMessage(message + groupID + strconv.Itoa(int(timestamp)))
var prevSig []byte var prevSig []byte
if len(group.Timeline.Messages) > 0 { if len(group.Timeline.Messages) > 0 {
prevSig = group.Timeline.Messages[len(group.Timeline.Messages)-1].Signature prevSig = group.Timeline.Messages[len(group.Timeline.Messages)-1].Signature
@ -305,12 +309,12 @@ func (p *Profile) EncryptMessageToGroup(message string, groupID string) ([]byte,
Text: proto.String(message), Text: proto.String(message),
SignedGroupId: group.SignedGroupID[:], SignedGroupId: group.SignedGroupID[:],
Timestamp: proto.Int32(int32(timestamp)), Timestamp: proto.Int32(int32(timestamp)),
Signature: signature,
PreviousMessageSig: prevSig, PreviousMessageSig: prevSig,
Padding: padding[:], Padding: padding[:],
} }
ciphertext := group.EncryptMessage(dm) ciphertext := group.EncryptMessage(dm)
return ciphertext, nil signature := p.SignMessage(groupID + group.GroupServer + string(ciphertext))
return ciphertext, signature, nil
} }
return nil, errors.New("group does not exist") return nil, nil, errors.New("group does not exist")
} }

View File

@ -104,29 +104,29 @@ func TestProfileGroup(t *testing.T) {
group := alice.GetGroupByGroupID(gid) group := alice.GetGroupByGroupID(gid)
sarah.AcceptInvite(group.GroupID) sarah.AcceptInvite(group.GroupID)
c, _ := sarah.EncryptMessageToGroup("Hello World", group.GroupID) c, s1, _ := sarah.EncryptMessageToGroup("Hello World", group.GroupID)
alice.AttemptDecryption(c) alice.AttemptDecryption(c, s1)
gid2, invite2, _ := alice.StartGroup("bbb.onion") gid2, invite2, _ := alice.StartGroup("bbb.onion")
gci2 := &protocol.CwtchPeerPacket{} gci2 := &protocol.CwtchPeerPacket{}
proto.Unmarshal(invite2, gci2) proto.Unmarshal(invite2, gci2)
sarah.ProcessInvite(gci2.GetGroupChatInvite(), alice.Onion) sarah.ProcessInvite(gci2.GetGroupChatInvite(), alice.Onion)
group2 := alice.GetGroupByGroupID(gid2) group2 := alice.GetGroupByGroupID(gid2)
c2, _ := sarah.EncryptMessageToGroup("Hello World", group2.GroupID) c2, s2, _ := sarah.EncryptMessageToGroup("Hello World", group2.GroupID)
alice.AttemptDecryption(c2) alice.AttemptDecryption(c2, s2)
bob := GenerateNewProfile("bob") bob := GenerateNewProfile("bob")
bob.AddContact(alice.Onion, &alice.PublicProfile) bob.AddContact(alice.Onion, &alice.PublicProfile)
bob.ProcessInvite(gci2.GetGroupChatInvite(), alice.Onion) bob.ProcessInvite(gci2.GetGroupChatInvite(), alice.Onion)
c3, err := bob.EncryptMessageToGroup("Bobs Message", group2.GroupID) c3, s3, err := bob.EncryptMessageToGroup("Bobs Message", group2.GroupID)
if err == nil { if err == nil {
ok, message := alice.AttemptDecryption(c3) ok, message := alice.AttemptDecryption(c3, s3)
if ok != true || message.Verified == true { if ok != true || message.Verified == true {
t.Errorf("Bobs message to the group should be decrypted but not verified by alice instead %v %v", message, ok) t.Errorf("Bobs message to the group should be decrypted but not verified by alice instead %v %v", message, ok)
} }
eve := GenerateNewProfile("eve") eve := GenerateNewProfile("eve")
ok, _ = eve.AttemptDecryption(c3) ok, _ = eve.AttemptDecryption(c3, s3)
if ok { if ok {
t.Errorf("Eves hould not be able to decrypt messages!") t.Errorf("Eves hould not be able to decrypt messages!")
} }

View File

@ -29,7 +29,7 @@ func (ts *TestServer) HandleGroupMessage(gm *protocol.GroupMessage) {
} }
func (ts *TestServer) HandleFetchRequest() []*protocol.GroupMessage { func (ts *TestServer) HandleFetchRequest() []*protocol.GroupMessage {
return []*protocol.GroupMessage{{Ciphertext: []byte("hello"), Spamguard: []byte{}}, {Ciphertext: []byte("hello"), Spamguard: []byte{}}} return []*protocol.GroupMessage{{Ciphertext: []byte("hello"), Signature: []byte{}, Spamguard: []byte{}}, {Ciphertext: []byte("hello"), Signature: []byte{}, Spamguard: []byte{}}}
} }
func runtestserver(t *testing.T, ts *TestServer, privateKey *rsa.PrivateKey) { func runtestserver(t *testing.T, ts *TestServer, privateKey *rsa.PrivateKey) {
@ -92,7 +92,7 @@ func TestPeerServerConnection(t *testing.T) {
t.Errorf("connection should now be authed(%v), instead was %v", AUTHENTICATED, state) t.Errorf("connection should now be authed(%v), instead was %v", AUTHENTICATED, state)
} }
gm := &protocol.GroupMessage{Ciphertext: []byte("hello")} gm := &protocol.GroupMessage{Ciphertext: []byte("hello"), Signature: []byte{}}
psc.SendGroupMessage(gm) psc.SendGroupMessage(gm)
time.Sleep(time.Second * 2) time.Sleep(time.Second * 2)
if ts.Received == false { if ts.Received == false {

View File

@ -214,7 +214,7 @@ func (cp *cwtchPeer) InviteOnionToGroup(onion string, groupid string) error {
// ReceiveGroupMessage is a callback function that processes GroupMessages from a given server // ReceiveGroupMessage is a callback function that processes GroupMessages from a given server
func (cp *cwtchPeer) ReceiveGroupMessage(server string, gm *protocol.GroupMessage) { func (cp *cwtchPeer) ReceiveGroupMessage(server string, gm *protocol.GroupMessage) {
cp.Profile.AttemptDecryption(gm.Ciphertext) cp.Profile.AttemptDecryption(gm.Ciphertext, gm.Signature)
} }
// JoinServer manages a new server connection with the given onion address // JoinServer manages a new server connection with the given onion address
@ -232,12 +232,13 @@ func (cp *cwtchPeer) SendMessageToGroup(groupid string, message string) error {
if psc == nil { if psc == nil {
return errors.New("could not find server connection to send message to") return errors.New("could not find server connection to send message to")
} }
ct, err := cp.Profile.EncryptMessageToGroup(message, groupid) ct, sig, err := cp.Profile.EncryptMessageToGroup(message, groupid)
if err != nil { if err != nil {
return err return err
} }
gm := &protocol.GroupMessage{ gm := &protocol.GroupMessage{
Ciphertext: ct, Ciphertext: ct,
Signature: sig,
} }
err = psc.SendGroupMessage(gm) err = psc.SendGroupMessage(gm)
return err return err

View File

@ -74,7 +74,7 @@ func TestPeerFetchChannel(t *testing.T) {
csp := &protocol.CwtchServerPacket{ csp := &protocol.CwtchServerPacket{
GroupMessage: &protocol.GroupMessage{ GroupMessage: &protocol.GroupMessage{
Ciphertext: []byte("hello"), Spamguard: []byte{}, Ciphertext: []byte("hello"), Signature: []byte{}, Spamguard: []byte{},
}, },
} }
packet, _ := proto.Marshal(csp) packet, _ := proto.Marshal(csp)

View File

@ -71,7 +71,7 @@ func TestPeerListenChannel(t *testing.T) {
} }
csp := &protocol.CwtchServerPacket{ csp := &protocol.CwtchServerPacket{
GroupMessage: &protocol.GroupMessage{Ciphertext: []byte("hello"), Spamguard: []byte{}}, GroupMessage: &protocol.GroupMessage{Ciphertext: []byte("hello"), Signature: []byte{}, Spamguard: []byte{}},
} }
packet, _ := proto.Marshal(csp) packet, _ := proto.Marshal(csp)

View File

@ -50,6 +50,7 @@ func (*FetchMessage) Descriptor() ([]byte, []int) { return fileDescriptor2, []in
type GroupMessage struct { type GroupMessage struct {
Ciphertext []byte `protobuf:"bytes,1,req,name=ciphertext" json:"ciphertext,omitempty"` Ciphertext []byte `protobuf:"bytes,1,req,name=ciphertext" json:"ciphertext,omitempty"`
Spamguard []byte `protobuf:"bytes,2,req,name=spamguard" json:"spamguard,omitempty"` Spamguard []byte `protobuf:"bytes,2,req,name=spamguard" json:"spamguard,omitempty"`
Signature []byte `protobuf:"bytes,3,req,name=signature" json:"signature,omitempty"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
} }
@ -72,6 +73,13 @@ func (m *GroupMessage) GetSpamguard() []byte {
return nil return nil
} }
func (m *GroupMessage) GetSignature() []byte {
if m != nil {
return m.Signature
}
return nil
}
// DecryptedGroupMessage is *never* sent in the clear on the wire // DecryptedGroupMessage is *never* sent in the clear on the wire
// and is only ever sent when encrypted in the ciphertext parameter of // and is only ever sent when encrypted in the ciphertext parameter of
// GroupMessage // GroupMessage
@ -79,11 +87,10 @@ type DecryptedGroupMessage struct {
Onion *string `protobuf:"bytes,1,req,name=onion" json:"onion,omitempty"` Onion *string `protobuf:"bytes,1,req,name=onion" json:"onion,omitempty"`
Timestamp *int32 `protobuf:"varint,2,req,name=timestamp" json:"timestamp,omitempty"` Timestamp *int32 `protobuf:"varint,2,req,name=timestamp" json:"timestamp,omitempty"`
Text *string `protobuf:"bytes,3,req,name=text" json:"text,omitempty"` Text *string `protobuf:"bytes,3,req,name=text" json:"text,omitempty"`
Signature []byte `protobuf:"bytes,4,req,name=signature" json:"signature,omitempty"` SignedGroupId []byte `protobuf:"bytes,4,req,name=signed_group_id,json=signedGroupId" json:"signed_group_id,omitempty"`
SignedGroupId []byte `protobuf:"bytes,5,req,name=signed_group_id,json=signedGroupId" json:"signed_group_id,omitempty"` PreviousMessageSig []byte `protobuf:"bytes,5,req,name=previous_message_sig,json=previousMessageSig" json:"previous_message_sig,omitempty"`
PreviousMessageSig []byte `protobuf:"bytes,6,req,name=previous_message_sig,json=previousMessageSig" json:"previous_message_sig,omitempty"`
// Used to prevent analysis on text length, length is 1024 - len(text) // Used to prevent analysis on text length, length is 1024 - len(text)
Padding []byte `protobuf:"bytes,7,req,name=padding" json:"padding,omitempty"` Padding []byte `protobuf:"bytes,6,req,name=padding" json:"padding,omitempty"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
} }
@ -113,13 +120,6 @@ func (m *DecryptedGroupMessage) GetText() string {
return "" return ""
} }
func (m *DecryptedGroupMessage) GetSignature() []byte {
if m != nil {
return m.Signature
}
return nil
}
func (m *DecryptedGroupMessage) GetSignedGroupId() []byte { func (m *DecryptedGroupMessage) GetSignedGroupId() []byte {
if m != nil { if m != nil {
return m.SignedGroupId return m.SignedGroupId
@ -161,29 +161,28 @@ func init() {
func init() { proto.RegisterFile("group_message.proto", fileDescriptor2) } func init() { proto.RegisterFile("group_message.proto", fileDescriptor2) }
var fileDescriptor2 = []byte{ var fileDescriptor2 = []byte{
// 372 bytes of a gzipped FileDescriptorProto // 360 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x52, 0xdd, 0xaa, 0xd3, 0x30, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x5c, 0x92, 0x4d, 0x6e, 0xdb, 0x30,
0x1c, 0xa7, 0xfb, 0x70, 0xee, 0xbf, 0x6e, 0x62, 0x9c, 0x1a, 0x44, 0xa4, 0xf4, 0x42, 0x76, 0x35, 0x10, 0x85, 0x21, 0xff, 0xb4, 0xf5, 0x58, 0x6e, 0x51, 0xd6, 0x6d, 0x89, 0xa2, 0x28, 0x0c, 0x2d,
0xc4, 0x4b, 0x87, 0x20, 0x4c, 0x14, 0x41, 0x45, 0xba, 0x07, 0x28, 0xa1, 0xfd, 0x2f, 0x0d, 0xb6, 0x0a, 0xaf, 0x8c, 0x20, 0xcb, 0x78, 0x13, 0xc0, 0x41, 0x82, 0x2c, 0x12, 0x04, 0xf2, 0x01, 0x04,
0x49, 0x48, 0xd2, 0x9d, 0x73, 0xde, 0xe0, 0x3c, 0xdc, 0x79, 0x99, 0xf3, 0x06, 0x87, 0xa6, 0xeb, 0x42, 0x1a, 0x53, 0x4c, 0x24, 0x92, 0x20, 0x29, 0x27, 0xb9, 0x41, 0x36, 0x39, 0x5d, 0x2e, 0x14,
0xd6, 0x9d, 0x8b, 0x73, 0x55, 0x7e, 0xdf, 0x21, 0x0d, 0xbc, 0xe2, 0x46, 0xd5, 0x3a, 0xad, 0xd0, 0x88, 0xb2, 0x6c, 0x39, 0x2b, 0x69, 0xde, 0x37, 0x6f, 0xde, 0x80, 0x24, 0xfc, 0xe0, 0x46, 0x55,
0x5a, 0xc6, 0x71, 0xad, 0x8d, 0x72, 0x8a, 0x3c, 0xf7, 0x9f, 0x4c, 0x95, 0xef, 0x96, 0x5b, 0x25, 0x3a, 0x29, 0xd1, 0x5a, 0xc6, 0x71, 0xa1, 0x8d, 0x72, 0x8a, 0x7c, 0xf1, 0x9f, 0x54, 0x15, 0x7f,
0x9d, 0x51, 0xe5, 0xb6, 0x60, 0x52, 0x62, 0xd9, 0xea, 0xf1, 0x5d, 0x00, 0x2f, 0xb7, 0x57, 0x2e, 0xa6, 0x2b, 0x25, 0x9d, 0x51, 0xc5, 0x2a, 0x67, 0x52, 0x62, 0xd1, 0xf0, 0xe8, 0x35, 0x80, 0xef,
0x2b, 0x76, 0x68, 0x0e, 0x68, 0xfe, 0xb1, 0xec, 0x3f, 0x3a, 0xb2, 0x81, 0xf9, 0x45, 0x19, 0x0d, 0xab, 0x47, 0x97, 0xe6, 0x6b, 0x34, 0x5b, 0x34, 0x77, 0x2c, 0x7d, 0x40, 0x47, 0x96, 0x30, 0x39,
0xa2, 0x60, 0x35, 0xfb, 0xfc, 0x66, 0xdd, 0xb5, 0xad, 0x7f, 0x36, 0xf2, 0x9f, 0x56, 0x4d, 0x42, 0x1a, 0x46, 0x83, 0x59, 0x30, 0x1f, 0x9f, 0xfe, 0x5a, 0xb4, 0xd3, 0x16, 0x57, 0x35, 0xbe, 0x69,
0xde, 0x43, 0x4d, 0x78, 0x8f, 0x2e, 0x2b, 0x4e, 0xe1, 0xc1, 0xe3, 0xf0, 0x8f, 0x46, 0x3e, 0x85, 0x68, 0x1c, 0xf2, 0x4e, 0x55, 0x9b, 0x37, 0xe8, 0xd2, 0x7c, 0x6f, 0xee, 0x7d, 0x34, 0x5f, 0xd6,
0xf7, 0x3d, 0x44, 0xbe, 0xc2, 0xe2, 0x62, 0xd9, 0xd2, 0x61, 0x34, 0x7c, 0x62, 0x7a, 0xde, 0x9f, 0x78, 0x6f, 0xde, 0x74, 0xaa, 0xe8, 0x2b, 0x84, 0x5d, 0x1a, 0xdd, 0x43, 0xd8, 0x8d, 0x22, 0xff,
0xb6, 0xf1, 0x02, 0xc2, 0x7e, 0x79, 0xfc, 0x1b, 0xc2, 0xbe, 0x9d, 0x7c, 0x00, 0xc8, 0x84, 0x2e, 0x00, 0x52, 0xa1, 0x73, 0x34, 0x0e, 0x9f, 0x1c, 0x0d, 0x66, 0xbd, 0x79, 0x18, 0x77, 0x14, 0xf2,
0xd0, 0x38, 0xbc, 0x76, 0x34, 0x88, 0x06, 0xab, 0x30, 0xe9, 0x31, 0xe4, 0x3d, 0x4c, 0xad, 0x66, 0x17, 0x46, 0x56, 0xb3, 0x92, 0x57, 0xcc, 0x64, 0xb4, 0xe7, 0xf1, 0x41, 0xf0, 0x54, 0x70, 0xc9,
0x15, 0xaf, 0x99, 0xc9, 0xe9, 0xc0, 0xcb, 0x67, 0x22, 0xbe, 0x0f, 0xe0, 0xf5, 0x77, 0xcc, 0xcc, 0x5c, 0x65, 0x90, 0xf6, 0x77, 0xb4, 0x15, 0xa2, 0xb7, 0x00, 0x7e, 0x5e, 0x60, 0x6a, 0x9e, 0xb5,
0x8d, 0x76, 0x98, 0x5f, 0xf4, 0x2e, 0x61, 0xac, 0xa4, 0x50, 0xd2, 0x57, 0x4e, 0x93, 0x16, 0x34, 0xc3, 0xec, 0x28, 0x75, 0x0a, 0x43, 0x25, 0x85, 0x92, 0x3e, 0x70, 0x14, 0x37, 0x45, 0x3d, 0xcd,
0x6d, 0x4e, 0x54, 0x68, 0x1d, 0xab, 0xb4, 0x6f, 0x1b, 0x27, 0x67, 0x82, 0x10, 0x18, 0xf9, 0x53, 0x89, 0x12, 0xad, 0x63, 0xa5, 0xf6, 0x59, 0xc3, 0xf8, 0x20, 0x10, 0x02, 0x03, 0xbf, 0x63, 0xdf,
0x0c, 0x7d, 0x64, 0x74, 0xda, 0x17, 0x5c, 0x32, 0x57, 0x1b, 0xa4, 0xa3, 0xe3, 0x7e, 0x47, 0x90, 0x5b, 0xfc, 0x3f, 0xf9, 0x0f, 0xdf, 0xea, 0x38, 0xcc, 0x92, 0xe6, 0x78, 0x45, 0x46, 0x07, 0x7e,
0x8f, 0xf0, 0xa2, 0x01, 0x98, 0xa7, 0xed, 0x1d, 0x89, 0x9c, 0x8e, 0xbd, 0x67, 0xde, 0xd2, 0xfe, 0x8b, 0x49, 0x23, 0xfb, 0xd0, 0xeb, 0x8c, 0x9c, 0xc0, 0x54, 0x1b, 0xdc, 0x0a, 0x55, 0xd9, 0xf6,
0x48, 0xbf, 0x72, 0xf2, 0x09, 0x96, 0xda, 0xe0, 0x41, 0xa8, 0xda, 0x76, 0xf7, 0x98, 0x5a, 0xc1, 0x14, 0x13, 0x2b, 0x38, 0x1d, 0xfa, 0x66, 0xd2, 0xb2, 0xdd, 0x7a, 0x6b, 0xc1, 0x09, 0x85, 0xcf,
0xe9, 0x33, 0x6f, 0x26, 0x9d, 0x76, 0x3c, 0xfc, 0x4e, 0x70, 0x42, 0x61, 0xa2, 0x59, 0x9e, 0x0b, 0x9a, 0x65, 0x99, 0x90, 0x9c, 0x7e, 0xf2, 0x4d, 0x6d, 0x79, 0xb6, 0x84, 0xd0, 0xfa, 0xbb, 0x4d,
0xc9, 0xe9, 0xc4, 0x9b, 0x3a, 0xf8, 0x65, 0x03, 0xa1, 0xf5, 0x4f, 0x23, 0x95, 0x4a, 0x66, 0x48, 0xa4, 0x92, 0x29, 0x92, 0xdf, 0x87, 0x7b, 0xd8, 0x3d, 0x85, 0x18, 0x6d, 0x55, 0x38, 0xfa, 0x72,
0xde, 0x9e, 0x7f, 0xc4, 0xf1, 0x25, 0x25, 0x68, 0xeb, 0xd2, 0xd1, 0xdb, 0x6f, 0x51, 0xb0, 0x0a, 0x3e, 0x0b, 0xe6, 0x61, 0x3c, 0x6e, 0xba, 0x6f, 0xeb, 0xe6, 0xf7, 0x00, 0x00, 0x00, 0xff, 0xff,
0x93, 0x59, 0xeb, 0xfe, 0xdb, 0x98, 0x1f, 0x02, 0x00, 0x00, 0xff, 0xff, 0x3c, 0x2e, 0xc6, 0x75, 0x33, 0x30, 0xca, 0x8b, 0x54, 0x02, 0x00, 0x00,
0x93, 0x02, 0x00, 0x00,
} }

View File

@ -18,6 +18,7 @@ message FetchMessage {
message GroupMessage { message GroupMessage {
required bytes ciphertext = 1; required bytes ciphertext = 1;
required bytes spamguard = 2; required bytes spamguard = 2;
required bytes signature = 3;
} }
// DecryptedGroupMessage is *never* sent in the clear on the wire // DecryptedGroupMessage is *never* sent in the clear on the wire
@ -27,9 +28,8 @@ message DecryptedGroupMessage {
required string onion = 1; required string onion = 1;
required int32 timestamp = 2; required int32 timestamp = 2;
required string text = 3; required string text = 3;
required bytes signature = 4; required bytes signed_group_id = 4;
required bytes signed_group_id = 5; required bytes previous_message_sig =5;
required bytes previous_message_sig =6;
// Used to prevent analysis on text length, length is 1024 - len(text) // Used to prevent analysis on text length, length is 1024 - len(text)
required bytes padding = 7; required bytes padding = 6;
} }

View File

@ -69,6 +69,7 @@ func TestServerListenChannel(t *testing.T) {
if control.GetChannelResult() != nil { if control.GetChannelResult() != nil {
gm := &protocol.GroupMessage{ gm := &protocol.GroupMessage{
Ciphertext: []byte("Hello"), Ciphertext: []byte("Hello"),
Signature: []byte{},
Spamguard: []byte{}, Spamguard: []byte{},
} }
cslc.SendGroupMessage(gm) cslc.SendGroupMessage(gm)

View File

@ -86,6 +86,7 @@ func TestServerSendChannel(t *testing.T) {
gm := &protocol.GroupMessage{ gm := &protocol.GroupMessage{
Ciphertext: []byte("Hello"), Ciphertext: []byte("Hello"),
Signature: []byte{},
Spamguard: sgsolve, Spamguard: sgsolve,
} }
@ -147,6 +148,7 @@ func TestServerSendChannelNoSpamGuard(t *testing.T) {
gm := &protocol.GroupMessage{ gm := &protocol.GroupMessage{
Ciphertext: []byte("hello"), Ciphertext: []byte("hello"),
Signature: []byte{},
Spamguard: sgsolve, Spamguard: sgsolve,
} }

View File

@ -182,7 +182,7 @@ func TestCwtchPeerIntegration(t *testing.T) {
bob.JoinServer(serverAddr) bob.JoinServer(serverAddr)
fmt.Println("Waiting for peerings and server joins...") fmt.Println("Waiting for peerings and server joins...")
time.Sleep(time.Second * 60) time.Sleep(time.Second * 120)
fmt.Println("Alice inviting Bob to group...") fmt.Println("Alice inviting Bob to group...")
err = alice.InviteOnionToGroup(bob.GetProfile().Onion, groupID) err = alice.InviteOnionToGroup(bob.GetProfile().Onion, groupID)