@@ -69,11 +69,11 @@ import (
6969 "sync"
7070 "time"
7171
72- "code.google.com/p/go.crypto/curve25519"
7372 "code.google.com/p/goprotobuf/proto"
7473 "github.com/agl/ed25519"
7574 "github.com/agl/pond/bbssig"
7675 "github.com/agl/pond/client/disk"
76+ "github.com/agl/pond/client/ratchet"
7777 "github.com/agl/pond/panda"
7878 pond "github.com/agl/pond/protos"
7979)
@@ -200,6 +200,10 @@ type client struct {
200200 // nowFunc is a function that, if not nil, will be used by the GUI to
201201 // get the current time. This is used in testing.
202202 nowFunc func () time.Time
203+
204+ // simulateOldClient causes the client to act like a pre-ratchet client
205+ // for testing purposes.
206+ simulateOldClient bool
203207}
204208
205209// UI abstracts behaviour that is specific to a given interface (GUI or CLI).
@@ -406,11 +410,14 @@ type Contact struct {
406410 // exchange failed.
407411 pandaResult string
408412
409- lastDHPrivate [ 32 ] byte
410- currentDHPrivate [32 ]byte
411-
413+ // Members for the old ratchet.
414+ lastDHPrivate [32 ]byte
415+ currentDHPrivate [ 32 ] byte
412416 theirLastDHPublic [32 ]byte
413417 theirCurrentDHPublic [32 ]byte
418+
419+ // New ratchet support.
420+ ratchet * ratchet.Ratchet
414421}
415422
416423// previousTagLifetime contains the amount of time that we'll store a previous
@@ -679,7 +686,7 @@ func (c *client) loadUI() error {
679686 return nil
680687}
681688
682- func (contact * Contact ) processKeyExchange (kxsBytes []byte , testing bool ) error {
689+ func (contact * Contact ) processKeyExchange (kxsBytes []byte , testing , simulateOldClient bool ) error {
683690 var kxs pond.SignedKeyExchange
684691 if err := proto .Unmarshal (kxsBytes , & kxs ); err != nil {
685692 return err
@@ -723,10 +730,25 @@ func (contact *Contact) processKeyExchange(kxsBytes []byte, testing bool) error
723730 }
724731 copy (contact .theirIdentityPublic [:], kx .IdentityPublic )
725732
726- if len (kx .Dh ) != len (contact .theirCurrentDHPublic ) {
727- return errors .New ("invalid public DH value" )
733+ if simulateOldClient {
734+ kx .Dh1 = nil
735+ }
736+
737+ if len (kx .Dh1 ) == 0 {
738+ // They are using an old-style ratchet. We have to extract the
739+ // private value from the Ratchet in order to use it with the
740+ // old code.
741+ contact .lastDHPrivate = contact .ratchet .GetKXPrivateForTransition ()
742+ if len (kx .Dh ) != len (contact .theirCurrentDHPublic ) {
743+ return errors .New ("invalid public DH value" )
744+ }
745+ copy (contact .theirCurrentDHPublic [:], kx .Dh )
746+ contact .ratchet = nil
747+ } else {
748+ if err := contact .ratchet .CompleteKeyExchange (& kx ); err != nil {
749+ return err
750+ }
728751 }
729- copy (contact .theirCurrentDHPublic [:], kx .Dh )
730752
731753 contact .generation = * kx .Generation
732754
@@ -774,26 +796,34 @@ func (c *client) registerId(id uint64) {
774796 c .usedIds [id ] = true
775797}
776798
799+ func (c * client ) newRatchet (contact * Contact ) * ratchet.Ratchet {
800+ r := ratchet .New (c .rand )
801+ r .MyIdentityPrivate = & c .identity
802+ r .MySigningPublic = & c .pub
803+ r .TheirIdentityPublic = & contact .theirIdentityPublic
804+ r .TheirSigningPublic = & contact .theirPub
805+ return r
806+ }
807+
777808func (c * client ) newKeyExchange (contact * Contact ) {
778809 var err error
779- c .randBytes (contact .lastDHPrivate [:])
780- c .randBytes (contact .currentDHPrivate [:])
781-
782- var pub [32 ]byte
783- curve25519 .ScalarBaseMult (& pub , & contact .lastDHPrivate )
784810 if contact .groupKey , err = c .groupPriv .NewMember (c .rand ); err != nil {
785811 panic (err )
786812 }
813+ contact .ratchet = c .newRatchet (contact )
787814
788815 kx := & pond.KeyExchange {
789816 PublicKey : c .pub [:],
790817 IdentityPublic : c .identityPublic [:],
791818 Server : proto .String (c .server ),
792- Dh : pub [:],
793819 Group : contact .groupKey .Group .Marshal (),
794820 GroupKey : contact .groupKey .Marshal (),
795821 Generation : proto .Uint32 (c .generation ),
796822 }
823+ contact .ratchet .FillKeyExchange (kx )
824+ if c .simulateOldClient {
825+ kx .Dh1 = nil
826+ }
797827
798828 kxBytes , err := proto .Marshal (kx )
799829 if err != nil {
0 commit comments