Fixing up messaging to use a proper ordering of messages based on timeline and previous hash.

This isn't perfect, but under normal conditions should prevent malicous server reordering. Still need a second order function
This commit is contained in:
Sarah Jamie Lewis 2018-04-02 14:10:29 -07:00
vecāks 5f44fb8ef8
revīzija f1d0a8e900
14 mainīti faili ar 315 papildinājumiem un 62 dzēšanām

Parādīt failu

@ -0,0 +1,49 @@
# Attacks On Cwtch
## Server Censorship
Servers must keep things for as long as possible. This messes with bandwidth requirements, means syncing takes really long.
We could improve fetch to say something like...fetch messages sent within the last day to improve that.
We should already restrict length to 1kb.
Force servers to keep things forever? Have clients do checks? Is this potentially creating a bigger issue down the line?
This means that secure key rotation is essential! We can't just rely on kdf because the rotation rate is known. Send secret
salt on invite!
## Subgroup Attack
* Alice invites Bob and Carol to her Group
* Carol invites Eve to the group, pretending that she is the Owner.
* After some time passes Carol send Eve a group key update
* Carol can now selectively reencrypt messages from Alice and Bob to Carol under the new group key.
Defenses
--------
Eve rejects the initial group invitation because the signed group id doesn't match Carol
Carol can create a new group with all the sam parameters and sign it herself though.
However Carol will notice messages she can decrypt but are intended for another group, and if she tries to send
a message to the group, Alice and Bob will discover their group has been compromised.
## Key Rotation Attacks
* Alice invites Bob and Carol to a new Group
* Alice invites Eve
* Alice rotates the key (using a kdf), sends the new key to the Group
* Alice sends invite to Eve with new Key
Now there is a window where Bob and Carol send messages without receiving the new Key. There is also a possibility that
Bob or Carol miss the Key rotation message by being offline during the entire Server buffer period.
Alice should then technically rebroadcast the key rotation message, along with the iteration, until she received confirmation from Bob and Carol?
RotateKey, 1
AckRotateKey
Invite
mAckInvite

Parādīt failu

