From cb651a908f425b2c5d4f9152fd682ae67253ad92 Mon Sep 17 00:00:00 2001 From: Will Scott Date: Mon, 22 May 2017 12:08:43 -0700 Subject: [PATCH 1/4] shorter handle representation. --- drbg/seed.go | 9 ++++----- libtalek/handle.go | 39 +++++++++++++++++++++++++++++++++++++++ libtalek/handle_test.go | 21 +++++++++++++++++++++ libtalek/topic.go | 20 ++++++++++++++++++++ 4 files changed, 84 insertions(+), 5 deletions(-) diff --git a/drbg/seed.go b/drbg/seed.go index cc2a7ec..ecd7064 100644 --- a/drbg/seed.go +++ b/drbg/seed.go @@ -46,14 +46,13 @@ func (s *Seed) MarshalBinary() ([]byte, error) { return s.value[:], nil } -// MarshalJSON serializes the seed to JSON -// Implements the json.Marshaller interface -func (s *Seed) MarshalJSON() ([]byte, error) { +// MarshalText serializes the seed to textual representation +func (s *Seed) MarshalText() ([]byte, error) { return json.Marshal(s.value) } -// UnmarshalJSON restores the seed from a JSON representation. -func (s *Seed) UnmarshalJSON(data []byte) error { +// UnmarshalText restores the seed from a Text representation. +func (s *Seed) UnmarshalText(data []byte) error { if err := json.Unmarshal(data, &s.value); err != nil { return err } diff --git a/libtalek/handle.go b/libtalek/handle.go index 917ef0a..617b023 100644 --- a/libtalek/handle.go +++ b/libtalek/handle.go @@ -3,6 +3,7 @@ package libtalek import ( "encoding/binary" "errors" + "fmt" "io" "github.com/agl/ed25519" @@ -184,3 +185,41 @@ func (h *Handle) retrieveResponse(args *common.ReadArgs, reply *common.ReadReply } return nil } + +// MarshalText is a compact textual representation of a handle +func (h *Handle) MarshalText() ([]byte, error) { + s1, err := h.Seed1.MarshalBinary() + if err != nil { + return nil, err + } + s2, err := h.Seed2.MarshalBinary() + if err != nil { + return nil, err + } + txt := fmt.Sprintf("%x.%x.%x.%x.%d", s1, s2, *h.SharedSecret, *h.SigningPublicKey, h.Seqno) + return []byte(txt), nil +} + +// UnmarshalText restores a handle from its compact textual representation +func (h *Handle) UnmarshalText(text []byte) error { + var s1, s2, ss, pk []byte + if n, err := fmt.Sscanf(string(text), "%x.%x.%x.%x.%d", &s1, &s2, &ss, &pk, &h.Seqno); n < 4 || err != nil { + if err != nil { + return err + } + return errors.New("invalid handle") + } + h.SharedSecret = new([32]byte) + copy(h.SharedSecret[:], ss) + h.SigningPublicKey = new([32]byte) + copy(h.SigningPublicKey[:], pk) + h.Seed1 = &drbg.Seed{} + h.Seed2 = &drbg.Seed{} + if err := h.Seed1.UnmarshalBinary(s1); err != nil { + return err + } + if err := h.Seed2.UnmarshalBinary(s2); err != nil { + return err + } + return nil +} diff --git a/libtalek/handle_test.go b/libtalek/handle_test.go index 0601555..d70d903 100644 --- a/libtalek/handle_test.go +++ b/libtalek/handle_test.go @@ -1,6 +1,7 @@ package libtalek import ( + "bytes" "crypto/rand" "fmt" "testing" @@ -39,6 +40,26 @@ func TestGeneratePoll(t *testing.T) { fmt.Printf("... done \n") } +func TestSerialization(t *testing.T) { + topic, _ := NewTopic() + h := topic.Handle + + txt, err := h.MarshalText() + if err != nil { + t.Fatalf("Error serializing: %v\n", err) + } + fmt.Printf("Serialized handle looks like %s\n", txt) + + h2, _ := NewHandle() + err = h2.UnmarshalText(txt) + if err != nil { + t.Fatalf("Could not deserialize: %v\n", err) + } + if !bytes.Equal(h.SharedSecret[:], h2.SharedSecret[:]) { + t.Fatalf("serialization log info!") + } +} + func BenchmarkGeneratePollN10K(b *testing.B) { HelperBenchmarkGeneratePoll(b, 10000/4) } diff --git a/libtalek/topic.go b/libtalek/topic.go index 7625575..f46ae1b 100644 --- a/libtalek/topic.go +++ b/libtalek/topic.go @@ -1,8 +1,10 @@ package libtalek import ( + "bytes" "crypto/rand" "encoding/binary" + "fmt" "github.com/agl/ed25519" "github.com/privacylab/talek/common" @@ -111,3 +113,21 @@ func (t *Topic) encrypt(plaintext []byte, nonce *[24]byte) ([]byte, error) { digest := ed25519.Sign(t.SigningPrivateKey, buf) return append(buf, digest[:]...), nil } + +// MarshalText is a compact textual representation of a topic +func (t *Topic) MarshalText() ([]byte, error) { + handle, err := t.Handle.MarshalText() + if err != nil { + return nil, err + } + txt := fmt.Sprintf("%x.", *t.SigningPrivateKey) + return append([]byte(txt), handle...), nil +} + +// UnmarshalText restores a topic from its compact textual representation +func (t *Topic) UnmarshalText(text []byte) error { + parts := bytes.SplitN(text, []byte("."), 1) + t.SigningPrivateKey = new([64]byte) + copy(t.SigningPrivateKey[:], parts[0]) + return t.Handle.UnmarshalText(parts[1]) +} From ac6f0d293b3212b7f25bf6aca3cbd74be5dc2898 Mon Sep 17 00:00:00 2001 From: Will Scott Date: Fri, 26 May 2017 08:35:59 -0400 Subject: [PATCH 2/4] address review comments --- libtalek/handle.go | 2 +- libtalek/handle_test.go | 4 ++-- libtalek/topic.go | 13 +++++++++++-- libtalek/topic_test.go | 18 ++++++++++++++++++ 4 files changed, 32 insertions(+), 5 deletions(-) diff --git a/libtalek/handle.go b/libtalek/handle.go index 617b023..b663369 100644 --- a/libtalek/handle.go +++ b/libtalek/handle.go @@ -203,7 +203,7 @@ func (h *Handle) MarshalText() ([]byte, error) { // UnmarshalText restores a handle from its compact textual representation func (h *Handle) UnmarshalText(text []byte) error { var s1, s2, ss, pk []byte - if n, err := fmt.Sscanf(string(text), "%x.%x.%x.%x.%d", &s1, &s2, &ss, &pk, &h.Seqno); n < 4 || err != nil { + if n, err := fmt.Sscanf(string(text), "%x.%x.%x.%x.%d", &s1, &s2, &ss, &pk, &h.Seqno); n < 5 || err != nil { if err != nil { return err } diff --git a/libtalek/handle_test.go b/libtalek/handle_test.go index d70d903..e056180 100644 --- a/libtalek/handle_test.go +++ b/libtalek/handle_test.go @@ -55,8 +55,8 @@ func TestSerialization(t *testing.T) { if err != nil { t.Fatalf("Could not deserialize: %v\n", err) } - if !bytes.Equal(h.SharedSecret[:], h2.SharedSecret[:]) { - t.Fatalf("serialization log info!") + if !bytes.Equal(h.SharedSecret[:], h2.SharedSecret[:]) || !bytes.Equal(h.SigningPublicKey[:], h2.SigningPublicKey[:]) { + t.Fatalf("serialization lost info!") } } diff --git a/libtalek/topic.go b/libtalek/topic.go index f46ae1b..ddd003b 100644 --- a/libtalek/topic.go +++ b/libtalek/topic.go @@ -4,6 +4,7 @@ import ( "bytes" "crypto/rand" "encoding/binary" + "errors" "fmt" "github.com/agl/ed25519" @@ -126,8 +127,16 @@ func (t *Topic) MarshalText() ([]byte, error) { // UnmarshalText restores a topic from its compact textual representation func (t *Topic) UnmarshalText(text []byte) error { - parts := bytes.SplitN(text, []byte("."), 1) + parts := bytes.SplitN(text, []byte("."), 2) + if len(parts) != 2 { + return errors.New("unparsable topic representation") + } t.SigningPrivateKey = new([64]byte) - copy(t.SigningPrivateKey[:], parts[0]) + var spk []byte + _, err := fmt.Sscanf(string(parts[0]), "%x", &spk) + if err != nil { + return err + } + copy(t.SigningPrivateKey[:], spk) return t.Handle.UnmarshalText(parts[1]) } diff --git a/libtalek/topic_test.go b/libtalek/topic_test.go index af77ea8..2824475 100644 --- a/libtalek/topic_test.go +++ b/libtalek/topic_test.go @@ -48,6 +48,8 @@ func TestSerializeRestore(t *testing.T) { if err != nil { t.Fatalf("Error creating topic: %v\n", err) } + + // test binary encoder var network bytes.Buffer enc := gob.NewEncoder(&network) err = enc.Encode(topic) @@ -60,6 +62,22 @@ func TestSerializeRestore(t *testing.T) { if err != nil { t.Fatalf("Unable to restore topic: %v\n", err) } + + // test text encoder + txt, err := topic.MarshalText() + if err != nil { + t.Fatalf("Error serializing: %v\n", err) + } + fmt.Printf("Serialized topic looks like %s\n", txt) + + clone = Topic{} + err = clone.UnmarshalText(txt) + if err != nil { + t.Fatalf("Could not deserialize: %v\n", err) + } + if !bytes.Equal(topic.SigningPrivateKey[:], clone.SigningPrivateKey[:]) { + t.Fatalf("serialization lost info!") + } } func TestGeneratePublish(t *testing.T) { From 494d8594df99145fc4bf15121a893f2df53cf370 Mon Sep 17 00:00:00 2001 From: Will Scott Date: Fri, 26 May 2017 12:53:55 -0400 Subject: [PATCH 3/4] one more test catch --- libtalek/topic_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libtalek/topic_test.go b/libtalek/topic_test.go index 2824475..5605ab6 100644 --- a/libtalek/topic_test.go +++ b/libtalek/topic_test.go @@ -75,7 +75,7 @@ func TestSerializeRestore(t *testing.T) { if err != nil { t.Fatalf("Could not deserialize: %v\n", err) } - if !bytes.Equal(topic.SigningPrivateKey[:], clone.SigningPrivateKey[:]) { + if !bytes.Equal(topic.SigningPrivateKey[:], clone.SigningPrivateKey[:]) || !bytes.Equal(topic.Handle.SharedSecret[:], clone.Handle.SharedSecret[:]) { t.Fatalf("serialization lost info!") } } From f6389d569d08d38f09c44690f6e3a4e23a694cc9 Mon Sep 17 00:00:00 2001 From: Will Scott Date: Sat, 27 May 2017 10:20:50 -0400 Subject: [PATCH 4/4] Equal methods --- drbg/seed.go | 6 ++++++ libtalek/handle.go | 16 ++++++++++++++++ libtalek/handle_test.go | 5 ++--- libtalek/topic_test.go | 2 +- 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/drbg/seed.go b/drbg/seed.go index ecd7064..7c84648 100644 --- a/drbg/seed.go +++ b/drbg/seed.go @@ -1,6 +1,7 @@ package drbg import ( + "bytes" "crypto/rand" "encoding/binary" "encoding/json" @@ -62,6 +63,11 @@ func (s *Seed) UnmarshalText(data []byte) error { return nil } +// Equal is used to test equality of two drbg seeds. +func Equal(a, b *Seed) bool { + return bytes.Equal(a.value, b.value) +} + // Key provides the byte representation of the underlying key for the Seed func (s *Seed) Key() []byte { return s.value[:16] diff --git a/libtalek/handle.go b/libtalek/handle.go index b663369..80a74fc 100644 --- a/libtalek/handle.go +++ b/libtalek/handle.go @@ -1,6 +1,7 @@ package libtalek import ( + "bytes" "encoding/binary" "errors" "fmt" @@ -223,3 +224,18 @@ func (h *Handle) UnmarshalText(text []byte) error { } return nil } + +// Equal tests equality of two handles +func Equal(a, b *Handle) bool { + if a.Seqno != b.Seqno { + return false + } + if !bytes.Equal(a.SharedSecret[:], b.SharedSecret[:]) || + !bytes.Equal(a.SigningPublicKey[:], b.SigningPublicKey[:]) { + return false + } + if (drbg.Equal(a.Seed1, b.Seed1) && drbg.Equal(a.Seed2, b.Seed2)) || (drbg.Equal(a.Seed1, b.Seed2) && drbg.Equal(a.Seed2, b.Seed1)) { + return true + } + return false +} diff --git a/libtalek/handle_test.go b/libtalek/handle_test.go index e056180..4082a94 100644 --- a/libtalek/handle_test.go +++ b/libtalek/handle_test.go @@ -1,7 +1,6 @@ package libtalek import ( - "bytes" "crypto/rand" "fmt" "testing" @@ -55,8 +54,8 @@ func TestSerialization(t *testing.T) { if err != nil { t.Fatalf("Could not deserialize: %v\n", err) } - if !bytes.Equal(h.SharedSecret[:], h2.SharedSecret[:]) || !bytes.Equal(h.SigningPublicKey[:], h2.SigningPublicKey[:]) { - t.Fatalf("serialization lost info!") + if !Equal(&h, h2) { + t.Fatalf("Serialization lost info!") } } diff --git a/libtalek/topic_test.go b/libtalek/topic_test.go index 5605ab6..388b560 100644 --- a/libtalek/topic_test.go +++ b/libtalek/topic_test.go @@ -75,7 +75,7 @@ func TestSerializeRestore(t *testing.T) { if err != nil { t.Fatalf("Could not deserialize: %v\n", err) } - if !bytes.Equal(topic.SigningPrivateKey[:], clone.SigningPrivateKey[:]) || !bytes.Equal(topic.Handle.SharedSecret[:], clone.Handle.SharedSecret[:]) { + if !bytes.Equal(topic.SigningPrivateKey[:], clone.SigningPrivateKey[:]) || !Equal(&topic.Handle, &clone.Handle) { t.Fatalf("serialization lost info!") } }