Browse Source

Adding padding and length stuff

pull/19/head
Sarah Jamie Lewis 2 years ago
parent
commit
6de91969ae
8 changed files with 108 additions and 31 deletions
  1. +2
    -1
      model/group.go
  2. +1
    -0
      model/group_test.go
  3. +5
    -4
      model/message.go
  4. +43
    -0
      model/message_test.go
  5. +14
    -1
      model/profile.go
  6. +35
    -25
      protocol/group_message.pb.go
  7. +2
    -0
      protocol/group_message.proto
  8. +6
    -0
      protocol/spam/spamguard.go

+ 2
- 1
model/group.go View File

@@ -50,6 +50,7 @@ func NewGroup(server string) *Group {
// SignGroup adds a signature to the group.
func (g *Group) SignGroup(signature []byte) {
g.SignedGroupID = signature
copy(g.Timeline.SignedGroupId[:], g.SignedGroupID)
}

// Compromised should be called if we detect a a groupkey leak.
@@ -95,7 +96,7 @@ func (g *Group) AddMessage(message *protocol.DecryptedGroupMessage, verified boo
return timelineMessage
}

// GetTimeline provides a safe copy of the timeline
// GetTimeline provides a safe copy of the timeline-=
func (g *Group) GetTimeline() (t []Message) {
g.lock.Lock()
t = g.Timeline.GetMessages()


+ 1
- 0
model/group_test.go View File

@@ -16,6 +16,7 @@ func TestGroup(t *testing.T) {
SignedGroupId: []byte{},
Signature: []byte{},
PreviousMessageSig: []byte{},
Padding: []byte{},
}
encMessage := g.EncryptMessage(dgm)
ok, message := g.DecryptMessage(encMessage)


+ 5
- 4
model/message.go View File

@@ -9,8 +9,9 @@ import (
// Timeline encapsulates a collection of ordered messages, and a mechanism to access them
// in a threadsafe manner.
type Timeline struct {
Messages []Message
lock sync.Mutex
Messages []Message
SignedGroupId []byte
lock sync.Mutex
}

// Message is a local representation of a given message sent over a group chat channel.
@@ -54,14 +55,14 @@ func (t *Timeline) Swap(i, j int) {
t.Messages[i], t.Messages[j] = t.Messages[j], t.Messages[i]
}

// Less checks 2 messages (i andj) in the timeline and returns true if i cccured before j, else false
// Less checks 2 messages (i andj) in the timeline and returns true if i occcured before j, else false
func (t *Timeline) Less(i, j int) bool {

if t.Messages[i].Timestamp.Before(t.Messages[j].Timestamp) {
return true
}

if compareSignatures(t.Messages[i].PreviousMessageSig, []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}) {
if compareSignatures(t.Messages[i].PreviousMessageSig, t.SignedGroupId) {
return true
}



+ 43
- 0
model/message_test.go View File

@@ -3,10 +3,44 @@ package model
import (
"git.mascherari.press/cwtch/protocol"
"github.com/golang/protobuf/proto"
"strconv"
"testing"
"time"
)

func TestMessagePadding(t *testing.T) {

// Setup the Group
sarah := GenerateNewProfile("Sarah")
alice := GenerateNewProfile("Alice")
sarah.AddContact(alice.Onion, &alice.PublicProfile)
alice.AddContact(sarah.Onion, &sarah.PublicProfile)

gid, invite, _ := alice.StartGroup("aaa.onion")
gci := &protocol.CwtchPeerPacket{}
proto.Unmarshal(invite, gci)
sarah.ProcessInvite(gci.GetGroupChatInvite(), alice.Onion)

group := alice.GetGroupByGroupID(gid)

c1, _ := sarah.EncryptMessageToGroup("Hello World 1", group.GroupID)
t.Logf("Length of Encrypted Message: %v", len(c1))
alice.AttemptDecryption(c1)

c2, _ := alice.EncryptMessageToGroup("Hello World 2", group.GroupID)
t.Logf("Length of Encrypted Message: %v", len(c2))
alice.AttemptDecryption(c2)

c3, _ := alice.EncryptMessageToGroup("Hello World 3", group.GroupID)
t.Logf("Length of Encrypted Message: %v", len(c3))
alice.AttemptDecryption(c3)

c4, _ := alice.EncryptMessageToGroup("Hello World this is a much longer message 3", group.GroupID)
t.Logf("Length of Encrypted Message: %v", len(c4))
alice.AttemptDecryption(c4)

}

func TestTranscriptConsistency(t *testing.T) {
timeline := new(Timeline)

@@ -26,20 +60,25 @@ func TestTranscriptConsistency(t *testing.T) {
t.Logf("group: %v, sarah %v", group, sarah)

c1, _ := sarah.EncryptMessageToGroup("Hello World 1", group.GroupID)
t.Logf("Length of Encrypted Message: %v", len(c1))
alice.AttemptDecryption(c1)

c2, _ := alice.EncryptMessageToGroup("Hello World 2", group.GroupID)
t.Logf("Length of Encrypted Message: %v", len(c2))
alice.AttemptDecryption(c2)

c3, _ := alice.EncryptMessageToGroup("Hello World 3", group.GroupID)
t.Logf("Length of Encrypted Message: %v", len(c3))
alice.AttemptDecryption(c3)

time.Sleep(time.Second * 1)

c4, _ := alice.EncryptMessageToGroup("Hello World 4", group.GroupID)
t.Logf("Length of Encrypted Message: %v", len(c4))
alice.AttemptDecryption(c4)

c5, _ := alice.EncryptMessageToGroup("Hello World 5", group.GroupID)
t.Logf("Length of Encrypted Message: %v", len(c5))

_, m1 := sarah.AttemptDecryption(c1)
_, m2 := sarah.AttemptDecryption(c2)
@@ -55,6 +94,10 @@ func TestTranscriptConsistency(t *testing.T) {
timeline.Insert(m2)

for i, m := range timeline.GetMessages() {
if m.Message != "Hello World "+strconv.Itoa(i+1) {
t.Fatalf("Timeline Out of Order!: %v %v", i, m)
}

t.Logf("Messages %v: %v %x %x", i, m.Message, m.Signature, m.PreviousMessageSig)
}
}

+ 14
- 1
model/profile.go View File

@@ -10,6 +10,7 @@ import (
"github.com/golang/protobuf/proto"
"github.com/s-rah/go-ricochet/utils"
"golang.org/x/crypto/ed25519"
"io"
"io/ioutil"
"strconv"
"time"
@@ -177,6 +178,12 @@ func (p *Profile) AttemptDecryption(ciphertext []byte) (bool, *Message) {
return false, nil
}

func getRandomness(arr *[]byte) {
if _, err := io.ReadFull(rand.Reader, (*arr)[:]); err != nil {
utils.CheckError(err)
}
}

// EncryptMessageToGroup when given a message and a group, encrypts and signs the message under the group and
// profile
func (p *Profile) EncryptMessageToGroup(message string, groupID string) ([]byte, error) {
@@ -188,8 +195,13 @@ func (p *Profile) EncryptMessageToGroup(message string, groupID string) ([]byte,
if len(group.Timeline.Messages) > 0 {
prevSig = group.Timeline.Messages[len(group.Timeline.Messages)-1].Signature
} else {
prevSig = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
prevSig = group.SignedGroupID
}

lenPadding := 1024 - len(message)
padding := make([]byte, lenPadding)
getRandomness(&padding)

dm := &protocol.DecryptedGroupMessage{
Onion: proto.String(p.Onion),
Text: proto.String(message),
@@ -197,6 +209,7 @@ func (p *Profile) EncryptMessageToGroup(message string, groupID string) ([]byte,
Timestamp: proto.Int32(int32(timestamp)),
Signature: signature,
PreviousMessageSig: prevSig,
Padding: padding[:],
}
ciphertext := group.EncryptMessage(dm)
return ciphertext, nil


+ 35
- 25
protocol/group_message.pb.go View File

@@ -90,7 +90,9 @@ type DecryptedGroupMessage struct {
Signature []byte `protobuf:"bytes,4,req,name=signature" json:"signature,omitempty"`
SignedGroupId []byte `protobuf:"bytes,5,req,name=signed_group_id,json=signedGroupId" json:"signed_group_id,omitempty"`
PreviousMessageSig []byte `protobuf:"bytes,6,req,name=previous_message_sig,json=previousMessageSig" json:"previous_message_sig,omitempty"`
XXX_unrecognized []byte `json:"-"`
// Used to prevent analysis on text length, length is 1024 - len(text)
Padding []byte `protobuf:"bytes,7,req,name=padding" json:"padding,omitempty"`
XXX_unrecognized []byte `json:"-"`
}

func (m *DecryptedGroupMessage) Reset() { *m = DecryptedGroupMessage{} }
@@ -140,6 +142,13 @@ func (m *DecryptedGroupMessage) GetPreviousMessageSig() []byte {
return nil
}

func (m *DecryptedGroupMessage) GetPadding() []byte {
if m != nil {
return m.Padding
}
return nil
}

var E_ServerNonce = &proto.ExtensionDesc{
ExtendedType: (*control.ChannelResult)(nil),
ExtensionType: ([]byte)(nil),
@@ -160,28 +169,29 @@ func init() {
func init() { proto.RegisterFile("group_message.proto", fileDescriptor2) }

var fileDescriptor2 = []byte{
// 358 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x52, 0xcd, 0x4a, 0xeb, 0x40,
0x14, 0x26, 0xfd, 0xb9, 0xdc, 0x9e, 0xa6, 0xbd, 0xdc, 0xb9, 0xbd, 0x3a, 0x88, 0x48, 0xc8, 0x42,
0xba, 0x2a, 0xe2, 0xd2, 0x22, 0x08, 0x15, 0x45, 0x50, 0x91, 0xf4, 0x01, 0x42, 0x48, 0x4e, 0x93,
0xc1, 0x64, 0x66, 0x98, 0x99, 0x54, 0x7d, 0x03, 0x1f, 0xce, 0xbd, 0xaf, 0x23, 0x99, 0x34, 0x6d,
0xea, 0xc2, 0xd5, 0x70, 0xbe, 0xdf, 0xc3, 0x61, 0xe0, 0x5f, 0xaa, 0x44, 0x29, 0xc3, 0x02, 0xb5,
0x8e, 0x52, 0x9c, 0x49, 0x25, 0x8c, 0x20, 0xbf, 0xed, 0x13, 0x8b, 0xfc, 0x68, 0xb2, 0x10, 0xdc,
0x28, 0x91, 0x2f, 0xb2, 0x88, 0x73, 0xcc, 0x6b, 0xde, 0xff, 0x70, 0xe0, 0xef, 0xe2, 0xc5, 0xc4,
0xd9, 0x12, 0xd5, 0x1a, 0xd5, 0x53, 0x14, 0x3f, 0xa3, 0x21, 0x73, 0x18, 0xed, 0x85, 0x51, 0xc7,
0x73, 0xa6, 0xc3, 0xf3, 0x83, 0x59, 0x93, 0x36, 0xbb, 0xad, 0xe8, 0x87, 0x9a, 0x0d, 0xdc, 0xb4,
0x35, 0x55, 0xe6, 0x15, 0x9a, 0x38, 0xdb, 0x9a, 0x3b, 0xdf, 0xcd, 0x37, 0x15, 0xbd, 0x35, 0xaf,
0x5a, 0x13, 0xb9, 0x84, 0xf1, 0x5e, 0xb3, 0xa6, 0x5d, 0xaf, 0xfb, 0x43, 0xf5, 0xa8, 0x5d, 0xad,
0xfd, 0x31, 0xb8, 0xed, 0x70, 0xff, 0x1e, 0xdc, 0xb6, 0x9c, 0x9c, 0x00, 0xc4, 0x4c, 0x66, 0xa8,
0x0c, 0xbe, 0x1a, 0xea, 0x78, 0x9d, 0xa9, 0x1b, 0xb4, 0x10, 0x72, 0x0c, 0x03, 0x2d, 0xa3, 0x22,
0x2d, 0x23, 0x95, 0xd0, 0x8e, 0xa5, 0x77, 0x80, 0xff, 0xe9, 0xc0, 0xff, 0x6b, 0x8c, 0xd5, 0x9b,
0x34, 0x98, 0xec, 0xe5, 0x4e, 0xa0, 0x2f, 0x38, 0x13, 0xdc, 0x46, 0x0e, 0x82, 0x7a, 0xa8, 0xd2,
0x0c, 0x2b, 0x50, 0x9b, 0xa8, 0x90, 0x36, 0xad, 0x1f, 0xec, 0x00, 0x42, 0xa0, 0x67, 0xb7, 0xe8,
0x5a, 0x4b, 0x6f, 0xdb, 0xcf, 0x52, 0x1e, 0x99, 0x52, 0x21, 0xed, 0x6d, 0xfa, 0x1b, 0x80, 0x9c,
0xc2, 0x9f, 0x6a, 0xc0, 0x24, 0xac, 0x6f, 0xc4, 0x12, 0xda, 0xb7, 0x9a, 0x51, 0x0d, 0xdb, 0x95,
0xee, 0x12, 0x72, 0x06, 0x13, 0xa9, 0x70, 0xcd, 0x44, 0xa9, 0x9b, 0x3b, 0x86, 0x9a, 0xa5, 0xf4,
0x97, 0x15, 0x93, 0x86, 0xdb, 0x2c, 0xbf, 0x64, 0xe9, 0xc5, 0x1c, 0x5c, 0x6d, 0x3f, 0x40, 0xc8,
0x05, 0x8f, 0x91, 0x1c, 0xee, 0xce, 0xbd, 0xf9, 0x2f, 0x01, 0xea, 0x32, 0x37, 0xf4, 0xfd, 0xca,
0x73, 0xa6, 0x6e, 0x30, 0xac, 0xd5, 0x8f, 0x95, 0xf8, 0x2b, 0x00, 0x00, 0xff, 0xff, 0x54, 0x1a,
0x6d, 0xda, 0x79, 0x02, 0x00, 0x00,
// 372 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x52, 0xdd, 0xaa, 0xd3, 0x30,
0x1c, 0xa7, 0xfb, 0x70, 0xee, 0xbf, 0x6e, 0x62, 0x9c, 0x1a, 0x44, 0xa4, 0xf4, 0x42, 0x76, 0x35,
0xc4, 0x4b, 0x87, 0x20, 0x4c, 0x14, 0x41, 0x45, 0xba, 0x07, 0x28, 0xa1, 0xfd, 0x2f, 0x0d, 0xb6,
0x49, 0x48, 0xd2, 0x9d, 0x73, 0xde, 0xe0, 0x3c, 0xdc, 0x79, 0x99, 0xf3, 0x06, 0x87, 0xa6, 0xeb,
0xd6, 0x9d, 0x8b, 0x73, 0x55, 0x7e, 0xdf, 0x21, 0x0d, 0xbc, 0xe2, 0x46, 0xd5, 0x3a, 0xad, 0xd0,
0x5a, 0xc6, 0x71, 0xad, 0x8d, 0x72, 0x8a, 0x3c, 0xf7, 0x9f, 0x4c, 0x95, 0xef, 0x96, 0x5b, 0x25,
0x9d, 0x51, 0xe5, 0xb6, 0x60, 0x52, 0x62, 0xd9, 0xea, 0xf1, 0x5d, 0x00, 0x2f, 0xb7, 0x57, 0x2e,
0x2b, 0x76, 0x68, 0x0e, 0x68, 0xfe, 0xb1, 0xec, 0x3f, 0x3a, 0xb2, 0x81, 0xf9, 0x45, 0x19, 0x0d,
0xa2, 0x60, 0x35, 0xfb, 0xfc, 0x66, 0xdd, 0xb5, 0xad, 0x7f, 0x36, 0xf2, 0x9f, 0x56, 0x4d, 0x42,
0xde, 0x43, 0x4d, 0x78, 0x8f, 0x2e, 0x2b, 0x4e, 0xe1, 0xc1, 0xe3, 0xf0, 0x8f, 0x46, 0x3e, 0x85,
0xf7, 0x3d, 0x44, 0xbe, 0xc2, 0xe2, 0x62, 0xd9, 0xd2, 0x61, 0x34, 0x7c, 0x62, 0x7a, 0xde, 0x9f,
0xb6, 0xf1, 0x02, 0xc2, 0x7e, 0x79, 0xfc, 0x1b, 0xc2, 0xbe, 0x9d, 0x7c, 0x00, 0xc8, 0x84, 0x2e,
0xd0, 0x38, 0xbc, 0x76, 0x34, 0x88, 0x06, 0xab, 0x30, 0xe9, 0x31, 0xe4, 0x3d, 0x4c, 0xad, 0x66,
0x15, 0xaf, 0x99, 0xc9, 0xe9, 0xc0, 0xcb, 0x67, 0x22, 0xbe, 0x0f, 0xe0, 0xf5, 0x77, 0xcc, 0xcc,
0x8d, 0x76, 0x98, 0x5f, 0xf4, 0x2e, 0x61, 0xac, 0xa4, 0x50, 0xd2, 0x57, 0x4e, 0x93, 0x16, 0x34,
0x6d, 0x4e, 0x54, 0x68, 0x1d, 0xab, 0xb4, 0x6f, 0x1b, 0x27, 0x67, 0x82, 0x10, 0x18, 0xf9, 0x53,
0x0c, 0x7d, 0x64, 0x74, 0xda, 0x17, 0x5c, 0x32, 0x57, 0x1b, 0xa4, 0xa3, 0xe3, 0x7e, 0x47, 0x90,
0x8f, 0xf0, 0xa2, 0x01, 0x98, 0xa7, 0xed, 0x1d, 0x89, 0x9c, 0x8e, 0xbd, 0x67, 0xde, 0xd2, 0xfe,
0x48, 0xbf, 0x72, 0xf2, 0x09, 0x96, 0xda, 0xe0, 0x41, 0xa8, 0xda, 0x76, 0xf7, 0x98, 0x5a, 0xc1,
0xe9, 0x33, 0x6f, 0x26, 0x9d, 0x76, 0x3c, 0xfc, 0x4e, 0x70, 0x42, 0x61, 0xa2, 0x59, 0x9e, 0x0b,
0xc9, 0xe9, 0xc4, 0x9b, 0x3a, 0xf8, 0x65, 0x03, 0xa1, 0xf5, 0x4f, 0x23, 0x95, 0x4a, 0x66, 0x48,
0xde, 0x9e, 0x7f, 0xc4, 0xf1, 0x25, 0x25, 0x68, 0xeb, 0xd2, 0xd1, 0xdb, 0x6f, 0x51, 0xb0, 0x0a,
0x93, 0x59, 0xeb, 0xfe, 0xdb, 0x98, 0x1f, 0x02, 0x00, 0x00, 0xff, 0xff, 0x3c, 0x2e, 0xc6, 0x75,
0x93, 0x02, 0x00, 0x00,
}

+ 2
- 0
protocol/group_message.proto View File

@@ -31,4 +31,6 @@ message DecryptedGroupMessage {
required bytes signature = 4;
required bytes signed_group_id = 5;
required bytes previous_message_sig =6;
// Used to prevent analysis on text length, length is 1024 - len(text)
required bytes padding = 7;
}

+ 6
- 0
protocol/spam/spamguard.go View File

@@ -79,6 +79,12 @@ func (sg *Guard) ValidateChallenge(message []byte, spamguard []byte) bool {
if len(spamguard) != 24 {
return false
}

// If the message is too large just throw it away.
if len(message) > 2048 {
return false
}

solve := make([]byte, len(sg.nonce)+len(message)+len(spamguard))
copy(solve[0:], sg.nonce[:])
copy(solve[len(sg.nonce):], message[:])


Loading…
Cancel
Save