@ -19,7 +19,7 @@ type Group struct {
SignedGroupID []byte
GroupKey [32]byte
GroupServer string
Timeline []Message
Timeline Timeline
Accepted bool
Owner string
}
@ -66,13 +66,14 @@ func (g *Group) Invite() []byte {
func (g *Group) AddMessage(message *protocol.DecryptedGroupMessage, verified bool) *Message {
timelineMessage := &Message{
Message: message.GetText(),
Timestamp: time.Unix(int64(message.GetTimestamp()), 0),
Signature: message.GetSignature(),
Verified: verified,
PeerID: message.GetOnion(),
Message: message.GetText(),
Timestamp: time.Unix(int64(message.GetTimestamp()), 0),
Signature: message.GetSignature(),
Verified: verified,
PeerID: message.GetOnion(),
PreviousMessageSig: message.GetPreviousMessageSig(),
}
g.Timeline = append(g.Timeline, *timelineMessage)
g.Timeline.Insert(timelineMessage)
return timelineMessage
}

Parādīt failu

@ -1,14 +1,73 @@
package model
import (
"log"
"sync"
"time"
)
type Timeline struct {
Messages []Message
lock sync.Mutex
}
// Message is a local representation of a given message sent over a group chat channel.
type Message struct {
Timestamp time.Time
PeerID string
Message string
Signature []byte
Verified bool
Timestamp time.Time
PeerID string
Message string
Signature []byte
Verified bool
PreviousMessageSig []byte
}
func (m *Message) IsBefore(message *Message) bool {
if m.Timestamp.Before(message.Timestamp) {
return true
}
return false
}
func compareSignatures(a []byte, b []byte) bool {
if len(a) != len(b) {
return false
}
for i := range a {
if a[i] != b[i] {
return false
}
}
return true
}
func (t *Timeline) Insert(mi *Message) {
t.lock.Lock()
insert := false
place := len(t.Messages)
for i, m := range t.Messages {
if compareSignatures(m.Signature, mi.PreviousMessageSig) {
log.Printf("comp %d %v %v %x %x", place, mi.Message, m.Message, m.Signature[0:3], mi.PreviousMessageSig[0:3])
insert = true
place = i + 1
break
}
if mi.IsBefore(&m) {
place = i
insert = true
break
}
}
if insert == false {
t.Messages = append(t.Messages, *mi)
} else {
temp := make([]Message, len(t.Messages)+1)
copy(temp[0:place], t.Messages[0:place])
temp[place] = *mi
copy(temp[place+1:], t.Messages[place:])
t.Messages = temp
}
t.lock.Unlock()
}

58
model/message_test.go Normal file
Parādīt failu

@ -0,0 +1,58 @@
package model
import (
"git.mascherari.press/cwtch/protocol"
"github.com/golang/protobuf/proto"
"testing"
"time"
)
func TestMessageInsert(t *testing.T) {
timeline := new(Timeline)
// 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)
alice.AttemptDecryption(c1)
c2 := alice.EncryptMessageToGroup("Hello World 2", group.GroupID)
alice.AttemptDecryption(c2)
c3 := alice.EncryptMessageToGroup("Hello World 3", group.GroupID)
alice.AttemptDecryption(c3)
time.Sleep(time.Second * 1)
c4 := alice.EncryptMessageToGroup("Hello World 4", group.GroupID)
alice.AttemptDecryption(c4)
c5 := alice.EncryptMessageToGroup("Hello World 5", group.GroupID)
_, m1 := sarah.AttemptDecryption(c1)
_, m2 := sarah.AttemptDecryption(c2)
_, m3 := sarah.AttemptDecryption(c3)
_, m4 := sarah.AttemptDecryption(c4)
_, m5 := sarah.AttemptDecryption(c5)
// Now we simulate a client receiving these messages completely out of order
timeline.Insert(m1)
timeline.Insert(m5)
timeline.Insert(m4)
timeline.Insert(m3)
timeline.Insert(m2)
for i, m := range timeline.Messages {
t.Logf("Messages %v: %v %x %x", i, m.Message, m.Signature, m.PreviousMessageSig)
}
}

Parādīt failu

@ -10,7 +10,7 @@ import (
"github.com/s-rah/go-ricochet/utils"
"golang.org/x/crypto/ed25519"
"io/ioutil"
"log"
// "log"
"strconv"
"time"
)
@ -127,10 +127,9 @@ func (p *Profile) ProcessInvite(gci *protocol.GroupChatInvite, peerHostname stri
func (p *Profile) AddGroup(group *Group) {
existingGroup, exists := p.Groups[group.GroupID]
if !exists {
// owned := ed25519.Verify(p.Contacts[group.Owner].Ed25519PublicKey,[]byte(group.GroupID),group.SignedGroupID)
p.Groups[group.GroupID] = group
}
if exists && existingGroup.Owner == group.Owner {
} else if exists && existingGroup.Owner == group.Owner {
p.Groups[group.GroupID] = group
}
@ -145,7 +144,7 @@ func (p *Profile) AddGroup(group *Group) {
func (p *Profile) AttemptDecryption(ciphertext []byte) (bool, *Message) {
for _, group := range p.Groups {
success, dgm := group.DecryptMessage(ciphertext)
log.Printf("Decrypt Attempt %v %v", success, dgm)
//log.Printf("Decrypt Attempt %v %v", success, dgm)
if success {
verified := p.VerifyGroupMessage(dgm.GetOnion(), group.GroupID, dgm.GetText(), dgm.GetTimestamp(), dgm.GetSignature())
return true, group.AddMessage(dgm, verified)
@ -160,12 +159,19 @@ func (p *Profile) EncryptMessageToGroup(message string, groupID string) (ciphert
group := p.Groups[groupID]
timestamp := time.Now().Unix()
signature := p.SignMessage(message + groupID + strconv.Itoa(int(timestamp)))
var prevSig []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}
}
dm := &protocol.DecryptedGroupMessage{
Onion: proto.String(p.Onion),
Text: proto.String(message),
SignedGroupId: group.SignedGroupID[:],
Timestamp: proto.Int32(int32(timestamp)),
Signature: signature,
Onion: proto.String(p.Onion),
Text: proto.String(message),
SignedGroupId: group.SignedGroupID[:],
Timestamp: proto.Int32(int32(timestamp)),
Signature: signature,
PreviousMessageSig: prevSig,
}
ciphertext = group.EncryptMessage(dm)
return

Parādīt failu

@ -1 +1 @@
{"Name":"Sarah","Ed25519PublicKey":"UsCWNjTraCR3Z2dqtsW1A++ubJD5E5FnC+ACSIP/8hk=","Trusted":false,"Blocked":false,"Contacts":{},"Ed25519PrivateKey":"n89RBVJD3T2KAxOUFsBgJcyBcOtgu0eeGs464orKNT9SwJY2NOtoJHdnZ2q2xbUD765skPkTkWcL4AJIg//yGQ==","OnionPrivateKey":{"N":123805553263348528457396531577890431199849926799850215350792942327090732394534595405543245927983354464965037398489749312360344572108681888509184005620780768892052483022600381118025061152186760477945751128712525497823295804735134482165349819329437248988124357774675993218222587847682647131583478848460913040243,"E":65537,"D":36374504906934646313489635099749458363262131933581273121740667172866198517734465027903858894110494685794311535589363611540022197170341482875998871297559138745889655544439413518334368519721005053246504047688085489173938252813690494094575739926433903954150053038634347562274030322729843548978331756633920952393,"Primes":[11696469543379902568303131723781955090117870500969155291133497643805055498454292242391505499241962759128566231590491957401660779652639301001660955427807509,10584865185531250093066719901396357065936568829189765800518363959386090914453659853194245194887656726848216858880202829552571699371710179494672080022887527],"Precomputed":{"Dp":10160546066712868045776669547990150376665097357075773683255583172245687391587977961328574691812932875168964159645365177332406882316926439191991697109426877,"Dq":9841112737610664672944159437140589723997848725150538012987853468625559479370285520771957035184623948003655181733807144213151331097197684620433635655501209,"Qinv":1336220763953049451525874385731316715417274408983287245077551897537966825948439529869489565316701741855547495791046015721525313869844240508900847744658372,"CRTValues":[]}},"Onion":"ln6hn7x65lfagspl","Groups":{}}
{"Name":"Sarah","Ed25519PublicKey":"j8RkHDyZPCFwuXjVxGtw8Qgv1l45moymwACxEXjQJnI=","Trusted":false,"Blocked":false,"Contacts":{},"Ed25519PrivateKey":"/TkSp0/IJ07+jLw/UAkyFC3mgd5WIAyJ7dRSz7M9kVePxGQcPJk8IXC5eNXEa3DxCC/WXjmajKbAALEReNAmcg==","OnionPrivateKey":{"N":110864111714001498673773375154532122354477779797956408709787762036989130004412378714867422979598016165479959916442576967379813396145904497664600025217339110732358507374657769751998789538776326442350416409397455856063370247022405840568758973841985645812850695658944529625449004363327908735536586292681231570813,"E":65537,"D":29258368192095608908884817685777310347483828667553504814753332196953842753808024509091764161544277089249452778045849081096193791289493937647541419902636631139610918217176285511499379852356646785160340611490902468063399499748079623910235136509595342699975150851412254552332235937599936863279394875342688545217,"Primes":[10479919459766681018465636257798402760984111495664175755942255404420416305820714717114953497775485113275270637658830475401064210738386560406839990913034719,10578717912825421118563933365610407240275592456669407680773574905407145537212719150546363664213151033473733068380589365500463635725956703879386470742958627],"Precomputed":{"Dp":8284056755927383160071597514918996216378258022687682149573348508872845365565133068650383233169949895375519101941128107453074315841465367073200569590456743,"Dq":6372702186525895688861316344573277352428100007466136918640473889031754670020876025200580396770300788890901041238776082975392592557803541040300560979782513,"Qinv":10360189342388704857040075408428853576974943026521455545260795237873844460252519600072106320342798867873256125020528899224644053095341386063420556723083365,"CRTValues":[]}},"Onion":"p2c3insyliefym26","Groups":{}}

Parādīt failu

@ -0,0 +1,23 @@
package model
import (
"testing"
)
// Nothing in this file constitutes a cryptographic proof, but acts to prevent aggressions in expected protocol
// behaviour.
// When a new member joins the group, they should be unable to decrypt any past messages
func TestGroupForwardSecrecy(t *testing.T) {
t.Fatalf("Failed")
}
// When a member leaves the group, they should be unable to decrypt any future messages.
func TestGroupBackwardSecrecy(t *testing.T) {
t.Fatalf("Failed")
}
// If a server reorders stuff, we will still be able to put things in the right order.
func TestTranscriptConsistency(t *testing.T) {
t.Fatalf("Failed")
}

Parādīt failu

@ -0,0 +1,10 @@
package connections
import (
"testing"
)
func TestConnectionsManager(t *testing.T) {
// TODO We need to encapsulate connections behind a well defined interface for tesintg
NewConnectionsManager()
}

Parādīt failu

@ -1 +1 @@
{"Profile":{"Name":"alice","Ed25519PublicKey":"GQjDT/ADqudCIZq/7i4flbRaLzBnPCj2IYI8S1qIWGM=","Trusted":false,"Blocked":false,"Contacts":{},"Ed25519PrivateKey":"hbG3RyQQ+r1PpW1UnE8B5kf54zDfHOvBz4bMgdW2IsAZCMNP8AOq50Ihmr/uLh+VtFovMGc8KPYhgjxLWohYYw==","OnionPrivateKey":{"N":118949437147999046779871097106577144824161312908242780099796773587901402109754265146160871793580686203857212353483161141299741736678609148375472482302726670540249479081752805338231525747022348201429435662507924057367176907320212979720249273484193414490356905146774628953953268592916404780858351871034973364651,"E":65537,"D":94181992508763271685525597753290425592727080704359767797710520442647537373960641663479161362904853560650542536805082850652072851335729546948313816304847468284377523922190377615541996345142801491115074550379060687848886736978676340143503908396698667066436989395508107231468852742294096428057812643803322726345,"Primes":[11093306403644218894981011451014980780451441495773111118759223267959318051098530285527407597744590710343913726393148960031173198769212333898347445271695669,10722631541929052848558646606992517878067322185889508722580532907231300392570442727893142668003376876119846036715047467381256380482736518424207582333117279],"Precomputed":{"Dp":288432398672654363139106817714108476889226792633129092670792322636109037018354450257697217549731946387933976071134257410212843595262795321158796507972129,"Dq":2883332097340673182326762426644935571740855072431310743824659832219009213395012164024304640710186775224072610968297015695864644296309957187387433410997235,"Qinv":9556280274383976646018218885445548987752711277953338363729408513927401398507573496665859225463898071345877217574624168387272500232882404725411489440703861,"CRTValues":[]}},"Onion":"kuzx57bbs6q7nymu","Groups":{}}}
{"Profile":{"Name":"alice","Ed25519PublicKey":"HePVPZDgQV5CPsKsfk8k9APAbFAaHo3h5IgcOLk8JkU=","Trusted":false,"Blocked":false,"Contacts":{},"Ed25519PrivateKey":"vW4vk9yJONpqLoooQrJLT3BsiJjNseagLkQelqIQppgd49U9kOBBXkI+wqx+TyT0A8BsUBoejeHkiBw4uTwmRQ==","OnionPrivateKey":{"N":124180052987038276908488971306097118499288790640484988517147166769877815582841930618153187145182425589345556238768813257991033435204827844882770722270092969225417271833713672261037744190852387384632814869090061694598739251480895491455885307591459276013910000175922066726291096488800388268492421362423280138243,"E":65537,"D":8323892957749960334757343957576401751184455456973168661303195196912785813440111711026549142145450594534309299432555604351047650653139581039260444984245820156701213023813296520282033216231123406154310401988822683123845588539154050789818510723459725427699399566036015352152852003341066008723635142189324534393,"Primes":[10318605891039665378109893427013360413384828451813995161940801274879978602208412774582196558435137474501959569416200754358158605387475412222231908504565973,12034576598653904425712782466302887117485091173704960260057943271715893247294740735187656822073438435145528143604740414620929110675044452637939150841583991],"Precomputed":{"Dp":1751913083442915553995892155002176805769763434141543313958760635756740801482719821517251340551257681596400569585029308539347708960532812179330369805305485,"Dq":11627835564337130720737672022387833102726565807121862361526909743375403088411089504151133028477566391355801045353607466539915973361080989821621113410604413,"Qinv":5168969236254874132993321993214963606790484960035248152574500117234718152121266178902971986905125868496286012732445791508496771810043600157469938696477522,"CRTValues":[]}},"Onion":"lxjwzgx5jwl7otgt","Groups":{}}}

Parādīt failu

@ -84,12 +84,13 @@ func (m *GroupMessage) GetSpamguard() []byte {
// and is only ever sent when encrypted in the ciphertext parameter of
// GroupMessage
type DecryptedGroupMessage struct {
Onion *string `protobuf:"bytes,1,req,name=onion" json:"onion,omitempty"`
Timestamp *int32 `protobuf:"varint,2,req,name=timestamp" json:"timestamp,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,5,req,name=signed_group_id,json=signedGroupId" json:"signed_group_id,omitempty"`
XXX_unrecognized []byte `json:"-"`
Onion *string `protobuf:"bytes,1,req,name=onion" json:"onion,omitempty"`
Timestamp *int32 `protobuf:"varint,2,req,name=timestamp" json:"timestamp,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,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:"-"`
}
func (m *DecryptedGroupMessage) Reset() { *m = DecryptedGroupMessage{} }
@ -132,6 +133,13 @@ func (m *DecryptedGroupMessage) GetSignedGroupId() []byte {
return nil
}
func (m *DecryptedGroupMessage) GetPreviousMessageSig() []byte {
if m != nil {
return m.PreviousMessageSig
}
return nil
}
var E_ServerNonce = &proto.ExtensionDesc{
ExtendedType: (*control.ChannelResult)(nil),
ExtensionType: ([]byte)(nil),
@ -152,26 +160,28 @@ func init() {
func init() { proto.RegisterFile("group_message.proto", fileDescriptor2) }
var fileDescriptor2 = []byte{
// 332 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x51, 0xdb, 0x4a, 0xf3, 0x30,
0x1c, 0xa7, 0x3b, 0xc0, 0xb7, 0xff, 0xba, 0x7d, 0x18, 0xa7, 0x06, 0x11, 0x29, 0xbd, 0x90, 0x5d,
0xed, 0xc2, 0x4b, 0x87, 0x20, 0x4c, 0x14, 0x41, 0x45, 0xea, 0x03, 0x8c, 0x90, 0xfe, 0xd7, 0x16,
0xdb, 0xa4, 0x24, 0xa9, 0x87, 0x37, 0xf0, 0x45, 0x7c, 0x1b, 0x1f, 0x4a, 0x9a, 0xee, 0x90, 0x7a,
0xe1, 0x55, 0xf8, 0x9d, 0x43, 0x02, 0xfb, 0x89, 0x92, 0x55, 0xb9, 0x2c, 0x50, 0x6b, 0x96, 0xe0,
0xac, 0x54, 0xd2, 0x48, 0xf2, 0xcf, 0x1e, 0x5c, 0xe6, 0xc7, 0x93, 0x85, 0x14, 0x46, 0xc9, 0x7c,
0x91, 0x32, 0x21, 0x30, 0x6f, 0xf4, 0xf0, 0xdb, 0x83, 0xbd, 0xc5, 0x9b, 0xe1, 0xe9, 0x33, 0xaa,
0x57, 0x54, 0x4f, 0x8c, 0xbf, 0xa0, 0x21, 0x73, 0x18, 0xb5, 0xca, 0xa8, 0x17, 0x78, 0xd3, 0xe1,
0xf9, 0xe1, 0x6c, 0xd3, 0x36, 0xbb, 0xad, 0xe5, 0x87, 0x46, 0x8d, 0xfc, 0xc4, 0x41, 0x75, 0x78,
0x85, 0x86, 0xa7, 0xdb, 0x70, 0xe7, 0x77, 0xf8, 0xa6, 0x96, 0xb7, 0xe1, 0x95, 0x83, 0xc8, 0x25,
0x8c, 0x5b, 0xcb, 0x9a, 0x76, 0x83, 0xee, 0x1f, 0xd3, 0x23, 0x77, 0x5a, 0x87, 0x63, 0xf0, 0xdd,
0xf2, 0xf0, 0x1e, 0x7c, 0xd7, 0x4e, 0x4e, 0x01, 0x78, 0x56, 0xa6, 0xa8, 0x0c, 0xbe, 0x1b, 0xea,
0x05, 0x9d, 0xa9, 0x1f, 0x39, 0x0c, 0x39, 0x81, 0x81, 0x2e, 0x59, 0x91, 0x54, 0x4c, 0xc5, 0xb4,
0x63, 0xe5, 0x1d, 0x11, 0x7e, 0x79, 0x70, 0x70, 0x8d, 0x5c, 0x7d, 0x94, 0x06, 0xe3, 0x56, 0xef,
0x04, 0xfa, 0x52, 0x64, 0x52, 0xd8, 0xca, 0x41, 0xd4, 0x80, 0xba, 0xcd, 0x64, 0x05, 0x6a, 0xc3,
0x8a, 0xd2, 0xb6, 0xf5, 0xa3, 0x1d, 0x41, 0x08, 0xf4, 0xec, 0x2d, 0xba, 0x36, 0xd2, 0xdb, 0xee,
0x67, 0x89, 0x60, 0xa6, 0x52, 0x48, 0x7b, 0xeb, 0xfd, 0x0d, 0x41, 0xce, 0xe0, 0x7f, 0x0d, 0x30,
0x5e, 0x36, 0x6f, 0x94, 0xc5, 0xb4, 0x6f, 0x3d, 0xa3, 0x86, 0xb6, 0x57, 0xba, 0x8b, 0x2f, 0xe6,
0xe0, 0x6b, 0xfb, 0x9d, 0x4b, 0x21, 0x05, 0x47, 0x72, 0xb4, 0x7b, 0xbc, 0xf5, 0xef, 0x47, 0xa8,
0xab, 0xdc, 0xd0, 0xcf, 0xab, 0xc0, 0x9b, 0xfa, 0xd1, 0xb0, 0x71, 0x3f, 0xd6, 0xe6, 0x9f, 0x00,
0x00, 0x00, 0xff, 0xff, 0xbf, 0x17, 0x09, 0x79, 0x47, 0x02, 0x00, 0x00,
// 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,
}

Parādīt failu

@ -30,4 +30,5 @@ message DecryptedGroupMessage {
required string text = 3;
required bytes signature = 4;
required bytes signed_group_id = 5;
required bytes previous_message_sig =6;
}

Parādīt failu

@ -16,6 +16,12 @@ type Guard struct {
nonce [24]byte
}
func getRandomness(arr *[24]byte) {
if _, err := io.ReadFull(rand.Reader, arr[:]); err != nil {
utils.CheckError(err)
}
}
//GenerateChallenge returns a channel result packet with a spamguard challenge nonce
func (sg *Guard) GenerateChallenge(channelID int32) []byte {
@ -25,9 +31,7 @@ func (sg *Guard) GenerateChallenge(channelID int32) []byte {
}
var nonce [24]byte
if _, err := io.ReadFull(rand.Reader, nonce[:]); err != nil {
utils.CheckError(err)
}
getRandomness(&nonce)
sg.nonce = nonce
err := proto.SetExtension(cr, protocol.E_ServerNonce, sg.nonce[:])
utils.CheckError(err)
@ -50,9 +54,7 @@ func (sg *Guard) SolveChallenge(challenge []byte, message []byte) []byte {
solve := make([]byte, len(challenge)+len(message)+len(spamguard))
for !solved {
if _, err := io.ReadFull(rand.Reader, spamguard[:]); err != nil {
utils.CheckError(err)
}
getRandomness(&spamguard)
copy(solve[0:], challenge[:])
copy(solve[len(challenge):], message[:])
@ -67,8 +69,6 @@ func (sg *Guard) SolveChallenge(challenge []byte, message []byte) []byte {
}
}
}
//log.Printf("Solved answer: %v %x %x\n", len(solve), solve, sum)
return spamguard[:]
}
@ -82,7 +82,7 @@ func (sg *Guard) ValidateChallenge(message []byte, spamguard []byte) bool {
copy(solve[len(sg.nonce):], message[:])
copy(solve[len(sg.nonce)+len(message):], spamguard[:])
sum := sha256.Sum256(solve)
//log.Printf("Got answer: %v %x %x\n", len(solve), solve, sum)
for i := 0; i < sg.Difficulty; i++ {
if sum[i] != 0x00 {
return false

Parādīt failu

@ -31,3 +31,39 @@ func TestSpamGuard(t *testing.T) {
t.Errorf("Failed SpamGaurd")
}
func TestSpamGuardBadLength(t *testing.T) {
var spamGuard Guard
spamGuard.Difficulty = 2
spamGuard.GenerateChallenge(3)
result := spamGuard.ValidateChallenge([]byte("test"), []byte{0x00, 0x00})
if result {
t.Errorf("Validating Guard should have failed")
}
}
func TestSpamGuardFail(t *testing.T) {
var spamGuard Guard
spamGuard.Difficulty = 2
challenge := spamGuard.GenerateChallenge(3)
control := new(Protocol_Data_Control.Packet)
proto.Unmarshal(challenge[:], control)
if control.GetChannelResult() != nil {
ce, _ := proto.GetExtension(control.GetChannelResult(), protocol.E_ServerNonce)
challenge := ce.([]byte)[:]
var spamGuard2 Guard
spamGuard2.Difficulty = 1
sgsolve := spamGuard2.SolveChallenge(challenge, []byte("Hello"))
t.Logf("Solved: %v %v", challenge, sgsolve)
result := spamGuard.ValidateChallenge([]byte("Hello"), sgsolve)
if result {
t.Errorf("Validating Guard successes")
}
return
}
t.Errorf("Failed SpamGaurd")
}

Parādīt failu

@ -1,9 +1,9 @@
package testing
import (
"git.mascherari.press/cwtch/peer"
"testing"
"time"
"git.mascherari.press/cwtch/peer"
)
func TestCwtchPeerIntegration(t *testing.T) {